>>>>> "Jeffrey" == Jeffrey W Baker writes:

I've cut down handler.pl to bare minimum.

=== cut handler.pl ==
#!/usr/bin/perl
# $Id: handler.pl,v 1.3 2000/01/14 19:42:16 tarkhil Exp $
#
$ENV{GATEWAY_INTERFACE} =~ /^CGI-Perl/
  or die "GATEWAY_INTERFACE not Perl!";
use Apache::Registry;
use Apache::Status;
use Socket;
use Carp qw(cluck confess);

package HTML::Mason;
use HTML::Mason;
use strict;
{
  package HTML::Mason::Commands;
  use Apache::Registry;
  use Apache::Status;
}

my $parser = new HTML::Mason::Parser
  (
#   allow_globals => [qw($dbh)]
  );
my $interp = new HTML::Mason::Interp 
  (parser=>$parser,
   data_dir => "/usr/local/www/tmp",
   comp_root => "/usr/local/www");

#$interp->set_global(dbh=>DBI->connect
#                   ("DBI:mysql:mail2pager",
#                    "tarkhil", "",
#                    { RaiseError => 1, PrintError => 1, 
#                      AutoCommit => 1, }
#));
my $ah = new HTML::Mason::ApacheHandler (interp=>$interp,
output_mode=>'batch');
chown ( 60001, 60001, $interp->files_written );
use Apache::Cookie;
use Apache::Session::File;
sub handler {
  my ($r) = @_;
  return -1 
    if defined($r->content_type) && $r->content_type !~ m|^text/|io;
  my $cook = Apache::Cookie->new($r);
  my $cookie = $cook->get('SESSION_ID');
  my %session;
  tie %session, 'Apache::Session::File', $cookie; 
  $cook->set(-name => "SESSION_ID", -value => $session{_session_id}) 
      if ( !$cookie );
  
  my $res = $ah->handle_request($r);
  untie %session;
  return $res;
}

1;
=== cut ===
No globals, yes?

I've used slightly modified File.pm:

== cut Apache::Session::File.pm ===
#############################################################################
#
# Apache::Session::File
# Apache persistent user sessions in the filesystem
# Copyright(c) 1998, 1999 Jeffrey William Baker ([EMAIL PROTECTED])
# Distribute under the Artistic License
#
############################################################################

package Apache::Session::File;

use strict;
use vars qw(@ISA $VERSION);

$VERSION = '1.00';
@ISA = qw(Apache::Session);

use Apache::Session;
use Apache::Session::DLocker;
use Apache::Session::FileStore;

sub get_object_store {
    my $self = shift;

    return new Apache::Session::FileStore $self;
}

sub get_lock_manager {
    my $self = shift;
    
    return new Apache::Session::DLocker $self;
}

1;
=== cut ===

with self-written daemon-based locker

=== cut Apache::Session::DLocker.pm ===
package Apache::Session::DLocker;

use strict;
use IO::Socket;
use vars qw($VERSION);

$VERSION = '1.00';

use constant LockerPort => 2015;

sub new {
    my $class   = shift;
    my $session = shift;
    
    return bless {read => 0, write => 0 }, $class;
}

sub request {
  my $self = shift;
  my $op = shift;
  my $session = shift;
  my $ready;
  until ($ready) {
    my $sock = new IO::Socket::INET(PeerAddr => '127.0.0.1',
                                    PeerPort => LockerPort);
    $sock->print(join(' ', $op, $session->{data}->{_session_id}, $$), "\n");
    $_ = $sock->getline();
    $sock->close;
    /OK/ and $ready = 1;
    sleep 1 unless $ready;
  }
}
sub acquire_read_lock  {
    my $self    = shift;
    my $session = shift;

    return if $self->{read};
    die if $self->{write};

    $self->request('LOCKR', $session);
    $self->{read} = 1;
}

sub acquire_write_lock {    
    my $self    = shift;
    my $session = shift;

    return if($self->{write});
    $self->request('LOCKW', $session);
    $self->{write} = 1;
}

sub release_read_lock  {
    my $self    = shift;
    my $session = shift;
    
    die unless $self->{read};
    $self->request('ULOCR', $session);
    $self->{read} = 0;
}

sub release_write_lock {
    my $self    = shift;
    my $session = shift;
    
    die unless $self->{write};
    
    $self->request('ULOCW', $session);
    $self->{write} = 0;
}

sub release_all_locks  {
    my $self    = shift;
    my $session = shift;

    if($self->{read}) {
        $self->release_read_lock($session);
    }
    if($self->{write}) {
        $self->release_write_lock($session);
    }
    
    $self->{read}  = 0;
    $self->{write} = 0;
}

1;
=== cut ===

and the following daemon to aid in debugging:

=== cut lockerd ===
#!/usr/bin/perl
use strict;
use IO::Socket;
use constant LockerPort => 2015;
my $dsock = new IO::Socket::INET(LocalAddr => '127.0.0.1', 
                                 LocalPort => LockerPort,
                                 Reuse => 1,
                                 Listen => 5);
die "Cannot allocate socket: $!"
  unless defined $dsock;
my %locks;
sub debug {
  print @_;
}

# Possible commands:
# LOCKR <session> <pid>
# LOCKW <session> <pid>
# ULOCR <session> <pid>
# ULOCW <session> <pid>
# Possible replies:
# +OK
# -ERR

sub ok {
  my $sock = shift;
  debug("OK");
  $sock->print("+OK\n");
  debug("\n");
}
sub err {
  my $sock = shift;
  debug("ERR");
  $sock->print("-ERR\n");
  debug("\n");
}
$SIG{INT} = sub {
  print "\n\nDumping locks state:\n";
  foreach (sort keys %locks) {
    print "Session $_:\n";
    if (defined($locks{$_}->{write})) {
      print " * Write locked by ",$locks{$_}->{write}, "\n";
    } else {
      print " * No write locks\n";
    }
    my $reader;
    print " * Read locked by: ", 
    join(', ',sort keys %{$locks{$_}->{read}}), "\n";
  }
  print "\n==========\n";
};

 
# Main loop
$| = 1;
while (my $client = $dsock->accept()) {
  $_ = $client->getline;
  chomp;
  next unless (/^([CKLORWU]{5}) ([\da-fA-F]+) (\d+)$/);
  $_ = $1;
  my $session = $2;
  my $pid = $3;
  /^LOCKR$/ and do {
    debug("$pid is r-locking $session...");
    if (defined $locks{$session}->{read}->{$pid}) {
      debug("already r-locked: ");
      err($client);
      next;
    } 
    if (defined $locks{$session}->{write}) {
      debug ("already w-locked with ", $locks{$session}->{write}, ": ");
      err($client);
      next;
    }
    $locks{$session}->{read}->{$pid} = 1;
    ok($client);
    next;
  };
  /^ULOKR$/ and do {
    debug("$pid is r-unlocking $session...");
    if (defined $locks{$session}->{read}->{$pid}) {
      delete $locks{$session}->{read}->{$pid};
      ok($client);
      next;
    }
    debug("no lock found:");
    err($client);
    next;
  };
  /^LOCKW$/ and do {
    debug("$pid is w-locking $session...");
    my $myrl = $locks{$session}->{read}->{$pid};
    if (scalar keys %{$locks{$session}->{read}} != $myrl) {
      debug("already r-locked by ", 
            join(':', sort keys %{$locks{$session}->{read}}), 
            ": ");
      err($client);
      next;
    }
    if (defined $locks{$session}->{write}) {
      debug("already w-locked by ", $locks{$session}->{write}, ": ");
      err($client);
      next;
    }
    $locks{$session}->{write} = $pid;
    ok($client);
    next;
  };
  /^ULOKW$/ and do {
    debug("$pid is w-unlocking $session...");
    if ($locks{$session}->{write} == $pid) {
      ok($client);
      next;
    }
    debug("not w-locked by $pid: ");
    err($client);
    next;
  };
} continue {
  $client->close() if defined $client;
}
=== cut ===

Everything is as simple as possible, and on first access to any HTML
page, lockerd informs me about r- or w-locking, but NO UNLOCK EVER
FOLLOWS.

It is beyond my understaning ability to find out why untie do not
force call to DESTROY, and even %session going out-of-scope do not.

>From my earlier expiriments I've found that untie _IS_ called, but
amazingly with no further effect.

Yes, I've tried to undef %session after untie, and even to undef
instead of untie.

Apparently Apache::DB cannot debug handlers, so I'm in total
darkness...

-- 
Alexander B. Povolotsky                            [ICQ 18277558]
[2:5020/145]                                    [[EMAIL PROTECTED]]

Reply via email to