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);