GlobalStore.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2004-2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
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 /* quiet */);
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     // if we're initializing the database for the first time, then we
00112     // prime the values accordingly and sync the database version
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         // store the new value
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             // YUCK
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     // we create a dummy Bundle and a Registration (and in the future
00196     // a link), then take their serialized form and MD5 it, such that
00197     // adding or deleting a field will change the digest
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     // make certain we don't attempt to write out globals before
00270     // load() has had a chance to load them from the database
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     // we prevent the potential for shutdown race crashes by leaving
00286     // the global store locked after it's been closed so other threads
00287     // will simply block, not crash due to a null store
00288     lock_->lock("GlobalStore::close");
00289     
00290     delete store_;
00291     store_ = NULL;
00292 
00293     delete instance_;
00294     instance_ = NULL;
00295 }
00296 
00297 } // namespace dtn

Generated on Sat Sep 8 08:43:28 2007 for DTN Reference Implementation by  doxygen 1.5.3