Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

Conrad Taylor


Thoughts, stories and ideas.

Playing with Maglev the Ruby VM

History

Maglev is a Ruby language implementation built on top of the Gemstone/S system. This system was created by Gemstone Systems, Inc. which have been recently acquired by VMWare, Inc. The notion to have a Smalltalk VM power the Ruby language was first presented by Avi Bryant at Railsconf 2007 and the initial proof of concept of Maglev was also demonstrated by him a year later at Railsconf 2008.

Gemstone/S: A Brief Tour

Gemstone/S is both a Smalltalk environment as well as a Object Oriented Database Management System (OODBMS). It’s unlike many of the NoSQL/SQL solutions like Redis, MongoDB, and MySQL because it can persist these Ruby objects as Ruby objects without mapping them to a different representation for the target datastore. Furthermore, Gemstone/S is a highly scalable data storage solution with the following features and functionality:

  • highly optimized garbage collector (GC)
  • virtual machine to transform source code into machine code for JIT execution
  • full ACID transactional persistence with thousands of transactions per second
  • multi-user support with thousands of concurrent user sessions
  • multi-machine support where VMs can be distributed across many machines
  • distributed shared cache for efficiently moving objects from disk to memory
  • seperate or shared namespaces per user
  • concurrency controls and locks for coordination
  • per object read and write access by user as well group object database index support
  • transaction logs for easy backup and recovery Installation and Startup

Let's Code!!!

So, I bet you’re excited about using Maglev. Maglev is supported on both Linux and Mac OS X operating systems and Windows users will need to migrate to a supported Unix based platform. Now, let’s get started:

If you have never installed Ruby Version Manager (RVM), then do the following and follow the on screen instructions that appear during the installation:

$ bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)

Otherwise, do the following:

$ rvm get head
$ rvm reload

Let’s install the most recent version of Maglev:

$ rvm install maglev-head

After the installation has been completed, we will need to start the maglev server by doing the following:

$ maglev start

The maglev-irb and maglev-ruby Commands

Now, let’s hop into the interactive Maglev console and write our first bit of code:

$ maglev-irb
maglev-head :001 > Maglev::PERSISTENT_ROOT[:stuff] = ["hello world"]  
 => ["hello world"] 
maglev-head :002 > Maglev.commit_transaction  
 => true 
maglev-head :003 > Maglev::PERSISTENT_ROOT[:stuff]  
 => ["hello world"] 
maglev-head :004 > quit  
$ maglev-irb
maglev-head :001 > Maglev::PERSISTENT_ROOT[:stuff]  
 => ["hello world"]

So, what did we just do?

entered the command to start the Maglev interactive console on line (1)
stored an array containing the string, “hello world”, and associated it to the symbol called stuff on line (2)
committed our changes to the repository on line (4)
retrieved the value of our stuff symbol from the repository on line (6)
verified that our value has been stored in the repository on lines (8), (9), and (10)
If you wanted to accomplish the same functionality within a text file called hello-world.rb, one would enter the text that follows into the file and execute the file using maglev-ruby:

hello-world.rb:

Maglev::PERSISTENT_ROOT[:stuff] = ["hello world"]  
Maglev.commit_transaction  
Maglev::PERSISTENT_ROOT[:stuff]  

terminal:

$ maglev-ruby hello-world.rb

In the above, Maglev::PERSISTENT_ROOT Hash is the persistent root for objects within Maglev. Thus, in order to access a persistent object within the Maglev system, it needs to be reachable from this persistent root.

Simple Example

A cool example of Maglev would be to create a module that can be included in our user defined class(es) for enabling this persistent goodness. For example, let’s create module which describes some simple persistence for concrete models:

maglev_model.rb:

module MaglevModel

  module ClassMethods

    def all
      # set the values including its state to current for all persistent objects.
      # i.e. give me the current state of the last commit.
      Maglev.abort_transaction

      # retrieve all the Post instances as a collection hash.
      Maglev::PERSISTENT_ROOT[self].values
    end

  end

  def save
    # store the current Post instance as a child of the Post class.
    Maglev::PERSISTENT_ROOT[self.class][self.__id__] = self

    # save the current state back to the repository.
    Maglev.commit_transaction
  end

  def self.included( klass )

    klass.extend ClassMethods

    # create a space in the PERSISTENT_ROOT to hold persistent klass objects.
    Maglev::PERSISTENT_ROOT[ klass ] ||= Hash.new

  end

end  

Now, let’s create the Post model and this will be a snap because we have done most of the work by creating a reusable module, MaglevModel, for enabling persistence within the Post class:

post.rb:

require 'maglev_model'

class Post

  include MaglevModel

  attr_reader :title, :description

  def initialize( params = {} )
    @title       = params[:title]
    @description = params[:description]
  end

  def to_s
    "title => #{@title}\ndescription => #{@description}\n"
  end

end  

Persist both maglev_model.rb and post.rb to the repository:

$ maglev-ruby -Mcommit maglev_model.rb
$ maglev-ruby -Mcommit post.rb

What? Did I hear you right? Yes, Maglev gives you the ability to persist code as well as Ruby objects to the Maglev object repository making it automatically available to every Maglev VM on start that’s apart of your deployment and connects to your shared Maglev object repository. Furthermore, the Ruby Standard Library is fully defined and loaded into the Maglev object repository so that you can concentrate on building your applications in Ruby. Let’s define a simple driver program which creates some Post instances:

driver.rb:

require 'post'

post_one = Post.new( :title => "This is post 1", :description => "This is post 1 description." )  
post_one.save

post_two = Post.new( :title => "This is post 2", :description => "This is post 2 description." )  
post_two.save

Post.all.each { |post| puts post }  

Now, if we were to run the above code, one should see the following:

$ maglev-ruby driver.rb

title => "This is post 1  
description => "This is post 1 description.  
title => "This is post 2  
description => "This is post 2 description.  

Fire up the maglev-irb and you should see the same output as the above:

$ maglev-irb
maglev-head :001 > Post.all.each { |post| puts post }  
title => "This is post 1  
description => "This is post 1 description.  
title => "This is post 2  
description => "This is post 2 description.  

Now, you should have noticed in the above that there was no database schema, SQL, or other things that one would normally see in regards to setting up a relational database. The only thing that I needed to do was define MaglevModel module and Post class. Then persist this to the Maglev object repository. That’s all to it. BTW, MaglevModel module is a user created module and one can customize and name as necessary for your project. You can read more about Maglev as well as its persistence API here. Lastly, if you’re a Rubyist or Ruby shop that’s struggling with the impedance mismatch with Ruby and relational databases or the c10K problem, then I would highly recommend taking a look at Maglev.

Think different and code well,

-Conrad


About the author

Conrad Taylor


Discussions

comments powered by Disqus