Skip to content

Commit b932ea5

Browse files
committed
GC: Don't delete own temproots file
Since file locks are per-process rather than per-file-descriptor, the garbage collector would always acquire a lock on its own temproots file and conclude that it's stale.
1 parent 8215b75 commit b932ea5

File tree

3 files changed

+34
-34
lines changed

3 files changed

+34
-34
lines changed

src/libstore/gc.cc

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ namespace nix {
1818

1919

2020
static string gcLockName = "gc.lock";
21-
static string tempRootsDir = "temproots";
2221
static string gcRootsDir = "gcroots";
2322

2423

@@ -153,30 +152,25 @@ void LocalStore::addTempRoot(const Path & path)
153152
if (!state->fdTempRoots) {
154153

155154
while (1) {
156-
Path dir = (format("%1%/%2%") % stateDir % tempRootsDir).str();
157-
createDirs(dir);
158-
159-
state->fnTempRoots = (format("%1%/%2%") % dir % getpid()).str();
160-
161155
AutoCloseFD fdGCLock = openGCLock(ltRead);
162156

163-
if (pathExists(state->fnTempRoots))
157+
if (pathExists(fnTempRoots))
164158
/* It *must* be stale, since there can be no two
165159
processes with the same pid. */
166-
unlink(state->fnTempRoots.c_str());
160+
unlink(fnTempRoots.c_str());
167161

168-
state->fdTempRoots = openLockFile(state->fnTempRoots, true);
162+
state->fdTempRoots = openLockFile(fnTempRoots, true);
169163

170164
fdGCLock = -1;
171165

172-
debug(format("acquiring read lock on '%1%'") % state->fnTempRoots);
166+
debug(format("acquiring read lock on '%1%'") % fnTempRoots);
173167
lockFile(state->fdTempRoots.get(), ltRead, true);
174168

175169
/* Check whether the garbage collector didn't get in our
176170
way. */
177171
struct stat st;
178172
if (fstat(state->fdTempRoots.get(), &st) == -1)
179-
throw SysError(format("statting '%1%'") % state->fnTempRoots);
173+
throw SysError(format("statting '%1%'") % fnTempRoots);
180174
if (st.st_size == 0) break;
181175

182176
/* The garbage collector deleted this file before we could
@@ -188,14 +182,14 @@ void LocalStore::addTempRoot(const Path & path)
188182

189183
/* Upgrade the lock to a write lock. This will cause us to block
190184
if the garbage collector is holding our lock. */
191-
debug(format("acquiring write lock on '%1%'") % state->fnTempRoots);
185+
debug(format("acquiring write lock on '%1%'") % fnTempRoots);
192186
lockFile(state->fdTempRoots.get(), ltWrite, true);
193187

194188
string s = path + '\0';
195189
writeFull(state->fdTempRoots.get(), s);
196190

197191
/* Downgrade to a read lock. */
198-
debug(format("downgrading to read lock on '%1%'") % state->fnTempRoots);
192+
debug(format("downgrading to read lock on '%1%'") % fnTempRoots);
199193
lockFile(state->fdTempRoots.get(), ltRead, true);
200194
}
201195

@@ -204,11 +198,10 @@ void LocalStore::readTempRoots(PathSet & tempRoots, FDs & fds)
204198
{
205199
/* Read the `temproots' directory for per-process temporary root
206200
files. */
207-
DirEntries tempRootFiles = readDirectory(
208-
(format("%1%/%2%") % stateDir % tempRootsDir).str());
201+
DirEntries tempRootFiles = readDirectory(tempRootsDir);
209202

210203
for (auto & i : tempRootFiles) {
211-
Path path = (format("%1%/%2%/%3%") % stateDir % tempRootsDir % i.name).str();
204+
Path path = tempRootsDir + "/" + i.name;
212205

213206
debug(format("reading temporary root file '%1%'") % path);
214207
FDPtr fd(new AutoCloseFD(open(path.c_str(), O_CLOEXEC | O_RDWR, 0666)));
@@ -222,21 +215,25 @@ void LocalStore::readTempRoots(PathSet & tempRoots, FDs & fds)
222215
//FDPtr fd(new AutoCloseFD(openLockFile(path, false)));
223216
//if (*fd == -1) continue;
224217

225-
/* Try to acquire a write lock without blocking. This can
226-
only succeed if the owning process has died. In that case
227-
we don't care about its temporary roots. */
228-
if (lockFile(fd->get(), ltWrite, false)) {
229-
printError(format("removing stale temporary roots file '%1%'") % path);
230-
unlink(path.c_str());
231-
writeFull(fd->get(), "d");
232-
continue;
233-
}
218+
if (path != fnTempRoots) {
234219

235-
/* Acquire a read lock. This will prevent the owning process
236-
from upgrading to a write lock, therefore it will block in
237-
addTempRoot(). */
238-
debug(format("waiting for read lock on '%1%'") % path);
239-
lockFile(fd->get(), ltRead, true);
220+
/* Try to acquire a write lock without blocking. This can
221+
only succeed if the owning process has died. In that case
222+
we don't care about its temporary roots. */
223+
if (lockFile(fd->get(), ltWrite, false)) {
224+
printError(format("removing stale temporary roots file '%1%'") % path);
225+
unlink(path.c_str());
226+
writeFull(fd->get(), "d");
227+
continue;
228+
}
229+
230+
/* Acquire a read lock. This will prevent the owning process
231+
from upgrading to a write lock, therefore it will block in
232+
addTempRoot(). */
233+
debug(format("waiting for read lock on '%1%'") % path);
234+
lockFile(fd->get(), ltRead, true);
235+
236+
}
240237

241238
/* Read the entire file. */
242239
string contents = readFile(fd->get());

src/libstore/local-store.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ LocalStore::LocalStore(const Params & params)
5151
, reservedPath(dbDir + "/reserved")
5252
, schemaPath(dbDir + "/schema")
5353
, trashDir(realStoreDir + "/trash")
54+
, tempRootsDir(stateDir + "/temproots")
55+
, fnTempRoots(fmt("%s/%d", tempRootsDir, getpid()))
5456
, publicKeys(getDefaultPublicKeys())
5557
{
5658
auto state(_state.lock());
@@ -61,7 +63,7 @@ LocalStore::LocalStore(const Params & params)
6163
createDirs(linksDir);
6264
Path profilesDir = stateDir + "/profiles";
6365
createDirs(profilesDir);
64-
createDirs(stateDir + "/temproots");
66+
createDirs(tempRootsDir);
6567
createDirs(dbDir);
6668
Path gcRootsDir = stateDir + "/gcroots";
6769
if (!pathExists(gcRootsDir)) {
@@ -242,12 +244,12 @@ LocalStore::LocalStore(const Params & params)
242244

243245
LocalStore::~LocalStore()
244246
{
245-
auto state(_state.lock());
246247

247248
try {
249+
auto state(_state.lock());
248250
if (state->fdTempRoots) {
249251
state->fdTempRoots = -1;
250-
unlink(state->fnTempRoots.c_str());
252+
unlink(fnTempRoots.c_str());
251253
}
252254
} catch (...) {
253255
ignoreException();

src/libstore/local-store.hh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ private:
5959
SQLiteStmt stmtQueryValidPaths;
6060

6161
/* The file to which we write our temporary roots. */
62-
Path fnTempRoots;
6362
AutoCloseFD fdTempRoots;
6463
};
6564

@@ -75,6 +74,8 @@ public:
7574
const Path reservedPath;
7675
const Path schemaPath;
7776
const Path trashDir;
77+
const Path tempRootsDir;
78+
const Path fnTempRoots;
7879

7980
private:
8081

0 commit comments

Comments
 (0)