Back to index

nordugrid-arc-nox  1.1.0~rc6
XmlContainer.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <iostream>
00006 
00007 #include <sys/stat.h>
00008 #include <sys/types.h>
00009 #include <glibmm.h>
00010 #ifdef WIN32
00011 #include <arc/win32.h>
00012 #endif
00013 
00014 #include "XmlContainer.h"
00015 
00016 namespace Arc
00017 {
00018 
00019 XmlContainer::XmlContainer(const std::string &db_path, const std::string &db_name):logger_(Arc::Logger::rootLogger, "DBXML")
00020 {
00021     env_ = NULL;
00022     db_ = NULL;
00023     update_tid_ = NULL;
00024     env_ = new DbEnv(0);
00025 
00026     if (!Glib::file_test(db_path, Glib::FILE_TEST_IS_DIR)) {
00027         if (mkdir(db_path.c_str(), 0700) != 0) {
00028             logger_.msg(Arc::ERROR, "cannot create directory: %s", db_path);
00029             return;
00030         }
00031     }
00032 
00033     env_->open(db_path.c_str(), DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN | DB_RECOVER | DB_THREAD, 0644);
00034     // setup internal deadlock detection mechanizm
00035     env_->set_lk_detect(DB_LOCK_DEFAULT);
00036     db_ = new Db(env_, 0);
00037     DbTxn *tid = NULL;
00038     try {
00039 #if (DB_VERSION_MAJOR < 4) || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0)
00040         db_->open(db_name.c_str(), NULL, DB_BTREE, DB_CREATE | DB_THREAD, 0644);
00041 #else
00042         env_->txn_begin(NULL, &tid, 0);
00043         db_->open(tid, db_name.c_str(), NULL, DB_BTREE, DB_CREATE | DB_THREAD, 0644);
00044         tid->commit(0);
00045 #endif
00046     } catch (DbException &e) {
00047         try {
00048             tid->abort();
00049             logger_.msg(Arc::ERROR, "Cannot open database");
00050         } catch (DbException &e) {
00051             logger_.msg(Arc::ERROR, "Cannot abort transaction %s", e.what()); 
00052         }
00053         db_ = NULL;
00054         return;
00055     }
00056 }
00057 
00058 XmlContainer::~XmlContainer()
00059 {
00060     if (db_ != NULL) {
00061         db_->close(0);
00062         delete db_;
00063         db_ = NULL;
00064     }
00065     if (env_ != NULL) {
00066         env_->close(0);
00067         delete env_;
00068         env_ = NULL;
00069     }
00070 }
00071 
00072 bool
00073 XmlContainer::put(const std::string &name, const std::string &content)
00074 {
00075     void *k = (void *)name.c_str();
00076     void *v = (void *)content.c_str();
00077     Dbt key(k, name.size() + 1);
00078     Dbt value(v, content.size() + 1);
00079     DbTxn *tid = NULL;
00080     while (true) {
00081         try {
00082             env_->txn_begin(NULL, &tid, 0);
00083             db_->put(tid, &key, &value, 0);
00084             tid->commit(0);
00085             return true;
00086 #ifdef HAVE_DBDEADLOCKEXCEPTION
00087         } catch (DbDeadlockException &e) {
00088             try { 
00089                 tid->abort();
00090                 logger_.msg(Arc::INFO, "put: deadlock handling: try again");
00091             } catch (DbException &e) {
00092                 logger_.msg(Arc::ERROR, "put: cannot abort transaction: %s", e.what());
00093                 return false;
00094             }
00095 #endif
00096         } catch (DbException &e) {
00097             logger_.msg(Arc::ERROR, "put: %s", e.what());
00098             try {
00099                 tid->abort();
00100             } catch (DbException &e) {
00101                 logger_.msg(Arc::ERROR, "put: cannot abort transaction: %s", e.what());
00102             }
00103             return false;
00104         }
00105     }
00106 }
00107 
00108 std::string
00109 XmlContainer::get(const std::string &name)
00110 {
00111     void *k = (void *)name.c_str();
00112     Dbt key(k, name.size() + 1);
00113     Dbt value;
00114     value.set_flags(DB_DBT_MALLOC);
00115     DbTxn *tid = NULL;
00116     while (true) {
00117         try {
00118             env_->txn_begin(NULL, &tid, 0);
00119             if (db_->get(tid, &key, &value, 0) != DB_NOTFOUND) {
00120                 std::string ret((char *)value.get_data());
00121                 free(value.get_data());
00122                 tid->commit(0);
00123                 return ret;
00124             }
00125             tid->commit(0);
00126             return "";
00127 #ifdef HAVE_DBDEADLOCKEXCEPTION
00128         } catch (DbDeadlockException &e) {
00129             try {
00130                 tid->abort();
00131                 logger_.msg(Arc::INFO, "get: deadlock handling, try again");
00132             } catch (DbException &e) {
00133                 logger_.msg(Arc::ERROR, "get: cannot abort transaction: %s", e.what());
00134                 return "";
00135             }
00136 #endif
00137         } catch (DbException &e) {
00138             logger_.msg(Arc::ERROR, "get: %s", e.what());
00139             try {
00140                 tid->abort();
00141             } catch (DbException &e) {
00142                 logger_.msg(Arc::ERROR, "get: cannot abort transaction: %s", e.what());
00143             }
00144             return "";
00145         }
00146     }
00147 }
00148 
00149 void
00150 XmlContainer::del(const std::string &name)
00151 {
00152     void *k = (void *)name.c_str();
00153     Dbt key(k, name.size() + 1);
00154     DbTxn *tid = NULL;
00155     try {
00156         env_->txn_begin(NULL, &tid, 0);
00157         db_->del(tid, &key, 0);
00158         tid->commit(0);
00159 #ifdef HAVE_DBDEADLOCKEXCEPTION
00160     } catch (DbDeadlockException &e) {
00161         try {
00162             tid->abort();
00163             logger_.msg(Arc::INFO, "del: deadlock handling, try again");
00164         } catch (DbException &e) {
00165             logger_.msg(Arc::ERROR, "del: cannot abort transaction: %s", e.what());
00166             return;
00167         }
00168 #endif
00169     } catch (DbException &e) {
00170         logger_.msg(Arc::ERROR, "del: %s", e.what());
00171         try {
00172             tid->abort();
00173         } catch (DbException &e) {
00174             logger_.msg(Arc::ERROR, "del: cannot abort transaction: %s", e.what());
00175         }
00176         return;
00177     }
00178     return;
00179 }
00180 
00181 void
00182 XmlContainer::start_update()
00183 {
00184 }
00185 
00186 void 
00187 XmlContainer::end_update()
00188 {
00189 }
00190 
00191 std::vector<std::string> 
00192 XmlContainer::get_doc_names()
00193 {
00194     Dbc *cursor = NULL;
00195     Dbt key, value;
00196     key.set_flags(0);
00197     value.set_flags(0);
00198     DbTxn *tid = NULL;
00199     std::vector<std::string> empty_result;
00200     while (true) {
00201         std::vector<std::string> result;
00202         // Looping through records in Berkeley DB in
00203         // transaction accumulates locks (sigh).
00204         // Usage patern seems not requiring cursor looping
00205         // to be protected by transaaction.
00206         // If You really need that uncomment following line.
00207         // env_->txn_begin(NULL, &tid, 0);
00208         try {
00209             db_->cursor(tid, &cursor, 0);
00210             int ret;
00211             for (;;) {
00212                 ret = cursor->get(&key, &value, DB_NEXT);
00213                 if (ret == DB_NOTFOUND) {
00214                     break;
00215                 }
00216                 char *k = (char *)key.get_data();
00217                 result.push_back(std::string(k));
00218             }
00219             cursor->close();
00220             if (tid != NULL) tid->commit(0);
00221             return result;
00222 #ifdef HAVE_DBDEADLOCKEXCEPTION
00223         } catch (DbDeadlockException &e) {
00224             try {
00225                 if (cursor != NULL) cursor->close();
00226                 if (tid != NULL) tid->abort();
00227                 logger_.msg(Arc::INFO, "get_doc_name: deadlock handling, try again");
00228             } catch (DbException &e) {
00229                 logger_.msg(Arc::ERROR, "get_doc_names: cannot abort transaction: %s", e.what());
00230                 return empty_result;
00231             }
00232 #endif
00233         } catch (DbException &e) {
00234             logger_.msg(Arc::ERROR, "Error during the transaction: %s", e.what());
00235             try {
00236                 if (cursor != NULL) cursor->close();
00237                 if (tid != NULL) tid->abort();
00238             } catch (DbException &e) {
00239                 logger_.msg(Arc::ERROR, "get_doc_names: cannot abort transaction: %s", e.what());
00240             }
00241             return empty_result;
00242         }
00243     }
00244 }
00245 
00246 void
00247 XmlContainer::checkpoint()
00248 {
00249     try {
00250         env_->txn_checkpoint(0, 0, 0);
00251     } catch(DbException &e) {
00252         logger_.msg(Arc::ERROR, "checkpoint: %s", e.what());
00253     }
00254 }
00255 
00256 } // namespace
00257