sample stasis web services for apache modperl and fastcgi. Both are multithreaded. However, the modperl one is racy. FastCGI is currently the recommended approach

This commit is contained in:
Sears Russell 2010-01-19 02:11:04 +00:00
parent 417eec45c4
commit 94b356f837
5 changed files with 224 additions and 0 deletions

22
lang/perl/README.cgi-bin Normal file
View file

@ -0,0 +1,22 @@
This should go in a sites-enabled file, inside a VirtualHost:
ScriptAlias /stasis-cgi/ /home/sears/stasis/lang/perl/cgi-bin/
<Directory "/home/sears/stasis/lang/perl/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</Directory>
This is the contents of my /etc/apache2/mods-enabled/fastcgi.conf
<IfModule mod_fastcgi.c>
AddHandler fastcgi-script .fcgi
#FastCgiWrapper /usr/lib/apache2/suexec
FastCgiIpcDir /var/lib/apache2/fastcgi
FastCgiConfig -maxClassProcesses 1 -maxProcesses 1 -processSlack 1
</IfModule>
Note that the fastcgi scripts are currently hardcoded to run in ~sears/stasis/www-data2

25
lang/perl/README.modperl Normal file
View file

@ -0,0 +1,25 @@
This goes in apache.conf:
<IfModule mpm_worker_module>
StartServers 1
# Only want 1 server; this is a correctness constraint for stasis.
ServerLimit 1
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 150
ThreadsPerChild 150
MaxClients 150
MaxRequestsPerChild 0
</IfModule>
This goes in the sites-enabled/???:
PerlRequire /home/sears/stasis/lang/perl/apache/inc/startup.pl
<Location /stasis>
SetHandler perl-script
PerlResponseHandler StasisWeb::Web
</Location>
Note that the modapache scripts are currently hardcoded to look in ~sears/stasis/www-data

View file

@ -0,0 +1,34 @@
#file:Stasis/Web.pm
#----------------------
package StasisWeb::Web;
use threads::shared;
my $thelock :shared;
use strict;
use warnings;
use Apache2::RequestRec ();
use Apache2::RequestIO ();
use Apache2::Const -compile => qw(OK);
sub handler {
my $r = shift;
$r->content_type('text/html');
print "<html><head></head><body><h1>Stasis</h1>" . `pwd`;
my $xid = Stasis::Tbegin();
warn "a\n";
my %h;
tie %h, 'Stasis::Hash', $xid, Stasis::ROOT_RID();
$h{foo}++;
print ("$xid $h{foo}\n");
Stasis::Tcommit($xid);
warn "b\n"; $| = 1;
print "</body></html>\n";
return Apache2::Const::OK;
}
1;

51
lang/perl/apache/inc/startup.pl Executable file
View file

@ -0,0 +1,51 @@
use threads;
use threads::shared;
use strict;
BEGIN {
my $thelock :shared;
$ENV{STASIS_DIR} = '/home/sears/stasis';
$ENV{STASIS_LOCK} = $thelock;
}
use lib ($ENV{STASIS_DIR}."/lang/perl/apache/");
push @INC, "$ENV{STASIS_DIR}/lang/perl/";
use Inline (Config =>
DIRECTORY => "$ENV{STASIS_DIR}/www-data/",
);
use Stasis;
# XXX Ideally, the rest of this would go in a post_config handler, but
# I can't get that to work...
my $data_dir = "$ENV{STASIS_DIR}/www-data/";
{
my $d = `date`;
chomp $d;
warn "$d: Starting Stasis in $data_dir\n";
chdir $data_dir
|| die "Could not chdir to $data_dir, which I must own!";
Stasis::Tinit();
$d = `date`;
chomp $d;
warn "$d: Stasis recovery complete\n";
my $xid = Stasis::Tbegin();
if(Stasis::TrecordType($xid, Stasis::ROOT_RID()) == Stasis::INVALID_SLOT()) {
$d = `date`;
chomp $d;
warn "$d: Bootstrapping new Stasis store.\n";
Stasis::ThashCreate($xid);
}
Stasis::Tcommit($xid);
$d = `date`;
chomp $d;
warn "$d: Stasis initialization complete.\n";
}
1;

92
lang/perl/cgi-bin/test.fcgi Executable file
View file

@ -0,0 +1,92 @@
#!/usr/bin/perl -w
use strict;
BEGIN {
$ENV{STASIS_DIR} = '/home/sears/stasis';
$ENV{STASIS_INLINE_DIRECTORY} = '/home/sears/stasis/www-data2';
$ENV{PATH} = '/usr/local/bin:/usr/bin:/bin';
# $ENV{LANG} = 'en_US.UTF-8';
# $ENV{SHELL} = '/bin/sh';
# warn `env`;
chdir "$ENV{STASIS_DIR}/www-data2" || die;
# warn "begin succeeded";
push @INC, "$ENV{STASIS_DIR}/lang/perl";
}
use threads;
use threads::shared;
use Stasis;
use IO::Handle;
use FCGI;
my $count = 0;
my $tot :shared = 0;
my $concurrent :shared = 0;
my $in = new IO::Handle;
my $out = new IO::Handle;
my $err = new IO::Handle;
my $num_procs = 25;
Stasis::Tinit();
my $xid = Stasis::Tbegin();
if(Stasis::TrecordType($xid, Stasis::ROOT_RID()) == Stasis::INVALID_SLOT()) {
warn "Creating new database\n";
Stasis::ThashCreate($xid);
}
Stasis::Tcommit($xid);
warn "Stasis bootstrap completed; accepting FastCGI requests\n";
my @thrs;
for(my $i = 0; $i < $num_procs; $i++) {
push @thrs, threads->create(\&event_loop, $i);
}
sub event_loop {
my $i = shift;
# warn "Event loop $i started\n";
my $request = FCGI::Request($in, $out, $err);
while($request->Accept() >= 0) {
my $s;
my $tot2;
{ lock $concurrent; $concurrent ++; }
{
lock($tot);
$tot ++;
$s = $tot;
my $xid = Stasis::Tbegin();
my %h;
tie %h, 'Stasis::Hash', $xid, Stasis::ROOT_RID();
$h{foo}++;
$tot2 = $h{foo};
Stasis::TsoftCommit($xid);
}
# Release lock before waiting for disk force.
Stasis::TforceCommits();
print $out "Content-type: text/html\r\n\r\n" . "$count of $s ($tot2) concurrent: $concurrent";
$count ++;
{ lock $concurrent; warn "concurr: $concurrent\n"; $concurrent --; }
# print $err "Event loop $i accepted request\n";
}
# warn "Event loop $i done\n";
}
warn "Done spawning worker threads\n";
foreach my $t (@thrs) {
$t->join();
}
Stasis::Tdeinit();
warn "Stasis cleanly shut down\n";