htcacheclean.c revision 03bdb4fb430b0d4e502ddfc75f7e9dbd91db72e9
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin/* Copyright 2001-2004 The Apache Software Foundation
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * Licensed under the Apache License, Version 2.0 (the "License");
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * you may not use this file except in compliance with the License.
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * You may obtain a copy of the License at
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * Unless required by applicable law or agreed to in writing, software
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * distributed under the License is distributed on an "AS IS" BASIS,
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * See the License for the specific language governing permissions and
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * limitations under the License.
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * htcacheclean.c: simple program for cleaning of
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * the disk cache of the Apache HTTP server
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * Contributed by Andreas Steinmetz <ast@domdv.de>
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * 8 Oct 2004
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin/* mod_disk_cache.c extract start */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrintypedef struct {
c1e7441013e1c8f09cb36e48117497f5650b154amartin /* Indicates the format of the header struct stored on-disk. */
c1e7441013e1c8f09cb36e48117497f5650b154amartin /* The HTTP status code returned for this response. */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin /* The size of the entity name that follows. */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin /* The number of times we've cached this entity. */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin /* Miscellaneous time values. */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin/* mod_disk_cache.c extract end */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin/* mod_disk_cache.c related definitions start */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * this is based on #define AP_TEMPFILE "/aptmpXXXXXX"
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * the above definition could be reworked into the following:
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * #define AP_TEMPFILE_PREFIX "/"
c1e7441013e1c8f09cb36e48117497f5650b154amartin * #define AP_TEMPFILE_BASE "aptmp"
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * #define AP_TEMPFILE_SUFFIX "XXXXXX"
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * #define AP_TEMPFILE_BASELEN strlen(AP_TEMPFILE_BASE)
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * #define AP_TEMPFILE_NAMELEN strlen(AP_TEMPFILE_BASE AP_TEMPFILE_SUFFIX)
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * #define AP_TEMPFILE AP_TEMPFILE_PREFIX AP_TEMPFILE_BASE AP_TEMPFILE_SUFFIX
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * these definitions would then match the definitions below:
c1e7441013e1c8f09cb36e48117497f5650b154amartin#define AP_TEMPFILE_NAMELEN strlen(AP_TEMPFILE_BASE AP_TEMPFILE_SUFFIX)
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin/* mod_disk_cache.c related definitions end */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin/* define the following for debugging */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * Note: on Linux delays <= 2ms are busy waits without
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * scheduling, so never use a delay <= 2ms below
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin#define DELETE_NICE 10 /* be nice after this amount of delete ops */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin#define STAT_ATTEMPTS 10 /* maximum stat attempts for a file */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin#define DIRINFO (APR_FINFO_MTIME|APR_FINFO_SIZE|APR_FINFO_TYPE|APR_FINFO_LINK)
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrintypedef struct _direntry {
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin int type; /* type of file/fileset: TEMP, HEADER, DATA, HEADERDATA */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin apr_time_t htime; /* headers file modification time */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrintypedef struct _entry {
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin apr_time_t response_time; /* cache entry time of last response to client */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin apr_time_t htime; /* headers file modification time */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrinstatic int delcount; /* file deletion count for nice mode */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrinstatic int interrupted; /* flag: true if SIGINT or SIGTERM occurred */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrinstatic int realclean; /* flag: true means user said apache is not running */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrinstatic int verbose; /* flag: true means print statistics */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrinstatic int benice; /* flag: true means nice mode is activated */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrinstatic int dryrun; /* flag: true means dry run, don't actually delete
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin anything */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrinstatic int baselen; /* string length of the path to the proxy directory */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrinstatic apr_time_t now; /* start time of this processing run */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrinstatic apr_off_t unsolicited; /* file size summary for deleted unsolicited
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrinstatic APR_RING_ENTRY(_entry) root; /* ENTRY ring anchor */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * fake delete for debug purposes
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrinstatic void fake_file_remove(char *pathname, apr_pool_t *p)
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin /* stat and printing to simulate some deletion system load and to
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin display what would actually have happened */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin apr_file_printf(errfile, "would delete %s\n", pathname);
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * called on SIGINT or SIGTERM
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * called in out of memory condition
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin static int called = 0;
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin /* be careful to call exit() only once */
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin * print purge statistics
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrinstatic void printstats(apr_off_t total, apr_off_t sum, apr_off_t max,
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin apr_file_printf(errfile, "unsolicited size %d.%d%c\n",
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin apr_file_printf(errfile, "size limit %d.0%c\n", (int)(max), mtype);
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin apr_file_printf(errfile, "total size was %d.%d%c, total size now "
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin "%d.%d%c\n",
abe0d0e38b9705f21a13ac8748bce1e3ed35e488minfrin apr_file_printf(errfile, "total entries was %d, total entries now %d\n",
char *nextpath;
apr_pool_t *p;
if (dryrun) {
apr_pool_destroy(p);
if (benice) {
delcount = 0;
char *nextpath;
apr_pool_t *p;
if (dryrun) {
apr_pool_destroy(p);
if (benice) {
delcount = 0;
apr_pool_t *p;
apr_hash_t *h;
apr_hash_index_t *i;
DIRENTRY *d, *t, *n;
ENTRY *e;
h = apr_hash_make(p);
skip = 0;
skip++;
if (interrupted) {
if (!base++) {
if (!ext) {
if (interrupted) {
switch(d->type) {
case HEADERDATA:
p) == APR_SUCCESS) {
case HEADER:
case DATA:
case TEMP:
if (interrupted) {
apr_pool_destroy(p);
if (benice) {
if (interrupted) {
sum = 0;
entries = 0;
entries++;
entries--;
if (!interrupted) {
if (interrupted) {
entries--;
if (!interrupted) {
if (interrupted) {
oldest = e;
entries--;
if (!interrupted) {
static void usage(void)
apr_getopt_t *o;
char opt;
const char *arg;
interrupted = 0;
repeat = 0;
isdaemon = 0;
dryrun = 0;
limit_found = 0;
max = 0;
verbose = 0;
realclean = 0;
benice = 0;
intelligent = 0;
usage();
switch (opt) {
if (intelligent) {
usage();
if (dryrun) {
usage();
if (benice) {
usage();
if (verbose) {
usage();
if (realclean) {
usage();
if (isdaemon) {
usage();
if (limit_found) {
usage();
if (limit_found) {
usage();
if (proxypath) {
usage();
usage();
usage();
usage();
usage();
usage();
usage();
#ifndef DEBUG
if (isdaemon) {
delcount = 0;
unsolicited = 0;
dowork = 0;
switch (intelligent) {
if (isdaemon) {
delay = 0;