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 <algorithm>
25 #include <iostream>
26 #include <limits>
27 #include <map>
28 #include <set>
29 #include <string>
30 #include <vector>
31 
32 #include "locks.h"
33 
34 /**
35  * The value changed listeners runs _without_ the global mutex for
36  * the configuration class, so you may access other configuration
37  * members from the callback.
38  * The callback is fired <b>after</b> the value is set, so if you
39  * want to prevent the caller from setting specific values you should
40  * use the ValueChangedValidator instead.
41  */
42 class ValueChangedListener {
43 public:
44     /**
45      * Callback if when a boolean configuration value changed
46      * @param key the key who changed
47      * @param value the new value for the key
48      */
booleanValueChanged(const std::string &key, bool)49     virtual void booleanValueChanged(const std::string &key, bool) {
50         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
51             " a boolean value", key.c_str());
52     }
53 
54     /**
55      * Callback if when a numeric configuration value changed
56      * @param key the key who changed
57      * @param value the new value for the key
58      */
sizeValueChanged(const std::string &key, size_t)59     virtual void sizeValueChanged(const std::string &key, size_t) {
60         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
61             " a size value", key.c_str());
62     }
63 
64     /**
65      * Callback if when a numeric configuration value changed
66      * @param key the key who changed
67      * @param value the new value for the key
68      */
ssizeValueChanged(const std::string &key, ssize_t)69     virtual void ssizeValueChanged(const std::string &key, ssize_t) {
70         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
71             " a size value", key.c_str());
72     }
73 
74     /**
75      * Callback if when a floatingpoint configuration value changed
76      * @param key the key who changed
77      * @param value the new value for the key
78      */
floatValueChanged(const std::string &key, float)79     virtual void floatValueChanged(const std::string &key, float) {
80         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
81             " a floating point value", key.c_str());
82     }
83     /**
84      * Callback if when a string configuration value changed
85      * @param key the key who changed
86      * @param value the new value for the key
87      */
stringValueChanged(const std::string &key, const char *)88     virtual void stringValueChanged(const std::string &key, const char *) {
89         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not expect"
90             " a string value", key.c_str());
91     }
92 
~ValueChangedListener()93     virtual ~ValueChangedListener() { /* EMPTY */}
94 };
95 
96 /**
97  * The validator for the values runs with the mutex held
98  * for the configuration class, so you can't try to access
99  * any other configuration variables from the callback
100  */
101 class ValueChangedValidator {
102 public:
103     /**
104      * Validator for boolean values
105      * @param key the key that is about to change
106      * @param value the requested new value
107      * @return true the value is ok, false the value is not ok
108      */
validateBool(const std::string &key, bool)109     virtual bool validateBool(const std::string &key, bool) {
110         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not take"
111             " a boolean parameter", key.c_str());
112         return false;
113     }
114 
115     /**
116      * Validator for a numeric value
117      * @param key the key that is about to change
118      * @param value the requested new value
119      * @return true the value is ok, false the value is not ok
120      */
validateSize(const std::string &key, size_t)121     virtual bool validateSize(const std::string &key, size_t) {
122         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not take"
123             " a size_t parameter", key.c_str());
124         return false;
125     }
126 
127     /**
128      * Validator for a signed numeric value
129      * @param key the key that is about to change
130      * @param value the requested new value
131      * @return true the value is ok, false the value is not ok
132      */
validateSSize(const std::string &key, ssize_t)133     virtual bool validateSSize(const std::string &key, ssize_t) {
134         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not take"
135             " a ssize_t parameter", key.c_str());
136         return false;
137     }
138 
139     /**
140      * Validator for a floating point
141      * @param key the key that is about to change
142      * @param value the requested new value
143      * @return true the value is ok, false the value is not ok
144      */
validateFloat(const std::string &key, float)145     virtual bool validateFloat(const std::string &key, float) {
146         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not take"
147             " a floating point parameter", key.c_str());
148         return false;
149     }
150 
151     /**
152      * Validator for a character string
153      * @param key the key that is about to change
154      * @param value the requested new value
155      * @return true the value is ok, false the value is not ok
156      */
validateString(const std::string &key, const char *)157     virtual bool validateString(const std::string &key, const char *) {
158         LOG(EXTENSION_LOG_DEBUG, "Configuration error.. %s does not take"
159             " a character string", key.c_str());
160         return false;
161     }
162 
~ValueChangedValidator()163     virtual ~ValueChangedValidator() { }
164 };
165 
166 /**
167  * A configuration input validator that ensures a numeric (size_t)
168  * value falls between a specified upper and lower limit.
169  */
170 class SizeRangeValidator : public ValueChangedValidator {
171 public:
SizeRangeValidator()172     SizeRangeValidator() : lower(0), upper(0) {}
173 
min(size_t v)174     SizeRangeValidator *min(size_t v) {
175         lower = v;
176         return this;
177     }
178 
max(size_t v)179     SizeRangeValidator *max(size_t v) {
180         upper = v;
181         return this;
182     }
183 
validateSize(const std::string &key, size_t value)184     virtual bool validateSize(const std::string &key, size_t value) {
185         (void)key;
186         return (value >= lower && value <= upper);
187     }
188 
validateSSize(const std::string &key, ssize_t value)189     virtual bool validateSSize(const std::string &key, ssize_t value) {
190         (void)key;
191         ssize_t s_lower = static_cast<ssize_t> (lower);
192         ssize_t s_upper = static_cast<ssize_t> (upper);
193         return (value >= s_lower && value <= s_upper);
194     }
195 private:
196     size_t lower;
197     size_t upper;
198 };
199 
200 /**
201  * A configuration input validator that ensures that a numeric (float)
202  * value falls between a specified upper and lower limit.
203  */
204 class FloatRangeValidator : public ValueChangedValidator {
205 public:
FloatRangeValidator()206     FloatRangeValidator() : lower(0), upper(0) {}
207 
min(float v)208     FloatRangeValidator *min(float v) {
209         lower = v;
210         return this;
211     }
212 
max(float v)213     FloatRangeValidator *max(float v) {
214         upper = v;
215         return this;
216     }
217 
validateFloat(const std::string &key, float value)218     virtual bool validateFloat(const std::string &key, float value) {
219         (void)key;
220         return (value >= lower && value <= upper);
221     }
222 private:
223     float lower;
224     float upper;
225 };
226 
227 /**
228  * A configuration input validator that ensures that a value is one
229  * from a predefined set of acceptable values.
230  */
231 class EnumValidator : public ValueChangedValidator {
232 public:
EnumValidator()233     EnumValidator() {}
234 
add(const char *s)235     EnumValidator *add(const char *s) {
236         acceptable.insert(std::string(s));
237         return this;
238     }
239 
validateString(const std::string &key, const char *value)240     virtual bool validateString(const std::string &key, const char *value) {
241         (void)key;
242         return acceptable.find(std::string(value)) != acceptable.end();
243     }
244 
245 private:
246     std::set<std::string> acceptable;
247 };
248 
249 /**
250  * The configuration class represents and provides access to the
251  * entire configuration of the server.
252  */
253 class Configuration {
254 public:
255     Configuration();
256     ~Configuration();
257 
258     // Include the generated prototypes for the member functions
259 #include "generated_configuration.h" // NOLINT(*)
260 
261     /**
262      * Parse a configuration string and set the local members
263      *
264      * @param str the string to parse
265      * @param sapi pointer to the server API
266      * @return true if success, false otherwise
267      */
268     bool parseConfiguration(const char *str, SERVER_HANDLE_V1* sapi);
269 
270     /**
271      * Add all of the configuration variables as stats
272      * @param add_stat the callback to add statistics
273      * @param c the cookie for the connection who wants the stats
274      */
275     void addStats(ADD_STAT add_stat, const void *c) const;
276 
277     /**
278      * Add a listener for changes for a key. The configuration class
279      * will release the memory for the ValueChangedListner by calling
280      * delete in it's destructor (so you have to allocate it by using
281      * new). There is no way to remove a valueChangeListner.
282      *
283      * @param key the key to add the listener for
284      * @param val the listener that will receive all of the callbacks
285      *            when the value change.
286      */
287     void addValueChangedListener(const std::string &key,
288                                  ValueChangedListener *val);
289 
290     /**
291      * Set a validator for a specific key. The configuration class
292      * will release the memory for the ValueChangedValidator by calling
293      * delete in its destructor (so you have to allocate it by using
294      * new). If a validator exists for the key, that will be returned
295      * (and it's up to the caller to release the memory for that
296      * validator).
297      *
298      * @param key the key to set the validator for
299      * @param validator the new validator
300      * @return the old validator (or NULL if there wasn't a validator)
301      */
302     ValueChangedValidator *setValueValidator(const std::string &key,
303                                              ValueChangedValidator *validator);
304 
305 protected:
306     /**
307      * Set the configuration parameter for a given key to
308      * a boolean value.
309      * @param key the key to specify
310      * @param value the new value
311      * @throws std::string if the value is refused by the validator
312      */
313     void setParameter(const std::string &key, bool value);
314     /**
315      * Set the configuration parameter for a given key to
316      * a size_t value.
317      * @param key the key to specify
318      * @param value the new value
319      * @throws std::string if the value is refused by the validator
320      */
321     void setParameter(const std::string &key, size_t value);
322     /**
323      * Set the configuration parameter for a given key to
324      * a ssize_t value.
325      * @param key the key to specify
326      * @param value the new value
327      * @throws std::string if the value is refused by the validator
328      */
329     void setParameter(const std::string &key, ssize_t value);
330     /**
331      * Set the configuration parameter for a given key to
332      * a floating value.
333      * @param key the key to specify
334      * @param value the new value
335      * @throws std::string if the value is refused by the validator
336      */
337     void setParameter(const std::string &key, float value);
338     /**
339      * Set the configuration parameter for a given key to
340      * a character string
341      * @param key the key to specify
342      * @param value the new value
343      * @throws std::string if the value is refused by the validator
344      */
345     void setParameter(const std::string &key, const char *value);
346     /**
347      * Set the configuration parameter for a given key to
348      * a string.
349      * @param key the key to specify
350      * @param value the new value
351      * @throws std::string if the value is refused by the validator
352      */
353     void setParameter(const std::string &key, const std::string &value);
354 
355 private:
356     void initialize();
357     std::string getString(const std::string &key) const;
358     bool getBool(const std::string &key) const;
359     float getFloat(const std::string &key) const;
360     size_t getInteger(const std::string &key) const;
361     ssize_t getSignedInteger(const std::string &key) const;
362 
363     struct value_t {
value_tConfiguration::value_t364         value_t() : validator(NULL) { val.v_string = 0; }
365         std::vector<ValueChangedListener *> changeListener;
366         ValueChangedValidator *validator;
367         config_datatype datatype;
368         union {
369             size_t v_size;
370             ssize_t v_ssize;
371             float v_float;
372             bool v_bool;
373             const char *v_string;
374         } val;
375     };
376 
377     // Access to the configuration variables is protected by the mutex
378     Mutex mutex;
379     std::map<std::string, value_t> attributes;
380 
381     friend std::ostream& operator<< (std::ostream& out,
382                                      const Configuration &config);
383 };
384 
385 #endif  // SRC_CONFIGURATION_H_
386