aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/gc.cc
blob: ba6e6bb9d4bba19ccffba0bbd89590d06f8c5d0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include "globals.hh"
#include "gc.hh"
#include "build.hh"

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>


void collectGarbage(const PathSet & roots, GCAction action,
    PathSet & result)
{
    result.clear();
    
    /* !!! TODO: Acquire an exclusive lock on the gcroots directory.
       This prevents the set of live paths from increasing after this
       point. */
    
    /* Determine the live paths which is just the closure of the
       roots under the `references' relation. */
    PathSet livePaths;
    for (PathSet::const_iterator i = roots.begin(); i != roots.end(); ++i)
        computeFSClosure(canonPath(*i), livePaths);

    if (action == gcReturnLive) {
        result = livePaths;
        return;
    }

    /* !!! TODO: Try to acquire (without blocking) exclusive locks on
       the files in the `pending' directory.  Delete all files for
       which we managed to acquire such a lock (since if we could get
       such a lock, that means that the process that owned the file
       has died). */

    /* !!! TODO: Acquire shared locks on all files in the pending
       directories.  This prevents the set of pending paths from
       increasing while we are garbage-collecting.  Read the set of
       pending paths from those files. */

    /* Read the Nix store directory to find all currently existing
       paths. */
    Strings storeNames = readDirectory(nixStore);

    for (Strings::iterator i = storeNames.begin(); i != storeNames.end(); ++i) {
        Path path = canonPath(nixStore + "/" + *i);

        if (livePaths.find(path) != livePaths.end()) {
            debug(format("live path `%1%'") % path);
            continue;
        }

        debug(format("dead path `%1%'") % path);
        result.insert(path);

        if (action == gcDeleteDead) {
            printMsg(lvlInfo, format("deleting `%1%'") % path);
            deleteFromStore(path);
        }
        
    }
}



#if 0
void followLivePaths(Path nePath, PathSet & live)
{
    /* Just to be sure, canonicalise the path.  It is important to do
       this here and in findDeadPath() to ensure that a live path is
       not mistaken for a dead path due to some non-canonical
       representation. */
    nePath = canonPath(nePath);
    
    if (live.find(nePath) != live.end()) return;
    live.insert(nePath);

    startNest(nest, lvlDebug, format("following `%1%'") % nePath);
    assertStorePath(nePath);

    if (isValidPath(nePath)) {

        /* !!! should make sure that no substitutes are used */
        StoreExpr ne = storeExprFromPath(nePath);

        /* !!! painfully similar to requisitesWorker() */
        if (ne.type == StoreExpr::neClosure)
            for (ClosureElems::iterator i = ne.closure.elems.begin();
                 i != ne.closure.elems.end(); ++i)
            {
                Path p = canonPath(i->first);
                if (live.find(p) == live.end()) {
                    debug(format("found live `%1%'") % p);
                    assertStorePath(p);
                    live.insert(p);
                }
            }
    
        else if (ne.type == StoreExpr::neDerivation)
            for (PathSet::iterator i = ne.derivation.inputs.begin();
                 i != ne.derivation.inputs.end(); ++i)
                followLivePaths(*i, live);

        else abort();
        
    }

    Path nfPath;
    if (querySuccessor(nePath, nfPath))
        followLivePaths(nfPath, live);
}


PathSet findLivePaths(const Paths & roots)
{
    PathSet live;

    startNest(nest, lvlDebug, "finding live paths");

    for (Paths::const_iterator i = roots.begin(); i != roots.end(); ++i)
        followLivePaths(*i, live);

    return live;
}


PathSet findDeadPaths(const PathSet & live, time_t minAge)
{
    PathSet dead;

    startNest(nest, lvlDebug, "finding dead paths");

    time_t now = time(0);

    Strings storeNames = readDirectory(nixStore);

    for (Strings::iterator i = storeNames.begin(); i != storeNames.end(); ++i) {
        Path p = canonPath(nixStore + "/" + *i);

        if (minAge > 0) {
            struct stat st;
            if (lstat(p.c_str(), &st) != 0)
                throw SysError(format("obtaining information about `%1%'") % p);
            if (st.st_atime + minAge >= now) continue;
        }
        
        if (live.find(p) == live.end()) {
            debug(format("dead path `%1%'") % p);
            dead.insert(p);
        } else
            debug(format("live path `%1%'") % p);
    }
    
    return dead;
}
#endif