00001 #ifndef _MAP_CONFIG_H
00002 #define _MAP_CONFIG_H
00003
00004 #include "basemap.h"
00005 #include "TemplateMap.h"
00006 #include "m_map.h"
00007 #include "mhash_map.h"
00008 #include "mdb.h"
00009 #include "Log.h"
00010 #include "params.h"
00011
00018 class MapConfig {
00019 public:
00020
00021 static const std::string TREE;
00022 static const std::string HASH;
00023 static const std::string DB;
00024 static const std::string DBHASH;
00025 static const std::string DBMEM;
00026
00027
00028 static const std::string DB_DIR;
00029
00030
00031 static const std::string FILE;
00032
00033
00034 static const std::string AUTO_SYNC;
00035
00036
00037 static const std::string CACHE;
00038 static const std::string KEY_SIZE;
00039 static const std::string DATA_SIZE;
00040
00041 private:
00042 struct DbEnvInfo {
00043 DbEnv* env;
00044 size_t count;
00045
00046 DbEnvInfo() : env(0), count(0) { }
00047 };
00048
00049 typedef mace::map<std::string, DbEnvInfo, mace::SoftState> EnvInfoMap;
00050 static EnvInfoMap envs;
00051 static std::string dbsubdir;
00052
00053 public:
00054 template<typename Key, typename Data>
00055 static mace::Map<Key, Data>& open(const std::string& name,
00056 size_t keySize = 0, size_t dataSize = 0) {
00057 std::string type = params::get<std::string>(name, "");
00058 if (type.empty()) {
00059 if (params::get("MAP_CONFIG_DEFAULT", 0)) {
00060 type = TREE;
00061 }
00062 else {
00063 Log::err() << "no map config for " << name << Log::endl;
00064 ABORT("attempt to instantiate unconfigured map");
00065 }
00066 }
00067
00068 if (type == TREE) {
00069 return *(new mace::TemplateMap<mace::map<Key, Data> >());
00070 }
00071
00072
00073
00074 else if (type == DBMEM) {
00075 mace::DB<Key, Data>* db = new mace::DB<Key, Data>(keySize, dataSize);
00076 db->open();
00077 return *db;
00078 }
00079 else if (type == DB || type == DBHASH) {
00080 DBTYPE dbtype = DB_BTREE;
00081 if (type == DBHASH) {
00082 dbtype = DB_HASH;
00083 }
00084 std::string file;
00085 std::string dir;
00086 uint32_t cacheSize;
00087 parseDbPaths(name, file, dir, cacheSize, keySize, dataSize);
00088
00089 bool autosync = params::get(name + "." + AUTO_SYNC, true);
00090
00091 DbEnvInfo& dbi = envs[dir];
00092 mace::DB<Key, Data>* db;
00093
00094 if (dbi.env) {
00095 Log::log("MapConfig::open") << "opening DB " << file << " in dir "
00096 << dir << " count=" << dbi.count
00097 << Log::endl;
00098 db = new mace::DB<Key, Data>(dbi.env, autosync, keySize, dataSize);
00099 db->open(file, dbtype);
00100 }
00101 else {
00102 Log::log("MapConfig::open") << "opening DB " << file
00103 << " in dir " << dir
00104 << " with cache=" << cacheSize
00105 << " autosync=" << autosync
00106 << " with new env" << Log::endl;
00107 dbi.env = new DbEnv(0);
00108 db = new mace::DB<Key, Data>(dbi.env, cacheSize, autosync, keySize,
00109 dataSize);
00110 db->open(dir, file, dbtype, true);
00111 }
00112 dbi.count++;
00113
00114 return *db;
00115 }
00116 else {
00117 Log::err() << "unsupported map type: " << type << Log::endl;
00118 ABORT("unsupported map type");
00119 }
00120 }
00121
00122 template<typename T>
00123 static void close(const std::string& name, T& m) {
00124 Log::log("MapConfig::close") << "closing " << name << Log::endl;
00125 m.close();
00126 delete &m;
00127 if (params::get<std::string>(name, TREE) == DB) {
00128 std::string dir = parseDbDir(name);
00129 DbEnvInfo& dbi = envs[dir];
00130 if (dbi.count == 0) {
00131 Log::err() << "cannot find db info for " << name << " on close"
00132 << Log::endl;
00133 ABORT("db close");
00134 }
00135 dbi.count--;
00136 if (dbi.count == 0) {
00137 dbi.env->close(0);
00138 delete dbi.env;
00139 envs.erase(dir);
00140 Log::log("MapConfig::close") << "closed and erased env for " << dir
00141 << Log::endl;
00142 }
00143 if (envs.empty()) {
00144 Log::log("MapConfig::close") << "all DBs closed" << Log::endl;
00145 }
00146 }
00147 }
00148
00149
00150
00151
00152
00153
00154
00155 static void setDbSubdir(const std::string& s) {
00156 dbsubdir = s;
00157 }
00158
00159 static std::string parseDbDir(const std::string& name) {
00160 std::string file;
00161 std::string dir;
00162 uint32_t cache;
00163 size_t keySize;
00164 size_t dataSize;
00165 parseDbPaths(name, file, dir, cache, keySize, dataSize);
00166 return dir;
00167 }
00168
00169 static void parseDbPaths(const std::string& name, std::string& file,
00170 std::string& dir, uint32_t& cacheSize,
00171 size_t& keySize, size_t& dataSize) {
00172 file = params::get<std::string>(name + "." + FILE, "");
00173 if (file.empty()) {
00174 Log::err() << "no file defined for db " << name << Log::endl;
00175 ABORT("no file for db");
00176 }
00177 size_t i = file.rfind('/');
00178 if (i == std::string::npos) {
00179 dir = params::get<std::string>(DB_DIR, "");
00180 cacheSize = params::get(DB_DIR + "." + CACHE, 0);
00181 keySize = params::get(DB_DIR + "." + KEY_SIZE, keySize);
00182 dataSize = params::get(DB_DIR + "." + DATA_SIZE, dataSize);
00183 }
00184 else {
00185 dir = file.substr(0, i);
00186 file = file.substr(i + 1);
00187 cacheSize = params::get(name + "." + CACHE, 0);
00188 keySize = params::get(name + "." + KEY_SIZE, keySize);
00189 dataSize = params::get(name + "." + DATA_SIZE, dataSize);
00190 }
00191
00192 if (!dbsubdir.empty()) {
00193 dir += "/" + dbsubdir;
00194 }
00195
00196 if (dir.empty()) {
00197 Log::err() << "no db dir defined for db " << name << Log::endl;
00198 ABORT("no dir for db");
00199 }
00200 }
00201
00202 };
00203
00204
00205 #endif // _MAP_CONFIG_H