Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "hash_db.h"
00037
00038 #include "util/file.h"
00039 #include "perf/perf.h"
00040
00041 #include "datahash/datahash_text.h"
00042 #include "datahash/datahash_util.h"
00043
00044
00045 namespace hash_db {
00046
00047
00048 Database::~Database(void) throw() { }
00049
00050
00051 static const char * s_fileHeader =
00052 "#\n"
00053 "# hash_db::Database persistence file.\n"
00054 "#\n"
00055 "# This is a simple text-only file for persisting hashes transactionally.\n"
00056 "# Be careful about editing--the database objects use advisory locks on\n"
00057 "# this file so that only one process can access it at a time.\n"
00058 "#\n";
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 class DbImpl : public Database {
00074 public:
00075 ~DbImpl(void) throw() { }
00076
00077
00078 bool initialize(IN const char * path);
00079
00080
00081 void getIds(OUT SetString& ids);
00082 bool addObject(IN const char * id,
00083 IN smart_ptr<Datahash> obj);
00084 smart_ptr<Datahash> getObject(IN const char * id);
00085 bool deleteObject(IN const char * id);
00086 bool commit(void);
00087
00088 private:
00089
00090
00091
00092 std::string m_path;
00093 smart_ptr<Datahash> m_root;
00094 AdvisoryLock m_lock;
00095 };
00096
00097
00098
00099 bool
00100 DbImpl::initialize
00101 (
00102 IN const char * path
00103 )
00104 {
00105 perf::Timer timer("hash_db::initialize");
00106 ASSERT(path, "null path");
00107
00108
00109 std::string lockfile = path;
00110 lockfile += ".lock";
00111 createEmptyFileIfDoesNotExist(lockfile.c_str());
00112
00113
00114 #ifndef WIN32
00115 if (!m_lock.attemptLock(lockfile.c_str(), LOCK_EX | LOCK_NB)) {
00116 DPRINTF("Failed to get advisory lock on database file: '%s'",
00117 path);
00118 return false;
00119 }
00120 #endif // WIN32
00121
00122
00123 m_path = path;
00124 createEmptyFileIfDoesNotExist(path);
00125
00126
00127 m_root = readHashFromTextFile(path);
00128 if (!m_root) {
00129 DPRINTF("Failed to read hash from text file: corrupt?\n");
00130 return false;
00131 }
00132
00133
00134 return true;
00135 }
00136
00137
00138
00139 void
00140 DbImpl::getIds
00141 (
00142 OUT SetString& ids
00143 )
00144 {
00145 ASSERT(m_root, "null");
00146
00147 ids.clear();
00148
00149 Datahash::iterator_t i;
00150 m_root->getIterator(i);
00151 std::string k;
00152 hash_value_t hv;
00153 while (m_root->getNextElement(i, k, hv)) {
00154 const char * name = k.c_str();
00155
00156 ASSERT_THROW(eHashDataType_Hash == hv.type,
00157 "All root children should be complex (hash type)");
00158
00159 ids.insert(name);
00160 }
00161 }
00162
00163
00164
00165 bool
00166 DbImpl::addObject
00167 (
00168 IN const char * id,
00169 IN smart_ptr<Datahash> obj
00170 )
00171 {
00172 ASSERT(id, "null id");
00173 ASSERT(obj, "null object hash");
00174
00175 SetString ids;
00176 this->getIds(ids);
00177
00178 if (ids.end() != ids.find(id)) {
00179 DPRINTF("Not adding object: id already exists: '%s'", id);
00180 return false;
00181 }
00182
00183 m_root->insert(id, obj);
00184 return true;
00185 }
00186
00187
00188
00189 smart_ptr<Datahash>
00190 DbImpl::getObject
00191 (
00192 IN const char * id
00193 )
00194 {
00195 ASSERT(m_root, "null");
00196 ASSERT(id, "null");
00197
00198 if (!m_root->count(id)) {
00199 DPRINTF("Cannot get object--no such id '%s'", id);
00200 return 0;
00201 }
00202
00203 smart_ptr<Datahash> obj = getSubhash(m_root, id);
00204 ASSERT(obj, "null retrieval?");
00205
00206 return obj;
00207 }
00208
00209
00210
00211 bool
00212 DbImpl::deleteObject
00213 (
00214 IN const char * id
00215 )
00216 {
00217 ASSERT(m_root, "null");
00218 ASSERT(id, "null id to delete");
00219
00220 if (!m_root->count(id)) {
00221 DPRINTF("Cannot delete object--no such id '%s'", id);
00222 return false;
00223 }
00224
00225 m_root->remove(id);
00226
00227 return true;
00228 }
00229
00230
00231
00232 bool
00233 DbImpl::commit(void)
00234 {
00235 perf::Timer timer("hash_db::commit");
00236 ASSERT(m_root, "null");
00237
00238
00239 writeHashToTextFile(m_root, m_path.c_str(), s_fileHeader);
00240
00241 return true;
00242 }
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 smart_ptr<Database>
00254 Database::create
00255 (
00256 IN const char * path
00257 )
00258 {
00259 ASSERT(path, "null db path");
00260
00261 #ifdef WIN32
00262 ASSERT_THROW(false,
00263 "Hash databases are not supported under Windows -- no advisory locking");
00264 #endif // WIN32
00265
00266 smart_ptr<DbImpl> local = new DbImpl;
00267 ASSERT(local, "out of memory");
00268
00269 if (!local->initialize(path)) {
00270 DPRINTF("Failed to initialize hash_db!");
00271 return NULL;
00272 }
00273
00274 return local;
00275 }
00276
00277
00278
00279 };
00280