Event Driven Architecture

It’s been a year since the previous post and coincidently yet again references SAPO Codebits.The 2010 edition was epic – retro computing, multiple tracks, 50+ presentations, activities and meticulous organization.

I presented Event Driven Architecture, covering some theory, Command and Query Segregation Responsibility (CQRS) and general do’s and dont’s.Also checkout a reference implementation in Ruby (don’t forget to note the caveats in the README which references several shortcomings of CQRS and Event Sourcing with this untyped language).

Dynamic Language VMs – Inside Ruby

I had the opportunity to present at SAPO Codebits this weekend, covering Ruby and scripting VMs in general.

See the session abstract for further details before digging into the slides below.

I’d also like to take a moment and state what a great experience the different tracks, venue, organization, catering, Internet access and entertainment bits was.Well on par, if not beyond, the vast majority of international conferences out there.

At no cost (free, grátis, gratis, gratuit) to attendees.

Bean bags, hammocks, work spaces, huge ass presentation areas, dedicated sound / camera crews, quizzes, projects, soldering workstations and a constant pizza and red bull supply.

A great reflection of the innovation at work inside SAPO and a peek into emerging technologies being rolled out.

I’ll dedicate a few blog posts to cover some Ruby VM sections in detail during the next few weeks if there’s sufficient demand – please leave a comment if that appeals to you.

Native MRI Callback

A few weeks ago after a discussion with raggi (yet again) about callback implementations for the Ruby language, we kicked off an attempt at a minimal native object that’s very close in performance to method dispatch.

Here’s a representation of the pure ruby version :

The game plan

The following inefficiencies would have to be addressed :

  • Instance variables Instance variable lookups in general require some symbol table overhead.
  • Block procedure arguments Block proc arguments are up to 6x slower than passing explicit objects.
  • Method dispatch The splat operator and __send__, although efficient, does have some noticeable overheads.
  • Kernel convenience method
  • Additional method dispatch in the critical path through this global function.

Ivar lookup overhead is mostly negated for Ruby 1.9 as the RObject struct stores the first three ivars for each object.

Implementation

The callback structure

We introduce a new callback struct with 2 members :

  • object Ruby object to invoke the callback on
  • method Method to call.Defaults to #call if no method argument given

Wrapping the C struct as T_DATA has the least overheads in accessing either the object and the method when our callback fires.

GC integration’s a piece of cake as well.

Allocation

Wrapping C structures requires an allocator function (Callback.allocate) to initialize our callback struct and register our mark and free functions with the GC.This is usually invoked prior to #initialize and is transparent for our use cases.

Definition

Three definition (setup) styles supported :

  • Object and method arguments
  • Block argument
  • Farmed off an existing object

We handle each of the argument or block definition styles in an initialize method and handle edge cases such as not assigning a callback method that’s not defined for the object.It’s also important to ensure that our callback is frozen at this point ( I’m looking at you lifo, this one’s legit :-) ) for consistency.

Our global function, Callback(), which is defined much like the popular Array() and Float() coercion helpers, and the farm out API reuse the alloc and init covered above.

Results

An intuitive callback API that’s slower than method dispatch, but faster than lambda callbacks.

Have a look at the source or install the gem to play around.

sudo gem install methodmissing-callback

Tested on MRI versions > 1.8.6 and 1.9.2 – please have a look through the test suite for further examples.

Follow me @ github or twitter if you enjoyed this article.Thanks for reading and special thanks to Aman Gupta for review !

Alternative HashWithIndifferentAccess

After having revisited ActiveSupport a few weeks ago to investigate Hash#reverse_merge!, I noticed ActiveSupport::HashWithIndifferentAccess.Excessive object allocation and branching in the critical path scratched an itch and spawned hwia.

Ruby hashes and the symbol table

MRI ships with a generic hash table for storage of variables, methods, class inheritance chains and the like.Please head off to an excellent overview on this subject by Jake Douglas and please do come back.

Hashes is tightly coupled with the symbol table implementation and as such requires a comparison (2 values as arguments) function

as well as a hashing function for each value (single argument)

A new object hash structure wraps the hash callback functions and is assigned as the hash type to the symbol table that represent the hash object.

Hashing symbols and strings

Symbols and strings are somewhat interchangeable at a lower level and conversion between either is relatively snappy.We extract a strhash function ( leeched from st.c ) and define


String#strhash
Symbol#strhash # thanks raggi!
'key'.strhash == :key.strhash #=> true

We also now need to define new hash and comparison functions to take advantage of this feature.Apologies for the fugly 1.8 / 1.9 conditionals.

and let the symbol table that powers our string like hash call them

Conversion and coercion

Special case handling for certain value assignments is required for the most prolific use case, that of representing request parameters, in a possibly nested fashion.

  • Hash converts to StrHash
  • Array converts Hash elements to StrHash

Installation


sudo gem install methodmissing-hwia
'require "hwia_rails"' # from within an initializer

This extension is compatible with MRI > 1.8.6 && 1.9.2 and Rails > 2.3.x

Examples

The Rails compatibility layer …


methodmissing:~ lourens$ irb
>> require 'rubygems'
=> true
>> require 'hwia_rails'
LoadError: Rails environment required!
from /opt/local/lib/ruby/gems/1.8/gems/hwia-1.0.0/lib/hwia_rails.rb:2
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'
from (irb):2
>> require 'activesupport'
=> true
>> require 'hwia_rails'
=> []
>> HashWithIndifferentAccess
=> StrHash

… basic usage


methodmissing:~ lourens$ irb
>> require 'rubygems'
=> true
>> require 'hwia'
=> true
>> h = StrHash[:a => 1, 'b' => 2]
=> {:a=>1, "b"=>2}
>> h[:a]
=> 1
>> h['a']
=> 1
>> h[:b]
=> 2
>> h.class
=> StrHash
>> h = { 'a' => 1, 'b' => 2 }
=> {"a"=>1, "b"=>2}
>> h = h.strhash
=> {"a"=>1, "b"=>2}
>> h[:a]
=> 1
>> h[:b]
=> 2

This implementation is compatible with the current (30/08/2009) Rails master branch’s test suite.Please refer to the test cases of either project for further examples.

Performance

Benchmarks available from the README.

You’d notice very little, if any, performance improvements using this extension in the request / response cycle for the vast majority of apps.HashWithIndifferentAccess is limited to query params and ActiveRecord nested attributes assignment.

Consider this a step towards an extraction of a query param object, reusable across many different frameworks and projects.

Follow me @ github or twitter if you enjoyed this article.Thanks for reading!