src/expire.c
/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following functions.
- getFreeFS
- expire_arts
- expire
/* $Id: expire.c,v 1.6 2002/03/26 11:18:35 proff Exp $
* $Copyright$
*/
#include "nglobal.h"
#include "filesystem.h"
#include "history.h"
#include "expire.h"
/* getFreeFS, get
* ffree, free file nodes in fs
* files, total file nodes in file system
* bavail, free blocks avail to non-superuser
* blocks, total data blocks in file system
*/
static bool getFreeFS (long *ffree, long *files, long *bavail, long *blocks)
/* [<][>][^][v][top][bottom][index][help] */
{
#ifdef HAVE_STATVFS
struct statvfs fs;
if (statvfs (".", &fs) < 0)
#else
#ifdef HAVE_STATFS
struct statfs fs;
if (statfs (".", &fs) < 0)
#else
#error no statfs type for this file system
#endif
#endif
{
loge (("unable to statfs() filesystem holding %s", con->cacheDir));
return FALSE;
}
*ffree = fs.f_ffree;
*files = fs.f_files;
*bavail = fs.f_bavail;
*blocks = fs.f_blocks;
return TRUE;
}
static time_t ti, OldestArt;
/*
* this routine is fast. also does xover db's
*/
static int expire_arts (char *group, int depth)
/* [<][>][^][v][top][bottom][index][help] */
{
DIR *dir;
char *p;
struct dirent *d;
struct stat st;
int hi = 0, lo = 0, artnum;
struct newsgroup *n;
struct strList *xover = NULL, *l;
#if 0
bool mark = FALSE;
int low=1; /* TODO fix me */
#endif
if (!(dir = opendir (".")))
return -1;
settaskinfo("expiring");
while ((d = readdir (dir)))
{
p = d->d_name;
if (!p || !*p || *p == '.')
continue;
#if 0
if ((*p >= '0' && *p <= '9') && mark)
{
char *p2 = strstr (p, "_xover");
if (p2)
*p2 = '\0';
if ((artnum = strToi (p)))
{
if (artnum < ((p2) ? low - XOVER_INDEX_SIZE : low))
{
if (p2)
{
*p2 = '_';
unlink (p);
Stats->expire_xovers++;
} else
{
unlink (p);
Stats->expire_articles++;
}
}
continue;
}
}
#endif
if (lstat (p, &st) == -1)
continue;
if ((*p >= '0' && *p <= '9') && S_ISREG (st.st_mode))
{
time_t t = (st.st_mtime > st.st_atime) ? st.st_mtime : st.st_atime;
if (t < OldestArt)
{
if (strstr (p, "_xover"))
xover = strListAdd(xover, p);
else
{
if (unlink (p) == 0)
Stats->articlesExpired++;
}
} else if (!strstr (p, "_xover"))
{
artnum = strToi(p);
if (!lo || artnum < lo)
lo = artnum;
if (artnum > hi)
hi = artnum;
}
continue;
}
if (S_ISDIR (st.st_mode))
{
char *newgroup = NULL;
if (chdir (p) < 0)
continue;
if (depth == 1)
newgroup = Sstrdup(p);
else if (depth > 1)
{
newgroup = Smalloc (strlen(group) + strlen(p) + 2);
sprintf (newgroup, "%s.%s", group, p);
}
if (!expire_arts (newgroup, depth + 1))
{
if (newgroup)
free(newgroup);
break;
}
if (newgroup)
free(newgroup);
if (chdir ("..") < 0) /* I'm stuck in a klien bottle! */
break;
rmdir (p);
}
}
closedir (dir);
if (!d)
{
if (depth > 1 && (n = newsgroupFindAddLock(group, NULL, TRUE)))
{
n->hi = hi;
n->lo = lo;
newsgroupUnlockWrite (n);
}
lo -= lo % XOVER_INDEX_SIZE;
for (l = xover ? xover->head : NULL; l; l = l->next)
{
p = strstr (l->data, "_xover");
*p = '\0';
if (strToi (l->data) < lo)
{
*p = '_';
if (unlink (l->data) == 0);
Stats->xoversExpired++;
}
}
}
if (xover)
strListFree (xover);
return (d ? FALSE : TRUE);
}
EXPORT int volatile ExpireDaemonPid;
EXPORT bool expire (bool force)
/* [<][>][^][v][top][bottom][index][help] */
{
static time_t last_expire;
long ffree = 0;
long files = 0, bavail = 0, blocks = 0;
if (!force && time (NULL) < last_expire + con->expireCheckPeriod)
return TRUE;
last_expire = time (NULL);
if (!force)
getFreeFS (&ffree, &files, &bavail, &blocks);
if (blocks < 1)
blocks = 1;
if (files < 1)
files = 1;
if (ffree < 1)
ffree = 1;
if (bavail < 1)
bavail = 1;
/* Create Blocks Used and Inodes Used shortcuts */
#define BU ((blocks - bavail) / (.01 * blocks ))
#define IU ((files - ffree) / (.01 * files ))
/* logen (("bu = %2.1f, iu = %2.1f", BU, IU)); */
if (!(force || BU > con->minBlocksFreePercent || IU > con->minFilesFreePercent))
return FALSE;
ti = time (NULL);
OldestArt = ti - con->maxArtAge;
if (Task->ti_state == nc_master)
{
if (!ExpireDaemonPid)
{
int pid;
sigset_t myset;
sigemptyset(&myset);
sigaddset(&myset, SIGCHLD);
sigprocmask (SIG_BLOCK, &myset, NULL);
pid = make_vm_proc (nc_expire, -1, "expire");
if (pid == 0)
{
sigprocmask (SIG_UNBLOCK, &myset, NULL);
if (chdir (con->cacheDir)==0)
{
time_t maxArtAge = con->maxArtAge;
expire_arts (NULL, 0);
getFreeFS(&ffree, &files, &bavail, &blocks);
while ((BU > con->minBlocksFreePercent ||
IU > con->minFilesFreePercent) &&
maxArtAge > 60)
{
maxArtAge = (maxArtAge * 2) / 3;
OldestArt = time (NULL) - maxArtAge;
expire_arts (NULL, 0);
getFreeFS(&ffree, &files, &bavail, &blocks);
}
logen (("usedblocks = %2.1f%%, usedinodes = %2.1f%%, maxArtAge = %ds, expire ended",
BU, IU, (int)maxArtAge));
retire_vm_proc (0);
}
else
{
loge (("couldn't chdir(\"%s\") for expire", con->cacheDir));
retire_vm_proc (1);
}
NOTREACHED;
}
if (pid > 0)
{
ExpireDaemonPid = pid;
sigprocmask (SIG_UNBLOCK, &myset, NULL);
}
}
}
else
{
if (chdir (con->cacheDir) == 0)
expire_arts (NULL, 0);
else
loge (("couldn't chdir(\"%s\") for expire", con->cacheDir));
}
chdir (con->cacheDir);
hisPrune ();
return TRUE;
}