Ref::Store::Walkthrough - Walkthrough on how to rewrite a module using Ref::Store
This document is to supplement the synopsis in the main module docuemntation.
We will try to dissect and pseudo-refactor the code in POE::Component::Client::HTTP (refered to as poco-http) to demonstrate the usefulness of this module.
We will assume that there is a gloabl object, <$Table> which may presumably be stored on the heap
We have a bunch of key types, so let's register them.
my @KEY_TYPES; BEGIN { @KEY_TYPES = map 'KT_'.$_, ( "EXT_REQ", #HTTP::Request object "POE_REQ", #POE::Component::Client::HTTP::Request object "POE_REQID", #ID of the POE request "POE_WID", #POE::Wheel ID, needed for events. ); foreach my $kt (@KEY_TYPES) { no strict 'refs'; *{$kt} = sub () { $kt } } } #.... #Assume a table has been created by now $Table->register_kt(@_) foreach (@KEY_TYPES);
The poco-http API takes a request object and optionally accepts a tag, by which the user can easily identify the response received. The prime internal identifier used by POE is an internal Request object (POE::Component::Client::HTTP::Request), identified by its refaddr:
POE::Component::Client::HTTP::Request
my $request = $heap->{factory}->create_request( $http_request, $response_event, $tag, $progress_event, $proxy_override, $sender ); $heap->{request}->{$request->ID} = $request; $heap->{ext_request_to_int_id}->{$http_request} = $request->ID;
Instead of the last two lines, we do:
$Table->store_kt($request->ID, KT_POE_REQID, $request, StongValue => 1); #Because this is our primary reference. $Table->store_kt($http_request, $request);
Later on, in the same function, we have this code:
if ($@) { delete $heap->{request}->{$request->ID}; delete $heap->{ext_request_to_int_id}->{$http_request}; # we can reach here for things like host being invalid. $request->error(400, $@); }
Which can be refactored to:
$Table->purge($request);
Which will clean up everything associated with $request.
At this point, poco-http has submitted a request to its connection manager (POE::Component::Client::KeepAlive), and is now awaiting a response. Here is the code which handles it, with ommisions not pertinent to the description of the Ref::Store module.
sub _poco_weeble_connect_done { my ($heap, $response) = @_[HEAP, ARG0]; my $connection = $response->{'connection'}; my $request_id = $response->{'context'}; if (defined $connection) { DEBUG and warn "CON: request $request_id connected ok..."; #my $request = $heap->{request}->{$request_id};
Nothing revolutionary here, replace with:
my $request = $Table->fetch_kt(KT_POE_REQID, $request_id); unless (defined $request) { DEBUG and warn "CON: ignoring connection for canceled request"; return; } my $block_size = $heap->{factory}->block_size; # get wheel from the connection my $new_wheel = $connection->start( Driver => POE::Driver::SysRW->new(BlockSize => $block_size), InputFilter => POE::Filter::HTTPHead->new(), OutputFilter => POE::Filter::Stream->new(), InputEvent => 'got_socket_input', FlushedEvent => 'got_socket_flush', ErrorEvent => 'got_socket_error', ); DEBUG and warn "CON: request $request_id uses wheel ", $new_wheel->ID; # Add the new wheel ID to the lookup table. #$heap->{wheel_to_request}->{ $new_wheel->ID() } = $request_id;
And instead of this construct, we use:
$Table->store_a($new_wheel->ID(), KT_POE_WID, $request);
We skip a bunch of SSL initialization code, since it does not seem to use any type of lookup
else { DEBUG and warn( "CON: Error connecting for request $request_id --- ", $_[SENDER]->ID ); my ($operation, $errnum, $errstr) = ( $response->{function}, $response->{error_num} || '??', $response->{error_str} ); DEBUG and warn( "CON: request $request_id encountered $operation error " . "$errnum: $errstr" ); DEBUG and warn "I/O: removing request $request_id"; #my $request = delete $heap->{request}->{$request_id}; #$request->remove_timeout(); #delete $heap->{ext_request_to_int_id}->{$request->[REQ_HTTP_REQUEST]};
Is replaced with:
$Table->purge($request); $request->remove_timeout();
Here is the timeout function:
sub _poco_weeble_timeout { my ($kernel, $heap, $request_id) = @_[KERNEL, HEAP, ARG0]; #my $request = delete $heap->{request}->{$request_id};
Instead, we delete ALL lookup data associated with the key by doing this:
my $request = $Table->purgeby_kt($request_id, KT_POE_REQID); ...
We don't need this line
delete $heap->{ext_request_to_int_id}->{$request->[REQ_HTTP_REQUEST]}; ...
Nor do we need this
delete $heap->{wheel_to_request}->{$wheel_id}; ...
etc. etc. The rest of the POE code is more or less the same.
Look here for some other code which could use an even better helping of this module.
To install Ref::Store, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Ref::Store
CPAN shell
perl -MCPAN -e shell install Ref::Store
For more information on module installation, please visit the detailed CPAN module installation guide.