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