Commit bafd78c4 authored by Bradley Nicholes's avatar Bradley Nicholes
Browse files

Enhance the util_ldap cache-info page to display the current contents of the...

Enhance the util_ldap cache-info page to display the current contents of the search, compare and dn_compare caches

Reviewed by: bnicholes, minfrin, jjclar


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/APACHE_2_0_BRANCH@104480 13f79535-47bb-0310-9956-ffa450edef68
parent 784e6aac
Loading
Loading
Loading
Loading
+1 −11
Changes for include/util_ldap.h: 1 added line, 11 removed lines.
Original line number Diff line number Diff line
@@ -279,16 +279,6 @@ LDAP_DECLARE(int) util_ldap_ssl_supported(request_rec *r);
 */
apr_status_t util_ldap_cache_init(apr_pool_t *pool, util_ldap_state_t *st);

/**
 * Display formatted stats for cache
 * @param The pool to allocate the returned string from
 * @tip This function returns a string allocated from the provided pool that describes
 *      various stats about the cache.
 * @deffunc char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st)
 */
char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st);


/* from apr_ldap_cache_mgr.c */

/**
@@ -298,7 +288,7 @@ char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st);
 *      various stats about the cache.
 * @deffunc char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st)
 */
char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st);
char *util_ald_cache_display(request_rec *r, util_ldap_state_t *st);

#endif /* APU_HAS_LDAP */
#endif /* UTIL_LDAP_H */
+9 −26
Changes for modules/experimental/util_ldap.c: 9 added lines, 26 removed lines.
Original line number Diff line number Diff line
@@ -134,22 +134,7 @@ int util_ldap_handler(request_rec *r)
             "<html><head><title>LDAP Cache Information</title></head>\n", r);
    ap_rputs("<body bgcolor='#ffffff'><h1 align=center>LDAP Cache Information</h1>\n", r);

    ap_rputs("<p>\n"
             "<table border='0'>\n"
             "<tr bgcolor='#000000'>\n"
             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name</b></font></td>"
             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Entries</b></font></td>"
             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg. Chain Len.</b></font></td>"
             "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Hits</b></font></td>"
             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Ins/Rem</b></font></td>"
             "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Purges</b></font></td>"
             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg Purge Time</b></font></td>"
             "</tr>\n", r
            );

    ap_rputs(util_ald_cache_display(r->pool, st), r);

    ap_rputs("</table>\n</p>\n", r);
    util_ald_cache_display(r, st);

    return OK;
}
@@ -627,7 +612,7 @@ LDAP_DECLARE(int) util_ldap_cache_compare(request_rec *r, util_ldap_connection_t
    util_url_node_t curnode;
    util_compare_node_t *compare_nodep;
    util_compare_node_t the_compare_node;
    apr_time_t curtime;
    apr_time_t curtime = 0; /* silence gcc -Wall */
    int failures = 0;

    util_ldap_state_t *st = 
@@ -972,7 +957,8 @@ static const char *util_ldap_set_cache_bytes(cmd_parms *cmd, void *dummy, const
    st->cache_bytes = atol(bytes);

    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server, 
                      "[%d] ldap cache: Setting shared memory cache size to %d bytes.", 
                 "[%" APR_PID_T_FMT "] ldap cache: Setting shared memory "
                 " cache size to %" APR_SIZE_T_FMT " bytes.", 
                 getpid(), st->cache_bytes);

    return NULL;
@@ -1085,7 +1071,7 @@ static const char *util_ldap_set_cert_auth(cmd_parms *cmd, void *dummy, const ch
}


const char *util_ldap_set_cert_type(cmd_parms *cmd, void *dummy, const char *Type)
static const char *util_ldap_set_cert_type(cmd_parms *cmd, void *dummy, const char *Type)
{
    util_ldap_state_t *st = 
    (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config, 
@@ -1137,19 +1123,16 @@ void *util_ldap_create_config(apr_pool_t *p, server_rec *s)

static apr_status_t util_ldap_cleanup_module(void *data)
{
#if APR_HAS_LDAP_SSL && APR_HAS_NOVELL_LDAPSDK
    server_rec *s = data;

    util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(
        s->module_config, &ldap_module);
    
    #if APR_HAS_LDAP_SSL
        #if APR_HAS_NOVELL_LDAPSDK
    if (st->ssl_support)
        ldapssl_client_deinit();
        #endif
    #endif

    return(APR_SUCCESS);
#endif
    return APR_SUCCESS;
}

static int util_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, 
@@ -1181,7 +1164,7 @@ static int util_ldap_post_config(apr_pool_t *p, apr_pool_t *plog,
        s_vhost = s->next;
        while (s_vhost) {
            ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, result, s, 
                         "LDAP merging Shared Cache conf: shm=0x%x rmm=0x%x for VHOST: %s",
                         "LDAP merging Shared Cache conf: shm=0x%pp rmm=0x%pp for VHOST: %s",
                         st->cache_shm, st->cache_rmm, s_vhost->server_hostname);

            st_vhost = (util_ldap_state_t *)ap_get_module_config(s_vhost->module_config, &ldap_module);
+81 −1
Changes for modules/experimental/util_ldap_cache.c: 81 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
 */

#include <apr_ldap.h>
#include <apr_strings.h>
#include "util_ldap.h"
#include "util_ldap_cache.h"

@@ -78,6 +79,12 @@ void util_ldap_url_node_free(util_ald_cache_t *cache, void *n)
    util_ald_free(cache, node);
}

void util_ldap_url_node_display(request_rec *r, util_ald_cache_t *cache, void *n)
{
    util_url_node_t *node = (util_url_node_t *)n;

}

/* ------------------------------------------------------------------ */

/* Cache functions for search nodes */
@@ -156,6 +163,27 @@ void util_ldap_search_node_free(util_ald_cache_t *cache, void *n)
    util_ald_free(cache, node);
}

void util_ldap_search_node_display(request_rec *r, util_ald_cache_t *cache, void *n)
{
    util_search_node_t *node = (util_search_node_t *)n;
    char date_str[APR_CTIME_LEN+1];
    char *buf;

    apr_ctime(date_str, node->lastbind);

    buf = apr_psprintf(r->pool, 
             "<tr valign='top'>"
             "<td nowrap>%s</td>"
             "<td nowrap>%s</td>"
             "<td nowrap>%s</td>"
             "<tr>",
         node->username,
         node->dn,
         date_str);

    ap_rputs(buf, r);
}

/* ------------------------------------------------------------------ */

unsigned long util_ldap_compare_node_hash(void *n)
@@ -203,6 +231,41 @@ void util_ldap_compare_node_free(util_ald_cache_t *cache, void *n)
    util_ald_free(cache, node);
}

void util_ldap_compare_node_display(request_rec *r, util_ald_cache_t *cache, void *n)
{
    util_compare_node_t *node = (util_compare_node_t *)n;
    char date_str[APR_CTIME_LEN+1];
    char *buf, *cmp_result;

    apr_ctime(date_str, node->lastcompare);

    if (node->result == LDAP_COMPARE_TRUE) {
        cmp_result = "LDAP_COMPARE_TRUE";
    }
    else if (node->result == LDAP_COMPARE_FALSE) {
        cmp_result = "LDAP_COMPARE_FALSE";
    }
    else {
        cmp_result = apr_itoa(r->pool, node->result);
    }

    buf = apr_psprintf(r->pool, 
             "<tr valign='top'>"
             "<td nowrap>%s</td>"
             "<td nowrap>%s</td>"
             "<td nowrap>%s</td>"
             "<td nowrap>%s</td>"
             "<td nowrap>%s</td>"
             "<tr>",
         node->dn,
         node->attrib,
         node->value,
         date_str,
         cmp_result);

    ap_rputs(buf, r);
}

/* ------------------------------------------------------------------ */

unsigned long util_ldap_dn_compare_node_hash(void *n)
@@ -241,6 +304,22 @@ void util_ldap_dn_compare_node_free(util_ald_cache_t *cache, void *n)
    util_ald_free(cache, node);
}

void util_ldap_dn_compare_node_display(request_rec *r, util_ald_cache_t *cache, void *n)
{
    util_dn_compare_node_t *node = (util_dn_compare_node_t *)n;
    char *buf;

    buf = apr_psprintf(r->pool, 
             "<tr valign='top'>"
             "<td nowrap>%s</td>"
             "<td nowrap>%s</td>"
             "<tr>",
         node->reqdn,
         node->dn);

    ap_rputs(buf, r);
}


/* ------------------------------------------------------------------ */
apr_status_t util_ldap_cache_child_kill(void *data);
@@ -290,7 +369,8 @@ apr_status_t util_ldap_cache_init(apr_pool_t *pool, util_ldap_state_t *st)
                              util_ldap_url_node_hash,
                              util_ldap_url_node_compare,
                              util_ldap_url_node_copy,
                              util_ldap_url_node_free);
                              util_ldap_url_node_free,
                              util_ldap_url_node_display);
    return APR_SUCCESS;
}

+11 −3
Changes for modules/experimental/util_ldap_cache.h: 11 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ struct util_ald_cache {
    int (*compare)(void *, void *);     /* Func to compare two payloads */
    void * (*copy)(util_ald_cache_t *cache, void *); /* Func to alloc mem and copy payload to new mem */
    void (*free)(util_ald_cache_t *cache, void *); /* Func to free mem used by the payload */
    void (*display)(request_rec *r, util_ald_cache_t *cache, void *); /* Func to display the payload contents */
    util_cache_node_t **nodes;

    unsigned long numpurges;    /* No. of times the cache has been purged */
@@ -157,18 +158,25 @@ unsigned long util_ldap_url_node_hash(void *n);
int util_ldap_url_node_compare(void *a, void *b);
void *util_ldap_url_node_copy(util_ald_cache_t *cache, void *c);
void util_ldap_url_node_free(util_ald_cache_t *cache, void *n);
void util_ldap_url_node_display(request_rec *r, util_ald_cache_t *cache, void *n);

unsigned long util_ldap_search_node_hash(void *n);
int util_ldap_search_node_compare(void *a, void *b);
void *util_ldap_search_node_copy(util_ald_cache_t *cache, void *c);
void util_ldap_search_node_free(util_ald_cache_t *cache, void *n);
void util_ldap_search_node_display(request_rec *r, util_ald_cache_t *cache, void *n);

unsigned long util_ldap_compare_node_hash(void *n);
int util_ldap_compare_node_compare(void *a, void *b);
void *util_ldap_compare_node_copy(util_ald_cache_t *cache, void *c);
void util_ldap_compare_node_free(util_ald_cache_t *cache, void *n);
void util_ldap_compare_node_display(request_rec *r, util_ald_cache_t *cache, void *n);

unsigned long util_ldap_dn_compare_node_hash(void *n);
int util_ldap_dn_compare_node_compare(void *a, void *b);
void *util_ldap_dn_compare_node_copy(util_ald_cache_t *cache, void *c);
void util_ldap_dn_compare_node_free(util_ald_cache_t *cache, void *n);
void util_ldap_dn_compare_node_display(request_rec *r, util_ald_cache_t *cache, void *n);


/* util_ldap_cache_mgr.c */
@@ -186,14 +194,14 @@ util_ald_cache_t *util_ald_create_cache(util_ldap_state_t *st,
                                unsigned long (*hashfunc)(void *), 
                                int (*comparefunc)(void *, void *),
                                void * (*copyfunc)(util_ald_cache_t *cache, void *),
                                void (*freefunc)(util_ald_cache_t *cache, void *));
                                void (*freefunc)(util_ald_cache_t *cache, void *),
                                void (*displayfunc)(request_rec *r, util_ald_cache_t *cache, void *));
                                
void util_ald_destroy_cache(util_ald_cache_t *cache);
void *util_ald_cache_fetch(util_ald_cache_t *cache, void *payload);
void util_ald_cache_insert(util_ald_cache_t *cache, void *payload);
void util_ald_cache_remove(util_ald_cache_t *cache, void *payload);
char *util_ald_cache_display_stats(apr_pool_t *p, util_ald_cache_t *cache,
                                 char *name);
char *util_ald_cache_display_stats(request_rec *r, util_ald_cache_t *cache, char *name, char *id);

#endif /* APU_HAS_LDAP */
#endif /* APU_LDAP_CACHE_H */
+141 −16
Changes for modules/experimental/util_ldap_cache_mgr.c: 141 added lines, 16 removed lines.
Original line number Diff line number Diff line
@@ -222,21 +222,25 @@ util_url_node_t *util_ald_create_caches(util_ldap_state_t *st, const char *url)
					  util_ldap_search_node_hash,
					  util_ldap_search_node_compare,
					  util_ldap_search_node_copy,
					  util_ldap_search_node_free);
					  util_ldap_search_node_free,
                      util_ldap_search_node_display);
    compare_cache = util_ald_create_cache(st,
					   util_ldap_compare_node_hash,
					   util_ldap_compare_node_compare,
					   util_ldap_compare_node_copy,
					   util_ldap_compare_node_free);
					   util_ldap_compare_node_free,
                       util_ldap_compare_node_display);
    dn_compare_cache = util_ald_create_cache(st,
					      util_ldap_dn_compare_node_hash,
					      util_ldap_dn_compare_node_compare,
					      util_ldap_dn_compare_node_copy,
					      util_ldap_dn_compare_node_free);
					      util_ldap_dn_compare_node_free,
                          util_ldap_dn_compare_node_display);

    /* check that all the caches initialised successfully */
    if (search_cache && compare_cache && dn_compare_cache) {

/*XXX This can be allocated on the stack since it will be copied anyway */
        curl = (util_url_node_t *)apr_pcalloc(st->pool, sizeof(util_url_node_t));
        curl->url = url;
        curl->search_cache = search_cache;
@@ -255,7 +259,8 @@ util_ald_cache_t *util_ald_create_cache(util_ldap_state_t *st,
                                unsigned long (*hashfunc)(void *), 
                                int (*comparefunc)(void *, void *),
                                void * (*copyfunc)(util_ald_cache_t *cache, void *),
                                void (*freefunc)(util_ald_cache_t *cache, void *))
                                void (*freefunc)(util_ald_cache_t *cache, void *),
                                void (*displayfunc)(request_rec *r, util_ald_cache_t *cache, void *))
{
    util_ald_cache_t *cache;
    unsigned long i;
@@ -297,6 +302,7 @@ util_ald_cache_t *util_ald_create_cache(util_ldap_state_t *st,
    cache->compare = comparefunc;
    cache->copy = copyfunc;
    cache->free = freefunc;
    cache->display = displayfunc;

    cache->fullmark = cache->maxentries / 4 * 3;
    cache->marktime = 0;
@@ -437,14 +443,15 @@ void util_ald_cache_remove(util_ald_cache_t *cache, void *payload)
    cache->numentries--;
}

char *util_ald_cache_display_stats(apr_pool_t *p, util_ald_cache_t *cache, char *name)
char *util_ald_cache_display_stats(request_rec *r, util_ald_cache_t *cache, char *name, char *id)
{
    unsigned long i;
    int totchainlen = 0;
    int nchains = 0;
    double chainlen;
    util_cache_node_t *n;
    char *buf;
    char *buf, *buf2;
    apr_pool_t *p = r->pool;

    if (cache == NULL) {
        return "";
@@ -459,6 +466,17 @@ char *util_ald_cache_display_stats(apr_pool_t *p, util_ald_cache_t *cache, char
    }
    chainlen = nchains? (double)totchainlen / (double)nchains : 0;

    if (id) {
        buf2 = apr_psprintf(p, 
                 "<a href=\"%s?%s\">%s</a>",
             r->uri,
             id,
             name);
    }
    else {
        buf2 = name;
    }

    buf = apr_psprintf(p, 
             "<tr valign='top'>"
             "<td nowrap>%s</td>"
@@ -467,7 +485,7 @@ char *util_ald_cache_display_stats(apr_pool_t *p, util_ald_cache_t *cache, char
             "<td align='right'>%lu/%lu</td>"
             "<td align='right'>%.0f%%</td>"
             "<td align='right'>%lu/%lu</td>",
             name,
         buf2,
         cache->numentries, 
         (double)cache->numentries / (double)cache->maxentries * 100.0,
         chainlen,
@@ -500,10 +518,16 @@ char *util_ald_cache_display_stats(apr_pool_t *p, util_ald_cache_t *cache, char
    return buf;
}

char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st)
char *util_ald_cache_display(request_rec *r, util_ldap_state_t *st)
{
    unsigned long i;
    unsigned long i,j;
    char *buf, *t1, *t2, *t3;
    char *id1, *id2, *id3;
    char *argfmt = "cache=%s&id=%d&off=%d";
    char *scanfmt = "cache=%4s&id=%u&off=%u%1s";
    apr_pool_t *pool = r->pool;
    util_cache_node_t *p;
    util_url_node_t *n;

    util_ald_cache_t *util_ldap_cache = st->util_ldap_cache;

@@ -512,30 +536,131 @@ char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st)
        return "<tr valign='top'><td nowrap colspan=7>Cache has not been enabled/initialised.</td></tr>";
    }

    buf = util_ald_cache_display_stats(pool, st->util_ldap_cache, "LDAP URL Cache");
    if (r->args && strlen(r->args)) {
        char cachetype[5], lint[2];
        unsigned int id, off;
        int ret;

        if ((3 == sscanf(r->args, scanfmt, cachetype, &id, &off, lint)) &&
            (id < util_ldap_cache->size)) {

            p = util_ldap_cache->nodes[id];
            n = (util_url_node_t *)p->payload;

            ap_rputs(apr_psprintf(r->pool, 
                     "<p>\n"
                     "<table border='0'>\n"
                     "<tr>\n"
                     "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name:</b></font></td>"
                     "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%s (%s)</b></font></td>"
                     "</tr>\n"
                     "</table>\n</p>\n",
                 n->url,
                 cachetype[0] == 's' ? "Search" : (cachetype[0] == 'c' ? "Compares" : "DNCompares")), r);
            
            switch (cachetype[0]) {
                case 's':
                    ap_rputs("<p>\n"
                             "<table border='0'>\n"
                             "<tr bgcolor='#000000'>\n"
                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>LDAP Filter</b></font></td>"
                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>User Name</b></font></td>"
                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Last Bind</b></font></td>"
                             "</tr>\n", r
                            );
                    for (i=0; i < n->search_cache->size; ++i) {
                        for (p = n->search_cache->nodes[i]; p != NULL; p = p->next) {

                            (*n->search_cache->display)(r, n->search_cache, p->payload);
                        }
                    }
                    ap_rputs("</table>\n</p>\n", r);
                    break;
                case 'c':
                    ap_rputs("<p>\n"
                             "<table border='0'>\n"
                             "<tr bgcolor='#000000'>\n"
                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>DN</b></font></td>"
                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Attribute</b></font></td>"
                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Value</b></font></td>"
                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Last Compare</b></font></td>"
                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Result</b></font></td>"
                             "</tr>\n", r
                            );
                    for (i=0; i < n->compare_cache->size; ++i) {
                        for (p = n->compare_cache->nodes[i]; p != NULL; p = p->next) {

                            (*n->compare_cache->display)(r, n->compare_cache, p->payload);
                        }
                    }
                    ap_rputs("</table>\n</p>\n", r);
                    break;
                case 'd':
                    ap_rputs("<p>\n"
                             "<table border='0'>\n"
                             "<tr bgcolor='#000000'>\n"
                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Require DN</b></font></td>"
                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Actual DN</b></font></td>"
                             "</tr>\n", r
                            );
                    for (i=0; i < n->dn_compare_cache->size; ++i) {
                        for (p = n->dn_compare_cache->nodes[i]; p != NULL; p = p->next) {

                            (*n->dn_compare_cache->display)(r, n->dn_compare_cache, p->payload);
                        }
                    }
                    ap_rputs("</table>\n</p>\n", r);
                    break;
                default:
                    break;
            }

        }
    }
    else {
        ap_rputs("<p>\n"
                 "<table border='0'>\n"
                 "<tr bgcolor='#000000'>\n"
                 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name</b></font></td>"
                 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Entries</b></font></td>"
                 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg. Chain Len.</b></font></td>"
                 "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Hits</b></font></td>"
                 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Ins/Rem</b></font></td>"
                 "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Purges</b></font></td>"
                 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg Purge Time</b></font></td>"
                 "</tr>\n", r
                );


        buf = util_ald_cache_display_stats(r, st->util_ldap_cache, "LDAP URL Cache", NULL);
    
        for (i=0; i < util_ldap_cache->size; ++i) {
        util_cache_node_t *p;
        for (p = util_ldap_cache->nodes[i]; p != NULL; p = p->next) {
            util_url_node_t *n;
            for (p = util_ldap_cache->nodes[i],j=0; p != NULL; p = p->next,j++) {
    
                n = (util_url_node_t *)p->payload;
    
                t1 = apr_psprintf(pool, "%s (Searches)", n->url);
                t2 = apr_psprintf(pool, "%s (Compares)", n->url);
                t3 = apr_psprintf(pool, "%s (DNCompares)", n->url);
                id1 = apr_psprintf(pool, argfmt, "srch", i, j);
                id2 = apr_psprintf(pool, argfmt, "cmpr", i, j);
                id3 = apr_psprintf(pool, argfmt, "dncp", i, j);
    
                buf = apr_psprintf(pool, "%s\n\n"
                                         "%s\n\n"
                                         "%s\n\n"
                                         "%s\n\n",
                                         buf,
                                     util_ald_cache_display_stats(pool, n->search_cache, t1),
                                     util_ald_cache_display_stats(pool, n->compare_cache, t2),
                                     util_ald_cache_display_stats(pool, n->dn_compare_cache, t3)
                                         util_ald_cache_display_stats(r, n->search_cache, t1, id1),
                                         util_ald_cache_display_stats(r, n->compare_cache, t2, id2),
                                         util_ald_cache_display_stats(r, n->dn_compare_cache, t3, id3)
                                  );
            }
        }
        ap_rputs(buf, r);
        ap_rputs("</table>\n</p>\n", r);
    }

    return buf;
}