mirror of
https://github.com/reactos/ccache.git
synced 2024-12-02 16:46:24 +00:00
*much* nicer cache_clean program
This commit is contained in:
parent
c2286aa2f6
commit
c79ad6ff5d
15
README
15
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:
|
||||
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.
|
||||
|
||||
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.
|
||||
You may wish to call ccache_clean from a cron job to keep your disk
|
||||
space usage reasonable.
|
||||
|
||||
How it works
|
||||
------------
|
||||
|
4
ccache.h
4
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,
|
||||
|
@ -22,29 +22,72 @@
|
||||
|
||||
#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;
|
||||
}
|
||||
|
30
util.c
30
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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user