ljr/livejournal/cgi-bin/Apache/SendStats.pm

149 lines
3.7 KiB
Perl
Raw Permalink Normal View History

2019-02-05 21:49:12 +00:00
#!/usr/bin/perl
#
package Apache::SendStats;
BEGIN {
$LJ::HAVE_INLINE = eval q{
use Inline (C => 'DATA',
DIRECTORY => $ENV{LJ_INLINE_DIR} ||"$ENV{'LJHOME'}/Inline",
);
1;
};
}
use strict;
use IO::Socket::INET;
use Apache::Constants qw(:common);
if ($LJ::HAVE_INLINE && $LJ::FREECHILDREN_BCAST) {
eval {
Inline->init();
};
if ($@ && ! $LJ::JUST_COMPILING) {
print STDERR "Warning: You seem to have Inline.pm, but you haven't run \$LJHOME/bin/lj-inline.pl. " .
"Continuing without it, but stats won't broadcast.\n";
$LJ::HAVE_INLINE = 0;
}
}
use vars qw(%udp_sock);
sub handler
{
my $r = shift;
return OK if $r->main;
return OK unless $LJ::HAVE_INLINE && $LJ::FREECHILDREN_BCAST;
my $callback = $r->current_callback() if $r;
my $cleanup = $callback eq "PerlCleanupHandler";
my $childinit = $callback eq "PerlChildInitHandler";
if ($LJ::TRACK_URL_ACTIVE)
{
my $key = "url_active:$LJ::SERVER_NAME:$$";
if ($cleanup) {
LJ::MemCache::delete($key);
} else {
LJ::MemCache::set($key, $r->uri . "(" . $r->method . "/" . scalar($r->args) . ")");
}
}
my ($active, $free) = count_servers();
$free += $cleanup;
$free += $childinit;
$active -= $cleanup if $active;
my $list = ref $LJ::FREECHILDREN_BCAST ?
$LJ::FREECHILDREN_BCAST : [ $LJ::FREECHILDREN_BCAST ];
foreach my $host (@$list) {
next unless $host =~ /^(\S+):(\d+)$/;
my $bcast = $1;
my $port = $2;
my $sock = $udp_sock{$host};
unless ($sock) {
$udp_sock{$host} = $sock = IO::Socket::INET->new(Proto => 'udp');
if ($sock) {
$sock->sockopt(SO_BROADCAST, 1);
} else {
$r->log_error("SendStats: couldn't create socket: $host");
next;
}
}
my $ipaddr = inet_aton($bcast);
my $portaddr = sockaddr_in($port, $ipaddr);
my $message = "bcast_ver=1\nfree=$free\nactive=$active\n";
my $res = $sock->send($message, 0, $portaddr);
$r->log_error("SendStats: couldn't broadcast")
unless $res;
}
return OK;
}
1;
__DATA__
__C__
extern unsigned char *ap_scoreboard_image;
/*
* the following structure is for Linux on i32 ONLY! It makes certan
* choices where apache's scoreboard.h has #ifdef's. See scoreboard.h
* for real declarations, here we only name a few things we actually need.
*/
/* total length of struct should be 164 bytes */
typedef struct {
int foo1;
short foo2;
unsigned char status;
int foo3[39];
} short_score;
/* length should be 16 bytes */
typedef struct {
int pid;
int foo[3];
} parent_score;
static int hard_limit = 512; /* array size on debian */
/*
* Scoreboard is laid out like this: array of short_score structs,
* then array of parent_score structs, then one int, the generation
* number. Both arrays are of size HARD_SERVERS_LIMIT, 256 by default
* on Unixes.
*/
void count_servers() {
int i, count_free, count_active;
short_score *ss;
parent_score *ps;
Inline_Stack_Vars;
ss = (short_score *)ap_scoreboard_image;
ps = (parent_score *) ((unsigned char *)ap_scoreboard_image + sizeof(short_score)*hard_limit);
count_free = 0; count_active = 0;
for (i=0; i<hard_limit; i++) {
if(ss[i].status == 2) /* READY */
count_free++;
if(ss[i].status > 2) /* busy doing something */
count_active++;
}
Inline_Stack_Reset;
Inline_Stack_Push(newSViv(count_active));
Inline_Stack_Push(newSViv(count_free));
Inline_Stack_Done;
return;
}