00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 # include <dtn-config.h>
00019 #endif
00020
00021 #include <oasys/storage/DurableStore.h>
00022 #include <oasys/storage/StorageConfig.h>
00023 #include <oasys/serialize/TypeShims.h>
00024 #include <oasys/thread/Mutex.h>
00025 #include <oasys/util/MD5.h>
00026
00027 #include "GlobalStore.h"
00028 #include "bundling/Bundle.h"
00029 #include "reg/APIRegistration.h"
00030 #include "routing/ProphetNode.h"
00031
00032 namespace dtn {
00033
00034
00035 const u_int32_t GlobalStore::CURRENT_VERSION = 3;
00036 static const char* GLOBAL_TABLE = "globals";
00037 static const char* GLOBAL_KEY = "global_key";
00038
00039
00040 class Globals : public oasys::SerializableObject
00041 {
00042 public:
00043 Globals() {}
00044 Globals(const oasys::Builder&) {}
00045
00046 u_int32_t version_;
00047 u_int32_t next_bundleid_;
00048 u_int32_t next_regid_;
00049 u_char digest_[oasys::MD5::MD5LEN];
00050
00054 virtual void serialize(oasys::SerializeAction* a);
00055 };
00056
00057
00058 void
00059 Globals::serialize(oasys::SerializeAction* a)
00060 {
00061 a->process("version", &version_);
00062 a->process("next_bundleid", &next_bundleid_);
00063 a->process("next_regid", &next_regid_);
00064 a->process("digest", digest_, 16);
00065 }
00066
00067
00068 GlobalStore* GlobalStore::instance_;
00069
00070
00071 GlobalStore::GlobalStore()
00072 : Logger("GlobalStore", "/dtn/storage/%s", GLOBAL_TABLE),
00073 globals_(NULL), store_(NULL)
00074 {
00075 lock_ = new oasys::Mutex(logpath_,
00076 oasys::Mutex::TYPE_RECURSIVE,
00077 true );
00078 }
00079
00080
00081 int
00082 GlobalStore::init(const oasys::StorageConfig& cfg,
00083 oasys::DurableStore* store)
00084 {
00085 if (instance_ != NULL)
00086 {
00087 PANIC("GlobalStore::init called multiple times");
00088 }
00089
00090 instance_ = new GlobalStore();
00091 return instance_->do_init(cfg, store);
00092 }
00093
00094
00095 int
00096 GlobalStore::do_init(const oasys::StorageConfig& cfg,
00097 oasys::DurableStore* store)
00098 {
00099 int flags = 0;
00100
00101 if (cfg.init_) {
00102 flags |= oasys::DS_CREATE;
00103 }
00104
00105 int err = store->get_table(&store_, GLOBAL_TABLE, flags);
00106
00107 if (err != 0) {
00108 log_err("error initializing global store: %s",
00109 (err == oasys::DS_NOTFOUND) ?
00110 "table not found" :
00111 "unknown error");
00112 return err;
00113 }
00114
00115
00116
00117 if (cfg.init_)
00118 {
00119 log_info("initializing global table");
00120
00121 globals_ = new Globals();
00122
00123 globals_->version_ = CURRENT_VERSION;
00124 globals_->next_bundleid_ = 0;
00125 globals_->next_regid_ = Registration::MAX_RESERVED_REGID + 1;
00126 calc_digest(globals_->digest_);
00127
00128
00129 err = store_->put(oasys::StringShim(GLOBAL_KEY), globals_,
00130 oasys::DS_CREATE | oasys::DS_EXCL);
00131
00132 if (err == oasys::DS_EXISTS)
00133 {
00134
00135 log_err_p("/dtnd", "Initializing datastore which already exists.");
00136 exit(1);
00137 } else if (err != 0) {
00138 log_err_p("/dtnd", "unknown error initializing global store");
00139 return err;
00140 }
00141
00142 loaded_ = true;
00143
00144 } else {
00145 loaded_ = false;
00146 }
00147
00148 return 0;
00149 }
00150
00151
00152 GlobalStore::~GlobalStore()
00153 {
00154 delete store_;
00155 delete globals_;
00156 delete lock_;
00157 }
00158
00159
00160 u_int32_t
00161 GlobalStore::next_bundleid()
00162 {
00163 oasys::ScopeLock l(lock_, "GlobalStore::next_bundleid");
00164
00165 ASSERT(globals_->next_bundleid_ != 0xffffffff);
00166 log_debug("next_bundleid %d -> %d",
00167 globals_->next_bundleid_,
00168 globals_->next_bundleid_ + 1);
00169
00170 u_int32_t ret = globals_->next_bundleid_++;
00171
00172 update();
00173
00174 return ret;
00175 }
00176
00177
00178 u_int32_t
00179 GlobalStore::next_regid()
00180 {
00181 oasys::ScopeLock l(lock_, "GlobalStore::next_regid");
00182
00183 ASSERT(globals_->next_regid_ != 0xffffffff);
00184 log_debug("next_regid %d -> %d",
00185 globals_->next_regid_,
00186 globals_->next_regid_ + 1);
00187
00188 u_int32_t ret = globals_->next_regid_++;
00189
00190 update();
00191
00192 return ret;
00193 }
00194
00195
00196 void
00197 GlobalStore::calc_digest(u_char* digest)
00198 {
00199
00200
00201
00202 Bundle b(oasys::Builder::builder());
00203 APIRegistration r(oasys::Builder::builder());
00204 ProphetNode n(oasys::Builder::builder());
00205
00206 oasys::StringSerialize s(oasys::Serialize::CONTEXT_LOCAL,
00207 oasys::StringSerialize::INCLUDE_NAME |
00208 oasys::StringSerialize::INCLUDE_TYPE |
00209 oasys::StringSerialize::SCHEMA_ONLY);
00210
00211 s.action(&b);
00212 s.action(&r);
00213 s.action(&n);
00214
00215 oasys::MD5 md5;
00216 md5.update(s.buf().data(), s.buf().length());
00217 md5.finalize();
00218
00219 log_debug("calculated digest %s for serialize string '%s'",
00220 md5.digest_ascii().c_str(), s.buf().c_str());
00221
00222 memcpy(digest, md5.digest(), oasys::MD5::MD5LEN);
00223 }
00224
00225
00226 bool
00227 GlobalStore::load()
00228 {
00229 log_debug("loading global store");
00230
00231 oasys::StringShim key(GLOBAL_KEY);
00232
00233 if (globals_ != NULL) {
00234 delete globals_;
00235 globals_ = NULL;
00236 }
00237
00238 if (store_->get(key, &globals_) != 0) {
00239 log_crit("error loading global data");
00240 return false;
00241 }
00242 ASSERT(globals_ != NULL);
00243
00244 if (globals_->version_ != CURRENT_VERSION) {
00245 log_crit("datastore version mismatch: "
00246 "expected version %d, database version %d",
00247 CURRENT_VERSION, globals_->version_);
00248 return false;
00249 }
00250
00251 u_char digest[oasys::MD5::MD5LEN];
00252 calc_digest(digest);
00253
00254 if (memcmp(digest, globals_->digest_, oasys::MD5::MD5LEN) != 0) {
00255 log_crit("datastore digest mismatch: "
00256 "expected %s, database contains %s",
00257 oasys::hex2str(digest, oasys::MD5::MD5LEN).c_str(),
00258 oasys::hex2str(globals_->digest_, oasys::MD5::MD5LEN).c_str());
00259 log_crit("(implies serialized schema change)");
00260 return false;
00261 }
00262
00263 loaded_ = true;
00264 return true;
00265 }
00266
00267
00268 void
00269 GlobalStore::update()
00270 {
00271 ASSERT(lock_->is_locked_by_me());
00272
00273 log_debug("updating global store");
00274
00275
00276
00277 ASSERT(loaded_);
00278
00279 int err = store_->put(oasys::StringShim(GLOBAL_KEY), globals_, 0);
00280
00281 if (err != 0) {
00282 PANIC("GlobalStore::update fatal error updating database: %s",
00283 oasys::durable_strerror(err));
00284 }
00285 }
00286
00287
00288 void
00289 GlobalStore::close()
00290 {
00291
00292
00293
00294 lock_->lock("GlobalStore::close");
00295
00296 delete store_;
00297 store_ = NULL;
00298
00299 delete instance_;
00300 instance_ = NULL;
00301 }
00302
00303 }