* A simple hack to fix NIX-18: the garbage collector cannot run when

the disk is full (because to delete something from the Nix store, we
  need a Berkeley DB transaction, which takes up disk space).  Under
  normal operation, we make sure that there exists a file
  /nix/var/nix/db/reserved of 1 MB.  When running the garbage
  collector, we delete that file before we open the Berkeley DB
  environment.
This commit is contained in:
Eelco Dolstra 2006-02-16 13:19:15 +00:00
parent d6f586d0ea
commit 651ab439cf
3 changed files with 24 additions and 4 deletions

View file

@ -76,10 +76,24 @@ static void upgradeStore07();
static void upgradeStore09(); static void upgradeStore09();
void openDB() void openDB(bool reserveSpace)
{ {
if (readOnlyMode) return; if (readOnlyMode) return;
try {
Path reservedPath = nixDBPath + "/reserved";
off_t reservedSize = 1024 * 1024;
if (reserveSpace) {
struct stat st;
if (stat(reservedPath.c_str(), &st) == -1 ||
st.st_size != reservedSize)
writeFile(reservedPath, string(1024 * 1024, 'X'));
}
else
deletePath(reservedPath);
} catch (SysError & e) { /* don't care about errors */
}
try { try {
nixDB.open(nixDBPath); nixDB.open(nixDBPath);
} catch (DbNoPermission & e) { } catch (DbNoPermission & e) {

View file

@ -37,8 +37,14 @@ struct Substitute
typedef list<Substitute> Substitutes; typedef list<Substitute> Substitutes;
/* Open the database environment. */ /* Open the database environment. If `reserveSpace' is true, make
void openDB(); sure that a big empty file exists in /nix/var/nix/db/reserved. If
`reserveSpace' is false, delete this file if it exists. The idea
is that on normal operation, the file exists; but when we run the
garbage collector, it is deleted. This is to ensure that the
garbage collector has a small amount of disk space available, which
is required to open the Berkeley DB environment. */
void openDB(bool reserveSpace = true);
/* Create the required database tables. */ /* Create the required database tables. */
void initDB(); void initDB();

View file

@ -686,7 +686,7 @@ void run(Strings args)
if (!op) throw UsageError("no operation specified"); if (!op) throw UsageError("no operation specified");
if (op != opDump && op != opRestore) /* !!! hack */ if (op != opDump && op != opRestore) /* !!! hack */
openDB(); openDB(op != opGC);
op(opFlags, opArgs); op(opFlags, opArgs);
} }