Cliff Woolley wrote:
>On Sun, 9 Sep 2001, Brian Pane wrote:
>
>>I think putting it in APR would work. The one limitation I can think of
>>is that adding the cache in apr_explode_localtime() itself wouldn't be a
>>win because we'd have to add the overhead of a gettimeofday() call to
>>check whether the supplied time was indeed current (and thus susceptible
>>to caching).
>>
>
>It took me a minute to figure out why this was a problem, but you're
>right. I don't really like the idea of combining time_now and
>explode_localtime, though. What about some kind of deal like
>apr_explode_recent_localtime() which is the same as
>apr_explode_localtime() except that the input must never be older than
>TIME_CACHE_SIZE seconds? Or is that too httpd-tailored? If so, no sweat,
>make it an ap_ function instead of an apr_ function.
>
I think it's relatively httpd-specific, so I used
ap_explode_recent_localtime().
Here's the revised patch, plus the new files include/util_time.h and
server/util_time.c
--Brian
Index: modules/loggers/mod_log_config.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/loggers/mod_log_config.c,v
retrieving revision 1.68
diff -u -r1.68 mod_log_config.c
--- modules/loggers/mod_log_config.c 2001/08/27 20:50:01 1.68
+++ modules/loggers/mod_log_config.c 2001/09/10 06:42:02
@@ -463,9 +463,9 @@
a problem with this, you can set the define. -djg
*/
#ifdef I_INSIST_ON_EXTRA_CYCLES_FOR_CLF_COMPLIANCE
- apr_explode_localtime(&xt, apr_time_now());
+ ap_explode_recent_localtime(&xt, apr_time_now());
#else
- apr_explode_localtime(&xt, r->request_time);
+ ap_explode_recent_localtime(&xt, r->request_time);
#endif
if (a && *a) { /* Custom format */
apr_strftime(tstr, &retcode, MAX_STRING_LEN, a, &xt);
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
#ifndef APACHE_UTIL_TIME_H
#define APACHE_UTIL_TIME_H
#include "apr.h"
#include "apr_time.h"
#include "httpd.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @package Apache date/time handling functions
*/
/* Maximum delta from the current time, in seconds, for a past time
* to qualify as "recent" for use in the ap_explode_recent_*() functions:
*/
#define AP_TIME_RECENT_THRESHOLD 15
/**
* convert a recent time to its human readable components in local timezone
* @param tm the exploded time
* @param t the time to explode: MUST be within the last
* AP_TIME_RECENT_THRESHOLD seconds
* @note This is a faster alternative to apr_explode_localtime that uses
* a cache of pre-exploded time structures. It is useful for things
* that need to explode the current time multiple times per second,
* like loggers.
* @return APR_SUCCESS iff successful
* @deffunc apr_status_t ap_explode_recent_localtime(apr_exploded_time_t *tm,
apr_time_t t);
*/
AP_DECLARE(apr_status_t) ap_explode_recent_localtime(apr_exploded_time_t *tm,
apr_time_t t);
/**
* convert a recent time to its human readable components in GMT timezone
* @param tm the exploded time
* @param t the time to explode: MUST be within the last
* AP_TIME_RECENT_THRESHOLD seconds
* @note This is a faster alternative to apr_explode_gmt that uses
* a cache of pre-exploded time structures. It is useful for things
* that need to explode the current time multiple times per second,
* like loggers.
* @return APR_SUCCESS iff successful
* @deffunc apr_status_t ap_explode_recent_gmt(apr_exploded_time_t *tm, apr_time_t t);
*/
AP_DECLARE(apr_status_t) ap_explode_recent_gmt(apr_exploded_time_t *tm,
apr_time_t t);
#ifdef __cplusplus
}
#endif
#endif /* !APACHE_UTIL_TIME_H */
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
#include "util_time.h"
/* Cache for exploded values of recent timestamps
*/
struct exploded_time_cache_element {
apr_int64_t t;
apr_exploded_time_t xt;
};
/* the "+ 1" is for the current second: */
#define TIME_CACHE_SIZE (AP_TIME_RECENT_THRESHOLD + 1)
static struct exploded_time_cache_element exploded_cache_localtime[TIME_CACHE_SIZE];
static struct exploded_time_cache_element exploded_cache_gmt[TIME_CACHE_SIZE];
static apr_status_t cached_explode(apr_exploded_time_t *xt, apr_time_t t,
struct exploded_time_cache_element *cache)
{
apr_int64_t seconds = t / APR_USEC_PER_SEC;
struct exploded_time_cache_element *cache_element =
&(cache[seconds % TIME_CACHE_SIZE]);
/* The cache is implemented as a ring buffer. Each second,
* it uses a different element in the buffer. The timestamp
* in the element indicates whether the element contains the
* exploded time for the current second (vs the time
* 'now - AP_TIME_RECENT_THRESHOLD' seconds ago). If the
* cached value is for the current time, we use it. Otherwise,
* we compute the apr_exploded_time_t and store it in this
* cache element. Note that the timestamp in the cache
* element is updated only after the exploded time. Thus
* if two threads hit this cache element simultaneously
* at the start of a new second, they'll both explode the
* time and store it. I.e., the writers will collide, but
* they'll be writing the same value.
*/
if (cache_element->t >= seconds) {
/* Note: If this memcpy ever takes more than TIME_CACHE_SIZE
* seconds, the value will be unpredictable (because this
* bucket in the ring buffer will have been recycled). This
* memcpy should never take multiple seconds, but TIME_CACHE_SIZE
* has a relatively large value just in case.
*/
memcpy(xt, &(cache_element->xt), sizeof(apr_exploded_time_t));
}
else {
apr_status_t r = apr_explode_localtime(xt, t);
if (!APR_STATUS_IS_SUCCESS(r)) {
return r;
}
memcpy(&(cache_element->xt), xt, sizeof(apr_exploded_time_t));
cache_element->t = seconds;
}
xt->tm_usec = t % APR_USEC_PER_SEC;
return APR_SUCCESS;
}
AP_DECLARE(apr_status_t) ap_explode_recent_localtime(apr_exploded_time_t * tm,
apr_time_t t)
{
return cached_explode(tm, t, exploded_cache_localtime);
}
AP_DECLARE(apr_status_t) ap_explode_recent_gmt(apr_exploded_time_t * tm,
apr_time_t t)
{
return cached_explode(tm, t, exploded_cache_gmt);
}