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 */ 42class ValueChangedListener { 43public: 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 101class ValueChangedValidator { 102public: 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 170class SizeRangeValidator : public ValueChangedValidator { 171public: 172 SizeRangeValidator() : lower(0), upper(0) {} 173 174 SizeRangeValidator *min(size_t v) { 175 lower = v; 176 return this; 177 } 178 179 SizeRangeValidator *max(size_t v) { 180 upper = v; 181 return this; 182 } 183 184 virtual bool validateSize(const std::string &key, size_t value) { 185 (void)key; 186 return (value >= lower && value <= upper); 187 } 188 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 } 195private: 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 */ 204class FloatRangeValidator : public ValueChangedValidator { 205public: 206 FloatRangeValidator() : lower(0), upper(0) {} 207 208 FloatRangeValidator *min(float v) { 209 lower = v; 210 return this; 211 } 212 213 FloatRangeValidator *max(float v) { 214 upper = v; 215 return this; 216 } 217 218 virtual bool validateFloat(const std::string &key, float value) { 219 (void)key; 220 return (value >= lower && value <= upper); 221 } 222private: 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 */ 231class EnumValidator : public ValueChangedValidator { 232public: 233 EnumValidator() {} 234 235 EnumValidator *add(const char *s) { 236 acceptable.insert(std::string(s)); 237 return this; 238 } 239 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 245private: 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 */ 253class Configuration { 254public: 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 305protected: 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 355private: 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 { 364 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