On Wed, 2006-08-30 at 10:37 -0400, Brian Akins wrote:
> With all the talk of a "generic scoreboard," here's something I whipped 
> up that allows any other module to have some amount of memory per 
> "worker slot."  We have a different module in-house at CNN which does 
> something similar. This one is a little rough around the edges, but 
> gives an idea of what I was thinking about doing.

Nice stuff but I am not sure that having shared memory per slot scales
when having a lot of entries, but that makes sure that one
process/thread won't overwrite another one slot.

I will try to use memory providers of httpd-scoreboard to provide the
memory to your module.

Cheers

Jean-Frederic

> 
> 
> plain text document attachment (mod_slotmem.h)
> #ifndef __MOD_slotmem__
> #define __MOD_slotmem__
> 
> typedef struct ap_slotmem_t ap_slotmem_t;
> 
> typedef apr_status_t ap_slotmem_callback_fn_t(void* mem, void *data, 
> apr_pool_t *pool);
> 
> AP_DECLARE(apr_status_t)ap_slotmem_do(ap_slotmem_t *s, 
> ap_slotmem_callback_fn_t *func, void *data, apr_pool_t *pool);
> 
> AP_DECLARE(apr_status_t) ap_slotmem_create(ap_slotmem_t **new, const char 
> *name, apr_size_t item_size, apr_pool_t *pool);
> 
> AP_DECLARE(apr_status_t) ap_slotmem_mem(ap_slotmem_t *s, conn_rec *c, 
> void**mem);
> 
> #endif
> plain text document attachment (mod_slotmem.c)
> #include "httpd.h"
> #include "http_config.h"
> #include "http_protocol.h"
> #include "http_connection.h"
> #include "ap_config.h"
> #include "http_log.h"
> #include "scoreboard.h"
> #include "apr_strings.h"
> #include "apr_shm.h"
> #include "ap_mpm.h" 
> 
> #include <sys/types.h>
> #include <unistd.h>
> 
> #include "mod_status.h"
> #include "mod_slotmem.h"
> 
> module AP_MODULE_DECLARE_DATA slotmem_module;
> 
> static int server_limit = 0;
> static int thread_limit = 0;
> static int total_limit = 0;
> 
> static apr_array_header_t *slotmem_array = NULL;
> 
> struct ap_slotmem_t {
>     apr_pool_t *pool;
>     const char *name;
>     apr_shm_t *shm;
>     void *mem;
>     apr_size_t item_size; /*size of each item*/
>     apr_size_t total_size;
> };
> 
> 
> AP_DECLARE(apr_status_t)ap_slotmem_do(ap_slotmem_t *s, 
> ap_slotmem_callback_fn_t *func, void *data, apr_pool_t *pool) {
>     apr_status_t rv = APR_SUCCESS;
>     int i;
>     void *mem;
>     
>     for(i = 0; i < total_limit; i++) {
>         mem = s->mem + (i * s->item_size);
>         if((rv = func(mem, data, pool)) != APR_SUCCESS) {
>             return rv;
>         }
>     }
>     return rv;
> }
> 
> AP_DECLARE(apr_status_t) ap_slotmem_create(ap_slotmem_t **n, const char 
> *name, apr_size_t item_size, apr_pool_t *pool) {
>     ap_slotmem_t *s, **new;
> 
>     s = apr_pcalloc(pool, sizeof(ap_slotmem_t));
>      
>     s->pool = pool;
>     s->name = apr_pstrdup(pool, name);
>     s->item_size = item_size;
>     
>     new = (ap_slotmem_t **) apr_array_push(slotmem_array);
>     (*new) = (ap_slotmem_t *) s;
>     
>     *n = s;
> 
>     return APR_SUCCESS;
> }
> 
> AP_DECLARE(apr_status_t) ap_slotmem_mem(ap_slotmem_t *s, conn_rec *c, void 
> **mem) {
>     /*this should work for all mpm's*/
>     void *d = s->mem + (c->id * s->item_size);
>     
>     *mem = d;
>     if(!d) {
>         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
>                       "ap_slotmem_mem: d is NULL, %ld, %p",
>                       c->id, s->mem
>                       );
>         return APR_EGENERAL;
>     }
>     return APR_SUCCESS;
> }
> 
> static int slotmem_status(request_rec *r, int flags)
> {
>     int i;
>     ap_slotmem_t *sb, **list;
>     
>     if (!(flags & AP_STATUS_SHORT)) {
>         ap_rputs("<hr /><b>slotmems</b>\n", r);
>         ap_rputs("<table border=1><tr><td><b>Name</b></td><td><b>Item 
> Size</b></td><td><b>Total Size</b></td></tr>\n", r); 
>     }
>     list = (ap_slotmem_t **)slotmem_array->elts;
>     for(i = 0; i < slotmem_array->nelts; i++) {
>         sb = list[i]; 
>         if (!(flags & AP_STATUS_SHORT)) {
>             ap_rprintf(r, 
> "<tr><td>%s</td><td>%"APR_SIZE_T_FMT"</td><td>%"APR_SIZE_T_FMT"</td></tr>\n",
>                        sb->name, sb->item_size, sb->total_size);
>         } else {
>             ap_rprintf(r, "slotmem: %s %"APR_SIZE_T_FMT"%"APR_SIZE_T_FMT"\n",
>                        sb->name, sb->item_size, sb->total_size);
>         }
>     }
>     
>     if (!(flags & AP_STATUS_SHORT)) {
>          ap_rputs("</table>\n", r); 
>     }
>     return OK;
> }
> 
> static int post_config(apr_pool_t *p, apr_pool_t * plog, apr_pool_t * ptemp,
>                        server_rec *s)
> {
> 
>     apr_size_t amt;
>     apr_time_t now;
>     pid_t pid;
>     char *file;
>     ap_slotmem_t *sb, **list;
>     int i;
>     apr_status_t rv;
>     const char *temp_dir; 
>     char *data = NULL;
>     
>     /*have we been here before? */
>     apr_pool_userdata_get((void *) &data, __FILE__,
>                           s->process->pool);
>     
>     if (!data) {
>         apr_pool_userdata_set((const void *) 1, __FILE__,
>                               apr_pool_cleanup_null, s->process->pool);
>         return OK;
>     }
>     
>     ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
>     ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);    
>     total_limit = thread_limit * server_limit;
>     
>     now = apr_time_now();    
>     pid = getpid();
>     if ((rv = apr_temp_dir_get(&temp_dir, p)) != APR_SUCCESS) {
>         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
>                      "apr_temp_dir_get failed");
>         return rv;
>     }
>     
>     /*XXX: currently, this uses one shm per slotmem.  We could try to pack 
> them
>     all into a few larger shm's*/
>     list = (ap_slotmem_t **)slotmem_array->elts;
>     for(i = 0; i < slotmem_array->nelts; i++) {
>         sb = list[i];
>         sb->total_size = amt = sb->item_size * total_limit;
>         
>         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
>                      "creating slotmem %d: %s : %"APR_SIZE_T_FMT" item size x 
> %d total = %"APR_SIZE_T_FMT" total bytes",
>                      i, sb->name, sb->item_size, total_limit, amt);
>         
>         file = apr_psprintf(p, "%s/" __FILE__ ":%s:%" APR_PID_T_FMT ":%" 
> APR_TIME_T_FMT"-%d", 
>                             temp_dir, sb->name, pid, now, i);
>         if ((rv =
>              apr_shm_create(&sb->shm, amt, file,
>                             p)) != APR_SUCCESS) {
>             ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
>                           __FILE__": apr_shm_create failed trying to allocate 
> %"APR_SIZE_T_FMT" bytes: %s",
>                           amt, file);
>             return rv;
>         }
> 
>         if((sb->mem = apr_shm_baseaddr_get(sb->shm)) == NULL) {
>                ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
>                             __FILE__": apr_shm_baseaddr_get failed for %s", 
> sb->name);
>                return APR_EGENERAL;
>         }
> 
>         memset(sb->mem, 0, amt);        
>     }
>     
>     return OK;
> }
> 
> static void register_hooks(apr_pool_t * p)
> {
>     ap_hook_post_config(post_config, NULL, NULL, APR_HOOK_REALLY_LAST);
>     slotmem_array = apr_array_make(p, 10, sizeof(ap_slotmem_t *));
>     APR_OPTIONAL_HOOK(ap, status_hook, slotmem_status, NULL, NULL,
>                       APR_HOOK_MIDDLE);
>      
> }
> 
> /* Dispatch list for API hooks */
> module AP_MODULE_DECLARE_DATA slotmem_module = {
>     STANDARD20_MODULE_STUFF,
>     NULL,                       /* create per-dir    config structures */
>     NULL,                       /* merge  per-dir    config structures */
>     NULL,                       /* create per-server config structures */
>     NULL,                       /* merge  per-server config structures */
>     NULL,                 /* table of config file commands       */
>     register_hooks        /* register hooks                      */
> };

Reply via email to