You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@perl.apache.org by Stas Bekman <st...@stason.org> on 2002/03/15 19:04:48 UTC

[patch] Apache::Scoreboard

This is a big patch porting Apache::Scoreboard to work with 2.0, with all
the tests working under the latest prefork and worker mpms on perl5.7.3.  
Haven't tested it yet with 5.6.1.

Docs are coming. The scoreboard has changed a bit in 2.0 mainly because of
the threads. I've changed a few APIs and struct names and added a few new
APIs.

I've Apache::VMonitor almost perfectly working with it.  It works but
still needs a few tweaks, since now we have threads and procs, so it
should be smart to work with both and present a usable monitor :)

Index: src/modules/perl/modperl_apache_includes.h
===================================================================
RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_apache_includes.h,v
retrieving revision 1.9
diff -u -r1.9 modperl_apache_includes.h
--- src/modules/perl/modperl_apache_includes.h	29 Jan 2002 05:32:39 -0000	1.9
+++ src/modules/perl/modperl_apache_includes.h	15 Mar 2002 17:47:14 -0000
@@ -51,5 +51,6 @@
 #include "util_filter.h"
 
 #include "util_script.h"
+#include "scoreboard.h"
 
 #endif /* MODPERL_APACHE_INCLUDES_H */
Index: src/modules/perl/modperl_types.h
===================================================================
RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_types.h,v
retrieving revision 1.56
diff -u -r1.56 modperl_types.h
--- src/modules/perl/modperl_types.h	21 Feb 2002 01:45:34 -0000	1.56
+++ src/modules/perl/modperl_types.h	15 Mar 2002 17:47:14 -0000
@@ -231,4 +231,24 @@
     char *path_info;
 } modperl_uri_t;
 
+/* scoreboard */
+typedef struct {
+    scoreboard *sb;
+    apr_pool_t *pool;
+} modperl_scoreboard_t;
+
+typedef struct {
+    worker_score record;
+    int parent_idx;
+    int worker_idx;
+} modperl_worker_score_t;
+
+typedef struct {
+    process_score record;
+    int idx;
+    scoreboard *sb;
+    apr_pool_t *pool;
+} modperl_parent_score_t;
+
+
 #endif /* MODPERL_TYPES_H */
Index: t/conf/extra.conf.in
===================================================================
RCS file: /home/cvs/modperl-2.0/t/conf/extra.conf.in,v
retrieving revision 1.2
diff -u -r1.2 extra.conf.in
--- t/conf/extra.conf.in	26 Feb 2002 19:12:04 -0000	1.2
+++ t/conf/extra.conf.in	15 Mar 2002 17:47:14 -0000
@@ -13,3 +13,12 @@
     PerlResponseHandler ModPerl::Registry
     PerlOptions +ParseHeaders
 </Directory>
+
+# debug
+ExtendedStatus On
+
+ PerlModule Apache::Scoreboard
+ <Location /scoreboard>
+    SetHandler perl-script
+    PerlHandler Apache::Scoreboard::send
+ </Location>

Index: xs/maps/apache_functions.map
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/maps/apache_functions.map,v
retrieving revision 1.45
diff -u -r1.45 apache_functions.map
--- xs/maps/apache_functions.map	10 Mar 2002 00:14:23 -0000	1.45
+++ xs/maps/apache_functions.map	15 Mar 2002 17:47:15 -0000
@@ -324,16 +324,22 @@
  ap_close_piped_log
  ap_open_piped_log
 
-!MODULE=Apache::Scoreboard
+MODULE=Apache::Scoreboard
  ap_exists_scoreboard_image
  ap_sync_scoreboard_image
 -ap_update_child_status
+-ap_update_child_status_from_indexes
+-ap_reopen_scoreboard
+-ap_init_scoreboard
+-ap_calc_scoreboard_size
+-ap_create_sb_handle
 -ap_time_process_request
 -ap_create_scoreboard
  ap_cleanup_scoreboard
  ap_increment_counts
- ap_get_parent_scoreboard
- ap_get_servers_scoreboard
+ ap_get_scoreboard_worker
+ ap_get_scoreboard_process
+ ap_get_scoreboard_global
 
 !MODULE=Apache::Hooks
  ap_location_walk
Index: xs/maps/apache_types.map
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/maps/apache_types.map,v
retrieving revision 1.6
diff -u -r1.6 apache_types.map
--- xs/maps/apache_types.map	10 Sep 2001 06:42:51 -0000	1.6
+++ xs/maps/apache_types.map	15 Mar 2002 17:47:15 -0000
@@ -26,8 +26,10 @@
 ap_mgmt_type_e          | IV
 ap_mgmt_value           | UNDEFINED
 ap_scoreboard_e         | IV
+struct scoreboard       | UNDEFINED
 struct process_score    | UNDEFINED
 struct worker_score     | UNDEFINED
+struct global_score     | UNDEFINED
 struct ap_pod_t         | UNDEFINED
 ap_unix_identity_t      | UNDEFINED
 
Index: xs/maps/modperl_functions.map
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/maps/modperl_functions.map,v
retrieving revision 1.35
diff -u -r1.35 modperl_functions.map
--- xs/maps/modperl_functions.map	29 Jan 2002 17:11:06 -0000	1.35
+++ xs/maps/modperl_functions.map	15 Mar 2002 17:47:15 -0000
@@ -98,3 +98,53 @@
 MODULE=Apache::SubProcess
  # ap_subprocess_ won't work
  modperl_spawn_proc_prog | MPXS_ | ... | spawn_proc_prog
+
+MODULE=Apache::Scoreboard  PACKAGE=Apache::Scoreboard BOOT=1
+ mpxs_Apache__Scoreboard_send
+ mpxs_Apache__Scoreboard_freeze
+ mpxs_Apache__Scoreboard_thaw
+ mpxs_Apache__Scoreboard_image
+ mpxs_Apache__Scoreboard_parent_score | | self, idx=0
+ mpxs_Apache__Scoreboard_worker_score
+ mpxs_Apache__Scoreboard_pids
+ mpxs_Apache__Scoreboard_thread_numbers
+ mpxs_Apache__Scoreboard_parent_idx_by_pid
+ apr_uint32_t:DEFINE_up_time    | | modperl_scoreboard_t *:self
+
+ mpxs_Apache__Scoreboard_add
+ mpxs_Apache__Scoreboard_print
+ mpxs_Apache__Scoreboard_add_sv
+ mpxs_Apache__Scoreboard_add_sv_sv
+ mpxs_Apache__Scoreboard_add_subst
+ mpxs_Apache__Scoreboard_subst_sp | | ...
+
+MODULE=Apache::Scoreboard  PACKAGE=Apache::ScoreboardParentScore
+ mpxs_Apache__ScoreboardParentScore_next
+ mpxs_Apache__ScoreboardParentScore_worker_score
+ mpxs_Apache__ScoreboardParentScore_next_worker_score
+ mpxs_Apache__ScoreboardParentScore_next_live_worker_score
+ mpxs_Apache__ScoreboardParentScore_next_active_worker_score
+ pid_t        :DEFINE_pid             | | modperl_parent_score_t *:mps
+
+MODULE=Apache::Scoreboard  PACKAGE=Apache::ScoreboardWorkerScore
+DEFINE_times      | MPXS_Apache__ScoreboardWorkerScore_times      | ... 
+DEFINE_start_time | MPXS_Apache__ScoreboardWorkerScore_start_time | ... 
+DEFINE_stop_time  | MPXS_Apache__ScoreboardWorkerScore_stop_time  | ... 
+ mpxs_Apache__ScoreboardWorkerScore_req_time
+ mpxs_Apache__ScoreboardWorkerScore_status
+ apr_uint32_t :DEFINE_most_recent     | | modperl_worker_score_t *:self
+ unsigned long:DEFINE_access_count    | | modperl_worker_score_t *:self
+ unsigned long:DEFINE_bytes_served    | | modperl_worker_score_t *:self
+ unsigned long:DEFINE_my_access_count | | modperl_worker_score_t *:self
+ unsigned long:DEFINE_my_bytes_served | | modperl_worker_score_t *:self
+ unsigned long:DEFINE_conn_bytes      | | modperl_worker_score_t *:self
+ unsigned long:DEFINE_conn_count      | | modperl_worker_score_t *:self
+ char *       :DEFINE_client          | | modperl_worker_score_t *:self
+ char *       :DEFINE_request         | | modperl_worker_score_t *:self
+ char *       :DEFINE_vhost           | | modperl_worker_score_t *:self
+
+
+!MODULE=Apache::Scoreboard  PACKAGE=Apache::ScoreboardGlobalScore
+
+
+
Index: xs/maps/modperl_types.map
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/maps/modperl_types.map,v
retrieving revision 1.3
diff -u -r1.3 modperl_types.map
--- xs/maps/modperl_types.map	19 Apr 2001 21:26:44 -0000	1.3
+++ xs/maps/modperl_types.map	15 Mar 2002 17:47:15 -0000
@@ -2,6 +2,10 @@
 
 struct modperl_filter_t | Apache::OutputFilter
 
+struct modperl_scoreboard_t   | Apache::Scoreboard
+struct modperl_worker_score_t | Apache::ScoreboardWorkerScore
+struct modperl_parent_score_t | Apache::ScoreboardParentScore
+
 ##########  Perl types  ##########
 
 SV *  | SV
--- /dev/null	Thu Jan  1 07:30:00 1970
+++ xs/Apache/Scoreboard/Apache__Scoreboard.h	Sat Mar 16 01:52:55 2002
@@ -0,0 +1,586 @@
+#include "scoreboard.h"
+#include "ap_mpm.h"
+
+#ifndef HZ
+#define HZ 100
+#endif
+
+/* XXX: When documenting don't forget to add the new 'vhost' accessor */
+/* and port accessor if it gets added (need to add it here too) */
+
+int server_limit, thread_limit;
+
+static char status_flags[SERVER_NUM_STATUS];
+
+#define mpxs_Apache__Scoreboard_up_time(image) \
+    (apr_uint32_t)((apr_time_now() - image->sb->global->restart_time) / APR_USEC_PER_SEC);
+
+#define mpxs_Apache__ScoreboardWorkerScore_most_recent(mws) \
+    (apr_uint32_t)((apr_time_now() - mws->record.last_used) / APR_USEC_PER_SEC);
+        
+#define mpxs_Apache__ScoreboardWorkerScore_access_count(mws)    mws->record.access_count
+#define mpxs_Apache__ScoreboardWorkerScore_bytes_served(mws)    mws->record.bytes_served
+#define mpxs_Apache__ScoreboardWorkerScore_my_access_count(mws) mws->record.my_access_count
+#define mpxs_Apache__ScoreboardWorkerScore_my_bytes_served(mws) mws->record.my_bytes_served
+#define mpxs_Apache__ScoreboardWorkerScore_conn_bytes(mws)      mws->record.conn_bytes
+#define mpxs_Apache__ScoreboardWorkerScore_conn_count(mws)      mws->record.conn_count
+#define mpxs_Apache__ScoreboardWorkerScore_client(mws)          mws->record.client
+#define mpxs_Apache__ScoreboardWorkerScore_request(mws)         mws->record.request
+#define mpxs_Apache__ScoreboardWorkerScore_vhost(mws)           mws->record.vhost
+
+#define mpxs_Apache__ScoreboardParentScore_pid(ps)  ps->record.pid
+
+/* a worker that have served/serves at least one request and isn't
+ * dead yet */
+#define LIVE_WORKER(ws) ws.access_count != 0 || \
+    ws.status != SERVER_DEAD
+
+/* a worker that does something at this very moment */
+#define ACTIVE_WORKER(ws) ws.access_count != 0 || \
+    (ws.status != SERVER_DEAD && ws.status != SERVER_READY)
+
+#define REMOTE_SCOREBOARD_TYPE "application/x-httpd-scoreboard"
+
+#ifndef Move
+#define Move(s,d,n,t) (void)memmove((char*)(d),(char*)(s), (n) * sizeof(t)) 
+#endif
+#ifndef Copy
+#define Copy(s,d,n,t) (void)memcpy((char*)(d),(char*)(s), (n) * sizeof(t))
+#endif
+
+#define SIZE16 2
+
+static void pack16(unsigned char *s, int p)
+{
+    short ashort = htons(p);
+    Move(&ashort, s, SIZE16, unsigned char);
+}
+
+static unsigned short unpack16(unsigned char *s)
+{
+    unsigned short ashort;
+    Copy(s, &ashort, SIZE16, char);
+    return ntohs(ashort);
+}
+
+
+static void status_flags_init(void)
+{
+    status_flags[SERVER_DEAD]           = '.';
+    status_flags[SERVER_READY]          = '_';
+    status_flags[SERVER_STARTING]       = 'S';
+    status_flags[SERVER_BUSY_READ]      = 'R';
+    status_flags[SERVER_BUSY_WRITE]     = 'W';
+    status_flags[SERVER_BUSY_KEEPALIVE] = 'K';
+    status_flags[SERVER_BUSY_LOG]       = 'L';
+    status_flags[SERVER_BUSY_DNS]       = 'D';
+    status_flags[SERVER_CLOSING]        = 'C';
+    status_flags[SERVER_GRACEFUL]       = 'G';
+    status_flags[SERVER_IDLE_KILL]      = 'I';
+}
+
+static void mpxs_Apache__Scoreboard_BOOT(pTHX)
+{
+    HV *stash;
+
+/* XXX: this must be performed only once and before other threads are spawned.
+ * but not sure. could be that need to use local storage.
+ *
+ */
+    status_flags_init();
+    
+    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
+    ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
+
+    stash = gv_stashpv("Apache::Const", TRUE);
+    newCONSTSUB(stash, "SERVER_LIMIT", newSViv(server_limit));
+    
+    stash = gv_stashpv("Apache::Const", TRUE);
+    newCONSTSUB(stash, "THREAD_LIMIT", newSViv(thread_limit));
+
+    stash = gv_stashpv("Apache::Scoreboard", TRUE);
+    newCONSTSUB(stash, "REMOTE_SCOREBOARD_TYPE",
+                newSVpv(REMOTE_SCOREBOARD_TYPE, 0));
+
+}
+
+#define WRITE_BUFF(buf, size, r) \
+    if (ap_rwrite(buf, size, r) < 0) { return APR_EGENERAL; }
+
+static MP_INLINE
+int mpxs_Apache__Scoreboard_send(request_rec *r)
+{
+    int i, psize, ssize, tsize;
+    char buf[SIZE16*2];
+    char *ptr = buf;
+
+    for (i = 0; i < server_limit; i++) {
+        if (!ap_scoreboard_image->parent[i].pid) {
+            break;
+        }
+    }
+    
+    psize = i * sizeof(process_score);
+    ssize = i * sizeof(worker_score);
+    tsize = psize + ssize + sizeof(global_score) + sizeof(buf);
+
+    pack16(ptr, psize);
+    ptr += SIZE16;
+    pack16(ptr, ssize);
+
+    ap_set_content_length(r, tsize);
+    r->content_type = REMOTE_SCOREBOARD_TYPE;
+    
+    if (!r->header_only) {
+	WRITE_BUFF(&buf[0],                          sizeof(buf),          r);
+	WRITE_BUFF(&ap_scoreboard_image->parent[0],  psize,                r);
+	WRITE_BUFF(&ap_scoreboard_image->servers[0], ssize,                r);
+	WRITE_BUFF(&ap_scoreboard_image->global,     sizeof(global_score), r);
+    }
+
+    return APR_SUCCESS;
+}
+
+static MP_INLINE
+SV *mpxs_Apache__Scoreboard_freeze(pTHX_ modperl_scoreboard_t *image)
+{
+    int i, psize, ssize, tsize;
+    char buf[SIZE16*2];
+    char *dptr, *data, *ptr = buf;
+    scoreboard *sb = image->sb;
+    SV *retval;
+    
+    for (i = 0; i < server_limit; i++) {
+        if (!sb->parent[i].pid) {
+            break;
+        }
+    }
+    
+    psize = i * sizeof(process_score);
+    ssize = i * sizeof(worker_score);
+    tsize = psize + ssize + sizeof(global_score) + sizeof(buf);
+    fprintf(stderr, "sizes %d, %d, %d, %d, %d, %d\n", i, psize, ssize, sizeof(global_score) , sizeof(buf), tsize);
+
+    data = (char *)apr_palloc(image->pool, tsize);
+    
+    pack16(ptr, psize);
+    ptr += SIZE16;
+    pack16(ptr, ssize);
+    
+    /* fill the data buffer with the data we want to freeze */
+    dptr = data;
+    Move(buf,             dptr, sizeof(buf),          char);
+    dptr += sizeof(buf);
+    Move(&sb->parent[0],  dptr, psize,                char);
+    dptr += psize;
+    Move(&sb->servers[0], dptr, ssize,                char);
+    dptr += ssize;
+    Move(&sb->global,     dptr, sizeof(global_score), char);
+
+    /* an equivalent C function can return 'data', in case of XS it'll
+     * try to convert char *data to PV, using strlen(), which will
+     * lose data, since it won't continue past the first \0
+     * char. Therefore in this case we explicitly return SV* and using
+     * newSVpvn(data, tsize) to tell the exact size */
+    retval = newSVpvn(data, tsize);
+    return retval;
+    
+    
+}
+
+
+static MP_INLINE
+SV *mpxs_Apache__Scoreboard_thaw(pTHX_ SV *Class, apr_pool_t *pool, SV *packet)
+{
+    modperl_scoreboard_t *image;
+    scoreboard *sb;
+    int psize, ssize;
+    char *ptr;
+    
+    if (!(SvOK(packet) && SvCUR(packet) > (SIZE16*2))) {
+	return &PL_sv_undef;
+    }
+
+    image = (modperl_scoreboard_t *)apr_palloc(pool, sizeof(*image));
+    sb          =     (scoreboard *)apr_palloc(pool, sizeof(scoreboard));
+    sb->parent  =  (process_score *)apr_palloc(pool, sizeof(process_score *));
+    sb->servers =  (worker_score **)apr_palloc(pool, server_limit * sizeof(worker_score));
+    sb->global  =   (global_score *)apr_palloc(pool, sizeof(global_score *));
+    
+    ptr = SvPVX(packet);
+    psize = unpack16(ptr);
+    ptr += SIZE16;
+    ssize = unpack16(ptr);
+    ptr += SIZE16;
+
+    Move(ptr, &sb->parent[0], psize, char);
+    ptr += psize;
+    Move(ptr, &sb->servers[0], ssize, char);
+    ptr += ssize;
+    Move(ptr, &sb->global, sizeof(global_score), char);
+
+    image->pool = pool;
+    image->sb   = sb;
+    
+    return SvREFCNT_inc(mp_xs_Apache__Scoreboard_2obj(image));
+}
+
+static MP_INLINE 
+modperl_scoreboard_t *mpxs_Apache__Scoreboard_image(pTHX_ SV *Class, apr_pool_t *pool)
+{
+    modperl_scoreboard_t *image;
+    
+    image = (modperl_scoreboard_t *)apr_palloc(pool, sizeof(*image));
+    
+    if (ap_exists_scoreboard_image()) {
+        image->sb = ap_scoreboard_image;
+        image->pool = pool;
+    }
+    else {
+        Perl_croak(aTHX_ "ap_scoreboard_image doesn't exist");
+    }
+
+    return image;
+    
+}
+
+static MP_INLINE
+modperl_parent_score_t *mpxs_Apache__Scoreboard_parent_score(modperl_scoreboard_t *self, int idx)
+{
+    modperl_parent_score_t *mps;
+
+    if (self->sb->parent[idx].pid) {
+        mps = (modperl_parent_score_t *)apr_pcalloc(self->pool, (sizeof(*mps)));
+        mps->record = self->sb->parent[idx];
+        mps->idx    = idx;
+        mps->sb     = self->sb;
+        mps->pool   = self->pool;
+        return mps;
+    }
+
+    return NULL;
+}
+
+static MP_INLINE
+modperl_worker_score_t *mpxs_Apache__Scoreboard_worker_score(pTHX_ modperl_scoreboard_t *self,
+                                                             int parent_idx,
+                                                             int worker_idx)
+{
+    modperl_worker_score_t *mws;
+    mws = (modperl_worker_score_t *)apr_pcalloc(self->pool, (sizeof(*mws)));
+
+    mws->record = self->sb->servers[parent_idx][worker_idx];
+    mws->parent_idx = parent_idx;
+    mws->worker_idx = worker_idx;
+    
+    return mws;
+}
+
+
+static MP_INLINE
+SV *mpxs_Apache__Scoreboard_pids(pTHX_ modperl_scoreboard_t *self)   
+{
+    AV *av = newAV();
+    int i;
+    scoreboard *sb = self->sb;
+
+    for (i = 0; i < server_limit; i++) {
+        if (!sb->parent[i].pid) {
+            break;
+        }
+        fprintf(stderr, "pids: server %d: pid %d\n", i, (int)(sb->parent[i].pid));
+        
+        av_push(av, newSViv(sb->parent[i].pid));
+    }
+        
+    return newRV_noinc((SV*)av);
+
+}
+
+/* XXX: need to move pid_t => apr_proc_t and work with pid->pid as in
+ * find_child_by_pid from scoreboard.c */
+static MP_INLINE
+int mpxs_Apache__Scoreboard_parent_idx_by_pid(pTHX_ modperl_scoreboard_t *self, pid_t pid)   
+{
+    int i;
+    scoreboard *sb = self->sb;
+
+    for (i = 0; i < server_limit; i++) {
+        if (sb->parent[i].pid == pid) {
+            return i;
+        }
+    }
+        
+    return -1;
+}
+
+
+/* return the thread numbers for a certain process idx */
+static MP_INLINE
+SV *mpxs_Apache__Scoreboard_thread_numbers(pTHX_ modperl_scoreboard_t *self, int parent_idx)   
+{
+    AV *av = newAV();
+    int i;
+    scoreboard *sb = self->sb;
+
+    for (i = 0; i < thread_limit; ++i) {
+        //  if (sb->servers[parent_idx][i].thread_num == NULL) {
+            // break;
+        // }
+        fprintf(stderr, "thread_num: server %d, thread %d pid %d\n", i,
+                sb->servers[parent_idx][i].thread_num, (int)(sb->parent[parent_idx].pid));
+        
+        av_push(av, newSViv(sb->servers[parent_idx][i].thread_num));
+    }
+
+    return newRV_noinc((SV*)av);
+
+}
+
+
+
+
+
+
+/* *** ParentScore *** */
+
+static MP_INLINE
+SV *mpxs_Apache__ScoreboardParentScore_next(pTHX_ modperl_parent_score_t *self)
+{
+    modperl_parent_score_t *next;
+    SV *retval = NULL;
+    int next_idx = self->idx + 1;
+    
+    if (self->sb->parent[next_idx].pid) {
+        next = (modperl_parent_score_t *)apr_pcalloc(self->pool, sizeof(*next));
+        next->record = self->sb->parent[next_idx];
+        next->idx    = next_idx;
+        next->sb     = self->sb;
+        next->pool   = self->pool;
+        retval = mp_xs_Apache__ScoreboardParentScore_2obj(next);
+    }
+
+    return retval ? SvREFCNT_inc(retval) : &PL_sv_undef;
+    
+}
+
+static MP_INLINE
+modperl_worker_score_t *mpxs_Apache__ScoreboardParentScore_worker_score(modperl_parent_score_t *self)
+{
+    modperl_worker_score_t *mws;
+    mws = (modperl_worker_score_t *)apr_pcalloc(self->pool, sizeof(*mws));
+    mws->record     = self->sb->servers[self->idx][0];
+    mws->parent_idx = self->idx;
+    mws->worker_idx = 0;
+    return mws;
+}
+
+
+
+static MP_INLINE
+SV *mpxs_Apache__ScoreboardParentScore_next_worker_score(pTHX_ modperl_parent_score_t *self,
+                                                         modperl_worker_score_t *mws)
+{
+    modperl_worker_score_t *next;
+    SV *retval = NULL;
+    int next_idx = mws->worker_idx + 1;
+    
+    if (next_idx < thread_limit) {
+        next = (modperl_worker_score_t *)apr_pcalloc(self->pool, sizeof(*next));
+        next->record     = self->sb->servers[mws->parent_idx][next_idx];
+        next->parent_idx = mws->parent_idx;
+        next->worker_idx = next_idx;
+        retval = mp_xs_Apache__ScoreboardWorkerScore_2obj(next);
+    }
+
+    return retval ? SvREFCNT_inc(retval) : &PL_sv_undef;
+}
+
+static MP_INLINE
+SV *mpxs_Apache__ScoreboardParentScore_next_live_worker_score(pTHX_ modperl_parent_score_t *self,
+                                                              modperl_worker_score_t *mws)
+{
+    modperl_worker_score_t *next;
+    SV *retval = NULL;
+    int next_idx = mws->worker_idx;
+    
+    while (++next_idx < thread_limit) {
+        if (LIVE_WORKER(self->sb->servers[mws->parent_idx][next_idx])) {
+            next = (modperl_worker_score_t *)apr_pcalloc(self->pool, sizeof(*next));
+            next->record     = self->sb->servers[mws->parent_idx][next_idx];
+            next->parent_idx = mws->parent_idx;
+            next->worker_idx = next_idx;
+            retval = mp_xs_Apache__ScoreboardWorkerScore_2obj(next);
+            break;
+        }
+    }
+
+    return retval ? SvREFCNT_inc(retval) : &PL_sv_undef;
+    
+}
+
+static MP_INLINE
+SV *mpxs_Apache__ScoreboardParentScore_next_active_worker_score(pTHX_ modperl_parent_score_t *self,
+                                                                modperl_worker_score_t *mws)
+{
+    modperl_worker_score_t *next;
+    SV *retval = NULL;
+    int next_idx = mws->worker_idx;
+    
+    while (++next_idx < thread_limit) {
+        if (ACTIVE_WORKER(self->sb->servers[mws->parent_idx][next_idx])) {
+            next = (modperl_worker_score_t *)apr_pcalloc(self->pool, sizeof(*next));
+            next->record     = self->sb->servers[mws->parent_idx][next_idx];
+            next->parent_idx = mws->parent_idx;
+            next->worker_idx = next_idx;
+            retval = mp_xs_Apache__ScoreboardWorkerScore_2obj(next);
+            break;
+        }
+    }
+
+    return retval ? SvREFCNT_inc(retval) : &PL_sv_undef;
+    
+}
+
+
+/* *** WorkerScore *** */
+
+static XS(MPXS_Apache__ScoreboardWorkerScore_times)
+{
+    dXSARGS;
+    modperl_worker_score_t *self;
+    
+    if (items != 1) {
+        Perl_croak(aTHX_ "usage: $worker_score->times");
+    }
+    self = mp_xs_sv2_Apache__ScoreboardWorkerScore(ST(0));
+
+    SP -= items;
+    
+    if (GIMME == G_ARRAY) {
+	/* same return values as CORE::times() */
+	EXTEND(sp, 4);
+	PUSHs(sv_2mortal(newSViv(self->record.times.tms_utime)));
+	PUSHs(sv_2mortal(newSViv(self->record.times.tms_stime)));
+	PUSHs(sv_2mortal(newSViv(self->record.times.tms_cutime)));
+	PUSHs(sv_2mortal(newSViv(self->record.times.tms_cstime)));
+    }
+    else {
+#ifdef _SC_CLK_TCK
+	float tick = sysconf(_SC_CLK_TCK);
+#else
+	float tick = HZ;
+#endif
+	if (self->record.access_count) {
+	    /* cpu %, same value mod_status displays */
+	      float RETVAL = (self->record.times.tms_utime +
+			      self->record.times.tms_stime +
+			      self->record.times.tms_cutime +
+			      self->record.times.tms_cstime);
+	    XPUSHs(sv_2mortal(newSVnv((double)RETVAL/tick)));
+	}
+	else {
+            
+	    XPUSHs(sv_2mortal(newSViv((0))));
+	}
+    }
+
+    PUTBACK;
+}
+
+
+static XS(MPXS_Apache__ScoreboardWorkerScore_start_time)
+{
+    dXSARGS;
+    modperl_worker_score_t *self;
+    apr_time_t tp;
+    
+    if (items != 1) {
+        Perl_croak(aTHX_ "usage: $worker_score->start_time");
+    }
+    self = mp_xs_sv2_Apache__ScoreboardWorkerScore(ST(0));
+
+    SP -= items;
+
+    tp = self->record.start_time;
+    /* fprintf(stderr, "start_time: %5" APR_TIME_T_FMT "\n", tp); */
+    
+     /* do the same as Time::HiRes::gettimeofday */
+    if (GIMME == G_ARRAY) {
+	EXTEND(sp, 2);
+	PUSHs(sv_2mortal(newSViv(tp / APR_USEC_PER_SEC)));
+	PUSHs(sv_2mortal(newSViv(tp / APR_USEC_PER_SEC - tp % APR_USEC_PER_SEC )));
+    } 
+    else {
+	EXTEND(sp, 1);
+	PUSHs(sv_2mortal(newSVnv((double)tp / APR_USEC_PER_SEC )));
+    }
+
+    PUTBACK;
+}
+
+/* XXX: this should be merged back into
+ * mpxs_Apache__Scoreboard_WorkerScore_start_time as an ALIAS when
+ * WrapXS provides it
+ */
+static XS(MPXS_Apache__ScoreboardWorkerScore_stop_time)
+{
+    dXSARGS;
+    modperl_worker_score_t *self;
+    apr_time_t tp;
+    
+    if (items != 1) {
+        Perl_croak(aTHX_ "usage: $worker_score->stop_time");
+    }
+    self = mp_xs_sv2_Apache__ScoreboardWorkerScore(ST(0));
+
+    SP -= items;
+
+    tp = self->record.stop_time;
+    /* fprintf(stderr, "stop_time: %5" APR_TIME_T_FMT "\n", tp); */
+    
+     /* do the same as Time::HiRes::gettimeofday */
+    if (GIMME == G_ARRAY) {
+	EXTEND(sp, 2);
+	PUSHs(sv_2mortal(newSViv(tp / APR_USEC_PER_SEC)));
+	PUSHs(sv_2mortal(newSViv(tp / APR_USEC_PER_SEC - tp % APR_USEC_PER_SEC )));
+    } 
+    else {
+	EXTEND(sp, 1);
+	PUSHs(sv_2mortal(newSVnv((double)tp / APR_USEC_PER_SEC )));
+    }
+
+    PUTBACK;
+}
+
+static MP_INLINE
+long mpxs_Apache__ScoreboardWorkerScore_req_time(modperl_worker_score_t *self)
+{
+    long req_time;
+    if (self->record.start_time == 0L) {
+	req_time = 0L;
+    }
+    else {
+	req_time = (long)
+            ((self->record.stop_time - self->record.start_time) / 1000);
+    }
+    if (req_time < 0L || !self->record.access_count) {
+	req_time = 0L;
+    }
+
+    return req_time;
+    
+}
+
+static MP_INLINE
+SV *mpxs_Apache__ScoreboardWorkerScore_status(pTHX_ modperl_worker_score_t *self)
+{
+    SV *sv = newSV(0);
+    sv_setnv(sv, (double)self->record.status);
+    sv_setpvf(sv, "%c", status_flags[self->record.status]);
+    SvNOK_on(sv); /* dual-var */ 
+    return sv;
+}
+
+/* Apache::ScoreboardGlobalScore functions */
+
--- /dev/null	Thu Jan  1 07:30:00 1970
+++ xs/Apache/Scoreboard/Scoreboard_pm	Thu Mar 14 00:44:51 2002
@@ -0,0 +1,56 @@
+use strict;
+use constant DEBUG => 0;
+
+my $ua;
+
+sub http_fetch {
+    my($self, $url) = @_;
+
+    require LWP::UserAgent;
+    unless ($ua) {
+	no strict 'vars';
+	$ua = LWP::UserAgent->new;
+	$ua->agent(join '/', __PACKAGE__, $VERSION);
+    }
+
+    my $request = HTTP::Request->new('GET', $url);
+    my $response = $ua->request($request);
+    unless ($response->is_success) {
+	warn "request failed: ", $response->status_line if DEBUG;
+	return undef;
+    }
+
+    my $type = $response->header('Content-type');
+    unless ($type eq Apache::Scoreboard::REMOTE_SCOREBOARD_TYPE) {
+	warn "invalid scoreboard Content-type: $type" if DEBUG;
+	return undef;
+    }
+
+    $response->content;
+}
+
+sub fetch {
+    my($self, $pool, $url) = @_;
+    $self->thaw($pool, $self->http_fetch($url));
+}
+
+sub fetch_store {
+    my($self, $url, $file) = @_;
+    $self->store($self->http_fetch($url), $file);
+}
+
+sub store {
+    my($self, $frozen_image, $file) = @_;
+    open my $fh, ">$file" or die "open $file: $!";
+    print $fh $frozen_image;
+    close $fh;
+}
+
+sub retrieve {
+    my($self, $pool, $file) = @_;
+    open my $fh, $file or die "open $file: $!";
+    local $/;
+    my $data = <$fh>;
+    close $fh;
+    $self->thaw($pool, $data);
+}


_____________________________________________________________________
Stas Bekman             JAm_pH      --   Just Another mod_perl Hacker
http://stason.org/      mod_perl Guide   http://perl.apache.org/guide
mailto:stas@stason.org  http://ticketmaster.com http://apacheweek.com
http://singlesheaven.com http://perl.apache.org http://perlmonth.com/


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org


Re: [patch] Apache::Scoreboard

Posted by Doug MacEachern <do...@covalent.net>.
On Tue, 26 Mar 2002, Stas Bekman wrote:

> So you want me to rewrite it in pure xs, right?

yeah.

> it won't work with WrapXS if it's not in the root.

right.  from what i have seen, WrapXS is more of a burden for 
Apache::Scoreboard than a help.  so pure xs makes more sense here.


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org


Re: [patch] Apache::Scoreboard

Posted by Stas Bekman <st...@stason.org>.
Doug MacEachern wrote:
> you could make it self contained in modperl-2.0/Apache-Scoreboard for the 
> moment, the same way ModPerl-Registry is self contained.  we can always 
> move them later if needed.

So you want me to rewrite it in pure xs, right? it won't work with 
WrapXS if it's not in the root.

__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org


Re: [patch] Apache::Scoreboard

Posted by Doug MacEachern <do...@covalent.net>.
you could make it self contained in modperl-2.0/Apache-Scoreboard for the 
moment, the same way ModPerl-Registry is self contained.  we can always 
move them later if needed.




---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org


Re: [patch] Apache::Scoreboard

Posted by Stas Bekman <st...@stason.org>.
Doug MacEachern wrote:
> two issues with this patch:
> 
> - as i mentioned, the code for sending the scoreboard image doesn't belong 
> tied to modperl, as it can be used in a server without modperl.  there 
> should be a mod_scoreboard_send.c that can be compiled with apxs without 
> any perl stuff.  it could then export an optional function for the perl 
> wrapper to call the send function.

Of course, this is just temporary until the new home will be found.

I was thinking about putting this functionality into mod_status, instead 
creating a new module. After all it already has a mode in which it 
responds with something similar to an image.

> - looking at the patch, seems that WrapXS is more trouble than a help 
> here.  that is, normally WrapXS takes care of many things for you, but in 
> this case it looks like too much extra effort is happening.  there is so 
> much mpxs_Apache__Scoreboard_* and _pm and DEFINE_* and MPXS_*'s that 
> make the code harder to read and more difficult to maintain than if 
> everything was done in a standard xs module without WrapXS.

Well, the interface is not much different from Apache::Scoreboard for 
1.x, so no surprises here.

> i'm thinking at the very least, the code should be moved to a 
> self-contained Apache-Scoreboard subdirectory, using standard xs.
> and given that mod_scoreboard_send.c should be usable without modperl, 
> perhaps this stuff should not be part of the modperl core, but its own 
> package like 1.x.  thoughts?

Sure, this can be done. Though I'm really not interested in expanding 
the ownership of the privately owned CPAN modules, but rather try to 
move all my works somewhere where other people can fix problems if I'm 
not around. So if the modules that I've developed or ported can be 
hosted at apache.org cvs or elsewhere that's cool with me. I'll still be 
the active developer/maintainer of these.

BTW, Doug, you can do the same for a bunch of the 1.x modules you own at 
CPAN. I believe that putting the sources under public control will make 
a better progress on these sources. Apache::Scoreboard comes to mind. 
Just a thought.

So how about creating a new repository modperl-2.0-modules or 
modperl-modules-2.0 and put Apache-Scoreboard there. Probably move 
Apache-Test and ModPerl-Registry there too. That will allow us to keep 
the core small, and still have a bunch of modules installable from one 
directory. So we may end up distributing modperl-2.x and 
modperl-modules-2.x and a combined version.

One concern is whether these modules can use WrapXS, it is going to be a 
problem to split them away till Gerald will come back with a standalone 
version.

__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org


Re: [patch] Apache::Scoreboard

Posted by Doug MacEachern <do...@covalent.net>.
two issues with this patch:

- as i mentioned, the code for sending the scoreboard image doesn't belong 
tied to modperl, as it can be used in a server without modperl.  there 
should be a mod_scoreboard_send.c that can be compiled with apxs without 
any perl stuff.  it could then export an optional function for the perl 
wrapper to call the send function.

- looking at the patch, seems that WrapXS is more trouble than a help 
here.  that is, normally WrapXS takes care of many things for you, but in 
this case it looks like too much extra effort is happening.  there is so 
much mpxs_Apache__Scoreboard_* and _pm and DEFINE_* and MPXS_*'s that 
make the code harder to read and more difficult to maintain than if 
everything was done in a standard xs module without WrapXS.

i'm thinking at the very least, the code should be moved to a 
self-contained Apache-Scoreboard subdirectory, using standard xs.
and given that mod_scoreboard_send.c should be usable without modperl, 
perhaps this stuff should not be part of the modperl core, but its own 
package like 1.x.  thoughts?


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org