9bd61c5d6a23f1d140fede162502268cdcd61db2
[ep-engine.git] / src / configuration.h
1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2011 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 #ifndef SRC_CONFIGURATION_H_
18 #define SRC_CONFIGURATION_H_ 1
19
20 #include "config.h"
21
22 #include <memcached/engine.h>
23
24 #include <iostream>
25 #include <limits>
26 #include <map>
27 #include <set>
28 #include <string>
29
30 #include "locks.h"
31 #include "utility.h"
32
33 /**
34  * The value changed listeners runs _without_ the global mutex for
35  * the configuration class, so you may access other configuration
36  * members from the callback.
37  * The callback is fired <b>after</b> the value is set, so if you
38  * want to prevent the caller from setting specific values you should
39  * use the ValueChangedValidator instead.
40  */
41 class ValueChangedListener {
42 public:
43     void valueChanged(const std::string& key, bool value) {
44         booleanValueChanged(key, value);
45     }
46
47     void valueChanged(const std::string& key, size_t value) {
48         sizeValueChanged(key, value);
49     }
50
51     void valueChanged(const std::string& key, ssize_t value) {
52         ssizeValueChanged(key, value);
53     }
54
55     void valueChanged(const std::string& key, float value) {
56         floatValueChanged(key, value);
57     }
58
59     void valueChanged(const std::string& key, std::string value) {
60         stringValueChanged(key, value.c_str());
61     }
62
63     void valueChanged(const std::string& key, const char* value) {
64         stringValueChanged(key, value);
65     }
66
67     /**
68      * Callback if when a boolean configuration value changed
69      * @param key the key who changed
70      * @param value the new value for the key
71      */
72     virtual void booleanValueChanged(const std::string &key, bool) {
73         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
74             " a boolean value", key.c_str());
75     }
76
77     /**
78      * Callback if when a numeric configuration value changed
79      * @param key the key who changed
80      * @param value the new value for the key
81      */
82     virtual void sizeValueChanged(const std::string &key, size_t) {
83         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
84             " a size value", key.c_str());
85     }
86
87     /**
88      * Callback if when a numeric configuration value changed
89      * @param key the key who changed
90      * @param value the new value for the key
91      */
92     virtual void ssizeValueChanged(const std::string &key, ssize_t) {
93         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
94             " a size value", key.c_str());
95     }
96
97     /**
98      * Callback if when a floatingpoint configuration value changed
99      * @param key the key who changed
100      * @param value the new value for the key
101      */
102     virtual void floatValueChanged(const std::string &key, float) {
103         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
104             " a floating point value", key.c_str());
105     }
106     /**
107      * Callback if when a string configuration value changed
108      * @param key the key who changed
109      * @param value the new value for the key
110      */
111     virtual void stringValueChanged(const std::string &key, const char *) {
112         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
113             " a string value", key.c_str());
114     }
115
116     virtual ~ValueChangedListener() { /* EMPTY */}
117 };
118
119 /**
120  * The validator for the values runs with the mutex held
121  * for the configuration class, so you can't try to access
122  * any other configuration variables from the callback
123  */
124 class ValueChangedValidator {
125 public:
126     void validate(const std::string& key, bool value) {
127         validateBool(key, value);
128     }
129
130     void validate(const std::string& key, size_t value) {
131         validateSize(key, value);
132     }
133
134     void validate(const std::string& key, ssize_t value) {
135         validateSSize(key, value);
136     }
137
138     void validate(const std::string& key, float value) {
139         validateFloat(key, value);
140     }
141
142     void validate(const std::string& key, const char* value) {
143         validateString(key, value);
144     }
145     void validate(const std::string& key, std::string value) {
146         validateString(key, value.c_str());
147     }
148
149     /**
150      * Validator for boolean values
151      * @param key the key that is about to change
152      * @param value the requested new value
153      * @throws runtime_error if the validation failed
154      */
155     virtual void validateBool(const std::string& key, bool) {
156         std::string error = "Configuration error.. " + key +
157                             " does not take a boolean parameter";
158         LOG(EXTENSION_LOG_DEBUG, "%s", error.c_str());
159         throw std::runtime_error(error);
160     }
161
162     /**
163      * Validator for a numeric value
164      * @param key the key that is about to change
165      * @param value the requested new value
166      * @throws runtime_error if the validation failed
167      */
168     virtual void validateSize(const std::string& key, size_t) {
169         std::string error = "Configuration error.. " + key +
170                             " does not take a size_t parameter";
171         LOG(EXTENSION_LOG_DEBUG, "%s", error.c_str());
172         throw std::runtime_error(error);
173     }
174
175     /**
176      * Validator for a signed numeric value
177      * @param key the key that is about to change
178      * @param value the requested new value
179      * @throws runtime_error if the validation failed
180      */
181     virtual void validateSSize(const std::string& key, ssize_t) {
182         std::string error = "Configuration error.. " + key +
183                             " does not take a ssize_t parameter";
184         LOG(EXTENSION_LOG_DEBUG, "%s", error.c_str());
185         throw std::runtime_error(error);
186     }
187
188     /**
189      * Validator for a floating point
190      * @param key the key that is about to change
191      * @param value the requested new value
192      * @throws runtime_error if the validation failed
193      */
194     virtual void validateFloat(const std::string& key, float) {
195         std::string error = "Configuration error.. " + key +
196                             " does not take a float parameter";
197         LOG(EXTENSION_LOG_DEBUG, "%s", error.c_str());
198         throw std::runtime_error(error);
199     }
200
201     /**
202      * Validator for a character string
203      * @param key the key that is about to change
204      * @param value the requested new value
205      * @throws runtime_error if the validation failed
206      */
207     virtual void validateString(const std::string& key, const char*) {
208         std::string error = "Configuration error.. " + key +
209                             " does not take a string parameter";
210         LOG(EXTENSION_LOG_DEBUG, "%s", error.c_str());
211         throw std::runtime_error(error);
212     }
213
214     virtual ~ValueChangedValidator() { }
215 };
216
217 /**
218  * A configuration input validator that ensures a numeric (size_t)
219  * value falls between a specified upper and lower limit.
220  */
221 class SizeRangeValidator : public ValueChangedValidator {
222 public:
223     SizeRangeValidator() : lower(0), upper(0) {}
224
225     SizeRangeValidator *min(size_t v) {
226         lower = v;
227         return this;
228     }
229
230     SizeRangeValidator *max(size_t v) {
231         upper = v;
232         return this;
233     }
234
235     virtual void validateSize(const std::string& key, size_t value) {
236         if (value < lower || value > upper) {
237             std::string error = "Validation Error, " + key +
238                                 " takes values between " +
239                                 std::to_string(lower) + " and " +
240                                 std::to_string(upper) + " (Got: " +
241                                 std::to_string(value) + ")";
242             throw std::range_error(error);
243         }
244     }
245
246     virtual void validateSSize(const std::string& key, ssize_t value) {
247         ssize_t s_lower = static_cast<ssize_t> (lower);
248         ssize_t s_upper = static_cast<ssize_t> (upper);
249
250         if (value < s_lower || value > s_upper) {
251             std::string error = "Validation Error, " + key +
252                                 " takes values between " +
253                                 std::to_string(s_lower) + " and " +
254                                 std::to_string(s_upper) + " (Got: " +
255                                 std::to_string(value) + ")";
256             throw std::range_error(error);
257         }
258     }
259 private:
260     size_t lower;
261     size_t upper;
262 };
263
264 /**
265  * A configuration input validator that ensures a signed numeric (ssize_t)
266  * value falls between a specified upper and lower limit.
267  */
268 class SSizeRangeValidator : public ValueChangedValidator {
269 public:
270     SSizeRangeValidator() : lower(0), upper(0) {}
271
272     SSizeRangeValidator* min(size_t v) {
273         lower = v;
274         return this;
275     }
276
277     SSizeRangeValidator* max(size_t v) {
278         upper = v;
279         return this;
280     }
281
282     virtual void validateSSize(const std::string& key, ssize_t value) {
283         if (value < lower || value > upper) {
284             std::string error = "Validation Error, " + key +
285                                 " takes values between " +
286                                 std::to_string(lower) + " and " +
287                                 std::to_string(upper) + " (Got: " +
288                                 std::to_string(value) + ")";
289             throw std::range_error(error);
290         }
291     }
292 private:
293     ssize_t lower;
294     ssize_t upper;
295 };
296
297 /**
298  * A configuration input validator that ensures that a numeric (float)
299  * value falls between a specified upper and lower limit.
300  */
301 class FloatRangeValidator : public ValueChangedValidator {
302 public:
303     FloatRangeValidator() : lower(0), upper(0) {}
304
305     FloatRangeValidator *min(float v) {
306         lower = v;
307         return this;
308     }
309
310     FloatRangeValidator *max(float v) {
311         upper = v;
312         return this;
313     }
314
315     virtual void validateFloat(const std::string& key, float value) {
316         if (value < lower || value > upper) {
317             std::string error = "Validation Error, " + key +
318                                 " takes values between " +
319                                 std::to_string(lower) + " and " +
320                                 std::to_string(upper) + " (Got: " +
321                                 std::to_string(value) + ")";
322             throw std::range_error(error);
323         }
324     }
325 private:
326     float lower;
327     float upper;
328 };
329
330 /**
331  * A configuration input validator that ensures that a value is one
332  * from a predefined set of acceptable values.
333  */
334 class EnumValidator : public ValueChangedValidator {
335 public:
336     EnumValidator() {}
337
338     EnumValidator *add(const char *s) {
339         acceptable.insert(std::string(s));
340         return this;
341     }
342
343     virtual void validateString(const std::string& key, const char* value) {
344         if (acceptable.find(std::string(value)) == acceptable.end()) {
345             std::string error = "Validation Error, " + key +
346                                 " takes one of [";
347             for (const auto& it : acceptable) {
348                 error += it + ", ";
349             }
350             if (acceptable.size() > 0) {
351                 error.pop_back();
352                 error.pop_back();
353             }
354
355             error += "] (Got: " + std::string(value) + ")";
356             throw std::range_error(error);
357         }
358     }
359
360 private:
361     std::set<std::string> acceptable;
362 };
363
364 class Requirement;
365
366 /**
367  * The configuration class represents and provides access to the
368  * entire configuration of the server.
369  */
370 class Configuration {
371 public:
372     struct value_t;
373
374     Configuration();
375     ~Configuration();
376
377     // Include the generated prototypes for the member functions
378 #include "generated_configuration.h" // NOLINT(*)
379
380     /**
381      * Parse a configuration string and set the local members
382      *
383      * @param str the string to parse
384      * @param sapi pointer to the server API
385      * @return true if success, false otherwise
386      */
387     bool parseConfiguration(const char *str, SERVER_HANDLE_V1* sapi);
388
389     /**
390      * Add all of the configuration variables as stats
391      * @param add_stat the callback to add statistics
392      * @param c the cookie for the connection who wants the stats
393      */
394     void addStats(ADD_STAT add_stat, const void *c) const;
395
396     /**
397      * Add a listener for changes for a key. The configuration class
398      * will release the memory for the ValueChangedListener by calling
399      * delete in it's destructor (so you have to allocate it by using
400      * new). There is no way to remove a ValueChangeListener.
401      *
402      * @param key the key to add the listener for
403      * @param val the listener that will receive all of the callbacks
404      *            when the value change.
405      */
406     void addValueChangedListener(const std::string &key,
407                                  ValueChangedListener *val);
408
409     /**
410      * Set a validator for a specific key. The configuration class
411      * will release the memory for the ValueChangedValidator by calling
412      * delete in its destructor (so you have to allocate it by using
413      * new). If a validator exists for the key, that will be returned
414      * (and it's up to the caller to release the memory for that
415      * validator).
416      *
417      * @param key the key to set the validator for
418      * @param validator the new validator
419      * @return the old validator (or NULL if there wasn't a validator)
420      */
421     ValueChangedValidator *setValueValidator(const std::string &key,
422                                              ValueChangedValidator *validator);
423     /**
424      * Adds an alias for a configuration. Values can be set in configuration
425      * under the original or aliased named, but setters/getters will only be
426      * generated for the main name.
427      *
428      * @param key the key to which the alias refers
429      * @param alias the new alias
430      */
431     void addAlias(const std::string& key, const std::string& alias);
432
433     /**
434      * Adds a prerequisite to a configuration option. This must be satisfied
435      * in order to set/get the config value or for it to appear in stats.
436      *
437      * @param key the key to set the requirement for
438      * @param requirement the requirement
439      */
440     Requirement* setRequirements(const std::string& key,
441                                  Requirement* requirement);
442
443     bool requirementsMet(const value_t& value) const;
444
445     void requirementsMetOrThrow(const std::string& key) const;
446
447 protected:
448     /**
449      * Set the configuration parameter for a given key to
450      * a new value (size_t, ssize_t, float, bool, string)
451      * @param key the key to specify
452      * @param value the new value
453      * @throws runtime_error if the validation failed
454      */
455     template <class T>
456     void setParameter(const std::string& key, T value);
457
458     /**
459      * Get the configuration parameter for a given key
460      * @param key the key to specify
461      * @return value the value
462      * @throws runtime_error if the validation failed
463      */
464     template <class T>
465     T getParameter(const std::string& key) const;
466
467 private:
468     void initialize();
469
470     // Access to the configuration variables is protected by the mutex
471     mutable std::mutex mutex;
472     std::map<std::string, std::shared_ptr<value_t>> attributes;
473
474     friend std::ostream& operator<< (std::ostream& out,
475                                      const Configuration &config);
476 };
477
478 // This specialisation is needed to convert char* to std::string to store in
479 // the variant.
480 template <>
481 void Configuration::setParameter<const char*>(const std::string& key,
482                                               const char* value);
483
484 #endif  // SRC_CONFIGURATION_H_