⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 proxy_cache.c

📁 apache 安装教程 apache 安装教程
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements.  See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License.  You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* Cache and garbage collection routines for Apache proxy */#include "mod_proxy.h"#include "http_conf_globals.h"#include "http_log.h"#include "http_main.h"#include "http_core.h"#include "util_date.h"#ifdef WIN32#include <sys/utime.h>#else#include <utime.h>#endif                          /* WIN32 */#include "multithread.h"#include "ap_md5.h"#ifdef __TANDEM#include <sys/types.h>#include <sys/stat.h>#endif#ifdef TPF#include "os.h"#endifstruct gc_ent {    unsigned long int len;    time_t expire;    char file[HASH_LEN + 1];};/* Poor man's 61 bit arithmetic */typedef struct {    long lower;                 /* lower 30 bits of result */    long upper;                 /* upper 31 bits of result */} long61_t;/* FIXME: The block size can be different on a `per file system' base. * This would make automatic detection highly OS specific. * In the GNU fileutils code for du(1), you can see how complicated it can * become to detect the block size. And, with BSD-4.x fragments, it * it even more difficult to get precise results. * As a compromise (and to improve on the incorrect counting of cache * size on byte level, omitting directory sizes entirely, which was * used up to apache-1.3b7) we're rounding to multiples of 512 here. * Your file system may be using larger blocks (I certainly hope so!) * but it will hardly use smaller blocks. * (So this approximation is still closer to reality than the old behavior). * The best solution would be automatic detection, the next best solution * IMHO is a sensible default and the possibility to override it. */#define ROUNDUP2BLOCKS(_bytes) (((_bytes)+block_size-1) & ~(block_size-1))static long block_size = 512;   /* this must be a power of 2 */static long61_t curbytes, cachesize;static time_t garbage_now, garbage_expire;static mutex *garbage_mutex = NULL;int ap_proxy_garbage_init(server_rec *r, pool *p){    if (!garbage_mutex)        garbage_mutex = ap_create_mutex(NULL);    return (0);}static int sub_garbage_coll(request_rec *r, array_header *files,                             const char *cachedir, const char *cachesubdir);static void help_proxy_garbage_coll(request_rec *r);static int should_proxy_garbage_coll(request_rec *r);#if !defined(WIN32) && !defined(MPE) && !defined(OS2) && !defined(NETWARE) && !defined(TPF)static void detached_proxy_garbage_coll(request_rec *r);#endifvoid ap_proxy_garbage_coll(request_rec *r){    static int inside = 0;    (void)ap_acquire_mutex(garbage_mutex);    if (inside == 1) {        (void)ap_release_mutex(garbage_mutex);        return;    }    else        inside = 1;    (void)ap_release_mutex(garbage_mutex);    ap_block_alarms();          /* avoid SIGALRM on big cache cleanup */    if (should_proxy_garbage_coll(r))#if !defined(WIN32) && !defined(MPE) && !defined(OS2) && !defined(NETWARE) && !defined(TPF)        detached_proxy_garbage_coll(r);#else        help_proxy_garbage_coll(r);#endif    ap_unblock_alarms();    (void)ap_acquire_mutex(garbage_mutex);    inside = 0;    (void)ap_release_mutex(garbage_mutex);}static void add_long61(long61_t *accu, long val){    /* Add in lower 30 bits */    accu->lower += (val & 0x3FFFFFFFL);    /* add in upper bits, and carry */    accu->upper += (val >> 30) + ((accu->lower & ~0x3FFFFFFFL) != 0L);    /* Clear carry */    accu->lower &= 0x3FFFFFFFL;}static void sub_long61(long61_t *accu, long val){    int carry = (val & 0x3FFFFFFFL) > accu->lower;    /* Subtract lower 30 bits */    accu->lower = accu->lower - (val & 0x3FFFFFFFL) + ((carry) ? 0x40000000 : 0);    /* add in upper bits, and carry */    accu->upper -= (val >> 30) + carry;}/* Compare two long61's: * return <0 when left < right * return  0 when left == right * return >0 when left > right */static long cmp_long61(long61_t *left, long61_t *right){    return (left->upper == right->upper) ? (left->lower - right->lower)    : (left->upper - right->upper);}/* Compare two gc_ent's, sort them by expiration date */static int gcdiff(const void *ap, const void *bp){    const struct gc_ent *a = (const struct gc_ent *) ap;    const struct gc_ent *b = (const struct gc_ent *) bp;    if (a->expire > b->expire)        return 1;    else if (a->expire < b->expire)        return -1;    else        return 0;}#if !defined(WIN32) && !defined(MPE) && !defined(OS2) && !defined(NETWARE) && !defined(TPF)static void detached_proxy_garbage_coll(request_rec *r){    pid_t pid;    int status;    pid_t pgrp;#if 0    ap_log_error(APLOG_MARK, APLOG_DEBUG, r->server,                 "proxy: Guess what; we fork() again...");#endif    switch (pid = fork()) {    case -1:        ap_log_error(APLOG_MARK, APLOG_ERR, r->server,                     "proxy: fork() for cache cleanup failed");        return;    case 0:                     /* Child */        /* close all sorts of things, including the socket fd */        ap_cleanup_for_exec();        /* Fork twice to disassociate from the child */        switch (pid = fork()) {        case -1:            ap_log_error(APLOG_MARK, APLOG_ERR, r->server,                         "proxy: fork(2nd) for cache cleanup failed");            exit(1);        case 0:         /* Child */            /* The setpgrp() stuff was snarfed from http_main.c */#ifndef NO_SETSID            if ((pgrp = setsid()) == -1) {                perror("setsid");                fprintf(stderr, "%s: setsid failed\n",                        ap_server_argv0);                exit(1);            }#elif defined(NEXT) || defined(NEWSOS)            if (setpgrp(0, getpid()) == -1 || (pgrp = getpgrp(0)) == -1) {                perror("setpgrp");                fprintf(stderr, "%S: setpgrp or getpgrp failed\n",                        ap_server_argv0);                exit(1);            }#elif defined(CYGWIN)            /* Cygwin does not take any argument for setpgrp() */            if ((pgrp = setpgrp()) == -1) {                perror("setpgrp");                fprintf(stderr, "%S: setpgrp failed\n",                        ap_server_argv0);                exit(1);            }#else            if ((pgrp = setpgrp(getpid(), 0)) == -1) {                perror("setpgrp");                fprintf(stderr, "%s: setpgrp failed\n",                        ap_server_argv0);                exit(1);            }#endif            help_proxy_garbage_coll(r);            exit(0);        default:                /* Father */            /* After grandson has been forked off, */            /* there's nothing else to do. */            exit(0);        }    default:        /* Wait until grandson has been forked off */        /* (without wait we'd leave a zombie) */        waitpid(pid, &status, 0);        return;    }}#endif                          /* ndef WIN32 */#define DOT_TIME "/.time"       /* marker */static int should_proxy_garbage_coll(request_rec *r){    void *sconf = r->server->module_config;    proxy_server_conf *pconf =    (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module);    const struct cache_conf *conf = &pconf->cache;    const char *cachedir = conf->root;    char *filename;    struct stat buf;    int timefd;    time_t every = conf->gcinterval;    static time_t lastcheck = BAD_DATE; /* static (per-process) data!!! */    if (cachedir == NULL || every == -1)        return 0;    filename = ap_palloc(r->pool, strlen(cachedir) + strlen(DOT_TIME) + 1);    garbage_now = time(NULL);    /*     * Usually, the modification time of <cachedir>/.time can only increase.     * Thus, even with several child processes having their own copy of     * lastcheck, if time(NULL) still < lastcheck then it's not time for GC     * yet.     */    if (garbage_now != -1 && lastcheck != BAD_DATE && garbage_now < lastcheck + every)        return 0;    strcpy(filename, cachedir);    strcat(filename, DOT_TIME);    /*     * At this point we have a bit of an engineering compromise. We could     * either create and/or mark the .time file  (prior to the fork which     * might fail on a resource issue) or wait until we are safely forked.     * The advantage of doing it now in this process is that we get some     * usefull live out of the global last check variable. (XXX which should     * go scoreboard IMHO.) Note that the actual counting is at a later     * moment.     */    if (stat(filename, &buf) == -1) {   /* does not exist */        if (errno != ENOENT) {            ap_log_error(APLOG_MARK, APLOG_ERR, r->server,                         "proxy: stat(%s)", filename);            return 0;        }        if ((timefd = creat(filename, 0666)) == -1) {            if (errno != EEXIST)                ap_log_error(APLOG_MARK, APLOG_ERR, r->server,                             "proxy: creat(%s)", filename);            else                lastcheck = garbage_now;        /* someone else got in there */            return 0;        }        close(timefd);    }    else {        lastcheck = buf.st_mtime;       /* save the time */        if (garbage_now < lastcheck + every) {            return 0;        }        if (utime(filename, NULL) == -1)            ap_log_error(APLOG_MARK, APLOG_ERR, r->server,                         "proxy: utimes(%s)", filename);    }    return 1;}static void help_proxy_garbage_coll(request_rec *r){    const char *cachedir;    void *sconf = r->server->module_config;    proxy_server_conf *pconf =    (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module);    const struct cache_conf *conf = &pconf->cache;    array_header *files;    struct gc_ent *fent;    char *filename;    int i;    cachedir = conf->root;    filename = ap_palloc(r->pool, strlen(cachedir) + HASH_LEN + 2);    /* configured size is given in kB. Make it bytes, convert to long61_t: */    cachesize.lower = cachesize.upper = 0;    add_long61(&cachesize, conf->space << 10);    ap_block_alarms();          /* avoid SIGALRM on big cache cleanup */    files = ap_make_array(r->pool, 100, sizeof(struct gc_ent));    curbytes.upper = curbytes.lower = 0L;    sub_garbage_coll(r, files, cachedir, "/");    if (cmp_long61(&curbytes, &cachesize) < 0L) {        ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server,                     "proxy GC: Cache is %ld%% full (nothing deleted)",                     (long)(((curbytes.upper << 20) | (curbytes.lower >> 10)) * 100 / conf->space));        ap_unblock_alarms();        return;    }    /* sort the files we found by expiration date */    qsort(files->elts, files->nelts, sizeof(struct gc_ent), gcdiff);    for (i = 0; i < files->nelts; i++) {        fent = &((struct gc_ent *) files->elts)[i];        sprintf(filename, "%s%s", cachedir, fent->file);        ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server, "GC Unlinking %s (expiry %ld, garbage_now %ld)", filename, (long)fent->expire, (long)garbage_now);#if TESTING

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -