Fwd: MPM-safe mp2 Singleton Pattern?

Fwd: MPM-safe mp2 Singleton Pattern?

am 07.11.2008 14:01:09 von ELINTPimp

Hello,

I want to implement a singleton pattern on my logger module. During
initial instantiation, the logger module is seeded with some
information (ie. transactionId) and creates some (ie. requestTime).
What I want is for the logger object to be instantiated (if needed)
and/or retrieved from the Logger::getInstance() method for each HTTP
request...basically I don't want to have to pass the object around but
instead return a the reference to the instance when I need it.

First, some info about my environment: mp2 on RHEL. The prefork MPM
is in use but I explicitly turned off worker as the existing
application I will be working against is not thread safe.

What I am running into is that the new instance is created for each
process and is accessible throughout the request as intended.
Unfortunately, what I am also noticing is that when the process is
reused by Apache, the previous logger instance still exists and is
pulled back by reference and therefore have incorrect parameters
(since the transactionID and requestTime has changed). I believe this
is by design because it obviously would give a decent performance
boost under situations where this is OK. However, this is not one of
these times =).

I thought of two solutions, both of which don't seem a great answer.
First was to explicitly DESTROY the logger object when I was done with
the request (which would work, since I have a controller/router
managing the request). however, if something goes wrong I can't be
sure the logger would be destroyed. Second was to create a factory
method in addition to the traditional singleton static method to
explicitly create a new instance and overwrite the existing. I think
this would work with my environment (only prefork MPM) but it smells
as if it wouldn't be thread safe - I imagine a spawned threat would
overwrite and corrupt multiple threads on a process. I included
psudo-code of the second theory below so you can pretty much see what
I am doing.

Is there any way to have a MPM-safe (specifically thread-safe)
singleton pattern?

P.S. For those of you who noticed, even though the app I'm eventually
going to integrate with is not thread safe, I am building a SOA
mid-tier that I wish to release open source and personally reuse, so I
want it to be thread safe. =)


Thanks,

Steve

psudo code:

package Logger;

my $this; # singleton instance

sub getInstance { my ( $self, $transId ) = @_;
unless (defined $this) {
$self->createNewInstance($transId);
}
return $this;
}

sub createNewInstance { my ( $self, $transId ) = @_;
my $vars = {'transId' => $transId};
$this = bless $vars, $self;

$this->_getRequestDate();

return $this;
}
1;

Re: Fwd: MPM-safe mp2 Singleton Pattern?

am 07.11.2008 15:23:50 von torsten.foertsch

On Fri 07 Nov 2008, Steven Siebert wrote:
> Is there any way to have a MPM-safe (specifically thread-safe)
> singleton pattern?

Modperl manages an interpreter pool if it runs under a threaded MPM.
That means the first modperl-related action in the request cycle pulls
an interpreter from the pool. Some time later the interpreter is the
put back to the pool. The point in time when that happens is defined by
the PerlInterpScope directive. It can happen immediately after the
current phase in the request cycle or when the request is over or when
the client connection is dropped. (And you can have a separate
interpreter for a subrequest.) Perl variables allocated in one
interpreter are accessible only from that interpreter unless they are
marked as shared. Shared variables are implemented by the
thread::shared module. This module creates another "shared" perl
interpreter that does the actual memory management. A shared variable
is then allocated inside that special interpreter and another one is
allocated inside the current interpreter. Then that variable is "tied"
to the variable in the shared interpreter in a similar way to what the
tie() command does.

So for what you want you need to make sure (if I understood your
problem) that the same instance is used throughout the request cycle.
Plus you want that it is destroyed when the request is over.

The simplest way is to put the object as a pnote:

sub getInstance {
my $r=shift;

return $r->pnotes->{Logger} if exists $r->pnotes->{Logger};
return $r->pnotes->{Logger}=Logger->new;
}

No global $this!

When the request pool is destroyed all pnotes are destroyed as well.

In theory that also binds the current interpreter to the pool. That
means it makes sure that the interpreter stays the same at least as
long as the request pool exists no matter what PerlInterpScope says.
But there were bugs with that in the past. So perhaps you have to
upgrade your modperl.

And finally an advice, don't use a threaded MPM with modperl in
production! If you want to help with the code it would be appreciated.
A good starting point is the threading branch at
http://svn.apache.org/repos/asf/perl/modperl/branches/thread ing

Torsten

--
Need professional mod_perl support?
Just hire me: torsten.foertsch@gmx.net

Re: Fwd: MPM-safe mp2 Singleton Pattern?

am 07.11.2008 19:18:45 von bharanee rathna

> The simplest way is to put the object as a pnote:

What Torsten said, but have a look at

http://search.cpan.org/~miyagawa/Apache-Singleton-0.07/lib/A pache/Singleton.pm

Apache::Singleton::Request is probably what you want.

Re: Fwd: MPM-safe mp2 Singleton Pattern?

am 07.11.2008 19:22:56 von ELINTPimp

Perfect! Great info from both...exactly what I needed. After
Torsten's response, I theorized that I could abstract that
functionality up and reveal a thin API for the creation/calling of
singleton objects within a namespace in pnotes....but that seems to
have already been done with Apache::Singleton::Request. I'm glad I
decided to ask the experts before attempting a hack myself. Thanks
guys!

On Fri, Nov 7, 2008 at 1:18 PM, bharanee rathna wrote:
>> The simplest way is to put the object as a pnote:
>
> What Torsten said, but have a look at
>
> http://search.cpan.org/~miyagawa/Apache-Singleton-0.07/lib/A pache/Singleton.pm
>
> Apache::Singleton::Request is probably what you want.
>

Re: Fwd: MPM-safe mp2 Singleton Pattern?

am 07.11.2008 21:56:51 von Rolf Schaufelberger

Am Freitag, 7. November 2008 19:22:56 schrieb Steven Siebert:
> Perfect! Great info from both...exactly what I needed. After
> Torsten's response, I theorized that I could abstract that
> functionality up and reveal a thin API for the creation/calling of
> singleton objects within a namespace in pnotes....but that seems to
> have already been done with Apache::Singleton::Request. I'm glad I
> decided to ask the experts before attempting a hack myself. Thanks
> guys!
>
> On Fri, Nov 7, 2008 at 1:18 PM, bharanee rathna wrote:
> >> The simplest way is to put the object as a pnote:
> >
> > What Torsten said, but have a look at
> >
> > http://search.cpan.org/~miyagawa/Apache-Singleton-0.07/lib/A pache/Singlet
> >on.pm
> >
> > Apache::Singleton::Request is probably what you want.

I couldn't get Apache::Singleton working with mp2 (used it before with no
problems with mp1). so I switched back to Class::Singelton and, at the top of
my handler (MasonX::WebApp) destroy the old instance and create a new one. I
couldn' t find ouy why it failed with mp2 since I had not much time and my
app had to become ready. The failure showed in a "hanging" request.

The reason why I use Class::Singelton (and not $r->pool or $r->pnotes) is
just, that I can reuse my perl modules in all apps running as stand alone
scripts. So for instance , I put my DBIx;:Class schema object in there, the
logging handler etc.

--
Rolf Schaufelberger

Re: Fwd: MPM-safe mp2 Singleton Pattern?

am 08.11.2008 06:16:10 von bharanee rathna

> I couldn't get Apache::Singleton working with mp2 (used it before with no
> problems with mp1). so I switched back to Class::Singelton ...

*sigh*, 2 yr old bug report. Maybe someone should write to the
author/maintainer and take ownership ?

http://rt.cpan.org/Public/Bug/Display.html?id=19775

Easy fix though as noted in the RT ticket. Also I think you should
turn on global request,

PerlOptions +GlobalRequest

otherwise you would not be able to get the request object via
Apache2::RequestUtil->request,. Alternatively you can set the request
object in your handler initially as Apache2->request($r);

- b