Skip to content

Commit 4bc4da3

Browse files
committed
Reserve some disk space for the garbage collector
We can't open a SQLite database if the disk is full. Since this prevents the garbage collector from running when it's most needed, we reserve some dummy space that we can free just before doing a garbage collection. This actually revives some old code from the Berkeley DB days. Fixes #27.
1 parent 2c26985 commit 4bc4da3

File tree

9 files changed

+35
-11
lines changed

9 files changed

+35
-11
lines changed

src/libstore/local-store.cc

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ void checkStoreNotSymlink()
195195
}
196196

197197

198-
LocalStore::LocalStore()
198+
LocalStore::LocalStore(bool reserveSpace)
199199
{
200200
substitutablePathsLoaded = false;
201201

@@ -221,6 +221,24 @@ LocalStore::LocalStore()
221221

222222
checkStoreNotSymlink();
223223

224+
/* We can't open a SQLite database if the disk is full. Since
225+
this prevents the garbage collector from running when it's most
226+
needed, we reserve some dummy space that we can free just
227+
before doing a garbage collection. */
228+
try {
229+
Path reservedPath = nixDBPath + "/reserved";
230+
if (reserveSpace) {
231+
int reservedSize = queryIntSetting("gc-reserved-space", 1024 * 1024);
232+
struct stat st;
233+
if (stat(reservedPath.c_str(), &st) == -1 ||
234+
st.st_size != reservedSize)
235+
writeFile(reservedPath, string(reservedSize, 'X'));
236+
}
237+
else
238+
deletePath(reservedPath);
239+
} catch (SysError & e) { /* don't care about errors */
240+
}
241+
224242
/* Acquire the big fat lock in shared mode to make sure that no
225243
schema upgrade is in progress. */
226244
try {

src/libstore/local-store.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public:
9191

9292
/* Initialise the local store, upgrading the schema if
9393
necessary. */
94-
LocalStore();
94+
LocalStore(bool reserveSpace = true);
9595

9696
~LocalStore();
9797

src/libstore/remote-store.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ RemoteStore::RemoteStore()
4343
}
4444

4545

46-
void RemoteStore::openConnection()
46+
void RemoteStore::openConnection(bool reserveSpace)
4747
{
4848
if (initialised) return;
4949
initialised = true;
@@ -75,6 +75,8 @@ void RemoteStore::openConnection()
7575
if (GET_PROTOCOL_MAJOR(daemonVersion) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION))
7676
throw Error("Nix daemon protocol version not supported");
7777
writeInt(PROTOCOL_VERSION, to);
78+
if (GET_PROTOCOL_MINOR(daemonVersion) >= 11)
79+
writeInt(reserveSpace, to);
7880
processStderr();
7981
}
8082
catch (Error & e) {
@@ -462,7 +464,7 @@ Roots RemoteStore::findRoots()
462464

463465
void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
464466
{
465-
openConnection();
467+
openConnection(false);
466468

467469
writeInt(wopCollectGarbage, to);
468470
writeInt(options.action, to);

src/libstore/remote-store.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ private:
8686
unsigned int daemonVersion;
8787
bool initialised;
8888

89-
void openConnection();
89+
void openConnection(bool reserveSpace = true);
9090

9191
void processStderr(Sink * sink = 0, Source * source = 0);
9292

src/libstore/store-api.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,10 @@ namespace nix {
322322
boost::shared_ptr<StoreAPI> store;
323323

324324

325-
boost::shared_ptr<StoreAPI> openStore()
325+
boost::shared_ptr<StoreAPI> openStore(bool reserveSpace)
326326
{
327327
if (getEnv("NIX_REMOTE") == "")
328-
return boost::shared_ptr<StoreAPI>(new LocalStore());
328+
return boost::shared_ptr<StoreAPI>(new LocalStore(reserveSpace));
329329
else
330330
return boost::shared_ptr<StoreAPI>(new RemoteStore());
331331
}

src/libstore/store-api.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ extern boost::shared_ptr<StoreAPI> store;
327327

328328
/* Factory method: open the Nix database, either through the local or
329329
remote implementation. */
330-
boost::shared_ptr<StoreAPI> openStore();
330+
boost::shared_ptr<StoreAPI> openStore(bool reserveSpace = true);
331331

332332

333333
/* Display a set of paths in human-readable form (i.e., between quotes

src/libstore/worker-protocol.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace nix {
88
#define WORKER_MAGIC_1 0x6e697863
99
#define WORKER_MAGIC_2 0x6478696f
1010

11-
#define PROTOCOL_VERSION 0x10a
11+
#define PROTOCOL_VERSION 0x10b
1212
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
1313
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
1414

src/nix-store/nix-store.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,7 @@ void run(Strings args)
843843
if (!op) throw UsageError("no operation specified");
844844

845845
if (op != opDump && op != opRestore) /* !!! hack */
846-
store = openStore();
846+
store = openStore(op != opGC);
847847

848848
op(opFlags, opArgs);
849849
}

src/nix-worker/nix-worker.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,8 +625,12 @@ static void processConnection()
625625
throw Error("if you run `nix-worker' as root, then you MUST set `build-users-group'!");
626626
#endif
627627

628+
bool reserveSpace = true;
629+
if (GET_PROTOCOL_MINOR(clientVersion) >= 11)
630+
reserveSpace = readInt(from) != 0;
631+
628632
/* Open the store. */
629-
store = boost::shared_ptr<StoreAPI>(new LocalStore());
633+
store = boost::shared_ptr<StoreAPI>(new LocalStore(reserveSpace));
630634

631635
stopWork();
632636
to.flush();

0 commit comments

Comments
 (0)