about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2009-11-20T17·12+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2009-11-20T17·12+0000
commit8824d60fe549e2fc9b5a852fc1b967eca241ea77 (patch)
treebf0f96064f5b77dd11bdcf0cf9bee58c03d3bda5
parent997db91e07882f0555e224a2687189a362567577 (diff)
* Remove the --use-atime / --max-atime garbage collector flags. Many
  (Linux) machines no longer maintain the atime because it's too
  expensive, and on the machines where --use-atime is useful (like the
  buildfarm), reading the atimes on the entire Nix store takes way too
  much time to make it practical.

-rw-r--r--doc/manual/nix-store.xml45
-rw-r--r--src/libstore/gc.cc136
-rw-r--r--src/libstore/remote-store.cc5
-rw-r--r--src/libstore/store-api.cc2
-rw-r--r--src/libstore/store-api.hh16
-rw-r--r--src/nix-store/nix-store.cc5
-rw-r--r--src/nix-worker/nix-worker.cc5
7 files changed, 11 insertions, 203 deletions
diff --git a/doc/manual/nix-store.xml b/doc/manual/nix-store.xml
index 9079fa3398b4..562a5439a6eb 100644
--- a/doc/manual/nix-store.xml
+++ b/doc/manual/nix-store.xml
@@ -213,8 +213,6 @@ linkend="sec-nix-build"><command>nix-build</command></link> does.</para>
   </group>
   <arg><option>--max-freed</option> <replaceable>bytes</replaceable></arg>
   <arg><option>--max-links</option> <replaceable>nrlinks</replaceable></arg>
-  <arg><option>--max-atime</option> <replaceable>atime</replaceable></arg>
-  <arg><option>--use-atime</option></arg>
 </cmdsynopsis>
 
 </refsection>
@@ -292,42 +290,6 @@ options control what gets deleted and in what order:
     
   </varlistentry>
 
-  <varlistentry><term><option>--max-atime</option> <replaceable>atime</replaceable></term>
-  
-    <listitem><para>Only delete a store path if its last-accessed time
-    is less than <replaceable>atime</replaceable>.  This allows you to
-    garbage-collect only packages that haven’t been used recently.
-    The time is expressed as the number of seconds in the Unix epoch,
-    i.e., since 1970-01-01 00:00:00 UTC.  An easy way to convert to
-    this format is <literal>date +%s -d "<replaceable>date
-    specification</replaceable>"</literal>.</para>
-
-    <para>For directories, the last-accessed time is the highest
-    last-accessed time of any regular file in the directory (or in any
-    of its subdirectories).  That is, the <literal>atime</literal>
-    field maintained by the filesystem is ignored for directories.
-    This is because operations such as rebuilding the
-    <command>locate</command> database tend to update the
-    <literal>atime</literal> values of all directories, so they’re not
-    a useful indicator of whether a package was recently used.</para>
-
-    <para>Note that <command>nix-store --optimise</command> reads all
-    regular files in the Nix store, and so causes all last-accessed
-    times to be set to the present time.  This makes
-    <option>--max-atime</option> ineffective (for a while at
-    least).</para></listitem>
-    
-  </varlistentry>
-
-  <varlistentry><term><option>--use-atime</option></term>
-
-    <listitem><para>Delete store paths in order of ascending
-    last-accessed time.  This is useful in conjunction with the other
-    options to delete only the least recently used
-    packages.</para></listitem>
-
-  </varlistentry>
-  
 </variablelist>
 
 </para>
@@ -358,13 +320,6 @@ deleting `/nix/store/kq82idx6g0nyzsp2s14gfsc38npai7lf-cairo-1.0.4.tar.gz.drv'
 
 </para>
 
-<para>To delete unreachable paths not accessed in the last two months:
-
-<screen>
-$ nix-store --gc -v --max-atime $(date +%s -d "2 months ago")</screen>
-
-</para>
-
 <para>To delete at least 100 MiBs of unreachable paths:
 
 <screen>
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 3415c1cb42ee..1d4099620a34 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -439,30 +439,6 @@ Paths topoSortPaths(const PathSet & paths)
 }
 
 
-static time_t lastFileAccessTime(const Path & path)
-{
-    checkInterrupt();
-    
-    struct stat st;
-    if (lstat(path.c_str(), &st) == -1)
-        throw SysError(format("statting `%1%'") % path);
-
-    if (S_ISDIR(st.st_mode)) {
-        time_t last = 0;
-	Strings names = readDirectory(path);
-	foreach (Strings::iterator, i, names) {
-            time_t t = lastFileAccessTime(path + "/" + *i);
-            if (t > last) last = t;
-        }
-        return last;
-    }
-
-    else if (S_ISLNK(st.st_mode)) return 0;
-
-    else return st.st_atime;
-}
-
-
 struct GCLimitReached { };
 
 
@@ -522,35 +498,6 @@ void LocalStore::gcPathRecursive(const GCOptions & options,
 }
 
 
-struct CachingAtimeComparator : public std::binary_function<Path, Path, bool> 
-{
-    std::map<Path, time_t> cache;
-
-    time_t lookup(const Path & p)
-    {
-        std::map<Path, time_t>::iterator i = cache.find(p);
-        if (i != cache.end()) return i->second;
-        debug(format("computing atime of `%1%'") % p);
-        cache[p] = lastFileAccessTime(p);
-        assert(cache.find(p) != cache.end());
-        return cache[p];
-    }
-        
-    bool operator () (const Path & p1, const Path & p2)
-    {
-        return lookup(p2) < lookup(p1);
-    }
-};
-
-
-static string showTime(const string & format, time_t t)
-{
-    char s[128];
-    strftime(s, sizeof s, format.c_str(), localtime(&t));
-    return string(s);
-}
-
-
 static bool isLive(const Path & path, const PathSet & livePaths,
     const PathSet & tempRoots, const PathSet & tempRootsClosed)
 {
@@ -699,87 +646,14 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
     }
 
     /* Delete all dead store paths (or until one of the stop
-       conditions is reached). */
+       conditions is reached), respecting the partial ordering
+       determined by the references graph. */
 
     PathSet done;
     try {
-
-        if (!options.useAtime) {
-            /* Delete the paths, respecting the partial ordering
-               determined by the references graph. */
-            printMsg(lvlError, format("deleting garbage..."));
-            foreach (PathSet::iterator, i, storePaths)
-                gcPathRecursive(options, results, done, *i);
-        }
-
-        else {
-
-            /* Delete in order of ascending last access time, still
-               maintaining the partial ordering of the reference
-               graph.  Note that we can't use a topological sort for
-               this because that takes time O(V+E), and in this case
-               E=O(V^2) (i.e. the graph is dense because of the edges
-               due to the atime ordering).  So instead we put all
-               deletable paths in a priority queue (ordered by atime),
-               and after deleting a path, add additional paths that
-               have become deletable to the priority queue. */
-
-            CachingAtimeComparator atimeComp;
-
-            /* Create a priority queue that orders paths by ascending
-               atime.  This is why C++ needs type inferencing... */
-            std::priority_queue<Path, vector<Path>, binary_function_ref_adapter<CachingAtimeComparator> > prioQueue =
-                std::priority_queue<Path, vector<Path>, binary_function_ref_adapter<CachingAtimeComparator> >(binary_function_ref_adapter<CachingAtimeComparator>(&atimeComp));
-
-           /* Initially put the paths that are invalid or have no
-              referrers into the priority queue. */
-            printMsg(lvlError, format("finding deletable paths..."));
-            foreach (PathSet::iterator, i, storePaths) {
-                checkInterrupt();
-                /* We can safely delete a path if it's invalid or
-                   it has no referrers.  Note that all the invalid
-                   paths will be deleted in the first round. */
-                if (isValidPath(*i)) {
-                    if (queryReferrersNoSelf(*i).empty()) prioQueue.push(*i);
-                } else prioQueue.push(*i);
-            }
-
-            debug(format("%1% initially deletable paths") % prioQueue.size());
-
-            /* Now delete everything in the order of the priority
-               queue until nothing is left. */
-            printMsg(lvlError, format("deleting garbage..."));
-            while (!prioQueue.empty()) {
-                checkInterrupt();
-                Path path = prioQueue.top(); prioQueue.pop();
-
-                if (options.maxAtime != (time_t) -1 &&
-                    atimeComp.lookup(path) > options.maxAtime)
-                    continue;
-                
-                printMsg(lvlInfo, format("deleting `%1%' (last accessed %2%)") % path % showTime("%F %H:%M:%S", atimeComp.lookup(path)));
-
-                PathSet references;
-                if (isValidPath(path)) references = queryReferencesNoSelf(path);
-
-                gcPath(options, results, path);
-
-                /* For each reference of the current path, see if the
-                   reference has now become deletable (i.e. is in the
-                   set of dead paths and has no referrers left).  If
-                   so add it to the priority queue. */
-                foreach (PathSet::iterator, i, references) {
-                    if (storePaths.find(*i) != storePaths.end() &&
-                        queryReferrersNoSelf(*i).empty())
-                    {
-                        debug(format("path `%1%' has become deletable") % *i);
-                        prioQueue.push(*i);
-                    }
-                }
-            }
-            
-        }
-        
+        printMsg(lvlError, format("deleting garbage..."));
+        foreach (PathSet::iterator, i, storePaths)
+            gcPathRecursive(options, results, done, *i);
     } catch (GCLimitReached & e) {
     }
 }
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index f54281e0d196..5143143f57c3 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -426,8 +426,9 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
     writeLongLong(options.maxFreed, to);
     writeInt(options.maxLinks, to);
     if (GET_PROTOCOL_MINOR(daemonVersion) >= 5) {
-        writeInt(options.useAtime, to);
-        writeInt(options.maxAtime, to);
+        /* removed options */
+        writeInt(0, to);
+        writeInt(0, to);
     }
     
     processStderr();
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 08ee922ef6a8..01dd51621625 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -14,8 +14,6 @@ GCOptions::GCOptions()
     ignoreLiveness = false;
     maxFreed = 0;
     maxLinks = 0;
-    useAtime = false;
-    maxAtime = (time_t) -1;
 }
 
 
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index bac2f6b9a26c..d827dff84124 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -64,22 +64,6 @@ struct GCOptions
        has dropped below `maxLinks'. */
     unsigned int maxLinks;
 
-    /* Delete paths in order of ascending last access time.  I.e.,
-       prefer deleting unrecently used paths.  Useful in conjunction
-       with `maxFreed' and `maxLinks' (or manual interruption).  The
-       access time of a path is defined as the highest atime of any
-       non-directory, non-symlink file under that path.  Directories
-       and symlinks are ignored because their atimes are frequently
-       mass-updated, e.g. by `locate'.  Note that optimiseStore()
-       somewhat reduces the usefulness of this option: it hard-links
-       regular files and symlink together, giving them a "shared"
-       atime. */
-    bool useAtime;
-
-    /* Do not delete paths newer than `maxAtime'.  -1 means no age
-       limit. */
-    time_t maxAtime;
-
     GCOptions();
 };
 
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index e84288137990..3740d0bf9546 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -536,11 +536,6 @@ static void opGC(Strings opFlags, Strings opArgs)
             if (options.maxFreed == 0) options.maxFreed = 1;
         }
         else if (*i == "--max-links") options.maxLinks = getIntArg(*i, i, opFlags.end());
-        else if (*i == "--use-atime") options.useAtime = true;
-        else if (*i == "--max-atime") {
-            options.useAtime = true;
-            options.maxAtime = getIntArg(*i, i, opFlags.end());
-        }
         else throw UsageError(format("bad sub-operation `%1%' in GC") % *i);
 
     if (!opArgs.empty()) throw UsageError("no arguments expected");
diff --git a/src/nix-worker/nix-worker.cc b/src/nix-worker/nix-worker.cc
index 109e3b7b603c..bd2209c6d756 100644
--- a/src/nix-worker/nix-worker.cc
+++ b/src/nix-worker/nix-worker.cc
@@ -464,8 +464,9 @@ static void performOp(unsigned int clientVersion,
         options.maxFreed = readLongLong(from);
         options.maxLinks = readInt(from);
         if (GET_PROTOCOL_MINOR(clientVersion) >= 5) {
-            options.useAtime = readInt(from);
-            options.maxAtime = readInt(from);
+            /* removed options */
+            readInt(from);
+            readInt(from);
         }
 
         GCResults results;