3 #include "local-store.hh"
20 static string gcLockName
= "gc.lock";
21 static string tempRootsDir
= "temproots";
22 static string gcRootsDir
= "gcroots";
25 /* Acquire the global GC lock. This is used to prevent new build
26 processes from starting after the temporary root files have been
27 read. To be precise: when they try to create a new temporary root
28 file, they will block until the garbage collector has finished /
29 yielded the GC lock. */
30 int LocalStore::openGCLock(LockType lockType
)
32 Path fnGCLock
= (format("%1%/%2%")
33 % settings
.nixStateDir
% gcLockName
).str();
35 debug(format("acquiring global GC lock `%1%'") % fnGCLock
);
37 AutoCloseFD fdGCLock
= open(fnGCLock
.c_str(), O_RDWR
| O_CREAT
, 0600);
39 throw SysError(format("opening global GC lock `%1%'") % fnGCLock
);
40 closeOnExec(fdGCLock
);
42 if (!lockFile(fdGCLock
, lockType
, false)) {
43 printMsg(lvlError
, format("waiting for the big garbage collector lock..."));
44 lockFile(fdGCLock
, lockType
, true);
47 /* !!! Restrict read permission on the GC root. Otherwise any
48 process that can open the file for reading can DoS the
51 return fdGCLock
.borrow();
55 static void makeSymlink(const Path
& link
, const Path
& target
)
57 /* Create directories up to `gcRoot'. */
58 createDirs(dirOf(link
));
60 /* Create the new symlink. */
61 Path tempLink
= (format("%1%.tmp-%2%-%3%")
62 % link
% getpid() % rand()).str();
63 createSymlink(target
, tempLink
);
65 /* Atomically replace the old one. */
66 if (rename(tempLink
.c_str(), link
.c_str()) == -1)
67 throw SysError(format("cannot rename `%1%' to `%2%'")
72 void LocalStore::syncWithGC()
74 AutoCloseFD fdGCLock
= openGCLock(ltRead
);
78 void LocalStore::addIndirectRoot(const Path
& path
)
80 string hash
= printHash32(hashString(htSHA1
, path
));
81 Path realRoot
= canonPath((format("%1%/%2%/auto/%3%")
82 % settings
.nixStateDir
% gcRootsDir
% hash
).str());
83 makeSymlink(realRoot
, path
);
87 Path
addPermRoot(StoreAPI
& store
, const Path
& _storePath
,
88 const Path
& _gcRoot
, bool indirect
, bool allowOutsideRootsDir
)
90 Path
storePath(canonPath(_storePath
));
91 Path
gcRoot(canonPath(_gcRoot
));
92 assertStorePath(storePath
);
94 if (isInStore(gcRoot
))
96 "creating a garbage collector root (%1%) in the store is forbidden "
97 "(are you running nix-build inside the store?)") % gcRoot
);
100 /* Don't clobber the link if it already exists and doesn't
101 point to the store. */
102 if (pathExists(gcRoot
) && (!isLink(gcRoot
) || !isInStore(readLink(gcRoot
))))
103 throw Error(format("cannot create symlink `%1%'; already exists") % gcRoot
);
104 makeSymlink(gcRoot
, storePath
);
105 store
.addIndirectRoot(gcRoot
);
109 if (!allowOutsideRootsDir
) {
110 Path rootsDir
= canonPath((format("%1%/%2%") % settings
.nixStateDir
% gcRootsDir
).str());
112 if (string(gcRoot
, 0, rootsDir
.size() + 1) != rootsDir
+ "/")
114 "path `%1%' is not a valid garbage collector root; "
115 "it's not in the directory `%2%'")
116 % gcRoot
% rootsDir
);
119 if (baseNameOf(gcRoot
) == baseNameOf(storePath
))
120 writeFile(gcRoot
, "");
122 makeSymlink(gcRoot
, storePath
);
125 /* Check that the root can be found by the garbage collector.
126 !!! This can be very slow on machines that have many roots.
127 Instead of reading all the roots, it would be more efficient to
128 check if the root is in a directory in or linked from the
129 gcroots directory. */
130 if (settings
.checkRootReachability
) {
131 Roots roots
= store
.findRoots();
132 if (roots
.find(gcRoot
) == roots
.end())
135 "warning: `%1%' is not in a directory where the garbage collector looks for roots; "
136 "therefore, `%2%' might be removed by the garbage collector")
137 % gcRoot
% storePath
);
140 /* Grab the global GC root, causing us to block while a GC is in
141 progress. This prevents the set of permanent roots from
142 increasing while a GC is in progress. */
149 void LocalStore::addTempRoot(const Path
& path
)
151 /* Create the temporary roots file for this process. */
152 if (fdTempRoots
== -1) {
155 Path dir
= (format("%1%/%2%") % settings
.nixStateDir
% tempRootsDir
).str();
158 fnTempRoots
= (format("%1%/%2%")
159 % dir
% getpid()).str();
161 AutoCloseFD fdGCLock
= openGCLock(ltRead
);
163 if (pathExists(fnTempRoots
))
164 /* It *must* be stale, since there can be no two
165 processes with the same pid. */
166 unlink(fnTempRoots
.c_str());
168 fdTempRoots
= openLockFile(fnTempRoots
, true);
172 debug(format("acquiring read lock on `%1%'") % fnTempRoots
);
173 lockFile(fdTempRoots
, ltRead
, true);
175 /* Check whether the garbage collector didn't get in our
178 if (fstat(fdTempRoots
, &st
) == -1)
179 throw SysError(format("statting `%1%'") % fnTempRoots
);
180 if (st
.st_size
== 0) break;
182 /* The garbage collector deleted this file before we could
183 get a lock. (It won't delete the file after we get a
189 /* Upgrade the lock to a write lock. This will cause us to block
190 if the garbage collector is holding our lock. */
191 debug(format("acquiring write lock on `%1%'") % fnTempRoots
);
192 lockFile(fdTempRoots
, ltWrite
, true);
194 string s
= path
+ '\0';
195 writeFull(fdTempRoots
, s
);
197 /* Downgrade to a read lock. */
198 debug(format("downgrading to read lock on `%1%'") % fnTempRoots
);
199 lockFile(fdTempRoots
, ltRead
, true);
203 typedef std::shared_ptr
<AutoCloseFD
> FDPtr
;
204 typedef list
<FDPtr
> FDs
;
207 static void readTempRoots(PathSet
& tempRoots
, FDs
& fds
)
209 /* Read the `temproots' directory for per-process temporary root
211 DirEntries tempRootFiles
= readDirectory(
212 (format("%1%/%2%") % settings
.nixStateDir
% tempRootsDir
).str());
214 for (auto & i
: tempRootFiles
) {
215 Path path
= (format("%1%/%2%/%3%") % settings
.nixStateDir
% tempRootsDir
% i
.name
).str();
217 debug(format("reading temporary root file `%1%'") % path
);
218 FDPtr
fd(new AutoCloseFD(open(path
.c_str(), O_RDWR
, 0666)));
220 /* It's okay if the file has disappeared. */
221 if (errno
== ENOENT
) continue;
222 throw SysError(format("opening temporary roots file `%1%'") % path
);
225 /* This should work, but doesn't, for some reason. */
226 //FDPtr fd(new AutoCloseFD(openLockFile(path, false)));
227 //if (*fd == -1) continue;
229 /* Try to acquire a write lock without blocking. This can
230 only succeed if the owning process has died. In that case
231 we don't care about its temporary roots. */
232 if (lockFile(*fd
, ltWrite
, false)) {
233 printMsg(lvlError
, format("removing stale temporary roots file `%1%'") % path
);
234 unlink(path
.c_str());
239 /* Acquire a read lock. This will prevent the owning process
240 from upgrading to a write lock, therefore it will block in
242 debug(format("waiting for read lock on `%1%'") % path
);
243 lockFile(*fd
, ltRead
, true);
245 /* Read the entire file. */
246 string contents
= readFile(*fd
);
248 /* Extract the roots. */
249 string::size_type pos
= 0, end
;
251 while ((end
= contents
.find((char) 0, pos
)) != string::npos
) {
252 Path
root(contents
, pos
, end
- pos
);
253 debug(format("got temporary root `%1%'") % root
);
254 assertStorePath(root
);
255 tempRoots
.insert(root
);
259 fds
.push_back(fd
); /* keep open */
264 static void foundRoot(StoreAPI
& store
,
265 const Path
& path
, const Path
& target
, Roots
& roots
)
267 Path storePath
= toStorePath(target
);
268 if (store
.isValidPath(storePath
))
269 roots
[path
] = storePath
;
271 printMsg(lvlInfo
, format("skipping invalid root from `%1%' to `%2%'") % path
% storePath
);
275 static void findRoots(StoreAPI
& store
, const Path
& path
, unsigned char type
, Roots
& roots
)
279 if (type
== DT_UNKNOWN
)
280 type
= getFileType(path
);
282 if (type
== DT_DIR
) {
283 for (auto & i
: readDirectory(path
))
284 findRoots(store
, path
+ "/" + i
.name
, i
.type
, roots
);
287 else if (type
== DT_LNK
) {
288 Path target
= readLink(path
);
289 if (isInStore(target
))
290 foundRoot(store
, path
, target
, roots
);
292 /* Handle indirect roots. */
294 target
= absPath(target
, dirOf(path
));
295 if (!pathExists(target
)) {
296 if (isInDir(path
, settings
.nixStateDir
+ "/" + gcRootsDir
+ "/auto")) {
297 printMsg(lvlInfo
, format("removing stale link from `%1%' to `%2%'") % path
% target
);
298 unlink(path
.c_str());
301 struct stat st2
= lstat(target
);
302 if (!S_ISLNK(st2
.st_mode
)) return;
303 Path target2
= readLink(target
);
304 if (isInStore(target2
)) foundRoot(store
, target
, target2
, roots
);
309 else if (type
== DT_REG
) {
310 Path storePath
= settings
.nixStore
+ "/" + baseNameOf(path
);
311 if (store
.isValidPath(storePath
))
312 roots
[path
] = storePath
;
317 catch (SysError
& e
) {
318 /* We only ignore permanent failures. */
319 if (e
.errNo
== EACCES
|| e
.errNo
== ENOENT
|| e
.errNo
== ENOTDIR
)
320 printMsg(lvlInfo
, format("cannot read potential root `%1%'") % path
);
327 Roots
LocalStore::findRoots()
331 /* Process direct roots in {gcroots,manifests,profiles}. */
332 nix::findRoots(*this, settings
.nixStateDir
+ "/" + gcRootsDir
, DT_UNKNOWN
, roots
);
333 if (pathExists(settings
.nixStateDir
+ "/manifests"))
334 nix::findRoots(*this, settings
.nixStateDir
+ "/manifests", DT_UNKNOWN
, roots
);
335 nix::findRoots(*this, settings
.nixStateDir
+ "/profiles", DT_UNKNOWN
, roots
);
341 static void addAdditionalRoots(StoreAPI
& store
, PathSet
& roots
)
343 debug(format("executing `%1% gc --list-busy' to find additional roots")
344 % settings
.guixProgram
);
346 const Strings args
= { "gc", "--list-busy" };
347 string result
= runProgram(settings
.guixProgram
, false, args
);
349 StringSet paths
= tokenizeString
<StringSet
>(result
, "\n");
351 foreach (StringSet::iterator
, i
, paths
) {
353 Path path
= toStorePath(*i
);
354 if (roots
.find(path
) == roots
.end() && store
.isValidPath(path
)) {
355 debug(format("got additional root `%1%'") % path
);
363 struct GCLimitReached
{ };
366 struct LocalStore::GCState
375 bool gcKeepDerivations
;
376 unsigned long long bytesInvalidated
;
377 bool moveToTrash
= true;
380 GCState(GCResults
& results_
) : results(results_
), bytesInvalidated(0) { }
384 bool LocalStore::isActiveTempFile(const GCState
& state
,
385 const Path
& path
, const string
& suffix
)
387 return hasSuffix(path
, suffix
)
388 && state
.tempRoots
.find(string(path
, 0, path
.size() - suffix
.size())) != state
.tempRoots
.end();
392 void LocalStore::deleteGarbage(GCState
& state
, const Path
& path
)
394 unsigned long long bytesFreed
;
396 /* When deduplication is on, store items always have at least two links:
397 the one at PATH, and one in /gnu/store/.links. In that case, increase
398 bytesFreed when PATH has two or fewer links. */
399 size_t linkThreshold
=
400 (settings
.autoOptimiseStore
&& isStorePath(path
)) ? 2 : 1;
402 deletePath(path
, bytesFreed
, linkThreshold
);
403 state
.results
.bytesFreed
+= bytesFreed
;
407 void LocalStore::deletePathRecursive(GCState
& state
, const Path
& path
)
411 unsigned long long size
= 0;
413 if (isValidPath(path
)) {
415 queryReferrers(path
, referrers
);
416 foreach (PathSet::iterator
, i
, referrers
)
417 if (*i
!= path
) deletePathRecursive(state
, *i
);
418 size
= queryPathInfo(path
).narSize
;
419 invalidatePathChecked(path
);
423 if (lstat(path
.c_str(), &st
)) {
424 if (errno
== ENOENT
) return;
425 throw SysError(format("getting status of %1%") % path
);
428 if (state
.options
.maxFreed
!= ULLONG_MAX
) {
429 auto freed
= state
.results
.bytesFreed
+ state
.bytesInvalidated
;
430 double fraction
= ((double) freed
) / (double) state
.options
.maxFreed
;
431 unsigned int percentage
= (fraction
> 1. ? 1. : fraction
) * 100.;
432 printMsg(lvlInfo
, format("[%1%%%] deleting '%2%'") % percentage
% path
);
434 auto freed
= state
.results
.bytesFreed
+ state
.bytesInvalidated
;
435 freed
/= 1024ULL * 1024ULL;
436 printMsg(lvlInfo
, format("[%1% MiB] deleting '%2%'") % freed
% path
);
439 state
.results
.paths
.insert(path
);
441 /* If the path is not a regular file or symlink, move it to the
442 trash directory. The move is to ensure that later (when we're
443 not holding the global GC lock) we can delete the path without
444 being afraid that the path has become alive again. Otherwise
445 delete it right away. */
446 if (state
.moveToTrash
&& S_ISDIR(st
.st_mode
)) {
447 // Estimate the amount freed using the narSize field. FIXME:
448 // if the path was not valid, need to determine the actual
451 if (chmod(path
.c_str(), st
.st_mode
| S_IWUSR
) == -1)
452 throw SysError(format("making `%1%' writable") % path
);
453 Path tmp
= state
.trashDir
+ "/" + baseNameOf(path
);
454 if (rename(path
.c_str(), tmp
.c_str()))
455 throw SysError(format("unable to rename `%1%' to `%2%'") % path
% tmp
);
456 state
.bytesInvalidated
+= size
;
457 } catch (SysError
& e
) {
458 /* In a Docker container, rename(2) returns EXDEV when the source
459 and destination are not both on the "top layer". See:
460 https://bugs.gnu.org/41607 */
461 if (e
.errNo
== ENOSPC
|| e
.errNo
== EXDEV
) {
462 printMsg(lvlInfo
, format("note: can't create move `%1%': %2%") % path
% e
.msg());
463 deleteGarbage(state
, path
);
467 deleteGarbage(state
, path
);
469 if (state
.results
.bytesFreed
+ state
.bytesInvalidated
> state
.options
.maxFreed
) {
470 printMsg(lvlInfo
, format("deleted or invalidated more than %1% bytes; stopping") % state
.options
.maxFreed
);
471 throw GCLimitReached();
476 bool LocalStore::canReachRoot(GCState
& state
, PathSet
& visited
, const Path
& path
)
478 if (visited
.find(path
) != visited
.end()) return false;
480 if (state
.alive
.find(path
) != state
.alive
.end()) {
484 if (state
.dead
.find(path
) != state
.dead
.end()) {
488 if (state
.roots
.find(path
) != state
.roots
.end()) {
489 printMsg(lvlDebug
, format("cannot delete `%1%' because it's a root") % path
);
490 state
.alive
.insert(path
);
494 visited
.insert(path
);
496 if (!isValidPath(path
)) return false;
500 /* Don't delete this path if any of its referrers are alive. */
501 queryReferrers(path
, incoming
);
503 /* If gc-keep-derivations is set and this is a derivation, then
504 don't delete the derivation if any of the outputs are alive. */
505 if (state
.gcKeepDerivations
&& isDerivation(path
)) {
506 PathSet outputs
= queryDerivationOutputs(path
);
507 foreach (PathSet::iterator
, i
, outputs
)
508 if (isValidPath(*i
) && queryDeriver(*i
) == path
)
512 /* If gc-keep-outputs is set, then don't delete this path if there
513 are derivers of this path that are not garbage. */
514 if (state
.gcKeepOutputs
) {
515 PathSet derivers
= queryValidDerivers(path
);
516 foreach (PathSet::iterator
, i
, derivers
)
520 foreach (PathSet::iterator
, i
, incoming
)
522 if (canReachRoot(state
, visited
, *i
)) {
523 state
.alive
.insert(path
);
531 void LocalStore::tryToDelete(GCState
& state
, const Path
& path
)
535 if (path
== linksDir
|| path
== state
.trashDir
) return;
537 startNest(nest
, lvlDebug
, format("considering whether to delete `%1%'") % path
);
539 if (!isValidPath(path
)) {
540 /* A lock file belonging to a path that we're building right
541 now isn't garbage. */
542 if (isActiveTempFile(state
, path
, ".lock")) return;
544 /* Don't delete .chroot directories for derivations that are
545 currently being built. */
546 if (isActiveTempFile(state
, path
, ".chroot")) return;
551 if (canReachRoot(state
, visited
, path
)) {
552 printMsg(lvlDebug
, format("cannot delete `%1%' because it's still reachable") % path
);
554 /* No path we visited was a root, so everything is garbage.
555 But we only delete ‘path’ and its referrers here so that
556 ‘nix-store --delete’ doesn't have the unexpected effect of
557 recursing into derivations and outputs. */
558 state
.dead
.insert(visited
.begin(), visited
.end());
559 if (state
.shouldDelete
)
560 deletePathRecursive(state
, path
);
565 /* Unlink all files in /nix/store/.links that have a link count of 1,
566 which indicates that there are no other links and so they can be
567 safely deleted. FIXME: race condition with optimisePath(): we
568 might see a link count of 1 just before optimisePath() increases
570 void LocalStore::removeUnusedLinks(const GCState
& state
)
572 AutoCloseDir dir
= opendir(linksDir
.c_str());
573 if (!dir
) throw SysError(format("opening directory `%1%'") % linksDir
);
575 long long actualSize
= 0, unsharedSize
= 0;
577 struct dirent
* dirent
;
578 while (errno
= 0, dirent
= readdir(dir
)) {
580 string name
= dirent
->d_name
;
581 if (name
== "." || name
== "..") continue;
582 Path path
= linksDir
+ "/" + name
;
585 # define st_size stx_size
586 # define st_nlink stx_nlink
587 static int statx_flags
= AT_SYMLINK_NOFOLLOW
| AT_STATX_DONT_SYNC
;
590 if (statx(AT_FDCWD
, path
.c_str(), statx_flags
,
591 STATX_SIZE
| STATX_NLINK
, &st
) == -1) {
592 if (errno
== EINVAL
) {
593 /* Old 3.10 kernels (CentOS 7) don't support
594 AT_STATX_DONT_SYNC, so try again without it. */
595 statx_flags
&= ~AT_STATX_DONT_SYNC
;
596 if (statx(AT_FDCWD
, path
.c_str(), statx_flags
,
597 STATX_SIZE
| STATX_NLINK
, &st
) == -1)
598 throw SysError(format("statting `%1%'") % path
);
600 throw SysError(format("statting `%1%'") % path
);
605 if (lstat(path
.c_str(), &st
) == -1)
606 throw SysError(format("statting `%1%'") % path
);
609 if (st
.st_nlink
!= 1) {
610 actualSize
+= st
.st_size
;
611 unsharedSize
+= (st
.st_nlink
- 1) * st
.st_size
;
615 printMsg(lvlTalkative
, format("deleting unused link `%1%'") % path
);
617 if (unlink(path
.c_str()) == -1)
618 throw SysError(format("deleting `%1%'") % path
);
620 state
.results
.bytesFreed
+= st
.st_size
;
626 if (stat(linksDir
.c_str(), &st
) == -1)
627 throw SysError(format("statting `%1%'") % linksDir
);
628 long long overhead
= st
.st_size
;
630 printMsg(lvlInfo
, format("note: currently hard linking saves %.2f MiB")
631 % ((unsharedSize
- actualSize
- overhead
) / (1024.0 * 1024.0)));
635 void LocalStore::collectGarbage(const GCOptions
& options
, GCResults
& results
)
637 GCState
state(results
);
638 state
.options
= options
;
639 state
.trashDir
= settings
.nixStore
+ "/trash";
640 state
.gcKeepOutputs
= settings
.gcKeepOutputs
;
641 state
.gcKeepDerivations
= settings
.gcKeepDerivations
;
643 /* Using `--ignore-liveness' with `--delete' can have unintended
644 consequences if `gc-keep-outputs' or `gc-keep-derivations' are
645 true (the garbage collector will recurse into deleting the
646 outputs or derivers, respectively). So disable them. */
647 if (options
.action
== GCOptions::gcDeleteSpecific
&& options
.ignoreLiveness
) {
648 state
.gcKeepOutputs
= false;
649 state
.gcKeepDerivations
= false;
652 state
.shouldDelete
= options
.action
== GCOptions::gcDeleteDead
|| options
.action
== GCOptions::gcDeleteSpecific
;
654 /* Acquire the global GC root. This prevents
655 a) New roots from being added.
656 b) Processes from creating new temporary root files. */
657 AutoCloseFD fdGCLock
= openGCLock(ltWrite
);
659 /* Find the roots. Since we've grabbed the GC lock, the set of
660 permanent roots cannot increase now. */
661 printMsg(lvlError
, format("finding garbage collector roots..."));
662 Roots rootMap
= options
.ignoreLiveness
? Roots() : findRoots();
664 foreach (Roots::iterator
, i
, rootMap
) state
.roots
.insert(i
->second
);
666 /* Add additional roots returned by 'guix gc --list-busy'. This is
667 typically used to add running programs to the set of roots (to prevent
668 them from being garbage collected). */
669 if (!options
.ignoreLiveness
)
670 addAdditionalRoots(*this, state
.roots
);
672 /* Read the temporary roots. This acquires read locks on all
673 per-process temporary root files. So after this point no paths
674 can be added to the set of temporary roots. */
676 readTempRoots(state
.tempRoots
, fds
);
677 state
.roots
.insert(state
.tempRoots
.begin(), state
.tempRoots
.end());
679 /* After this point the set of roots or temporary roots cannot
680 increase, since we hold locks on everything. So everything
681 that is not reachable from `roots' is garbage. */
683 if (state
.shouldDelete
) {
684 if (pathExists(state
.trashDir
)) deleteGarbage(state
, state
.trashDir
);
686 createDirs(state
.trashDir
);
687 } catch (SysError
& e
) {
688 if (e
.errNo
== ENOSPC
) {
689 printMsg(lvlInfo
, format("note: can't create trash directory: %1%") % e
.msg());
690 state
.moveToTrash
= false;
695 /* Now either delete all garbage paths, or just the specified
696 paths (for gcDeleteSpecific). */
698 if (options
.action
== GCOptions::gcDeleteSpecific
) {
700 foreach (PathSet::iterator
, i
, options
.pathsToDelete
) {
702 tryToDelete(state
, *i
);
703 if (state
.dead
.find(*i
) == state
.dead
.end())
704 throw Error(format("cannot delete path `%1%' since it is still alive") % *i
);
707 } else if (options
.maxFreed
> 0) {
709 if (state
.shouldDelete
)
710 printMsg(lvlError
, format("deleting garbage..."));
712 printMsg(lvlError
, format("determining live/dead paths..."));
716 AutoCloseDir dir
= opendir(settings
.nixStore
.c_str());
717 if (!dir
) throw SysError(format("opening directory `%1%'") % settings
.nixStore
);
719 /* Read the store and immediately delete all paths that
720 aren't valid. When using --max-freed etc., deleting
721 invalid paths is preferred over deleting unreachable
722 paths, since unreachable paths could become reachable
723 again. We don't use readDirectory() here so that GCing
726 struct dirent
* dirent
;
727 while (errno
= 0, dirent
= readdir(dir
)) {
729 string name
= dirent
->d_name
;
730 if (name
== "." || name
== "..") continue;
731 Path path
= settings
.nixStore
+ "/" + name
;
732 if (isValidPath(path
))
733 entries
.push_back(path
);
735 tryToDelete(state
, path
);
740 /* Now delete the unreachable valid paths. Randomise the
741 order in which we delete entries to make the collector
742 less biased towards deleting paths that come
743 alphabetically first (e.g. /nix/store/000...). This
744 matters when using --max-freed etc. */
745 vector
<Path
> entries_(entries
.begin(), entries
.end());
746 random_shuffle(entries_
.begin(), entries_
.end());
748 foreach (vector
<Path
>::iterator
, i
, entries_
)
749 tryToDelete(state
, *i
);
751 } catch (GCLimitReached
& e
) {
755 if (state
.options
.action
== GCOptions::gcReturnLive
) {
756 state
.results
.paths
= state
.alive
;
760 if (state
.options
.action
== GCOptions::gcReturnDead
) {
761 state
.results
.paths
= state
.dead
;
765 /* Allow other processes to add to the store from here on. */
769 /* Delete the trash directory. */
770 printMsg(lvlInfo
, format("deleting `%1%'") % state
.trashDir
);
771 deleteGarbage(state
, state
.trashDir
);
773 /* Clean up the links directory. */
774 if (options
.action
== GCOptions::gcDeleteDead
|| options
.action
== GCOptions::gcDeleteSpecific
) {
775 printMsg(lvlError
, format("deleting unused links..."));
776 removeUnusedLinks(state
);
779 /* While we're at it, vacuum the database. */
780 //if (options.action == GCOptions::gcDeleteDead) vacuumDB();