Kyle R . Burton on Thu, 12 Apr 2001 22:07:57 -0400


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

question about xs


I'm working on a website where we do real time contract based pricing
and availability.  The interface to the pricing system is currently RPC
based - we were originaly provided with a command line binary that we
could call to obtain pricing information.  It read it's input from
stdin, and wrote it's output to stdout (sounds familliar eh?).

The site is Apache+mod_perl based, and connects to an Oracle database.  
So in genral, it performs well.  The pricing call has been a thorn in
our side since the beginning - as we have to create a pair of pipes, and
do a fork+exec to safely run the pricing program and pass data to/from
it (we've managed to keep taint checking on).  The busier the site gets,
the more forking for pricing takes place - and we've recently been told
that for performance reasons (since traffic has risen) we shouldn't
price more than 15 products at a time (we sometimes have to price more 
than 40 for a single page), so this forces even more forking on the web
servers.

To obviate all of the forking, I've decided to just wrap the RPC call in
an XS module.  This is the first time I've written an XS module and had
Perl calling C code, so I wanted advice/confirmation on the approach
that I'm using.

There are 3 basic C (RPC) calls that need to be made:

clnt_create

  Which makes the RPC connection, and 
  returns a pointer to an RPC CLIENT 
  struct.

the_pricing_call

  which basicly takes a string, and 
  returns a string

clnt_destroy

  to disconnect, and free the client 
  struct


The approach I've taken so far is to wrap each of these in an XS
function.  For clnt_create, I'm casting the CLIENT* to an I32 and
storing it inside the calling object by using call_method to call 
a get/set that is implemented in native Perl.  The man pages [perlcall,
perlguts, perlxs] recommended this approach (casting the pointer to an
I32 and back).

For the pricing call, on success, I'm storing the resulting returned
buffer in an SV* inside the calling object [native Perl code].  It is
getting it's arguments by using call_method on get/sets, and storing the
results (or errors) in the same manner.

clnt_destroy uses call_method to obtain the I32 value from a get/set
implemented in Perl.


So far, this has worked out well - we even have an advantage over the
command line program - we can keep the RPC connection open and make
multiple pricing calls before closing it.


I've seen a few other approaches.  One where you use a C structure 
and bless it to make it an object.  This worked for the first prototype, 
though it ended up being a scalar reference, and I couldn't figure out 
how to successfuly have it be derived from another base class - especially 
since our universal base class is implemented as a hash ref.

Has anyone done anything similar?  Does anyone know if there is a better
way to accomplish this?  Any general advice/gotchas?

thanks,
Kyle


-- 
------------------------------------------------------------------------------
   Of course power tools and alcohol don't mix.  Everyone knows power tools 
   aren't soluble in alcohol...      -- Crazy Nigel
mortis@voicenet.com                            http://www.voicenet.com/~mortis
------------------------------------------------------------------------------
**Majordomo list services provided by PANIX <URL:http://www.panix.com>**
**To Unsubscribe, send "unsubscribe phl" to majordomo@lists.pm.org**