Apache-Scoreboard

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

apxs/mod_scoreboard_send.c has been ported to Apache 2.0

Apache::DummyScoreboard was ported to mp2 (this is used to process a
scoreboard outside running Apache).

when freezing/sending don't try to figure out what are the live
servers, since a sequential search doesn't work. if a server went
away, there will be a hole, e.g. if C goes down in ABCDE, we will get
ABXDE and send only AB info. so just send them all

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 correct and
useful only for the image of the Apache server parsed from within the
running server.

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

Dummy/DummyScoreboard.pm  view on Meta::CPAN

C<Apache::Scoreboard-E<gt>fetch> instead.

=item * C<Apache::Const::SERVER_LIMIT> and C<Apache::Const::THREAD_LIMIT> 

At the moment the deprecated constants 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).
However, you should be using
C<L<$image->server_limit|Apache::Scoreboard/C_server_limit_>> and
C<L<$image->thread_limit|Apache::Scoreboard/C_thread_limit_>>.

=back

=cut

Dummy/dummy.c  view on Meta::CPAN

#include "httpd.h"
#include "scoreboard.h"

extern int server_limit, thread_limit;

#define DUMMY_SCOREBOARD

scoreboard *ap_scoreboard_image = NULL;

int ap_exists_scoreboard_image(void)
{
    return 0;
}

Makefile.PL  view on Meta::CPAN

use strict;
#use warnings;
use warnings FATAL => 'all';
#no warnings 'redefine';

use mod_perl2;

# XXX: need to check that the same perl is used as the one mod_perl
# was built with, otherwise unresolved symbols problems occur:
# e.g. try using mod_perl.so built with blead-perl and build the
# scoreboard with blead-ithreads-perl
#use Apache::Build ();
#my $build = Apache::Build->new;
#use lib qw(../lib ../Apache-Test/lib);

use ModPerl::MM ();

# enable 'make test|clean'
use Apache::TestMM qw(test clean);

# prerequisites

Scoreboard.xs  view on Meta::CPAN

#define SB_TRACE modperl_trace
#else
#define SB_TRACE if (0) modperl_trace
#endif

/* scoreboard */
typedef struct {
    scoreboard *sb;
    apr_pool_t *pool;
    int server_limit;
    int thread_limit;
} modperl_scoreboard_t;

typedef struct {
    worker_score *record;
    int parent_idx;
    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

Scoreboard.xs  view on Meta::CPAN

    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;

static char status_flags[SERVER_NUM_STATUS];

#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)                                   \
    (apr_uint32_t) apr_time_sec(apr_time_now() - mws->record->last_used);

/* XXX: as of 20031219, tid is not maintained in scoreboard */
#if APR_HAS_THREADS
#define worker_score_tid(mws)             mws->record->tid
#else
#define worker_score_tid(mws)             NULL
#endif

#define worker_score_thread_num(mws)      mws->record->thread_num
#define worker_score_access_count(mws)    mws->record->access_count
#define worker_score_bytes_served(mws)    mws->record->bytes_served
#define worker_score_my_access_count(mws) mws->record->my_access_count
#define worker_score_my_bytes_served(mws) mws->record->my_bytes_served
#define worker_score_conn_bytes(mws)      mws->record->conn_bytes
#define worker_score_conn_count(mws)      mws->record->conn_count
#define worker_score_client(mws)          mws->record->client
#define worker_score_request(mws)         mws->record->request
#define worker_score_vhost(mws)           mws->record->vhost

Scoreboard.xs  view on Meta::CPAN

    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 constants_init(pTHX)
{
      HV *stash;
      int server_limit, 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));
    
    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));

}

MP_INLINE
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];
}

MP_INLINE
static process_score *my_get_scoreboard_process(pTHX_
                                                modperl_scoreboard_t *image,
                                                int x)
{

Scoreboard.xs  view on Meta::CPAN

#else
#define MY_WARN ap_log_error(APLOG_MARK, APLOG_ERR, 0, modperl_global_get_server_rec(),
#endif
      
#if 0
static void debug_dump_sb(modperl_scoreboard_t *image)
{
    int i, j;

    for (i = 0; i < image->server_limit; i++) {
        for (j = 0; j < image->thread_limit; j++) {
            worker_score *ws = &image->sb->servers[i][j];
            if (ws->access_count) {
                MY_WARN
                    "rcv %02d-%02d: stat: %c cnt: %d\n", i, j,
                    status_flags[ws->status],
                    (int)ws->access_count);
            }
        }
    }
}

Scoreboard.xs  view on Meta::CPAN






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
scoreboard_send(r)

Scoreboard.xs  view on Meta::CPAN

    PREINIT:
    int psize, ssize, tsize, msize, i;
    char buf[SIZE16*4];
    char *dptr, *ptr = buf;
    scoreboard *sb;

    CODE:
    sb = image->sb;
    
    psize = sizeof(process_score) * image->server_limit;
    msize = sizeof(worker_score)  * image->thread_limit;
    ssize = msize * image->server_limit;
    tsize = psize + ssize + sizeof(global_score) + sizeof(buf);
    /* fprintf(stderr, "sizes %d, %d, %d, %d, %d\n",
       psize, ssize, sizeof(global_score) , sizeof(buf), tsize); */
                 
    pack16(ptr, psize);
    ptr += SIZE16;
    pack16(ptr, ssize);
    ptr += SIZE16;
    pack16(ptr, image->server_limit);
    ptr += SIZE16;
    pack16(ptr, image->thread_limit);

    RETVAL = NEWSV(0, tsize);
    dptr = SvPVX(RETVAL);
    SvCUR_set(RETVAL, tsize+1);
    SvPOK_only(RETVAL);

    /* fill the data buffer with the data we want to freeze */
    Move(&buf[0],        dptr, sizeof(buf),          char);
    dptr += sizeof(buf);
    Move(&sb->parent[0], dptr, psize,                char);

Scoreboard.xs  view on Meta::CPAN

 
    image = (modperl_scoreboard_t *)apr_pcalloc(pool, sizeof(*image));

    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;

   /* MY_WARN
      "recv: sizes server_num=%d, thread_num=%d, psize=%d, "
                 "ssize=%d\n",
                 image->server_limit, image->thread_limit, psize, ssize);
   */

    sb = (scoreboard *)apr_palloc(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 **)((char*)sb + sizeof(scoreboard));
    for (i = 0; i < image->server_limit; i++) {
        sb->servers[i] = (worker_score *)Copy_pool(pool, ptr,
                                                   image->thread_limit * sizeof(worker_score), char);
        ptr += image->thread_limit * sizeof(worker_score);
    }

    sb->global  = (global_score *)Copy_pool(pool, ptr,
                                            sizeof(global_score), char);

    image->pool = pool;
    image->sb   = sb;

   /* debug_dump_sb(image); */

Scoreboard.xs  view on Meta::CPAN


    CODE:
    image_sanity_check(aTHX);

    image = (modperl_scoreboard_t *)apr_palloc(pool, sizeof(*image));

    if (ap_exists_scoreboard_image()) {
        image->sb   = ap_scoreboard_image;
        image->pool = pool;
        ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &(image->server_limit));
        ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &(image->thread_limit));
    }
    else {
        Perl_croak(aTHX_ "ap_scoreboard_image doesn't exist");
    }
    RETVAL = sv_setref_pv(NEWSV(0, 0), "Apache::Scoreboard", (void*)image);
    /* make sure the pool sticks around as long as this object is alive */
    mpxs_add_pool_magic(RETVAL, pool_sv);

    CLASS = CLASS; /* avoid warnings */

    OUTPUT:
    RETVAL


int
server_limit(image)
    Apache::Scoreboard image

int
thread_limit(image)
    Apache::Scoreboard image

    
Apache::ScoreboardParentScore
parent_score(image, idx=0)
    Apache::Scoreboard image
    int idx

    PREINIT:
    process_score *ps;

Scoreboard.xs  view on Meta::CPAN

        if (sb->parent[i].pid == pid) {
            RETVAL = i;
            break;
        }
    }

    OUTPUT:
    RETVAL

SV *
thread_numbers(image, parent_idx)
    Apache::Scoreboard image
    int parent_idx

    PREINIT:
    AV *av = newAV();
    int i;
    scoreboard *sb;

    CODE:
    sb = image->sb;

    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)); */
        
        av_push(av, newSViv(sb->servers[parent_idx][i].thread_num));
    }

    RETVAL = newRV_noinc((SV*)av);

    OUTPUT:
    RETVAL

apr_uint32_t
scoreboard_up_time(image)
    Apache::Scoreboard image

Scoreboard.xs  view on Meta::CPAN

Apache::ScoreboardWorkerScore
next_worker_score(self, mws)
    Apache::ScoreboardParentScore self
    Apache::ScoreboardWorkerScore mws

    PREINIT:
    int next_idx;
    
    CODE:
    next_idx = mws->worker_idx + 1;
    if (next_idx < self->image->thread_limit) {
        RETVAL = (modperl_worker_score_t *)apr_pcalloc(self->image->pool,
                                                       sizeof(*RETVAL));
        RETVAL->parent_idx = mws->parent_idx;
        RETVAL->worker_idx = next_idx;
        RETVAL->record     = my_get_scoreboard_worker(aTHX_ self->image,
                                                      mws->parent_idx, next_idx);
    }
    else {
        XSRETURN_UNDEF;
    }

Scoreboard.xs  view on Meta::CPAN

    Apache::ScoreboardParentScore self
    Apache::ScoreboardWorkerScore mws

    PREINIT:
    int next_idx;
    int found = 0;
    
    CODE:
    next_idx = mws->worker_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->image->pool,
                                                           sizeof(*RETVAL));
            RETVAL->record     = ws;
            RETVAL->parent_idx = mws->parent_idx;
            RETVAL->worker_idx = next_idx;
            found++;
            break;

Scoreboard.xs  view on Meta::CPAN

next_active_worker_score(self, mws)
    Apache::ScoreboardParentScore self
    Apache::ScoreboardWorkerScore mws

    PREINIT:
    int next_idx;
    int found = 0;

    CODE:
    next_idx = mws->worker_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->image->pool,
                                                           sizeof(*RETVAL));
            RETVAL->record     = ws;
            RETVAL->parent_idx = mws->parent_idx;
            RETVAL->worker_idx = next_idx;
            found++;
            break;

Scoreboard.xs  view on Meta::CPAN

worker_score_tid(self)
    Apache::ScoreboardWorkerScore self

    CODE:
    RETVAL = worker_score_tid(self);

    OUTPUT:
    RETVAL
    
int
worker_score_thread_num(self)
    Apache::ScoreboardWorkerScore self
    
unsigned long
worker_score_access_count(self)
    Apache::ScoreboardWorkerScore self

unsigned long
worker_score_bytes_served(self)
    Apache::ScoreboardWorkerScore self

apxs/send.c  view on Meta::CPAN

}

#define WRITE_BUFF(buf, size, r)                                \
    if (ap_rwrite(buf, size, r) < 0) { return APR_EGENERAL; }

static int scoreboard_send(request_rec *r)
{
    int psize, ssize, tsize;
    char buf[SIZE16*4];
    char *ptr = buf;
    int server_limit, thread_limit;

    /* In httpd-2.x, each content handler is invoked, and is responsible for
       checking wether it's enabled or not for a given url. That's different
       from how 1.3 used to do it.
    */
    if (strcmp(r->handler, HANDLER_NAME)) {
        return DECLINED;
    }

    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
    ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);

    psize = sizeof(process_score) * server_limit;
    ssize = sizeof(worker_score)  * server_limit * 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);

#if 0
    ap_log_error(APLOG_MARK, APLOG_ERR, 0, modperl_global_get_server_rec(),
                 "send: sizes server_limit=%d, thread_num=%d, psize=%d, "
                 "ssize=%d, %d, %d, %d\n",
                 server_limit, thread_limit, psize, ssize,
                 sizeof(global_score), sizeof(buf), tsize);
#endif

#if 0
{
    int i, j;
    for (i = 0; i < server_limit; i++) {
        for (j = 0; j < thread_limit; j++) {
            worker_score *ws = &ap_scoreboard_image->servers[i][j];
            if (ws->access_count) {
                ap_log_error(APLOG_MARK, APLOG_ERR, 0, modperl_global_get_server_rec(),
                             "snd %02d-%02d: stat: %c cnt: %d\n", i, j,
                             status_flags[ws->status],
                             (int)ws->access_count);
            }
        }
    }
} 

lib/Apache/Scoreboard.pm  view on Meta::CPAN

  my $image = Apache::Scoreboard->fetch("http://localhost/scoreboard");





=head1 DESCRIPTION

Apache keeps track of server activity in a structure known as the
C<scoreboard>.  There is a I<slot> in the scoreboard for each child
server and its workers (be it threads or processes), containing
information such as status, access count, bytes served and cpu time,
and much more.  This same information is used by C<mod_status> to
provide current server statistics in a human readable
form. C<Apache::Scoreboard> provides the Perl API to access the
scoreboard. C<Apache::VMonitor> is an extended equivalent of
C<mod_status> written in Perl.




lib/Apache/Scoreboard.pm  view on Meta::CPAN

=head2 C<thaw>

  my $thawed_image = Apache::Scoreboard->thaw($pool, $frozen_image);

thaws a C<L<frozen|/freeze>> image, turning it into the
C<L<Apache::Scoreboard|/The_Apache::Scoreboard_Methods>> object.




=head2 C<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.







lib/Apache/Scoreboard.pm  view on Meta::CPAN


  my($tv_sec, $tv_usec) = $worker_score->stop_time;

  my $secs = $worker_score->stop_time;

META: as of Apache 2.0.53 it's yet unavailable (needs to be ported)




=head2 C<thread_num>

XXX




=head2 C<tid>

XXX

t/lib/MyTest/Common.pm  view on Meta::CPAN

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(access_count bytes_served
       client conn_bytes conn_count most_recent
       my_access_count my_bytes_served request req_time
       status thread_num tid);
# vhost is not available outside mod_perl, since it requires a call to
# an Apache method
push @worker_score_scalar_props, "vhost" if $ENV{MOD_PERL};

my @worker_score_dual_ctx_props = qw(
    times start_time stop_time
);

my @worker_score_dual_var_props = qw(status);

t/lib/MyTest/Common.pm  view on Meta::CPAN

    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 >= 0; # can be 0 if tested too fast

    my $worker_score = $image->worker_score(0, 0);
    ok $worker_score;

    my $pid = $pids[0];

t/lib/MyTest/Common.pm  view on Meta::CPAN

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



( run in 0.443 second using v1.01-cache-2.11-cpan-3cd7ad12f66 )