diff options
Diffstat (limited to 'src/libstore/db.cc')
-rw-r--r-- | src/libstore/db.cc | 474 |
1 files changed, 0 insertions, 474 deletions
diff --git a/src/libstore/db.cc b/src/libstore/db.cc deleted file mode 100644 index 26e82d695524..000000000000 --- a/src/libstore/db.cc +++ /dev/null @@ -1,474 +0,0 @@ -#include "config.h" - -#ifdef OLD_DB_COMPAT - -#include "db.hh" -#include "util.hh" -#include "pathlocks.hh" - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> - -#include <memory> - -#include <db_cxx.h> - - -namespace nix { - - -/* Wrapper class to ensure proper destruction. */ -class DestroyDbc -{ - Dbc * dbc; -public: - DestroyDbc(Dbc * _dbc) : dbc(_dbc) { } - ~DestroyDbc() { dbc->close(); /* close() frees dbc */ } -}; - - -class DestroyDbEnv -{ - DbEnv * dbenv; -public: - DestroyDbEnv(DbEnv * _dbenv) : dbenv(_dbenv) { } - ~DestroyDbEnv() { - if (dbenv) { - if (dbenv->get_DB_ENV()) dbenv->close(0); - delete dbenv; - } - } - void release() { dbenv = 0; }; -}; - - -static void rethrow(DbException & e) -{ - throw Error(e.what()); -} - - -Transaction::Transaction() - : txn(0) -{ -} - - -Transaction::Transaction(Database & db) - : txn(0) -{ - begin(db); -} - - -Transaction::~Transaction() -{ - if (txn) abort(); -} - - -void Transaction::begin(Database & db) -{ - assert(txn == 0); - db.requireEnv(); - try { - db.env->txn_begin(0, &txn, 0); - } catch (DbException e) { rethrow(e); } -} - - -void Transaction::commit() -{ - if (!txn) throw Error("commit called on null transaction"); - debug(format("committing transaction %1%") % (void *) txn); - DbTxn * txn2 = txn; - txn = 0; - try { - txn2->commit(0); - } catch (DbException e) { rethrow(e); } -} - - -void Transaction::abort() -{ - if (!txn) throw Error("abort called on null transaction"); - debug(format("aborting transaction %1%") % (void *) txn); - DbTxn * txn2 = txn; - txn = 0; - try { - txn2->abort(); - } catch (DbException e) { rethrow(e); } -} - - -void Transaction::moveTo(Transaction & t) -{ - if (t.txn) throw Error("target txn already exists"); - t.txn = txn; - txn = 0; -} - - -void Database::requireEnv() -{ - checkInterrupt(); - if (!env) throw Error("database environment is not open " - "(maybe you don't have sufficient permission?)"); -} - - -Db * Database::getDb(TableId table) -{ - if (table == 0) - throw Error("database table is not open " - "(maybe you don't have sufficient permission?)"); - std::map<TableId, Db *>::iterator i = tables.find(table); - if (i == tables.end()) - throw Error("unknown table id"); - return i->second; -} - - -Database::Database() - : env(0) - , nextId(1) -{ -} - - -Database::~Database() -{ - close(); -} - - -void openEnv(DbEnv * & env, const string & path, u_int32_t flags) -{ - try { - createDirs(path); - } catch (SysError & e) { - if (e.errNo == EPERM || e.errNo == EACCES) - throw DbNoPermission(format("cannot create the Nix database in `%1%'") % path); - else - throw; - } - - try { - env->open(path.c_str(), - DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | - DB_CREATE | flags, - 0666); - } catch (DbException & e) { - printMsg(lvlError, format("environment open failed: %1%") % e.what()); - throw; - } -} - - -static int my_fsync(int fd) -{ - return 0; -} - - -static void errorPrinter(const DbEnv * env, const char * errpfx, const char * msg) -{ - printMsg(lvlError, format("Berkeley DB error: %1%") % msg); -} - - -static void messagePrinter(const DbEnv * env, const char * msg) -{ - printMsg(lvlError, format("Berkeley DB message: %1%") % msg); -} - - -void Database::open2(const string & path, bool removeOldEnv) -{ - if (env) throw Error(format("environment already open")); - - debug(format("opening database environment")); - - - /* Create the database environment object. */ - DbEnv * env = new DbEnv(0); - DestroyDbEnv deleteEnv(env); - - env->set_errcall(errorPrinter); - env->set_msgcall(messagePrinter); - if (getEnv("NIX_DEBUG_DB_REGISTER") == "1") - env->set_verbose(DB_VERB_REGISTER, 1); - env->set_verbose(DB_VERB_RECOVERY, 1); - - /* Smaller log files. */ - env->set_lg_bsize(32 * 1024); /* default */ - env->set_lg_max(256 * 1024); /* must be > 4 * lg_bsize */ - - /* Write the log, but don't sync. This protects transactions - against application crashes, but if the system crashes, some - transactions may be undone. An acceptable risk, I think. */ - env->set_flags(DB_TXN_WRITE_NOSYNC | DB_LOG_AUTOREMOVE, 1); - - /* Increase the locking limits. If you ever get `Dbc::get: Cannot - allocate memory' or similar, especially while running - `nix-store --verify', just increase the following number, then - run db_recover on the database to remove the existing DB - environment (since changes only take effect on new - environments). */ - env->set_lk_max_locks(10000); - env->set_lk_max_lockers(10000); - env->set_lk_max_objects(10000); - env->set_lk_detect(DB_LOCK_DEFAULT); - - /* Dangerous, probably, but from the docs it *seems* that BDB - shouldn't sync when DB_TXN_WRITE_NOSYNC is used, but it still - fsync()s sometimes. */ - db_env_set_func_fsync(my_fsync); - - - if (removeOldEnv) { - printMsg(lvlError, "removing old Berkeley DB database environment..."); - env->remove(path.c_str(), DB_FORCE); - return; - } - - openEnv(env, path, DB_REGISTER | DB_RECOVER); - - deleteEnv.release(); - this->env = env; -} - - -void Database::open(const string & path) -{ - try { - - open2(path, false); - - } catch (DbException e) { - - if (e.get_errno() == DB_VERSION_MISMATCH) { - /* Remove the environment while we are holding the global - lock. If things go wrong there, we bail out. - !!! argh, we abolished the global lock :-( */ - open2(path, true); - - /* Try again. */ - open2(path, false); - - /* Force a checkpoint, as per the BDB docs. */ - env->txn_checkpoint(DB_FORCE, 0, 0); - - printMsg(lvlError, "database succesfully upgraded to new version"); - } - -#if 0 - else if (e.get_errno() == DB_RUNRECOVERY) { - /* If recovery is needed, do it. */ - printMsg(lvlError, "running recovery..."); - open2(path, false, true); - } -#endif - - else - rethrow(e); - } -} - - -void Database::close() -{ - if (!env) return; - - /* Close the database environment. */ - debug(format("closing database environment")); - - try { - - for (std::map<TableId, Db *>::iterator i = tables.begin(); - i != tables.end(); ) - { - std::map<TableId, Db *>::iterator j = i; - ++j; - closeTable(i->first); - i = j; - } - - /* Do a checkpoint every 128 kilobytes, or every 5 minutes. */ - env->txn_checkpoint(128, 5, 0); - - env->close(0); - - } catch (DbException e) { rethrow(e); } - - delete env; - - env = 0; -} - - -TableId Database::openTable(const string & tableName, bool sorted) -{ - requireEnv(); - TableId table = nextId++; - - try { - - Db * db = new Db(env, 0); - - try { - db->open(0, tableName.c_str(), 0, - sorted ? DB_BTREE : DB_HASH, - DB_CREATE | DB_AUTO_COMMIT, 0666); - } catch (...) { - delete db; - throw; - } - - tables[table] = db; - - } catch (DbException e) { rethrow(e); } - - return table; -} - - -void Database::closeTable(TableId table) -{ - try { - Db * db = getDb(table); - db->close(DB_NOSYNC); - delete db; - tables.erase(table); - } catch (DbException e) { rethrow(e); } -} - - -void Database::deleteTable(const string & table) -{ - try { - env->dbremove(0, table.c_str(), 0, DB_AUTO_COMMIT); - } catch (DbException e) { rethrow(e); } -} - - -bool Database::queryString(const Transaction & txn, TableId table, - const string & key, string & data) -{ - checkInterrupt(); - - try { - Db * db = getDb(table); - - Dbt kt((void *) key.c_str(), key.length()); - Dbt dt; - - int err = db->get(txn.txn, &kt, &dt, 0); - if (err) return false; - - if (!dt.get_data()) - data = ""; - else - data = string((char *) dt.get_data(), dt.get_size()); - - } catch (DbException e) { rethrow(e); } - - return true; -} - - -bool Database::queryStrings(const Transaction & txn, TableId table, - const string & key, Strings & data) -{ - string d; - if (!queryString(txn, table, key, d)) - return false; - data = unpackStrings(d); - return true; -} - - -void Database::setString(const Transaction & txn, TableId table, - const string & key, const string & data) -{ - checkInterrupt(); - try { - Db * db = getDb(table); - Dbt kt((void *) key.c_str(), key.length()); - Dbt dt((void *) data.c_str(), data.length()); - db->put(txn.txn, &kt, &dt, 0); - } catch (DbException e) { rethrow(e); } -} - - -void Database::setStrings(const Transaction & txn, TableId table, - const string & key, const Strings & data, bool deleteEmpty) -{ - if (deleteEmpty && data.size() == 0) - delPair(txn, table, key); - else - setString(txn, table, key, packStrings(data)); -} - - -void Database::delPair(const Transaction & txn, TableId table, - const string & key) -{ - checkInterrupt(); - try { - Db * db = getDb(table); - Dbt kt((void *) key.c_str(), key.length()); - db->del(txn.txn, &kt, 0); - /* Non-existence of a pair with the given key is not an - error. */ - } catch (DbException e) { rethrow(e); } -} - - -void Database::enumTable(const Transaction & txn, TableId table, - Strings & keys, const string & keyPrefix) -{ - try { - Db * db = getDb(table); - - Dbc * dbc; - db->cursor(txn.txn, &dbc, 0); - DestroyDbc destroyDbc(dbc); - - Dbt kt, dt; - u_int32_t flags = DB_NEXT; - - if (!keyPrefix.empty()) { - flags = DB_SET_RANGE; - kt = Dbt((void *) keyPrefix.c_str(), keyPrefix.size()); - } - - while (dbc->get(&kt, &dt, flags) != DB_NOTFOUND) { - checkInterrupt(); - string data((char *) kt.get_data(), kt.get_size()); - if (!keyPrefix.empty() && - string(data, 0, keyPrefix.size()) != keyPrefix) - break; - keys.push_back(data); - flags = DB_NEXT; - } - - } catch (DbException e) { rethrow(e); } -} - - -void Database::clearTable(const Transaction & txn, TableId table) -{ - try { - Db * db = getDb(table); - u_int32_t count; - db->truncate(txn.txn, &count, 0); - } catch (DbException e) { rethrow(e); } -} - - -} - -#endif |