forked from facebookarchive/scribe
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConf.cpp
More file actions
330 lines (284 loc) · 9.3 KB
/
Copy pathConf.cpp
File metadata and controls
330 lines (284 loc) · 9.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
// Copyright (c) 2007-2008 Facebook
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// See accompanying file LICENSE or visit the Scribe site at:
// http://developers.facebook.com/scribe/
//
// @author Bobby Johnson
// @author Jason Sobel
// @author John Song
#include <boost/algorithm/string.hpp>
#include "Common.h"
#include "Conf.h"
#include "ScribeServer.h"
using namespace boost;
using namespace std;
namespace scribe {
StoreConf::StoreConf() {
}
StoreConf::~StoreConf() {
}
bool StoreConf::getStore(const string& storeName, StoreConfPtr* value) {
StoreConfMap::iterator iter = stores_.find(storeName);
if (iter != stores_.end()) {
*value = iter->second;
return true;
} else {
return false;
}
}
void StoreConf::setParent(StoreConfPtr parent) {
parent_ = parent;
}
void StoreConf::getAllStores(vector<StoreConfPtr>* value) {
for (StoreConfMap::iterator iter = stores_.begin();
iter != stores_.end();
++iter) {
value->push_back(iter->second);
}
}
bool StoreConf::getInt(const string& intName, long* value) const {
string str;
if (getString(intName, &str)) {
*value = lexical_cast<long>(str);
return true;
} else {
return false;
}
}
bool StoreConf::getFloat(const string& floatName, float* value) const {
string str;
if (getString(floatName, &str)) {
*value = lexical_cast<float>(str);
return true;
} else {
return false;
}
}
bool StoreConf::getUnsigned(const string& intName, unsigned long* value) const {
string str;
if (getString(intName, &str)) {
*value = lexical_cast<unsigned long>(str);
return true;
} else {
return false;
}
}
bool StoreConf::getUint64(const string& intName, uint64_t* value) const {
string str;
if (getString(intName, &str)) {
*value = lexical_cast<uint64_t>(str);
return true;
} else {
return false;
}
}
bool StoreConf::getString(const string& stringName, string* value) const {
// allow parameter inheritance, i.e. if a named value is not found in the
// current store's configuration, we keep looking up the current StoreConf's
// ancestors until it is either found or we hit the root store.
// To avoid ambiguity, when searching for named parameter in the ancestor
// store we are looking for $type::$stringName where $type is the store type.
// check the current store conf
// first check the current store
StringMap::const_iterator iter = values_.find(stringName);
if (iter != values_.end()) {
*value = iter->second;
return true;
}
// "category", "categories", "type" parameters can't be inherited
StringMap::const_iterator typeIt = values_.find("type");
string storeType = (typeIt == values_.end() ? "" : typeIt->second);
if (storeType.empty() ||
stringName == "type" ||
stringName == "category" ||
stringName == "categories") {
return false;
}
// not found
bool found = false;
string inheritedName = storeType + "::" + stringName;
// searching for type::stringName start with the current configuration
// this allows a parameter to be used by the current configuration
// and descendant stores. E.g.
// file::fs_type = std
// can be used by this file store and all descendant file stores.
for (const StoreConf* pconf = this; pconf;
pconf = const_cast<StoreConf*>(pconf->parent_.get())) {
StringMap::const_iterator iter = pconf->values_.find(inheritedName);
if (iter != pconf->values_.end()) {
*value = iter->second;
found = true;
break;
}
}
// if we didn't find any. then try g_handler's config
if (!found) {
const StoreConf& gconf = g_handler->getConfig();
StringMap::const_iterator iter = gconf.values_.find(inheritedName);
if (iter != gconf.values_.end()) {
*value = iter->second;
found = true;
}
}
return found;
}
void StoreConf::setString(const string& stringName, const string& value) {
values_[stringName] = value;
}
void StoreConf::setUnsigned(const string& stringName, unsigned long value) {
ostringstream oss;
oss << value;
setString(stringName, oss.str());
}
void StoreConf::setUint64(const string& stringName, uint64_t value) {
ostringstream oss;
oss << value;
setString(stringName, oss.str());
}
// reads and parses the config data
void StoreConf::parseConfig(const string& filename) {
queue<string> configStrings;
if (readConfFile(filename, &configStrings)) {
LOG_OPER("got configuration data from file <%s>", filename.c_str());
} else {
ostringstream msg;
msg << "Failed to open config file <" << filename << ">";
throw std::runtime_error(msg.str());
}
parseStore(configStrings, this);
}
// Side-effects: - removes items from rawConfig and adds items to parsedConfig
//
// Returns true if a valid entry was found
bool StoreConf::parseStore(queue<string>& rawConfig,
/*out*/ StoreConf* parsedConfig) {
int storeIndex = 0; // used to give things named "store" different names
string line;
while (!rawConfig.empty()) {
line = rawConfig.front();
rawConfig.pop();
// remove leading and trailing whitespace
line = trimString(line);
// remove comment
size_t comment = line.find_first_of('#');
if (comment != string::npos) {
line.erase(comment);
}
int length = line.size();
if (0 >= length) {
continue;
}
if (line[0] == '<') {
if (length > 1 && line[1] == '/') {
// This is the end of the current store
return true;
}
// This is the start of a new store
string::size_type pos = line.find('>');
if (pos == string::npos) {
LOG_OPER("Bad config - line %s has a < but not a >", line.c_str());
continue;
}
string storeName = line.substr(1, pos - 1);
StoreConfPtr newStore(new StoreConf);
if (parseStore(rawConfig, newStore.get())) {
if (0 == storeName.compare("store")) {
// This is a special case for the top-level stores. They share
// the same name, so we append an index to put them in the map
ostringstream oss;
oss << storeIndex;
storeName += oss.str();
++storeIndex;
}
StoreConfMap& stores = parsedConfig->stores_;
if (stores.find(storeName) != stores.end()) {
LOG_OPER("Bad config - duplicate store name %s", storeName.c_str());
}
stores[storeName] = newStore;
}
} else {
string::size_type eq = line.find('=');
if (eq == string::npos) {
LOG_OPER("Bad config - line %s is missing an =", line.c_str());
} else {
string arg = line.substr(0, eq);
string val = line.substr(eq + 1, string::npos);
// remove leading and trailing whitespace
arg = trimString(arg);
val = trimString(val);
if (parsedConfig->values_.find(arg) != parsedConfig->values_.end()) {
LOG_OPER("Bad config - duplicate key %s", arg.c_str());
}
parsedConfig->values_[arg] = val;
}
}
}
return true;
}
// trims leading and trailing whitespace from a string
string StoreConf::trimString(const string& str) {
string whitespace = " \t";
size_t start = str.find_first_not_of(whitespace);
size_t end = str.find_last_not_of(whitespace);
if (start != string::npos) {
return str.substr(start, end - start + 1);
} else {
return "";
}
}
// reads every line from the file and pushes then onto _return
// returns false on error
bool StoreConf::readConfFile(const string& filename, queue<string>* contents) {
string line;
ifstream configFile;
configFile.open(filename.c_str());
if (!configFile.good()) {
return false;
}
while (getline(configFile, line)) {
contents->push(line);
}
configFile.close();
return true;
}
// serialize StoreConf
ostream& operator<<(ostream& os, const StoreConf& storeConf) {
return storeConf.print(os, 0);
}
static string indent(uint32_t depth, bool useSpace, uint32_t tabWidth) {
int len = useSpace ? depth * tabWidth : depth;
return string(len, useSpace ? ' ' : '\t');
}
ostream& StoreConf::print(ostream& os, uint32_t depth,
bool useSpace, uint32_t tabWidth) const {
// we only need to iterator through keys. as map guaranteed keys
// are weakly ordered, so we will get consistent output.
for (StringMap::const_iterator iter = values_.begin();
iter != values_.end(); iter++) {
os << indent(depth, useSpace, tabWidth) << iter->first
<< "=" << iter->second << endl;
}
// print out sub stores
for (StoreConfMap::const_iterator iter = stores_.begin();
iter != stores_.end(); iter++) {
os << indent(depth, useSpace, tabWidth) << "<" << iter->first << ">"
<< endl;
iter->second->print(os, depth + 1, useSpace, tabWidth);
os << indent(depth, useSpace, tabWidth) << "</" << iter->first << ">"
<< endl;
}
return os;
}
} //! namespace scribe