* Automatically upgrade the Berkeley DB environment if necessary.
This commit is contained in:
parent
88dea78cdf
commit
8f57634c14
|
@ -165,12 +165,10 @@ static int my_fsync(int fd)
|
|||
}
|
||||
|
||||
|
||||
void Database::open(const string & path)
|
||||
void Database::open2(const string & path, bool removeOldEnv)
|
||||
{
|
||||
if (env) throw Error(format("environment already open"));
|
||||
|
||||
try {
|
||||
|
||||
debug(format("opening database environment"));
|
||||
|
||||
|
||||
|
@ -183,39 +181,37 @@ void Database::open(const string & path)
|
|||
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. */
|
||||
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). */
|
||||
/* 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. */
|
||||
shouldn't sync when DB_TXN_WRITE_NOSYNC is used, but it still
|
||||
fsync()s sometimes. */
|
||||
db_env_set_func_fsync(my_fsync);
|
||||
|
||||
|
||||
/* The following code provides automatic recovery of the
|
||||
database environment. Recovery is necessary when a process
|
||||
dies while it has the database open. To detect this,
|
||||
processes atomically increment a counter when they open the
|
||||
database, and decrement it when they close it. If we see
|
||||
that counter is > 0 but no processes are accessing the
|
||||
database---determined by attempting to obtain a write lock
|
||||
on a lock file on which all accessors have a read lock---we
|
||||
must run recovery. Note that this also ensures that we
|
||||
only run recovery when there are no other accessors (which
|
||||
could cause database corruption). */
|
||||
/* The following code provides automatic recovery of the database
|
||||
environment. Recovery is necessary when a process dies while
|
||||
it has the database open. To detect this, processes atomically
|
||||
increment a counter when they open the database, and decrement
|
||||
it when they close it. If we see that counter is > 0 but no
|
||||
processes are accessing the database---determined by attempting
|
||||
to obtain a write lock on a lock file on which all accessors
|
||||
have a read lock---we must run recovery. Note that this also
|
||||
ensures that we only run recovery when there are no other
|
||||
accessors (which could cause database corruption). */
|
||||
|
||||
/* !!! close fdAccessors / fdLock on exception */
|
||||
|
||||
|
@ -241,8 +237,14 @@ void Database::open(const string & path)
|
|||
|
||||
debug(format("write lock granted"));
|
||||
|
||||
/* We have a write lock, which means that there are no
|
||||
other readers or writers. */
|
||||
/* We have a write lock, which means that there are no other
|
||||
readers or writers. */
|
||||
|
||||
if (removeOldEnv) {
|
||||
printMsg(lvlError, "removing old Berkeley DB database environment...");
|
||||
env->remove(path.c_str(), DB_FORCE);
|
||||
return;
|
||||
}
|
||||
|
||||
int n = getAccessorCount(fdAccessors);
|
||||
|
||||
|
@ -284,8 +286,31 @@ void Database::open(const string & path)
|
|||
}
|
||||
|
||||
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. !!!
|
||||
there is some leakage here op DbEnv and lock
|
||||
handles. */
|
||||
open2(path, true);
|
||||
|
||||
/* Try again. */
|
||||
open2(path, false);
|
||||
}
|
||||
else
|
||||
rethrow(e);
|
||||
}
|
||||
|
||||
} catch (DbException e) { rethrow(e); }
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -58,6 +58,8 @@ private:
|
|||
|
||||
Db * getDb(TableId table);
|
||||
|
||||
void open2(const string & path, bool removeOldEnv);
|
||||
|
||||
public:
|
||||
Database();
|
||||
~Database();
|
||||
|
|
Loading…
Reference in a new issue