2013/12/02

Futures advent day 2

Day 2 - Doing something when a Future completes

Because a Future object represents an operation that is currently in progress or has finished it provides the ideal place to attach logic to ask for further activity to happen when the original has completed. The most immediate way is to pass a piece of code in a sub reference to the on_done method.

my $f = GET("http://my-site-here.com/");

$f->on_done( sub {
  my ( $response ) = @_;
  print "Got a response\n";
});

In this case, as for many posts yet to come, we are presuming some hypothetical GET function that returns a Future wrapping an HTTP operation in the obvious manner.

If the returned Future is already complete (perhaps because it is a synchronous client that always completes immediately, or because it was served internally from a cache) then the on_done method invokes the code immediately. If not, the code is stored inside the Future object itself for when it eventually gets its result.

<< First | < Prev | Next >

2013/12/01

Futures advent day 1

It is traditional around this time of year for Perl blogs to publish an advent calendar - a series of 24 short little posts around a common theme.

People have suggested I might write one about Futures, so here goes...

Day 1 - Futures can return values synchronously

You don't in fact have to use a Future for anything asynchronous. A simple synchronous-returning function can use them too.

use Future;

sub sum
{
   my @numbers = @_;
   my $total = 0;
   $total += $_ for @numbers;
   return Future->new->done( $total );
}

say "The total is " . sum( 10, 20, 30 )->get;

It may not be immediately obvious currently why you want to do this, but I hope to motivate why over the following 23 posts...

<< First | < Prev | Next >

2013/10/23

Parallel Name Resolving using IO::Async

Perl has a variety of modules and frameworks that allow multiple, parallel operations at once. Some are specific to one kind of task, and some more generic. One of the larger general-purpose ones is IO::Async.

IO::Async provides an abstraction around the system name resolver, getaddrinfo(), allowing it to be called asynchronously to resolve a number of names at once, and returning results later as they arrive.

To do this, start with the resolver object itself. This can be obtained from the underlying IO::Async::Loop object. We do not actually need to keep a reference to the Loop, as the resolver will keep that itself.

use IO::Async::Loop;

my $resolver = IO::Async::Loop->new->resolver;

Next, call the getaddrinfo method on it, passing in the details of the name lookup required, and collect the result list. We need to pass a hint to the method so that it returns just one kind of socket address rather than iterating all the possible kinds. Since we only care about the IP address and not the service port number it doesn't matter too much what hint we pass, but one of the simpler ones is to ask for the stream socket type (i.e. TCP ports).

my @results = $resolver->getaddrinfo(
   host     => "www.google.com",
   socktype => 'stream',
)->get;

This method is intended for creating packed socket address structures for passing directly to connect() or bind(), so to obtain a human-readable string it will need converting back to a printable numeric form by using Socket::getnameinfo(). We need to pass in the NI_NUMERICHOST flag in order to have it return a plain numeric IP address instead of reverse resolving that address back into a name. The numeric address string itself will come in the second positional result from getnameinfo(), so we will have to use a list slice operator to return just that.

use Socket qw( getnameinfo NI_NUMERICHOST );

my @addrs = map { ( getnameinfo $_->{addr}, NI_NUMERICHOST )[1] }
            @results;

print "$_\n" for @addrs;

This yields the list of IP addresses for this one hostname:

2a00:1450:4009:809::1014
173.194.34.112
173.194.34.115
173.194.34.113
173.194.34.116
173.194.34.114

The reason for the get method here is that, like (almost) all of the IO::Async methods that perform a single asynchronous operation, the getaddrinfo method returns a Future. A Future is an object representing an outstanding operation that may not yet be complete. In this first simple example we simply wanted to wait for that operation to complete, so we forced it by calling the get method on it. This method waits for the Future to be complete then returns its result.

Of course, the entire reason for our using IO::Async was to perform multiple operations at the same time, and wait concurrently for them all to complete. So rather than calling get on each individual getaddrinfo future, we can combine them all together into a single future that needs them all to complete before it itself is considered completed.

my @hosts = qw( www.google.com www.facebook.com www.iana.org );

my @futures = map {
   my $host = $_;
   $resolver->getaddrinfo(
      host     => $host,
      socktype => 'stream',
   )
} @hosts;

my @results = Future->needs_all( @futures )->get;

my @addrs = map { ( getnameinfo $_->{addr}, NI_NUMERICHOST )[1] }
                @results;

print "$_\n" for @addrs;

This now yields:

2a00:1450:4009:809::1011
173.194.41.180
173.194.41.177
173.194.41.179
173.194.41.176
173.194.41.178
2a03:2880:f00a:401:face:b00c:0:1
31.13.72.65
2620:0:2d0:200::8
192.0.32.8

Oh dear. Unfortunately, the needs_all future has simply concatenated all of the individual results together, so we have lost track of which host has which addresses. To solve this, we can make each individual host future return not a list of its results, but a two-element list containing its hostname and an ARRAY ref of the IP addresses it resolved to. That way, when we fetch the results of the overall needs_all future we will have an even-sized name-value list, perfect for assigning into a hash.

To do this we can have each host future be a two-stage operation, consisting of first the getaddrinfo call, and then altering its result using a code block passed to the transform method.

my @futures = map {
   my $host = $_;
   $resolver->getaddrinfo(
      host     => $host,
      socktype => 'stream',
   )->transform(
      done => sub {
         my @results = @_;
         my @addrs = map { (getnameinfo $_->{addr}, NI_NUMERICHOST)[1] }
                         @results;
         return ( $host, \@addrs );
      }
   );
} @hosts;

my %addrs = Future->needs_all( @futures )->get;

use Data::Dump 'pp';
print STDERR pp(\%addrs);

Now we retain the mapping from hostnames to the list of IP addresses they resolved to:

{
  "www.facebook.com" => ["2a03:2880:f00a:201:face:b00c:0:1", "31.13.72.1"],
  "www.google.com"   => [
                          "2a00:1450:4009:809::1010",
                          "173.194.41.177",
                          "173.194.41.178",
                          "173.194.41.180",
                          "173.194.41.179",
                          "173.194.41.176",
                        ],
  "www.iana.org"     => ["2620:0:2d0:200::8", "192.0.32.8"],
}

Now, this post is fairly obviously written in response to Parallel DNS lookups using AnyEvent but from the perspective of IO::Async instead. Asides from the choice of event system, two important differences should be observed:

  • Through the use of futures, this example manages both the flow of control and data along with it. It does not need to declare variables that get captured by callback functions to cause data to flow separately from the way it uses an object to handle the flow of control. Each future object yields its result, and the individual futures can form linear flows by using transform or other methods to return different results, or needs_all or other methods to combine individual futures into larger ones.
  • Nowhere in the above did I mention DNS. This is intentional. IO::Async's getaddrinfo resolver really is an asynchronous wrapper around the underlying Socket function of the same name. Because of this it uses the system's standard name resolver as provided by libc, ensuring it will yield the same identical results as any other program using the system resolver, regardless of whether libc is configured to use DNS, files, LDAP, or any other resolution method. It also automatically handles IPv6 if the underlying system does; returning a mixture of IPv4 and IPv6 addresses in the host's preferred order. The caller does not need to be aware of the subtle distinctions of RFC 3484 sorting order, for example.

2013/09/30

Perl - Tickit - 0.40

Latest Tickit version (0.40) is now up on CPAN. Recent changes include:

  • Mouse drag-and-drop events (0.32)

    Windows now create more interesting events to represent mouse drag-and-drop operations. Starting, moving, and ending a mouse-drag all create events that can help widgets render more interesting behaviours.

  • Added Tickit::RenderBuffer (0.33)

    RenderBuffer is an in-memory buffer to store content that will eventually be rendered to the terminal. In effect it stores a double-buffer of content, allowing widgets to draw in whatever order is most convenient for them, before efficiently flushing it in a top-to-bottom manner.

    Being implemented in C/XS instead of Perl allows it to operate more efficiently than the previous-generation direct rendering to Windows. As it stores the content before rendering it also allows better handling of Unicode line-drawing characters; allowing for characters to be merged together out of multiple line segments, creating the ability for complex line-drawing shapes to be easily rendered.

  • Added timer support to core event loop (0.34)

    Widgets can now react to timed events, allowing for animation effects and other behaviours.

  • Focus management (0.34 and 0.35)

    Container widgets now provide management of the focus-chain order of their children, allowing the whole widget tree to maintain the "next" and "previous" direction of focusing. The base code handles the <Tab> and <Shift-Tab> key events to cycle input focus around the widget tree automatically.

  • Use RenderBuffer in favour of direct Window rendering (0.40)

    Now that RenderBuffer is in the core distribution, all widgets should be using it rather the previous render method to render directly on the window. This is a stepping-stone change to allow for further improvements.

  • New sizing model (0.40)

    New methods are provided by the base Tickit::Widget class that cache the requested size of the widget, and only inform the parent container when this size actually changes. This allows for more efficient reshaping and redrawing operations when widgets change their size requirements, without needing to recalculate the whole widget tree.

These final two changes help support a couple of interesting planned improvements:

  • Widget minimal/maximal size handling

    Because the base widget class now handles size information more directly, it can implement bounds on minimal and maximal widget size. These will be derived from Tickit::Style. It may also be possible to consider padding and margin controls in the base widget class and thus automatically apply to every widget.

  • Whole-tree rendering via RenderBuffer

    By adding area masks to RenderBuffer it should then support being used as a single buffer object to render the entire window hierarchy. Because the masking code will be implemented in C code, it will much more efficient than the current pure-perl Window-based solution involving visibility testing per character cell. This will allow for much more better redrawing performance.

    This will also allow RenderBuffer to move out of the Tickit.xs file and into libtickit itself, where it can be useful to non-Perl code (such as native C programs or other language bindings).

2013/08/30

Perl - constructors don't have to be called "new"

I've recently been writing a module to communicate with the Cassandra database server. Messages arrive from the server and are placed in objects called Frames, which have methods for extracting various protocol-sized items like integers, strings, etc.. A few helper objects exist which are structures formed by parsing messages out of Frame objects. (I won't go into detail what this all means in this post, as the details aren't important here).

Up until about half an hour before the first release, the constructors for these were just called new.

Protocol::CassandraCQL::Result->new( $frame )

But then I stopped, and had a thought. This operation isn't really creating a new result, as just extracting one from the frame. Requiring "the" constructor to be passed a Frame object also restricts the future direction of the API - perhaps one day I'll have to construct one from some direct arguments, or by parsing something else. Then I'd have to play awkward tricks like working out what types the constructor was passed.

If course, there's nothing special about the word new to Perl. The constructor could be called whatever we want, and it's only convention that we call them new. If I just call it something more sensible, then it easily leaves the way open to other constructors to be added another time. Plus it actually reads better, I think.

Protocol::CassandraCQL::Result->from_frame( $frame )

2013/07/23

Double-width and double-height in libvterm and pangoterm

I've been keeping a list of terminal sequences unrecognised by libvterm and pangoterm. For a while I've kept the DEC double-width line and double-height line sequences in there, because I wasn't sure how they would interact with the arbitrary scrolling rectangles defined by VT4xx. The VT400 manual doesn't really mention how to handle this, but by chance I happened to be reading a VT500 manual instead, which does. It explains that the double-width or -height sequences aren't recognised in SLRM (Set Left/Right Mode; newly renamed from the identical but differently-named Vertical Split-Screen Mode in VT400); and that enabling SLRM will revert all lines back to single-width, single-height.

This neatly handles the problem that would otherwise occur, in that these line modes apply to entire lines. If a partial scrolling operation were to affect such a line, what would happen to the double-width characters in it? By linking it with SLRM this is avoided - either the terminal is in a mode where double-width can happen, or it's an a mode where partial lines can be scrolled - but never both.

With this neatly resolved, I finally got around to implementing DECDHL and DECDWL in libvterm and pangoterm. Here's a screenshot showing the ever-useful vttest.

With this out of the way, the list of unsupported VT1xx features is rapidly diminishing. About all that's left asides real-hardware things like interlace mode (which will be impossible to do), is 80/132 column mode. That's another one I'm still not sure how to implement...

2013/05/07

Tickit version 0.31

(mostly a copy of the mail to the tickit-dev mailing list)

A lot of stuff happening lately. And also I haven't written one of these for ages. I won't go into every detail, but here's a rundown of the most interesting parts:

  • Rect/RectSet are now C library based (0.26)

    Fairly simple, no surprises here. C implementation means it's available in C and other languages, and probably a bit faster in actual use.

  • New Term event binding API (0.26)

    Rather than a single on_key/on_mouse/etc..., there is now just a list of possible event handlers. Event handling subs don't have to be restricted to a single event; each is registered with a bitmask. This is done to more closely match the C API.

    The existing Perl API of having a single on_* handler for each event type is still supported, by wrapping the newer API.

  • All windows are now FLOAT windows (0.28)

    As was first suggested in 0.23, all the windows now use the new float logic. The previous environment variable has now been removed. This hopefully shouldn't actually affect anything as it's been the default for a while now, but does simplify the code internals.

  • $win->close and no more weak references (0.28)

    Using weak references and relying on DESTROY works OK in some circumstances in Perl, but won't scale to C and other languages, and still makes for tricky logic. To this end, I've removed all the weaken()ing and replaced it with an explicit ->close method to remove a window. This also makes it much more robust in nontrivial cases.

    This change is mostly of interest to container widget developers, or in more dynamic long-lived programs.

  • Tickit::Style (0.29)

    This one's the big main one of the list; in fact so bit I'll probably write another mail. In summary; we now have something of a first attempt at being able to separate out style from widget implementations, in a way that's easy to add to application- or user-specific style files. More on this later.

  • Tickit::Pen now comes in mutable and immutable forms (0.30)

    Since most pens don't get mutated, and Tickit::Style performs better with cached pens, I've split the idea of a Pen into mutable and immutable types. Tickit::Style returns immutable pens, so widgets shouldn't attempt to mutate them.

    Tickit::Pen->new itself still returns a mutable pen for now, but in the future this may change; code that specifically wants a mutable or immutable pen should use the appropriate subclass.

  • Tickit::Pen changes to support upcoming Tickit::RenderContext (0.31)

    A few small changes that allow the new Tickit::RenderContext to work better.

Also some changes in the underlying libtickit C library:

  • Generic string/integer value termctl operations

    Primarily provided to let the xterm driver set the window title, etc..., but the general idea is something similar to ioctl(), so we don't have to extend the API a thousand times just to add lots of little options for specific terminals.

  • Split xterm/TI-based driver model

    To support more specific options in future, and also to give a better (or more accurate) terminfo-based driver. There are now two drivers, selected by the $TERM environment variable, so the xterm-specific things can be done nicely, and still arrange for the generic terminfo driver to work.

    This also allows for other terminal-specific drivers in future, in case we find those useful. Perhaps a Win32 console one too.