Ryan Bloom wrote:

>On Sunday 09 September 2001 19:46, Brian Pane wrote:
>
>Can we get this as a unified diff?
>
sure, here's the unified form:

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 04:17:59
@@ -445,6 +445,58 @@
     return NULL;
 }
 
+
+/* Cache of expanded timestamps:
+ *  Because apr_explode_localtime is an expensive function call,
+ *  we cache the exploded time and re-use it for the rest of the
+ *  current second.
+ */
+
+struct exploded_time_cache_element {
+    apr_int64_t t;
+    apr_exploded_time_t xt;
+};
+
+#define TIME_CACHE_SIZE 16
+static struct exploded_time_cache_element 
exploded_time_cache[TIME_CACHE_SIZE];
+
+static void cached_explode_localtime(apr_exploded_time_t *xt, apr_time_t t)
+{
+    apr_int64_t seconds = t / APR_USEC_PER_SEC;
+    struct exploded_time_cache_element *cache =
+        &(exploded_time_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 - TIME_CACHE_SIZE' 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->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->xt), sizeof(apr_exploded_time_t));
+    }
+    else {
+        apr_explode_localtime(xt, t);
+        memcpy(&(cache->xt), xt, sizeof(apr_exploded_time_t));
+        cache->t = seconds;
+    }
+}
+
 static const char *log_request_time(request_rec *r, char *a)
 {
     apr_exploded_time_t xt;
@@ -463,9 +515,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());
+    cached_explode_localtime(&xt, apr_time_now());
 #else
-    apr_explode_localtime(&xt, r->request_time);
+    cached_explode_localtime(&xt, r->request_time);
 #endif
     if (a && *a) {              /* Custom format */
         apr_strftime(tstr, &retcode, MAX_STRING_LEN, a, &xt);


Reply via email to