[svn:modperl-modules] rev 143 - in Apache-Scoreboard-2.0/trunk: . Dummy apxs lib/Apache t t/apache t/external t/internal t/lib t/lib/MyTest t/response/TestApache t/response/TestInternal

[email protected] 12 Feb 2005 06:47:32 -0000
Newsgroups perl.modperl.modules.svn
Message-ID <[email protected]>
Author: stas
Date: Fri Feb 11 22:47:32 2005
New Revision: 143

Added:
   Apache-Scoreboard-2.0/trunk/Dummy/Makefile.PL
      - copied, changed from rev 88, Apache-Scoreboard-2.0/trunk/Dummy/Makefile.PL.orig
   Apache-Scoreboard-2.0/trunk/t/external/
   Apache-Scoreboard-2.0/trunk/t/external/basic.t   (contents, props changed)
   Apache-Scoreboard-2.0/trunk/t/internal/
   Apache-Scoreboard-2.0/trunk/t/internal/basic.t
      - copied, changed from rev 89, Apache-Scoreboard-2.0/trunk/t/apache/scoreboard.t
   Apache-Scoreboard-2.0/trunk/t/lib/
   Apache-Scoreboard-2.0/trunk/t/lib/MyTest/
   Apache-Scoreboard-2.0/trunk/t/lib/MyTest/Common.pm   (contents, props changed)
   Apache-Scoreboard-2.0/trunk/t/response/TestInternal/
   Apache-Scoreboard-2.0/trunk/t/response/TestInternal/basic.pm
      - copied, changed from rev 140, Apache-Scoreboard-2.0/trunk/t/response/TestApache/scoreboard.pm
Removed:
   Apache-Scoreboard-2.0/trunk/Dummy/Makefile
   Apache-Scoreboard-2.0/trunk/Dummy/Makefile.PL.orig
   Apache-Scoreboard-2.0/trunk/t/apache/scoreboard.t
   Apache-Scoreboard-2.0/trunk/t/response/TestApache/scoreboard.pm
Modified:
   Apache-Scoreboard-2.0/trunk/Changes
   Apache-Scoreboard-2.0/trunk/Dummy/DummyScoreboard.pm
   Apache-Scoreboard-2.0/trunk/Dummy/dummy.c
   Apache-Scoreboard-2.0/trunk/MANIFEST
   Apache-Scoreboard-2.0/trunk/Scoreboard.xs
   Apache-Scoreboard-2.0/trunk/TODO
   Apache-Scoreboard-2.0/trunk/apxs/send.c
   Apache-Scoreboard-2.0/trunk/lib/Apache/Scoreboard.pm
   Apache-Scoreboard-2.0/trunk/t/TEST.PL
Log:
implementing Apache::DummyScoreboard for reading the scoreboard 
outside mod_perl: still work in a progress 


Modified: Apache-Scoreboard-2.0/trunk/Changes
==============================================================================
--- Apache-Scoreboard-2.0/trunk/Changes	(original)
+++ Apache-Scoreboard-2.0/trunk/Changes	Fri Feb 11 22:47:32 2005
@@ -1,5 +1,21 @@
 2.05 -
 
+added new methods $image->thread_limit and $image->server_limit and
+deprecated the Apache::Const::SERVER_LIMIT and
+Apache::Const::THREAD_LIMIT constants, since those are useful only for
+the image of the Apache server inside which the script is run (if
+any).
+
+use the passed image object, rather than accessing the global
+ap_scoreboard_image. Previously we have switched to use Apache
+accessors, instead of accessing the struct directly, but the problem
+was that we no longer processed the real image object. So if the
+script has acquired a different image (not the one seen by the current
+process), we were handing bogus information. Now this has been fixed
+by copying the apache accessors and changing them to use the passed
+image.
+
+correct docs s/parent/parent_score/
 
 
 2.04 - Sat Jan 22 00:13:35 EST 2005

Modified: Apache-Scoreboard-2.0/trunk/Dummy/DummyScoreboard.pm
==============================================================================
--- Apache-Scoreboard-2.0/trunk/Dummy/DummyScoreboard.pm	(original)
+++ Apache-Scoreboard-2.0/trunk/Dummy/DummyScoreboard.pm	Fri Feb 11 22:47:32 2005
@@ -1,14 +1,38 @@
 package Apache::DummyScoreboard;
 
 use strict;
-use DynaLoader ();
+use warnings FATAL => 'all';
 
-{
-    no strict;
-    $VERSION = '0.04';
-    @ISA = qw(DynaLoader);
-    __PACKAGE__->bootstrap($VERSION);
-}
+$Apache::DummyScoreboard::VERSION = '2.00';
+require XSLoader;
+XSLoader::load(__PACKAGE__, $Apache::DummyScoreboard::VERSION);
 
 1;
 __END__
+
+=head1 NAME
+
+Apache::DummyScoreboard - Perl interface to the Apache scoreboard structure
+
+=head1 DESCRIPTION
+
+when loading C<Apache::Scoreboard>, C<Apache::DummyScoreboard> is used
+internally if the code is not running under mod_perl. It has almost
+the same functionality with some limitations. See the
+C<Apache::Scoreboard> manpage for more info.
+
+=head1 LIMITATIONS
+
+=over
+
+=item *
+
+At the moment C<Apache::Const::SERVER_LIMIT> and
+C<Apache::Const::THREAD_LIMIT> are hardwired to 0, since the methods
+that provide this information are only accessible via a running Apache
+(i.e. via C<Apache::Scoreboad> running under mod_perl).
+
+=back
+
+=cut
+

Copied: Apache-Scoreboard-2.0/trunk/Dummy/Makefile.PL (from rev 88, Apache-Scoreboard-2.0/trunk/Dummy/Makefile.PL.orig)
==============================================================================
--- Apache-Scoreboard-2.0/trunk/Dummy/Makefile.PL.orig	(original)
+++ Apache-Scoreboard-2.0/trunk/Dummy/Makefile.PL	Fri Feb 11 22:47:32 2005
@@ -1,10 +1,9 @@
 use ExtUtils::MakeMaker;
 
 use strict;
-use Apache::src ();
+use warnings FATAL => 'all';
 
-my $src = Apache::src->new;
-my $typemaps = $src->typemaps;
+use ModPerl::MM ();
 
 #mmm
 system "cp ../typemap ." unless -e "typemap";
@@ -12,17 +11,14 @@
 sub genxs {
     system "cat dummy.c ../Scoreboard.xs > DummyScoreboard.xs";
     system $^X, "-pi", "-e",
-    "s/(MODULE *= *Apache::)Scoreboard/\$1.DummyScoreboard/e", 
-    "DummyScoreboard.xs";
+        "s/(MODULE *= *Apache::)Scoreboard/\$1.DummyScoreboard/e; " .
+        "s|apxs/send.c|../apxs/send.c|;",
+        "DummyScoreboard.xs";
 }
 
 genxs();
-exit if $ARGV[0] eq '-g';
 
-WriteMakefile1(
-    'NAME'	=> 'Apache::DummyScoreboard',
-    'VERSION_FROM' => 'DummyScoreboard.pm', 
-    'INC'       => "-I../ " . $src->inc,	      
-    'DEFINE' => $src->define,
-    'TYPEMAPS' => $typemaps,
+ModPerl::MM::WriteMakefile(
+    NAME	 => 'Apache::DummyScoreboard',
+    VERSION_FROM => 'DummyScoreboard.pm',
 );

Modified: Apache-Scoreboard-2.0/trunk/Dummy/dummy.c
==============================================================================
--- Apache-Scoreboard-2.0/trunk/Dummy/dummy.c	(original)
+++ Apache-Scoreboard-2.0/trunk/Dummy/dummy.c	Fri Feb 11 22:47:32 2005
@@ -1,13 +1,21 @@
 #include "httpd.h"
 #include "scoreboard.h"
 
+extern int server_limit, thread_limit;
+
+#define DUMMY_SCOREBOARD
+
 scoreboard *ap_scoreboard_image = NULL;
 
-void ap_sync_scoreboard_image(void)
+int ap_exists_scoreboard_image(void)
 {
+    return 0;
 }
 
-int ap_exists_scoreboard_image(void)
+void modperl_trace(const char *func, const char *fmt, ...);
+void modperl_trace(const char *func, const char *fmt, ...)
 {
-    return 0;
+
 }
+
+

Modified: Apache-Scoreboard-2.0/trunk/MANIFEST
==============================================================================
--- Apache-Scoreboard-2.0/trunk/MANIFEST	(original)
+++ Apache-Scoreboard-2.0/trunk/MANIFEST	Fri Feb 11 22:47:32 2005
@@ -3,8 +3,7 @@
 Changes
 Dummy/dummy.c
 Dummy/DummyScoreboard.pm
-Dummy/DummyScoreboard.xs
-Dummy/Makefile.PL.orig
+Dummy/Makefile.PL
 Dummy/typemap
 examples/scoreboard-access-png.pl
 examples/scoreboard-cpu-png.pl

Modified: Apache-Scoreboard-2.0/trunk/Scoreboard.xs
==============================================================================
--- Apache-Scoreboard-2.0/trunk/Scoreboard.xs	(original)
+++ Apache-Scoreboard-2.0/trunk/Scoreboard.xs	Fri Feb 11 22:47:32 2005
@@ -18,6 +18,8 @@
 typedef struct {
     scoreboard *sb;
     apr_pool_t *pool;
+    int server_limit;
+    int thread_limit;
 } modperl_scoreboard_t;
 
 typedef struct {
@@ -26,31 +28,35 @@
     int worker_idx;
 } modperl_worker_score_t;
 
+/* XXX: notice that here we reference a struct living in a different
+ * perl object ($image), so if that object is destroyed earlier we get
+ * a segfault. a possible solution: inline modperl_scoreboard_t in
+ * modperl_parent_score_t (can't create a dependency inside $image,
+ * since there can be many objects referencing it, will require a
+ * complicated real ref counting)
+ */
 typedef struct {
     process_score *record;
     int idx;
-    scoreboard *sb;
-    apr_pool_t *pool;
+    modperl_scoreboard_t *image;
 } modperl_parent_score_t;
 
 typedef modperl_scoreboard_t   *Apache__Scoreboard;
 typedef modperl_worker_score_t *Apache__ScoreboardWorkerScore;
 typedef modperl_parent_score_t *Apache__ScoreboardParentScore;
 
-/* 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 scoreboard_up_time(image) \
-    (apr_uint32_t) apr_time_sec( \
+#define server_limit(image) image->server_limit
+#define thread_limit(image) image->thread_limit
+    
+#define scoreboard_up_time(image)                               \
+    (apr_uint32_t) apr_time_sec(                                \
         apr_time_now() - image->sb->global->restart_time);
 
 #define parent_score_pid(mps)  mps->record->pid
 
-#define worker_score_most_recent(mws) \
+#define worker_score_most_recent(mws)                                   \
     (apr_uint32_t) apr_time_sec(apr_time_now() - mws->record->last_used);
 
 /* XXX: as of 20031219, tid is not maintained in scoreboard */
@@ -73,16 +79,14 @@
 
 /* a worker that have served/serves at least one request and isn't
  * dead yet */
-#define LIVE_WORKER(ws) ws->access_count != 0 || \
+#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 || \
+#define ACTIVE_WORKER(ws) ws->access_count != 0 ||              \
     (ws->status != SERVER_DEAD && ws->status != SERVER_READY)
 
-
-
-
+#include "apxs/send.c"
 
 static void status_flags_init(void)
 {
@@ -99,23 +103,23 @@
     status_flags[SERVER_IDLE_KILL]      = 'I';
 }
 
-#include "apxs/send.c"
-
-MODULE = Apache::Scoreboard   PACKAGE = Apache::Scoreboard   PREFIX = scoreboard_
-
-BOOT:
+static void constants_init(pTHX)
 {
-    HV *stash;
+      HV *stash;
+      int server_limit, thread_limit;
 
-    /* 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);
+      /* SERVER_LIMIT and THREAD_LIMIT constants are deprecated, use
+       * $image->server_limit and $image->thread_limit instead */
+#ifndef DUMMY_SCOREBOARD
     ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
-
+    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
+#else
+    /* XXX: how can we figure out that data w/o having an access to
+     * ap_mpm_query? */
+    server_limit = 0;
+    thread_limit = 0;
+#endif
+    
     stash = gv_stashpv("Apache::Const", TRUE);
     newCONSTSUB(stash, "SERVER_LIMIT", newSViv(server_limit));
     
@@ -125,6 +129,57 @@
     stash = gv_stashpv("Apache::Scoreboard", TRUE);
     newCONSTSUB(stash, "REMOTE_SCOREBOARD_TYPE",
                 newSVpv(REMOTE_SCOREBOARD_TYPE, 0));
+
+}
+
+static worker_score *my_get_scoreboard_worker(pTHX_
+                                              modperl_scoreboard_t *image,
+                                              int x, int y)
+{
+    if (((x < 0) || (image->server_limit < x)) ||
+        ((y < 0) || (image->thread_limit < y))) {
+        Perl_croak(aTHX_ "worker score [%d][%d] is out of limit", x, y);
+    }
+    return &image->sb->servers[x][y];
+}
+
+static process_score *my_get_scoreboard_process(pTHX_
+                                                modperl_scoreboard_t *image,
+                                                int x)
+{
+    if ((x < 0) || (image->server_limit < x)) {
+        Perl_croak(aTHX_ "parent score [%d] is out of limit", x);
+    }
+    return &image->sb->parent[x];
+}
+
+static void image_sanity_check(pTHX)
+{
+#ifdef DUMMY_SCOREBOARD
+    Perl_croak(aTHX_ "Don't call the image() method when not"
+               "running under mod_perl");
+#endif
+}
+
+
+
+
+
+
+
+
+MODULE = Apache::Scoreboard   PACKAGE = Apache::Scoreboard   PREFIX = scoreboard_
+
+BOOT:
+{
+
+    /* 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();
+    
+    constants_init(aTHX);
 }
 
 int
@@ -138,32 +193,41 @@
     Apache::Scoreboard image
 
     PREINIT:
-    int i, psize, ssize, tsize;
-    char buf[SIZE16*2];
+    int server_num, psize, ssize, tsize;
+    char buf[SIZE16*4];
     char *dptr, *data, *ptr = buf;
     scoreboard *sb;
 
     CODE:
     sb = image->sb;
     
-    for (i = 0; i < server_limit; i++) {
-        if (!sb->parent[i].pid) {
+    for (server_num = 0; server_num < image->server_limit; server_num++) {
+        if (!sb->parent[server_num].pid) {
             break;
         }
     }
-    
-    psize = i * sizeof(process_score);
-    ssize = i * sizeof(worker_score);
+
+    //server_num = image->server_limit;
+
+    psize = sizeof(process_score) * server_num;
+    ssize = sizeof(worker_score)  * server_num * image->thread_limit;
     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); */
+       server_num, psize, ssize, sizeof(global_score) , sizeof(buf), tsize); */
 
     data = (char *)apr_palloc(image->pool, tsize);
     
     pack16(ptr, psize);
     ptr += SIZE16;
     pack16(ptr, ssize);
-    
+    ptr += SIZE16;
+    pack16(ptr, image->server_limit);
+    ptr += SIZE16;
+    pack16(ptr, image->thread_limit);
+
+    /* XXX: sync with send(), since the data frozen by this
+     * method won't work outside the same Apache */
+
     /* fill the data buffer with the data we want to freeze */
     dptr = data;
     Move(buf,             dptr, sizeof(buf),          char);
@@ -195,7 +259,8 @@
     scoreboard *sb;
     int psize, ssize;
     char *ptr;
-
+    int i;
+    
     CODE:
     if (!(SvOK(packet) && SvCUR(packet) > (SIZE16*2))) {
 	XSRETURN_UNDEF;
@@ -204,19 +269,35 @@
     CLASS = CLASS; /* avoid warnings */
  
     image = (modperl_scoreboard_t *)apr_pcalloc(pool, sizeof(*image));
-    sb    =           (scoreboard *)apr_pcalloc(pool, sizeof(scoreboard));
 
     ptr = SvPVX(packet);
     psize = unpack16(ptr);
     ptr += SIZE16;
     ssize = unpack16(ptr);
     ptr += SIZE16;
+    image->server_limit = unpack16(ptr);
+    ptr += SIZE16;
+    image->thread_limit = unpack16(ptr);
+    ptr += SIZE16;
+
+   /* ap_log_error(APLOG_MARK, APLOG_ERR, 0, modperl_global_get_server_rec(), */
+   /* fprintf(stderr,
+      "recv: sizes server_num=%d, thread_num=%d, psize=%d, "
+                 "ssize=%d\n",
+                 image->server_limit, image->thread_limit, psize, ssize);
+   */
 
+    sb = (scoreboard *)apr_pcalloc(pool, sizeof(scoreboard) +
+                                   image->server_limit * sizeof(worker_score *));
     sb->parent  = (process_score *)Copy_pool(pool, ptr, psize, char);
     ptr += psize;
-    sb->servers = (worker_score **)Copy_pool(pool, ptr, ssize, char);
-    ptr += ssize;
-    sb->global  = (global_score *) Copy_pool(pool, ptr, sizeof(global_score), char);
+    sb->servers = (worker_score **)((char*)sb + sizeof(scoreboard));
+    for (i = 0; i < image->server_limit; i++) {
+        sb->servers[i] = (worker_score *)Copy_pool(pool, ptr, sizeof(worker_score), char);
+        ptr += image->thread_limit * sizeof(worker_score);
+    }
+
+    sb->global  = (global_score *)ptr;
 
     image->pool = pool;
     image->sb   = sb;
@@ -231,12 +312,17 @@
     SV *CLASS
     APR::Pool pool
     
+    
     CODE:
+    image_sanity_check(aTHX);
+
     RETVAL = (modperl_scoreboard_t *)apr_palloc(pool, sizeof(*RETVAL));
     
     if (ap_exists_scoreboard_image()) {
-        RETVAL->sb = ap_scoreboard_image;
+        RETVAL->sb   = ap_scoreboard_image;
         RETVAL->pool = pool;
+        ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &(RETVAL->server_limit));
+        ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &(RETVAL->thread_limit));
     }
     else {
         Perl_croak(aTHX_ "ap_scoreboard_image doesn't exist");
@@ -247,23 +333,33 @@
     OUTPUT:
     RETVAL
 
+
+int
+server_limit(image)
+    Apache::Scoreboard image
+
+int
+thread_limit(image)
+    Apache::Scoreboard image
+
+    
 Apache::ScoreboardParentScore
-parent_score(self, idx=0)
-    Apache::Scoreboard self
+parent_score(image, idx=0)
+    Apache::Scoreboard image
     int idx
 
     PREINIT:
     process_score *ps;
     
     CODE:
-    ps = ap_get_scoreboard_process(idx);
-/* XXX */
+    ps = my_get_scoreboard_process(aTHX_ image, idx);
+    /* XXX */
     if (!ps->quiescing && ps->pid) {
-        RETVAL = (modperl_parent_score_t *)apr_pcalloc(self->pool, (sizeof(*RETVAL)));
+        RETVAL = (modperl_parent_score_t *)apr_pcalloc(image->pool,
+                                                       (sizeof(*RETVAL)));
         RETVAL->record = ps;
         RETVAL->idx    = idx;
-        RETVAL->sb     = self->sb;
-        RETVAL->pool   = self->pool;
+        RETVAL->image  = image;
     }
     else {
 	XSRETURN_UNDEF;
@@ -273,15 +369,27 @@
     RETVAL
 
 Apache::ScoreboardWorkerScore
-worker_score(self, parent_idx, worker_idx)
-    Apache::Scoreboard self
+worker_score(image, parent_idx, worker_idx)
+    Apache::Scoreboard image
     int parent_idx
     int worker_idx
 
+    PREINIT:
+    //worker_score *ws;
+    
     CODE:
-    RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->pool, (sizeof(*RETVAL)));
-
-    RETVAL->record = ap_get_scoreboard_worker(parent_idx, worker_idx);
+    //ws = my_get_scoreboard_worker(aTHX_ image, parent_idx, worker_idx);
+    //RETVAL = (modperl_worker_score_t *)apr_pcalloc(image->pool,
+    //                                               (sizeof(*RETVAL)));
+    //RETVAL->record = ws;
+    if (((parent_idx < 0) || (image->server_limit < parent_idx)) ||
+        ((worker_idx < 0) || (image->thread_limit < worker_idx))) {
+        Perl_croak(aTHX_ "worker score [%d][%d] is out of limit",
+                   parent_idx, worker_idx);
+    }
+    RETVAL = (modperl_worker_score_t *)apr_pcalloc(image->pool,
+                                                   (sizeof(*RETVAL)));
+    RETVAL->record = &(image->sb->servers[parent_idx][worker_idx]);
     RETVAL->parent_idx = parent_idx;
     RETVAL->worker_idx = worker_idx;
     
@@ -289,8 +397,8 @@
     RETVAL
 
 SV *
-pids(self)
-    Apache::Scoreboard self
+pids(image)
+    Apache::Scoreboard image
 
     PREINIT:
     AV *av = newAV();
@@ -298,8 +406,8 @@
     scoreboard *sb;
 
     CODE:
-    sb = self->sb;
-    for (i = 0; i < server_limit; i++) {
+    sb = image->sb;
+    for (i = 0; i < image->server_limit; i++) {
         if (!(sb->parent[i].pid)) {
             break;
         }
@@ -317,8 +425,8 @@
 # find_child_by_pid from scoreboard.c
 
 int
-parent_idx_by_pid(self, pid)   
-    Apache::Scoreboard self
+parent_idx_by_pid(image, pid)   
+    Apache::Scoreboard image
     pid_t pid
 
     PREINIT:
@@ -326,10 +434,10 @@
     scoreboard *sb;
 
     CODE:
-    sb = self->sb;
+    sb = image->sb;
     RETVAL = -1;
 
-    for (i = 0; i < server_limit; i++) {
+    for (i = 0; i < image->server_limit; i++) {
         if (sb->parent[i].pid == pid) {
             RETVAL = i;
             break;
@@ -340,8 +448,8 @@
     RETVAL
 
 SV *
-thread_numbers(self, parent_idx)
-    Apache::Scoreboard self
+thread_numbers(image, parent_idx)
+    Apache::Scoreboard image
     int parent_idx
 
     PREINIT:
@@ -350,9 +458,9 @@
     scoreboard *sb;
 
     CODE:
-    sb = self->sb;
+    sb = image->sb;
 
-    for (i = 0; i < thread_limit; ++i) {
+    for (i = 0; i < image->thread_limit; ++i) {
         /* 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)); */
@@ -366,8 +474,15 @@
     RETVAL
 
 apr_uint32_t
-scoreboard_up_time(self)
-    Apache::Scoreboard self
+scoreboard_up_time(image)
+    Apache::Scoreboard image
+
+
+
+
+
+
+
 
 MODULE = Apache::Scoreboard PACKAGE = Apache::ScoreboardParentScore PREFIX = parent_score_
     
@@ -378,17 +493,24 @@
     PREINIT:
     int next_idx;
     process_score *ps;
+    modperl_scoreboard_t *image;
 
     CODE:
+    image = self->image;
     next_idx = self->idx + 1;
-    ps = ap_get_scoreboard_process(next_idx);
+    if (next_idx <= image->server_limit) {
+        ps = my_get_scoreboard_process(aTHX_ image, next_idx);
+    }
+    else {
+	XSRETURN_UNDEF;
+    }
 
     if (ps->pid) {
-        RETVAL = (modperl_parent_score_t *)apr_pcalloc(self->pool, sizeof(*RETVAL));
+        RETVAL = (modperl_parent_score_t *)apr_pcalloc(image->pool,
+                                                       sizeof(*RETVAL));
         RETVAL->record = ps;
         RETVAL->idx    = next_idx;
-        RETVAL->sb     = self->sb;
-        RETVAL->pool   = self->pool;
+        RETVAL->image  = image;
     }
     else {
 	XSRETURN_UNDEF;
@@ -402,8 +524,17 @@
     Apache::ScoreboardParentScore self
 
     CODE:
-    RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->pool, sizeof(*RETVAL));
-    RETVAL->record     = ap_get_scoreboard_worker(self->idx, 0);
+    RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->image->pool,
+                                                   sizeof(*RETVAL));
+//RETVAL->record     = my_get_scoreboard_worker(aTHX_ self->image,
+//                                                 self->idx, 0);
+
+    if (((self->idx < 0) || (self->image->server_limit < self->idx))) {
+        Perl_croak(aTHX_ "worker score [%d][%d] is out of limit",
+                   self->idx, 0);
+    }
+    RETVAL->record = &(self->image->sb->servers[self->idx][0]);
+
     RETVAL->parent_idx = self->idx;
     RETVAL->worker_idx = 0;
 
@@ -420,9 +551,11 @@
     
     CODE:
     next_idx = mws->worker_idx + 1;
-    if (next_idx < thread_limit) {
-        RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->pool, sizeof(*RETVAL));
-        RETVAL->record = ap_get_scoreboard_worker(mws->parent_idx, next_idx);
+    if (next_idx < self->image->thread_limit) {
+        RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->image->pool,
+                                                       sizeof(*RETVAL));
+        RETVAL->record = my_get_scoreboard_worker(aTHX_ self->image,
+                                                  mws->parent_idx, next_idx);
         RETVAL->parent_idx = mws->parent_idx;
         RETVAL->worker_idx = next_idx;
     }
@@ -446,10 +579,12 @@
     CODE:
     next_idx = mws->worker_idx;
 
-    while (++next_idx < thread_limit) {
-        worker_score *ws = ap_get_scoreboard_worker(mws->parent_idx, next_idx);
+    while (++next_idx < self->image->thread_limit) {
+        worker_score *ws = my_get_scoreboard_worker(aTHX_ self->image,
+                                                    mws->parent_idx, next_idx);
         if (LIVE_WORKER(ws)) {
-            RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->pool, sizeof(*RETVAL));
+            RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->image->pool,
+                                                           sizeof(*RETVAL));
             RETVAL->record     = ws;
             RETVAL->parent_idx = mws->parent_idx;
             RETVAL->worker_idx = next_idx;
@@ -478,10 +613,11 @@
 
     CODE:
     next_idx = mws->worker_idx;
-    while (++next_idx < thread_limit) {
-        worker_score *ws = ap_get_scoreboard_worker(mws->parent_idx, next_idx);
+    while (++next_idx < self->image->thread_limit) {
+        worker_score *ws = my_get_scoreboard_worker(aTHX_ self->image,
+                                                    mws->parent_idx, next_idx);
         if (ACTIVE_WORKER(ws)) {
-            RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->pool,
+            RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->image->pool,
                                                            sizeof(*RETVAL));
             RETVAL->record     = ws;
             RETVAL->parent_idx = mws->parent_idx;
@@ -501,7 +637,15 @@
 pid_t
 parent_score_pid(self)
     Apache::ScoreboardParentScore self
-    
+
+
+
+
+
+
+
+
+
 MODULE = Apache::Scoreboard PACKAGE = Apache::ScoreboardWorkerScore PREFIX = worker_score_
 
 void
@@ -556,14 +700,12 @@
             (XSANY.any_i32 == 0 ? "start" : "stop"), tp);
 
     {
-        /*** XXX debug ***/
-        worker_score *ws_record = ap_get_scoreboard_worker(0, 0);
         SB_TRACE(MP_FUNC, "start: %5" APR_TIME_T_FMT "\n"
                  "stop: %5" APR_TIME_T_FMT "\n"
                  "last used: %5" APR_TIME_T_FMT "\n",
-                 ws_record->start_time,
-                 ws_record->stop_time,
-                 ws_record->last_used);
+                 self->record->start_time,
+                 self->record->stop_time,
+                 self->record->last_used);
     }
 
     /* do the same as Time::HiRes::gettimeofday */

Modified: Apache-Scoreboard-2.0/trunk/TODO
==============================================================================
--- Apache-Scoreboard-2.0/trunk/TODO	(original)
+++ Apache-Scoreboard-2.0/trunk/TODO	Fri Feb 11 22:47:32 2005
@@ -1,3 +1,7 @@
+
+DummyScoreboard needs to be implemented, so the image can be processed
+w/o requiring a running modperl environment.
+
 modperl's xs/typemap while includes the conversions for certain types
 it doesn't include the typemap declaration, so XS extensions have to
 add things like:

Modified: Apache-Scoreboard-2.0/trunk/apxs/send.c
==============================================================================
--- Apache-Scoreboard-2.0/trunk/apxs/send.c	(original)
+++ Apache-Scoreboard-2.0/trunk/apxs/send.c	Fri Feb 11 22:47:32 2005
@@ -26,36 +26,55 @@
     return ntohs(ashort);
 }
 
-#define WRITE_BUFF(buf, size, r) \
+#define WRITE_BUFF(buf, size, r)                                \
     if (ap_rwrite(buf, size, r) < 0) { return APR_EGENERAL; }
 
 static int scoreboard_send(request_rec *r)
 {
-    int i, psize, ssize, tsize;
-    char buf[SIZE16*2];
+    int server_num, psize, ssize, tsize;
+    char buf[SIZE16*4];
     char *ptr = buf;
+    int server_limit, thread_limit;
 
-    for (i = 0; i < server_limit; i++) {
-        if (!ap_scoreboard_image->parent[i].pid) {
+    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
+    ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
+    
+    for (server_num = 0; server_num < server_limit; server_num++) {
+        if (!ap_scoreboard_image->parent[server_num].pid) {
             break;
         }
     }
+
+    server_num = server_limit;
     
-    psize = i * sizeof(process_score);
-    ssize = i * sizeof(worker_score);
+    psize = sizeof(process_score) * server_num;
+    ssize = sizeof(worker_score)  * server_num * thread_limit;
     tsize = psize + ssize + sizeof(global_score) + sizeof(buf);
 
     pack16(ptr, psize);
     ptr += SIZE16;
     pack16(ptr, ssize);
-
+    ptr += SIZE16;
+    pack16(ptr, server_limit);
+    ptr += SIZE16;
+    pack16(ptr, thread_limit);
+    ap_log_error(APLOG_MARK, APLOG_ERR, 0, modperl_global_get_server_rec(),
+                 "send: sizes server_num=%d, thread_num=%d, psize=%d, "
+                 "ssize=%d, %d, %d, %d\n",
+                 server_num, thread_limit, psize, ssize,
+                 sizeof(global_score), sizeof(buf), tsize);
+ 
     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);
+        //int i;
+    //for (i = 0; i < server_limit; i++) {
+    //    WRITE_BUFF(ap_scoreboard_image->servers[i], sizeof(worker_score), r);
+    //}
+    WRITE_BUFF(ap_scoreboard_image->servers[0], ssize,                r);
 	WRITE_BUFF(&ap_scoreboard_image->global,     sizeof(global_score), r);
     }
 

Modified: Apache-Scoreboard-2.0/trunk/lib/Apache/Scoreboard.pm
==============================================================================
--- Apache-Scoreboard-2.0/trunk/lib/Apache/Scoreboard.pm	(original)
+++ Apache-Scoreboard-2.0/trunk/lib/Apache/Scoreboard.pm	Fri Feb 11 22:47:32 2005
@@ -18,6 +18,9 @@
     require XSLoader;
     XSLoader::load(__PACKAGE__, $Apache::Scoreboard::VERSION);
 }
+else {
+    require Apache::DummyScoreboard;
+}
 
 
 use constant DEBUG => 0;
@@ -158,19 +161,21 @@
 
  my $image = Apache::Scoreboard->retrieve($local_filename);
 
-=item parent
+=item parent_score
 
 This method returns a reference to the first parent score entry in the 
 list, blessed into the I<Apache::ParentScore> class:
 
- my $parent = $image->parent;
+ my $parent_score = $image->parent_score;
 
 Iterating over the list of scoreboard slots is done like so:
 
- for (my $parent = $image->parent; $parent; $parent = $parent->next) {
-     my $pid = $parent->pid; #pid of the child
+ for (my $parent_score = $image->parent_score;
+      $parent_score;
+      $parent_score = $parent_score->next) {
+     my $pid = $parent_score->pid; #pid of the child
 
-     my $server = $parent->server; #Apache::ServerScore object
+     my $server = $parent_score->server; #Apache::ServerScore object
 
      ...
  }
@@ -181,8 +186,34 @@
 
  my $pids = $image->pids;
 
+
+=item server_limit
+
+Returns a server limit for the given image.
+
+ my $server_limit = $image->server_limit;
+
+use this instead of the deprecated C<Apache::Const::SERVER_LIMIT>
+constant.
+
+
+=item thread_limit
+
+Returns a threads limit per process for the given image.
+
+ my $thread_limit = $image->thread_limit;
+
+use this instead of the deprecated C<Apache::Const::THREAD_LIMIT>
+constant.
+
+
 =back
 
+
+
+
+
+
 =head2 The Apache::ParentScore Class
 
 =over 4
@@ -302,8 +333,21 @@
 
  my $req_time = $server->req_time;
 
+=item vhost
+
+Returns the vhost string if there is one.
+
+ my $vhost = $server->vhost;
+
 =back
 
+
+=head1 Outside of mod_perl Usage
+
+C<Apache::DummyScoreboard> is used internally if the code is not
+running under mod_perl. It has almost the same functionality with some
+limitations. See the C<Apache::DummyScoreboard> manpage for more info.
+
 =head1 SEE ALSO
 
 Apache::VMonitor(3), GTop(3)
@@ -311,3 +355,6 @@
 =head1 AUTHOR
 
 Doug MacEachern
+
+Stas Bekman
+

Modified: Apache-Scoreboard-2.0/trunk/t/TEST.PL
==============================================================================
--- Apache-Scoreboard-2.0/trunk/t/TEST.PL	(original)
+++ Apache-Scoreboard-2.0/trunk/t/TEST.PL	Fri Feb 11 22:47:32 2005
@@ -3,7 +3,7 @@
 use strict;
 use warnings FATAL => 'all';
 
-use lib qw(lib ../Apache-Test/lib);
+use lib qw(t/lib lib ../Apache-Test/lib);
 
 use Apache::TestRunPerl ();
 

Added: Apache-Scoreboard-2.0/trunk/t/external/basic.t
==============================================================================
--- (empty file)
+++ Apache-Scoreboard-2.0/trunk/t/external/basic.t	Fri Feb 11 22:47:32 2005
@@ -0,0 +1,26 @@
+use strict;
+use warnings FATAL => 'all';
+
+use MyTest::Common ();
+use Apache::Scoreboard ();
+use APR::Pool ();
+
+use Apache::Test;
+use Apache::TestTrace;
+use Apache::TestRequest ();
+
+my $retrieve_url = MyTest::Common::retrieve_url();
+
+my $pool = APR::Pool->new; #XXX: pool's life
+my $ntests = MyTest::Common::num_of_tests();
+
+plan todo => [], tests => $ntests, ['status'];
+
+MyTest::Common::test1();
+
+my $image = Apache::Scoreboard->fetch($pool, $retrieve_url);
+MyTest::Common::test2($image);
+
+1;
+
+__END__

Copied: Apache-Scoreboard-2.0/trunk/t/internal/basic.t (from rev 89, Apache-Scoreboard-2.0/trunk/t/apache/scoreboard.t)
==============================================================================
--- Apache-Scoreboard-2.0/trunk/t/apache/scoreboard.t	(original)
+++ Apache-Scoreboard-2.0/trunk/t/internal/basic.t	Fri Feb 11 22:47:32 2005
@@ -6,4 +6,4 @@
 #  a dummy request to / to get the scoreboard counters going
 my $discard = GET_BODY "/index.html";
 
-print GET_BODY_ASSERT "/TestApache__scoreboard";
+print GET_BODY_ASSERT "/TestInternal__basic";

Added: Apache-Scoreboard-2.0/trunk/t/lib/MyTest/Common.pm
==============================================================================
--- (empty file)
+++ Apache-Scoreboard-2.0/trunk/t/lib/MyTest/Common.pm	Fri Feb 11 22:47:32 2005
@@ -0,0 +1,279 @@
+package MyTest::Common;
+
+use strict;
+use warnings FATAL => 'all';
+
+use Apache::Scoreboard ();
+use APR::Pool ();
+
+use Apache::Test;
+use Apache::TestUtil;
+use Apache::TestTrace;
+use Apache::TestRequest ();
+
+use File::Spec::Functions qw(catfile);
+
+my $cfg = Apache::Test::config();
+my $vars = $cfg->{vars};
+
+my $store_file = catfile $vars->{documentroot}, "scoreboard";
+my $hostport = Apache::TestRequest::hostport($cfg);
+my $retrieve_url = "http://$hostport/scoreboard";
+
+my @worker_score_scalar_props = qw(
+    thread_num tid req_time most_recent status access_count
+    bytes_served my_access_count my_bytes_served conn_bytes conn_count
+    client request vhost
+);
+
+my @worker_score_dual_props = qw(
+    times start_time stop_time
+);
+
+sub retrieve_url { return $retrieve_url }
+
+sub num_of_tests {
+    my $ntests = 15 + @worker_score_scalar_props + @worker_score_dual_props * 2;
+    $ntests += 2 if $ENV{MOD_PERL}; # deprecated constants
+    return $ntests;
+}
+
+sub test1 {
+
+    my $pool = APR::Pool->new;
+
+    debug "PID: ", $$, " ppid:", getppid(), "\n";
+
+    ### constants ###
+    {
+        t_debug "constants";
+        # deprecated and available only under mod_perl
+        if ($ENV{MOD_PERL}) {
+            ok Apache::Const::SERVER_LIMIT;
+            ok Apache::Const::THREAD_LIMIT;
+        }
+
+        ok Apache::Scoreboard::REMOTE_SCOREBOARD_TYPE;
+    }
+
+    ### the scoreboard image fetching methods ###
+
+    # need to have two available workers, otherwise it'll hang
+    # run the test with: -maxclients 2
+    if ($ENV{MOD_PERL} && $vars->{maxclients} < 2) {
+        die "maxclients needs to be 2 or higher";
+    }
+
+    my $image;
+    # fetch the image via lwp and run a few basic tests
+    {
+        t_debug("fetching: $retrieve_url");
+        $image = Apache::Scoreboard->fetch($pool, $retrieve_url);
+        ok image_is_ok($image);
+
+        t_debug("fetch_store/retrieve ($store_file)");
+        Apache::Scoreboard->fetch_store($retrieve_url, $store_file);
+        $image = Apache::Scoreboard->retrieve($pool, $store_file);
+        ok image_is_ok($image);
+    }
+
+    # testing freeze/store/retrieve/thaw the scoreboard image
+    {
+        t_debug "image freeze/thaw";
+        my $frozen_image = $image->freeze;
+        my $thawed_image = Apache::Scoreboard->thaw($pool, $frozen_image);
+        ok image_is_ok($thawed_image);
+
+        t_debug("image store/retrieve ($store_file)");
+        Apache::Scoreboard->store($frozen_image, $store_file);
+        my $image = Apache::Scoreboard->retrieve($pool, $store_file);
+        ok image_is_ok($image);
+    }
+}
+
+sub test2 {
+    my $image = shift;
+    ### parents/workers iteration functions ###
+
+    ok image_is_ok($image);
+
+    t_debug "iterating over procs/workers";
+    my $parent_ok      = 1;
+    my $next_ok        = 1;
+    my $next_live_ok   = 1;
+    my $next_active_ok = 1;
+    for (my $parent_score = $image->parent_score;
+         $parent_score;
+         $parent_score = $parent_score->next) {
+
+        $parent_ok = 0 unless parent_score_is_ok($parent_score);
+
+        my $pid = $parent_score->pid;
+        t_debug "pid = $pid";
+
+        # iterating over all workers for the given parent
+        for (my $worker_score = $parent_score->worker_score;
+                $worker_score;
+                $worker_score = $parent_score->next_worker_score($worker_score)
+            ) {
+            $next_ok = 0 unless worker_score_is_ok($worker_score);
+        }
+
+        # iterating over only live workers for the given parent
+        for (my $worker_score = $parent_score->worker_score;
+                $worker_score;
+                $worker_score = $parent_score->next_live_worker_score($worker_score)
+            ) {
+            $next_live_ok = 0 unless worker_score_is_ok($worker_score);
+        }
+
+
+        # iterating over only active workers for the given parent
+        for (my $worker_score = $parent_score->worker_score;
+                $worker_score;
+                $worker_score = $parent_score->next_active_worker_score($worker_score)
+            ) {
+            $next_active_ok = 0 unless worker_score_is_ok($worker_score);
+        }
+    }
+    t_debug "parent ok";
+    ok $parent_ok;
+    t_debug "iterating over all workers";
+    ok $next_ok;
+    t_debug "iterating over all live workers";
+    ok $next_live_ok;
+    t_debug "iterating over all active workers";
+    ok $next_active_ok;
+
+
+    ### other scoreboard image accessors ###
+
+    my @pids = @{ $image->pids };
+    t_debug "pids: @pids";
+    ok @pids;
+
+    my @thread_numbers = @{ $image->thread_numbers(0) };
+    t_debug "thread_numbers: @thread_numbers";
+    ok @thread_numbers;
+
+    my $up_time = $image->up_time;
+    t_debug "up_time: $up_time";
+    ok $up_time;
+
+    my $worker_score = $image->worker_score(0, 0);
+    ok $worker_score;
+
+    my $pid = $pids[0];
+
+    my $self_parent_idx = $image->parent_idx_by_pid($pid);
+    t_debug "pid: $$, self_parent_idx: $self_parent_idx";
+    my $self_parent_score = $image->parent_score($self_parent_idx);
+    t_debug "parent_idx_by_pid";
+    ok parent_score_is_ok($self_parent_score);
+
+    ### worker_score properties ###
+
+    t_debug "worker_score properties:";
+    for (@worker_score_dual_props) {
+        my $res = $worker_score->$_();
+        t_debug "$_ (scalar ctx): $res";
+        ok defined $res;
+
+        my @res = $worker_score->$_();
+        t_debug "$_   (list ctx): @res";
+        ok @res;
+
+    }
+
+    for (@worker_score_scalar_props) {
+        my $res = $worker_score->$_();
+        t_debug "$_: $res";
+        ok defined $res;
+    }
+
+}
+
+my @methods = qw(status access_count request client
+                 bytes_served conn_bytes conn_count times start_time
+                 stop_time req_time);
+
+# vhost is not available outside mod_perl, since it requires a call to
+# an Apache method
+push @methods, "vhost" if $ENV{MOD_PERL};
+
+sub score_is_ok {
+    my $parent = shift;
+
+    my $ok = 1;
+    $ok = 0 unless $parent->pid;
+
+    my $server = $parent->server; # Apache::ServerScore object
+    for (@methods) {
+        no strict 'refs';
+        my $val = $server->$_;
+        #error "$_ [$val]";
+        $ok = 0 unless defined $val;
+    }
+
+    return $ok;
+}
+
+# try to access various underlying datastructures to test that the
+# image is valid
+sub image_is_ok {
+    my ($image) = shift;
+    my $status = 1;
+    $status = 0 unless $image && 
+        ref($image) eq 'Apache::Scoreboard' &&
+        $image->pids &&
+        $image->worker_score(0, 0)->status &&
+        $image->parent_score &&
+        $image->parent_score->worker_score->vhost &&
+        $image->server_limit && 
+        $image->thread_limit;
+
+    # check that we don't segfault here
+    #for (my $proc = $image->parent; $proc; $proc = $proc->next) {
+    #    my $pid = $proc->pid;
+    #}
+
+    return $status;
+}
+
+# check that all worker_score props return something
+sub parent_score_is_ok {
+    my ($parent_score) = shift;
+
+    my $ok = 1;
+
+    $ok = 0 unless $parent_score && 
+                   $parent_score->pid && 
+                   $parent_score->worker_score;
+
+    return $ok;
+}
+
+# check that all worker_score props return something
+sub worker_score_is_ok {
+    my ($worker_score) = shift;
+
+    return 0 unless $worker_score;
+
+    my $ok = 1;
+    for (@worker_score_dual_props) {
+        my $res = $worker_score->$_();
+        $ok = 0 unless defined $res;
+
+        my @res = $worker_score->$_();
+        $ok = 0 unless @res;
+    }
+
+    for (@worker_score_scalar_props) {
+        my $res = $worker_score->$_();
+        $ok = 0 unless defined $res;
+    }
+
+    return $ok;
+}
+
+1;

Copied: Apache-Scoreboard-2.0/trunk/t/response/TestInternal/basic.pm (from rev 140, Apache-Scoreboard-2.0/trunk/t/response/TestApache/scoreboard.pm)
==============================================================================
--- Apache-Scoreboard-2.0/trunk/t/response/TestApache/scoreboard.pm	(original)
+++ Apache-Scoreboard-2.0/trunk/t/response/TestInternal/basic.pm	Fri Feb 11 22:47:32 2005
@@ -1,238 +1,32 @@
-package TestApache::scoreboard;
+package TestInternal::basic;
 
 use strict;
 use warnings FATAL => 'all';
 
 use Apache::Test;
-use Apache::TestUtil;
-use Apache::TestTrace;
-use Apache::TestRequest ();
 
 use Apache::Response ();
-use Apache::RequestRec;
-use Apache::Scoreboard;
+use Apache::RequestRec ();
 
-use File::Spec::Functions qw(catfile);
+use Apache::Scoreboard ();
+use MyTest::Common ();
 
 use Apache::Const -compile => 'OK';
 
-my @worker_score_scalar_props = qw(
-    thread_num tid req_time most_recent status access_count
-    bytes_served my_access_count my_bytes_served conn_bytes conn_count
-    client request vhost
-);
-
-my @worker_score_dual_props = qw(
-    times start_time stop_time
-);
-
-my $cfg = Apache::Test::config();
-my $vars = $cfg->{vars};
-
-my $store_file = catfile $vars->{documentroot}, "scoreboard";
-my $hostport = Apache::TestRequest::hostport($cfg);
-my $retrieve_url = "http://$hostport/scoreboard";
-
 sub handler {
     my $r = shift;
 
-    my $ntests = 15 + @worker_score_scalar_props + @worker_score_dual_props * 2;
-    $ntests += 2 if $vars->{maxclients} > 1;
+    my $ntests = MyTest::Common::num_of_tests();
 
     plan $r, todo => [], tests => $ntests, ['status'];
 
-    ### constants ###
-
-    debug "PID: ", $$, " ppid:", getppid(), "\n";
-
-    t_debug("constants");
-    ok Apache::Const::SERVER_LIMIT;
-    ok Apache::Const::THREAD_LIMIT;
-    ok Apache::Scoreboard::REMOTE_SCOREBOARD_TYPE;
-
-    ### the scoreboard image fetching methods ###
+    MyTest::Common::test1();
 
-    # get the image internally
+    # get the image internally (only under the live server)
     my $image = Apache::Scoreboard->image($r->pool);
-    ok image_is_ok($image);
-
-    # now fetch the image via lwp and run a few basic tests
-    # need to have two availble workers, otherwise it'll hang
-    # run the test with: -maxclients 2
-    if ($vars->{maxclients} > 1) {
-        t_debug("fetching: $retrieve_url");
-        my $image = Apache::Scoreboard->fetch($r->pool, $retrieve_url);
-        ok image_is_ok($image);
-
-        t_debug("fetch_store/retrieve ($store_file)");
-        Apache::Scoreboard->fetch_store($retrieve_url, $store_file);
-        $image = Apache::Scoreboard->retrieve($r->pool, $store_file);
-        ok image_is_ok($image);
-    }
-
-    # testing freeze/store/retrieve/thaw the scoreboard image
-    {
-        t_debug "image freeze/thaw";
-        my $frozen_image = $image->freeze;
-        my $thawed_image =  Apache::Scoreboard->thaw($r->pool, $frozen_image);
-        ok image_is_ok($thawed_image);
-
-        t_debug("image store/retrieve ($store_file)");
-        Apache::Scoreboard->store($frozen_image, $store_file);
-        my $image = Apache::Scoreboard->retrieve($r->pool, $store_file);
-        ok image_is_ok($image);
-    }
-
-    ### parents/workers iteration functions ###
-
-    t_debug "iterating over procs/workers";
-    my $parent_ok      = 1;
-    my $next_ok        = 1;
-    my $next_live_ok   = 1;
-    my $next_active_ok = 1;
-    for (my $parent_score = $image->parent_score;
-         $parent_score;
-         $parent_score = $parent_score->next) {
-
-        $parent_ok = 0 unless parent_score_is_ok($parent_score);
-
-        my $pid = $parent_score->pid;
-        t_debug "pid = $pid";
-
-        # iterating over all workers for the given parent
-        for (my $worker_score = $parent_score->worker_score;
-                $worker_score;
-                $worker_score = $parent_score->next_worker_score($worker_score)
-            ) {
-            $next_ok = 0 unless worker_score_is_ok($worker_score);
-        }
-
-        # iterating over only live workers for the given parent
-        for (my $worker_score = $parent_score->worker_score;
-                $worker_score;
-                $worker_score = $parent_score->next_live_worker_score($worker_score)
-            ) {
-            $next_live_ok = 0 unless worker_score_is_ok($worker_score);
-        }
-
-
-        # iterating over only active workers for the given parent
-        for (my $worker_score = $parent_score->worker_score;
-                $worker_score;
-                $worker_score = $parent_score->next_active_worker_score($worker_score)
-            ) {
-            $next_active_ok = 0 unless worker_score_is_ok($worker_score);
-        }
-    }
-    t_debug "parent ok";
-    ok $parent_ok;
-    t_debug "iterating over all workers";
-    ok $next_ok;
-    t_debug "iterating over all live workers";
-    ok $next_live_ok;
-    t_debug "iterating over all active workers";
-    ok $next_active_ok;
-
-
-    ### other scoreboard image accessors ###
-
-    my @pids = @{ $image->pids };
-    t_debug "pids: @pids";
-    ok @pids;
-
-    my @thread_numbers = @{ $image->thread_numbers(0) };
-    t_debug "thread_numbers: @thread_numbers";
-    ok @thread_numbers;
-
-    my $up_time = $image->up_time;
-    t_debug "up_time: $up_time";
-    ok $up_time;
-
-    my $worker_score = $image->worker_score(0, 0);
-    ok $worker_score;
-
-    my $self_parent_idx = $image->parent_idx_by_pid($$);
-    my $self_parent_score = $image->parent_score($self_parent_idx);
-    t_debug "parent_idx_by_pid";
-    ok parent_score_is_ok($self_parent_score);
-
-    ### worker_score properties ###
-
-    t_debug "worker_score properties:";
-    for (@worker_score_dual_props) {
-        my $res = $worker_score->$_();
-        t_debug "$_ (scalar ctx): $res";
-        ok defined $res;
-
-        my @res = $worker_score->$_();
-        t_debug "$_   (list ctx): @res";
-        ok @res;
-
-    }
-
-    for (@worker_score_scalar_props) {
-        my $res = $worker_score->$_();
-        t_debug "$_: $res";
-        ok defined $res;
-    }
+    MyTest::Common::test2($image);
 
     Apache::OK;
 }
 
-# try to access various underlying datastructures to test that the
-# image is valid
-sub image_is_ok {
-    my ($image) = shift;
-    my $status = 1;
-    $status = 0 unless $image && 
-        ref($image) eq 'Apache::Scoreboard' &&
-        $image->pids &&
-        $image->worker_score(0, 0)->status &&
-        $image->parent_score &&
-        $image->parent_score->worker_score->vhost;
-
-    # check that we don't segfault here
-    #for (my $proc = $image->parent; $proc; $proc = $proc->next) {
-    #    my $pid = $proc->pid;
-    #}
-
-    return $status;
-}
-
-# check that all worker_score props return something
-sub parent_score_is_ok {
-    my ($parent_score) = shift;
-
-    my $ok = 1;
-
-    $ok = 0 unless $parent_score && 
-                   $parent_score->pid && 
-                   $parent_score->worker_score;
-
-    return $ok;
-}
-
-# check that all worker_score props return something
-sub worker_score_is_ok {
-    my ($worker_score) = shift;
-
-    return 0 unless $worker_score;
-
-    my $ok = 1;
-    for (@worker_score_dual_props) {
-        my $res = $worker_score->$_();
-        $ok = 0 unless defined $res;
-
-        my @res = $worker_score->$_();
-        $ok = 0 unless @res;
-    }
-
-    for (@worker_score_scalar_props) {
-        my $res = $worker_score->$_();
-        $ok = 0 unless defined $res;
-    }
-
-    return $ok;
-}
-
 1;