]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
*much* nicer cache_clean program
authorAndrew Tridgell <tridge@samba.org>
Thu, 28 Mar 2002 05:37:27 +0000 (06:37 +0100)
committerAndrew Tridgell <tridge@samba.org>
Thu, 28 Mar 2002 05:37:27 +0000 (06:37 +0100)
README
ccache.h
ccache_clean.c
util.c

diff --git a/README b/README
index 97cb071285774e3f38aedc49269a4a6c84e14ef4..a34f0062f283f920433b7ddb06aa1dd7c0e5be43 100644 (file)
--- a/README
+++ b/README
@@ -105,14 +105,15 @@ Cleaning the cache
 
 ccache tends to quickly fill up the cache directory. You may find the
 ccache_clean utility for removing old cache files. If called with no
-arguments it will remove any cache files older than a week. You can
-also pass a single argument specifying the number of days old files
-need to be to be cleaned. For example:
-
-     ccache_clean 3
-
-will remove any files older than 3 days. You may wish to call
-ccache_clean from a cron job to keep your disk space usage reasonable.
+arguments it will trim the cache to be less than 1 Gigabyte. You can
+also pass a single argument specifying the size limit on the cache,
+for example:
+     ccache_clean 2G
+would clear the oldest files to bring the cache below 2G in size. You
+can use 'M' for megabytes, 'G' for gigabytes or 'K' for kilobytes.
+
+You may wish to call ccache_clean from a cron job to keep your disk
+space usage reasonable.
 
 How it works
 ------------
index d3a111f5d5f72b2bb0e870595ba5e067124fcb6a..8f0b1b40f10529e718e216d93231fbc864bc6844 100644 (file)
--- a/ccache.h
+++ b/ccache.h
@@ -41,7 +41,9 @@ int copy_file(const char *src, const char *dest);
 int create_dir(const char *dir);
 void x_asprintf(char **ptr, const char *format, ...);
 char *x_strdup(const char *s);
-void traverse(const char *dir, void (*fn)(const char *));
+void *x_realloc(void *ptr, size_t size);
+void *x_malloc(size_t size);
+void traverse(const char *dir, void (*fn)(const char *, struct stat *));
 
 int execute(char **argv, 
            const char *path_stdout,
index 1cb88b44b5cab1def4cb16ae043627b2d21fdbf8..9ed3aed3830dca6e43fa7b6e468d72f6f10044e2 100644 (file)
 
 #include "ccache.h"
 
-static time_t threshold;
+#define BLOCK_SIZE 1024
+
 char *cache_logfile = NULL;
 
-static void clean_fn(const char *fname)
+static struct files {
+       char *fname;
+       time_t mtime;
+       size_t size;
+} **files;
+static unsigned allocated;
+static unsigned num_files;
+static size_t total_size;
+static size_t size_threshold = 1024*1024; /* 1G default */
+
+static int files_compare(struct files *f1, struct files *f2)
 {
-       struct stat st;
-       if (stat(fname, &st) != 0 || !S_ISREG(st.st_mode)) return;
+       return f2->mtime - f1->mtime;
+}
 
-       if (st.st_mtime >= threshold) return;
+/* this builds the list of files in the cache */
+static void traverse_fn(const char *fname, struct stat *st)
+{
+       if (!S_ISREG(st->st_mode)) return;
 
-       if (unlink(fname) != 0) {
-               cc_log("unlink %s - %s\n", fname, strerror(errno));
-               return;
+       if (num_files == allocated) {
+               allocated = 10000 + num_files*2;
+               files = x_realloc(files, sizeof(struct files *)*allocated);
        }
-       cc_log("cleaned %s\n", fname);
+
+       files[num_files] = x_malloc(sizeof(struct files *));
+       files[num_files]->fname = x_strdup(fname);
+       files[num_files]->mtime = st->st_mtime;
+       /* we deliberately overestimate by up to 1 block */
+       files[num_files]->size = 1 + (st->st_size/BLOCK_SIZE);
+       total_size += files[num_files]->size;
+       num_files++;
+}
+
+static void sort_and_clean(void)
+{
+       unsigned i;
+
+       if (num_files > 1) {
+               /* sort in ascending data order */
+               qsort(files, num_files, sizeof(struct files *), files_compare);
+       }
+
+       /* delete enough files to bring us below the threshold */
+       for (i=0;i<num_files && total_size >= size_threshold;i++) {
+               if (unlink(files[i]->fname) != 0) {
+                       fprintf(stderr, "unlink %s - %s\n", 
+                               files[i]->fname, strerror(errno));
+                       continue;
+               }
+               total_size -= files[i]->size;
+       }
+
+       printf("cleaned %d of %d files (cache is now %.1f MByte)\n", 
+              i, num_files, total_size/1024.0);
 }
 
 
 int main(int argc, char *argv[])
 {
        char *cache_dir;
-       int num_days = 7;
-
+       
        cache_dir = getenv("CCACHE_DIR");
        if (!cache_dir) {
                x_asprintf(&cache_dir, "%s/.ccache", getenv("HOME"));
@@ -59,13 +102,33 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
+       /* work out what size cache they want */
        if (argc > 1) {
-               num_days = atoi(argv[1]);
+               char *s = argv[1];
+               char m;
+               size_threshold = atoi(s);
+               m = s[strlen(s)-1];
+               switch (m) {
+               case 'G':
+               case 'g':
+                       size_threshold *= 1024*1024;
+                       break;
+               case 'M':
+               case 'm':
+                       size_threshold *= 1024;
+                       break;
+               case 'K':
+               case 'k':
+                       size_threshold *= 1;
+                       break;
+               }
        }
 
-       threshold = time(NULL) - num_days*24*60*60;
+       /* build a list of files */
+       traverse(cache_dir, traverse_fn);
 
-       traverse(cache_dir, clean_fn);
+       /* clean the cache */
+       sort_and_clean();
 
        return 0;
 }
diff --git a/util.c b/util.c
index 39d1bfe74736951e89ea829b5d100dfe13b0486a..1d5d35de63642cf741cc51f54985a220dc3a18fe 100644 (file)
--- a/util.c
+++ b/util.c
@@ -142,12 +142,38 @@ char *x_strdup(const char *s)
        return ret;
 }
 
+/*
+  this is like malloc() but dies if the malloc fails
+*/
+void *x_malloc(size_t size)
+{
+       void *ret;
+       ret = malloc(size);
+       if (!ret) {
+               fatal("out of memory in malloc\n");
+       }
+       return ret;
+}
+
+/*
+  this is like strdup() but dies if the malloc fails
+*/
+void *x_realloc(void *ptr, size_t size)
+{
+       if (!ptr) return x_malloc(size);
+       ptr = realloc(ptr, size);
+       if (!ptr) {
+               fatal("out of memory in x_realloc");
+       }
+       return ptr;
+}
+
 
 /* 
    revsusive directory traversal - used for cleanup
    fn() is called on all files/dirs in the tree
  */
-void traverse(const char *dir, void (*fn)(const char *))
+void traverse(const char *dir, void (*fn)(const char *, struct stat *))
 {
        DIR *d;
        struct dirent *de;
@@ -173,7 +199,7 @@ void traverse(const char *dir, void (*fn)(const char *))
                        traverse(fname, fn);
                }
 
-               fn(fname);
+               fn(fname, &st);
                free(fname);
        }