httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Rainer Jung <rainer.j...@kippdata.de>
Subject Re: svn commit: r917013 - in /httpd/httpd/branches/2.2.x: CHANGES STATUS docs/manual/mod/mod_cache.xml modules/cache/cache_storage.c modules/cache/cache_util.c modules/cache/mod_cache.c modules/cache/mod_cache.h
Date Sun, 28 Feb 2010 11:52:15 GMT
On 27.02.2010 19:54, minfrin@apache.org wrote:
> Author: minfrin
> Date: Sat Feb 27 18:54:40 2010
> New Revision: 917013
>
> URL: http://svn.apache.org/viewvc?rev=917013&view=rev
> Log:
> mod_cache: Introduce the thundering herd lock, a mechanism to keep
> the flood of requests at bay that strike a backend webserver as
> a cached entity goes stale.
> +1: minfrin, jim, pgollucci
>
> Modified:
>      httpd/httpd/branches/2.2.x/CHANGES
>      httpd/httpd/branches/2.2.x/STATUS
>      httpd/httpd/branches/2.2.x/docs/manual/mod/mod_cache.xml
>      httpd/httpd/branches/2.2.x/modules/cache/cache_storage.c
>      httpd/httpd/branches/2.2.x/modules/cache/cache_util.c
>      httpd/httpd/branches/2.2.x/modules/cache/mod_cache.c
>      httpd/httpd/branches/2.2.x/modules/cache/mod_cache.h
>


> Modified: httpd/httpd/branches/2.2.x/modules/cache/cache_util.c
> URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/cache/cache_util.c?rev=917013&r1=917012&r2=917013&view=diff
> ==============================================================================
> --- httpd/httpd/branches/2.2.x/modules/cache/cache_util.c (original)
> +++ httpd/httpd/branches/2.2.x/modules/cache/cache_util.c Sat Feb 27 18:54:40 2010
> @@ -22,6 +22,8 @@
>
>   /* -------------------------------------------------------------- */
>
> +extern APR_OPTIONAL_FN_TYPE(ap_cache_generate_key) *cache_generate_key;
> +
>   extern module AP_MODULE_DECLARE_DATA cache_module;
>
>   /* Determine if "url" matches the hostname, scheme and port and path
> @@ -164,9 +166,182 @@
>       return apr_time_sec(current_age);
>   }
>
> +/**
> + * Try obtain a cache wide lock on the given cache key.
> + *
> + * If we return APR_SUCCESS, we obtained the lock, and we are clear to
> + * proceed to the backend. If we return APR_EEXISTS, then the lock is
> + * already locked, someone else has gone to refresh the backend data
> + * already, so we must return stale data with a warning in the mean
> + * time. If we return anything else, then something has gone pear
> + * shaped, and we allow the request through to the backend regardless.
> + *
> + * This lock is created from the request pool, meaning that should
> + * something go wrong and the lock isn't deleted on return of the
> + * request headers from the backend for whatever reason, at worst the
> + * lock will be cleaned up when the request dies or finishes.
> + *
> + * If something goes truly bananas and the lock isn't deleted when the
> + * request dies, the lock will be trashed when its max-age is reached,
> + * or when a request arrives containing a Cache-Control: no-cache. At
> + * no point is it possible for this lock to permanently deny access to
> + * the backend.
> + */
> +CACHE_DECLARE(apr_status_t) ap_cache_try_lock(cache_server_conf *conf,
> +        request_rec *r, char *key) {
> +    apr_status_t status;
> +    const char *lockname;
> +    const char *path;
> +    char dir[5];
> +    apr_time_t now = apr_time_now();
> +    apr_finfo_t finfo;
> +    apr_file_t *lockfile;
> +    void *dummy;
> +
> +    finfo.mtime = 0;
> +
> +    if (!conf || !conf->lock || !conf->lockpath) {
> +        /* no locks configured, leave */
> +        return APR_SUCCESS;
> +    }
> +
> +    /* lock already obtained earlier? if so, success */
> +    apr_pool_userdata_get(&dummy, CACHE_LOCKFILE_KEY, r->pool);
> +    if (dummy) {
> +        return APR_SUCCESS;
> +    }
> +
> +    /* create the key if it doesn't exist */
> +    if (!key) {
> +        cache_generate_key(r, r->pool,&key);
> +    }
> +
> +    /* create a hashed filename from the key, and save it for later */
> +    lockname = ap_cache_generate_name(r->pool, 0, 0, key);
> +
> +    /* lock files represent discrete just-went-stale URLs "in flight", so
> +     * we support a simple two level directory structure, more is overkill.
> +     */
> +    dir[0] = '/';
> +    dir[1] = lockname[0];
> +    dir[2] = '/';
> +    dir[3] = lockname[1];
> +    dir[4] = 0;
> +
> +    /* make the directories */
> +    path = apr_pstrcat(r->pool, conf->lockpath, dir, NULL);
> +    if (APR_SUCCESS != (status = apr_dir_make_recursive(path,
> +            APR_UREAD|APR_UWRITE|APR_UEXECUTE, r->pool))) {
> +        ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
> +                     "Could not create a cache lock directory: %s",
> +                     path);
> +        return status;
> +    }
> +    lockname = apr_pstrcat(r->pool, path, "/", lockname, NULL);
> +    apr_pool_userdata_set(lockname, CACHE_LOCKNAME_KEY, NULL, r->pool);
> +
> +    /* is an existing lock file too old? */
> +    status = apr_stat(&finfo, lockname,
> +                APR_FINFO_MTIME | APR_FINFO_NLINK, r->pool);
> +    if (!(APR_STATUS_IS_ENOENT(status))&&  APR_SUCCESS != status) {
> +        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EEXIST, r->server,
> +                     "Could not stat a cache lock file: %s",
> +                     lockname);
> +        return status;
> +    }
> +    if (APR_SUCCESS == status&&  ((now - finfo.mtime)>  conf->lockmaxage)
> +            || (now<  finfo.mtime)) {

Compiler warns:

cache_util.c: In function 'ap_cache_try_lock':
cache_util.c:253: warning: suggest parentheses around && within ||

and indeed trunk has additional parentheses surrounding the "or" clause:

If ((status == APR_SUCCESS) && (((now - finfo.mtime) > conf->lockmaxage)
                               || (now < finfo.mtime))) {

It seems the backport missed something.

> +        ap_log_error(APLOG_MARK, APLOG_INFO, status, r->server,
> +                     "Cache lock file for '%s' too old, removing: %s",
> +                     r->uri, lockname);
> +        apr_file_remove(lockname, r->pool);
> +    }
> +
> +    /* try obtain a lock on the file */
> +    if (APR_SUCCESS == (status = apr_file_open(&lockfile, lockname,
> +            APR_WRITE | APR_CREATE | APR_EXCL | APR_DELONCLOSE,
> +            APR_UREAD | APR_UWRITE, r->pool))) {
> +        apr_pool_userdata_set(lockfile, CACHE_LOCKFILE_KEY, NULL, r->pool);
> +    }
> +    return status;
> +
> +}

Regards,

Rainer

Mime
View raw message