From 651ab439cf5b0c6ab2044257a30b0d94406d57d3 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 16 Feb 2006 13:19:15 +0000 Subject: [PATCH] * 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. --- src/libstore/store.cc | 16 +++++++++++++++- src/libstore/store.hh | 10 ++++++++-- src/nix-store/main.cc | 2 +- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/libstore/store.cc b/src/libstore/store.cc index 9c68c3392b..25e2d6e360 100644 --- a/src/libstore/store.cc +++ b/src/libstore/store.cc @@ -76,10 +76,24 @@ static void upgradeStore07(); static void upgradeStore09(); -void openDB() +void openDB(bool reserveSpace) { 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 { nixDB.open(nixDBPath); } catch (DbNoPermission & e) { diff --git a/src/libstore/store.hh b/src/libstore/store.hh index 2d8018d5fa..c617585bab 100644 --- a/src/libstore/store.hh +++ b/src/libstore/store.hh @@ -37,8 +37,14 @@ struct Substitute typedef list Substitutes; -/* Open the database environment. */ -void openDB(); +/* Open the database environment. If `reserveSpace' is true, make + 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. */ void initDB(); diff --git a/src/nix-store/main.cc b/src/nix-store/main.cc index 88e6720c02..0ee7b0a7e9 100644 --- a/src/nix-store/main.cc +++ b/src/nix-store/main.cc @@ -686,7 +686,7 @@ void run(Strings args) if (!op) throw UsageError("no operation specified"); if (op != opDump && op != opRestore) /* !!! hack */ - openDB(); + openDB(op != opGC); op(opFlags, opArgs); }