NAME

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:

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.