aboutsummaryrefslogtreecommitdiffstats
path: root/CommonLibs
diff options
context:
space:
mode:
Diffstat (limited to 'CommonLibs')
-rw-r--r--CommonLibs/Configuration.cpp193
-rw-r--r--CommonLibs/Configuration.h70
-rw-r--r--CommonLibs/ConfigurationTest.cpp40
3 files changed, 267 insertions, 36 deletions
diff --git a/CommonLibs/Configuration.cpp b/CommonLibs/Configuration.cpp
index 3ad4f01..7d0bea2 100644
--- a/CommonLibs/Configuration.cpp
+++ b/CommonLibs/Configuration.cpp
@@ -1,6 +1,7 @@
/*
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
+* Copyright 2011, 2012 Range Networks, Inc.
*
*
* This software is distributed under the terms of the GNU Affero Public License.
@@ -33,6 +34,7 @@
using namespace std;
+char gCmdName[20] = {0}; // Use a char* to avoid avoid static initialization of string, and race at startup.
static const char* createConfigTable = {
"CREATE TABLE IF NOT EXISTS CONFIG ("
@@ -45,19 +47,36 @@ static const char* createConfigTable = {
};
-ConfigurationTable::ConfigurationTable(const char* filename)
+
+float ConfigurationRecord::floatNumber() const
+{
+ float val;
+ sscanf(mValue.c_str(),"%f",&val);
+ return val;
+}
+
+
+ConfigurationTable::ConfigurationTable(const char* filename, const char *wCmdName, int wFacility)
+ :mFacility(wFacility)
{
+ syslog(LOG_INFO | mFacility, "opening configuration table from path %s", filename);
// Connect to the database.
int rc = sqlite3_open(filename,&mDB);
+ // (pat) When I used malloc here, sqlite3 sporadically crashes.
+ if (wCmdName) {
+ strncpy(gCmdName,wCmdName,18);
+ gCmdName[18] = 0;
+ strcat(gCmdName,":");
+ }
if (rc) {
- cerr << "Cannot open configuration database: " << sqlite3_errmsg(mDB);
+ syslog(LOG_EMERG | mFacility, "cannot open configuration database at %s, error message: %s", filename, sqlite3_errmsg(mDB));
sqlite3_close(mDB);
mDB = NULL;
return;
}
// Create the table, if needed.
if (!sqlite3_command(mDB,createConfigTable)) {
- cerr << "Cannot create configuration table:" << sqlite3_errmsg(mDB);
+ syslog(LOG_EMERG | mFacility, "cannot create configuration table in database at %s, error message: %s", filename, sqlite3_errmsg(mDB));
}
}
@@ -101,9 +120,6 @@ const ConfigurationRecord& ConfigurationTable::lookup(const string& key)
ConfigurationMap::const_iterator where = mCache.find(key);
if (where!=mCache.end()) {
if (where->second.defined()) return where->second;
- // Unlock the mutex before throwing the exception.
- mLock.unlock();
- syslog(LOG_ALERT, "configuration key %s not found", key.c_str());
throw ConfigurationTableKeyNotFound(key);
}
@@ -117,8 +133,6 @@ const ConfigurationRecord& ConfigurationTable::lookup(const string& key)
if (!value) {
// Cache the failure.
mCache[key] = ConfigurationRecord(false);
- // Unlock the mutex before throwing the exception.
- mLock.unlock();
throw ConfigurationTableKeyNotFound(key);
}
@@ -156,51 +170,134 @@ bool ConfigurationTable::isRequired(const string& key) const
string ConfigurationTable::getStr(const string& key)
{
// We need the lock because rec is a reference into the cache.
- ScopedLock lock(mLock);
- return lookup(key).value();
+ try {
+ ScopedLock lock(mLock);
+ return lookup(key).value();
+ } catch (ConfigurationTableKeyNotFound) {
+ // Raise an alert and re-throw the exception.
+ syslog(LOG_ALERT | mFacility, "configuration parameter %s has no defined value", key.c_str());
+ throw ConfigurationTableKeyNotFound(key);
+ }
}
string ConfigurationTable::getStr(const string& key, const char* defaultValue)
{
try {
- return getStr(key);
+ ScopedLock lock(mLock);
+ return lookup(key).value();
} catch (ConfigurationTableKeyNotFound) {
+ syslog(LOG_NOTICE | mFacility, "deinfing missing parameter %s with value %s", key.c_str(),defaultValue);
set(key,defaultValue);
return string(defaultValue);
}
}
+bool ConfigurationTable::getBool(const string& key)
+{
+ try {
+ return getNum(key) != 0;
+ } catch (ConfigurationTableKeyNotFound) {
+ return false;
+ }
+}
+
+
long ConfigurationTable::getNum(const string& key)
{
// We need the lock because rec is a reference into the cache.
- ScopedLock lock(mLock);
- return lookup(key).number();
+ try {
+ ScopedLock lock(mLock);
+ return lookup(key).number();
+ } catch (ConfigurationTableKeyNotFound) {
+ // Raise an alert and re-throw the exception.
+ syslog(LOG_ALERT | mFacility, "configuration parameter %s has no defined value", key.c_str());
+ throw ConfigurationTableKeyNotFound(key);
+ }
}
long ConfigurationTable::getNum(const string& key, long defaultValue)
{
try {
- return getNum(key);
+ ScopedLock lock(mLock);
+ return lookup(key).number();
} catch (ConfigurationTableKeyNotFound) {
+ syslog(LOG_NOTICE | mFacility, "deinfing missing parameter %s with value %ld", key.c_str(),defaultValue);
set(key,defaultValue);
return defaultValue;
}
}
+float ConfigurationTable::getFloat(const string& key)
+{
+ // We need the lock because rec is a reference into the cache.
+ ScopedLock lock(mLock);
+ return lookup(key).floatNumber();
+}
+
+std::vector<string> ConfigurationTable::getVectorOfStrings(const string& key)
+{
+ // Look up the string.
+ char *line=NULL;
+ try {
+ ScopedLock lock(mLock);
+ const ConfigurationRecord& rec = lookup(key);
+ line = strdup(rec.value().c_str());
+ } catch (ConfigurationTableKeyNotFound) {
+ // Raise an alert and re-throw the exception.
+ syslog(LOG_ALERT | mFacility, "configuration parameter %s has no defined value", key.c_str());
+ throw ConfigurationTableKeyNotFound(key);
+ }
+
+ assert(line);
+ char *lp = line;
+
+ // Parse the string.
+ std::vector<string> retVal;
+ while (lp) {
+ while (*lp==' ') lp++;
+ if (*lp == '\0') break;
+ char *tp = strsep(&lp," ");
+ if (!tp) break;
+ retVal.push_back(tp);
+ }
+ free(line);
+ return retVal;
+}
+
+
+std::vector<string> ConfigurationTable::getVectorOfStrings(const string& key, const char* defaultValue){
+ try {
+ return getVectorOfStrings(key);
+ } catch (ConfigurationTableKeyNotFound) {
+ set(key,defaultValue);
+ return getVectorOfStrings(key);
+ }
+}
+
+
std::vector<unsigned> ConfigurationTable::getVector(const string& key)
{
// Look up the string.
- mLock.lock();
- const ConfigurationRecord& rec = lookup(key);
- char* line = strdup(rec.value().c_str());
- mLock.unlock();
+ char *line=NULL;
+ try {
+ ScopedLock lock(mLock);
+ const ConfigurationRecord& rec = lookup(key);
+ line = strdup(rec.value().c_str());
+ } catch (ConfigurationTableKeyNotFound) {
+ // Raise an alert and re-throw the exception.
+ syslog(LOG_ALERT | mFacility, "configuration parameter %s has no defined value", key.c_str());
+ throw ConfigurationTableKeyNotFound(key);
+ }
+
+ assert(line);
+ char *lp = line;
+
// Parse the string.
std::vector<unsigned> retVal;
- char *lp=line;
while (lp) {
// Watch for multiple or trailing spaces.
while (*lp==' ') lp++;
@@ -228,6 +325,21 @@ bool ConfigurationTable::unset(const string& key)
return sqlite3_command(mDB,cmd.c_str());
}
+bool ConfigurationTable::remove(const string& key)
+{
+ assert(mDB);
+ if (isRequired(key)) return false;
+
+ ScopedLock lock(mLock);
+ // Clear the cache entry and the database.
+ ConfigurationMap::iterator where = mCache.find(key);
+ if (where!=mCache.end()) mCache.erase(where);
+ // Really remove it.
+ string cmd = "DELETE FROM CONFIG WHERE KEYSTRING=='"+key+"'";
+ return sqlite3_command(mDB,cmd.c_str());
+}
+
+
void ConfigurationTable::find(const string& pat, ostream& os) const
{
@@ -252,13 +364,7 @@ bool ConfigurationTable::set(const string& key, const string& value)
{
assert(mDB);
ScopedLock lock(mLock);
- // Is it there already?
- char * oldValue = NULL;
- bool exists = sqlite3_single_lookup(mDB,"CONFIG","KEYSTRING",key.c_str(),"VALUESTRING",oldValue);
- // Update or insert as appropriate.
- string cmd;
- if (exists) cmd = "UPDATE CONFIG SET VALUESTRING=\""+value+"\" WHERE KEYSTRING==\""+key+"\"";
- else cmd = "INSERT INTO CONFIG (KEYSTRING,VALUESTRING,OPTIONAL) VALUES (\"" + key + "\",\"" + value + "\",1)";
+ string cmd = "INSERT OR REPLACE INTO CONFIG (KEYSTRING,VALUESTRING,OPTIONAL) VALUES (\"" + key + "\",\"" + value + "\",1)";
bool success = sqlite3_command(mDB,cmd.c_str());
// Cache the result.
if (success) mCache[key] = ConfigurationRecord(value);
@@ -277,7 +383,7 @@ bool ConfigurationTable::set(const string& key)
{
assert(mDB);
ScopedLock lock(mLock);
- string cmd = "INSERT INTO CONFIG (KEYSTRING) VALUES (\"" + key + "\")";
+ string cmd = "INSERT OR REPLACE INTO CONFIG (KEYSTRING,VALUESTRING,OPTIONAL) VALUES (\"" + key + "\",NULL,1)";
bool success = sqlite3_command(mDB,cmd.c_str());
if (success) mCache[key] = ConfigurationRecord(true);
return success;
@@ -335,5 +441,38 @@ void HashString::computeHash()
}
+void SimpleKeyValue::addItem(const char* pair_orig)
+{
+ char *pair = strdup(pair_orig);
+ char *key = pair;
+ char *mark = strchr(pair,'=');
+ if (!mark) return;
+ *mark = '\0';
+ char *value = mark+1;
+ mMap[key] = value;
+ free(pair);
+}
+
+
+
+const char* SimpleKeyValue::get(const char* key) const
+{
+ HashStringMap::const_iterator p = mMap.find(key);
+ if (p==mMap.end()) return NULL;
+ return p->second.c_str();
+}
+
+
+void SimpleKeyValue::addItems(const char* pairs_orig)
+{
+ char *pairs = strdup(pairs_orig);
+ char *thisPair;
+ while ((thisPair=strsep(&pairs," "))!=NULL) {
+ addItem(thisPair);
+ }
+ free(pairs);
+}
+
+
// vim: ts=4 sw=4
diff --git a/CommonLibs/Configuration.h b/CommonLibs/Configuration.h
index c9c4cf3..0b14633 100644
--- a/CommonLibs/Configuration.h
+++ b/CommonLibs/Configuration.h
@@ -1,6 +1,6 @@
/*
* Copyright 2009, 2010 Free Software Foundation, Inc.
-* Copyright 2010 Kestrel Signal Processing, Inc.
+* Copyright 2010, 2012 Kestrel Signal Processing, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
@@ -32,6 +32,7 @@
#include <assert.h>
#include <stdlib.h>
+#include <syslog.h>
#include <map>
#include <vector>
@@ -44,6 +45,7 @@
/** A class for configuration file errors. */
class ConfigurationTableError {};
+extern char gCmdName[]; // Gotta be global, gotta be char*, gotta love it.
/** An exception thrown when a given config key isn't found. */
class ConfigurationTableKeyNotFound : public ConfigurationTableError {
@@ -56,7 +58,7 @@ class ConfigurationTableKeyNotFound : public ConfigurationTableError {
ConfigurationTableKeyNotFound(const std::string& wKey)
:mKey(wKey)
- { std::cerr << "cannot find configuration value " << mKey << std::endl; }
+ { }
const std::string& key() const { return mKey; }
@@ -94,6 +96,8 @@ class ConfigurationRecord {
long number() const { return mNumber; }
bool defined() const { return mDefined; }
+ float floatNumber() const;
+
};
@@ -176,11 +180,12 @@ class ConfigurationTable {
sqlite3* mDB; ///< database connection
ConfigurationMap mCache; ///< cache of recently access configuration values
mutable Mutex mLock; ///< control for multithreaded access to the cache
+ int mFacility;
public:
- ConfigurationTable(const char* filename = ":memory:");
+ ConfigurationTable(const char* filename = ":memory:", const char *wCmdName = 0, int wFacility = LOG_USER);
/** Return true if the key is used in the table. */
bool defines(const std::string& key);
@@ -212,12 +217,34 @@ class ConfigurationTable {
long getNum(const std::string& key);
/**
+ Get a boolean from the table.
+ Return false if NULL or 0, true otherwise.
+ */
+ bool getBool(const std::string& key);
+
+ /**
Get a numeric parameter from the table.
Define the parameter to the default value if not found.
*/
long getNum(const std::string& key, long defaultValue);
/**
+ Get a vector of strings from the table.
+ */
+ std::vector<std::string> getVectorOfStrings(const std::string& key);
+
+ /**
+ Get a vector of strings from the table, with a default value..
+ */
+ std::vector<std::string> getVectorOfStrings(const std::string& key, const char* defaultValue);
+
+ /**
+ Get a float from the table.
+ Throw ConfigurationTableKeyNotFound if not found.
+ */
+ float getFloat(const std::string& key);
+
+ /**
Get a numeric vector from the table.
*/
std::vector<unsigned> getVector(const std::string& key);
@@ -236,13 +263,21 @@ class ConfigurationTable {
bool set(const std::string& key);
/**
- Remove a key from the table.
- Will not remove static or required values.
- @param key The key of the item to be deleted.
- @return true if anything was actually removed.
+ Set a corresponding value to NULL.
+ Will not alter required values.
+ @param key The key of the item to be nulled-out.
+ @return true if anything was actually nulled-out.
*/
bool unset(const std::string& key);
+ /**
+ Remove an entry from the table.
+ Will not alter required values.
+ @param key The key of the item to be removed.
+ @return true if anything was actually removed.
+ */
+ bool remove(const std::string& key);
+
/** Search the table, dumping to a stream. */
void find(const std::string& pattern, std::ostream&) const;
@@ -268,6 +303,27 @@ class ConfigurationTable {
};
+typedef std::map<HashString, std::string> HashStringMap;
+
+class SimpleKeyValue {
+
+ protected:
+
+ HashStringMap mMap;
+
+ public:
+
+ /** Take a C string "A=B" and set map["A"]="B". */
+ void addItem(const char*);
+
+ /** Take a C string "A=B C=D E=F ..." and add all of the pairs to the map. */
+ void addItems(const char*s);
+
+ /** Return a reference to the string at map["key"]. */
+ const char* get(const char*) const;
+};
+
+
#endif
diff --git a/CommonLibs/ConfigurationTest.cpp b/CommonLibs/ConfigurationTest.cpp
index ef82601..5acb9d5 100644
--- a/CommonLibs/ConfigurationTest.cpp
+++ b/CommonLibs/ConfigurationTest.cpp
@@ -28,10 +28,11 @@
#include "Configuration.h"
#include <iostream>
+#include <string>
using namespace std;
-ConfigurationTable gConfig("exampleconfig.db");
+ConfigurationTable gConfig("exampleconfig.db","test",LOG_LOCAL7);
void purgeConfig(void*,int,char const*, char const*, sqlite3_int64)
{
@@ -61,9 +62,44 @@ int main(int argc, char *argv[])
cout << "defined table[" << keys[i] << "]=" << gConfig.defines(keys[i]) << endl;
}
- gConfig.set("key5","100 200 300 400");
+ gConfig.set("key5","100 200 300 400 ");
std::vector<unsigned> vect = gConfig.getVector("key5");
cout << "vect length " << vect.size() << ": ";
for (unsigned i=0; i<vect.size(); i++) cout << " " << vect[i];
cout << endl;
+ std::vector<string> svect = gConfig.getVectorOfStrings("key5");
+ cout << "vect length " << svect.size() << ": ";
+ for (unsigned i=0; i<svect.size(); i++) cout << " " << svect[i] << ":";
+ cout << endl;
+
+ cout << "bool " << gConfig.getBool("booltest") << endl;
+ gConfig.set("booltest",1);
+ cout << "bool " << gConfig.getBool("booltest") << endl;
+ gConfig.set("booltest",0);
+ cout << "bool " << gConfig.getBool("booltest") << endl;
+
+ gConfig.getStr("newstring","new string value");
+ gConfig.getNum("numnumber",42);
+
+
+ SimpleKeyValue pairs;
+ pairs.addItems(" a=1 b=34 dd=143 ");
+ cout<< pairs.get("a") << endl;
+ cout<< pairs.get("b") << endl;
+ cout<< pairs.get("dd") << endl;
+
+ gConfig.set("fkey","123.456");
+ float fval = gConfig.getFloat("fkey");
+ cout << "fkey " << fval << endl;
+
+ cout << "search fkey:" << endl;
+ gConfig.find("fkey",cout);
+ gConfig.unset("fkey");
+ cout << "search fkey:" << endl;
+ gConfig.find("fkey",cout);
+ gConfig.remove("fkey");
+ cout << "search fkey:" << endl;
+ gConfig.find("fkey",cout);
+
+ gConfig.getNum("supposedtoabort");
}