DataMapper on Infinispan

62
DataMapper on Infinispan Clustered NoSQL Lance Ball 1 Thursday, September 22, 11

Transcript of DataMapper on Infinispan

Page 1: DataMapper on Infinispan

DataMapper on InfinispanClustered NoSQL

Lance Ball

1Thursday, September 22, 11

Page 2: DataMapper on Infinispan

Lance Ball

•Red Hat senior engineer•TorqueBox core developer•Perl -> C++ -> Java -> Ruby•@lanceball

2Thursday, September 22, 11

Page 3: DataMapper on Infinispan

project:odd

3Thursday, September 22, 11

Page 4: DataMapper on Infinispan

What are we talking about?

•DataMapper - Ruby ORM

• Infinispan - Java+Scala distributed cache•Hibernate Search - Java ORM

• Lucene - Indexing and search

• JBoss AS7 - JEE application server

• TorqueBox - JRuby application server

4Thursday, September 22, 11

Page 5: DataMapper on Infinispan

TorqueBox

JRuby Application Serverhttp://torquebox.org

5Thursday, September 22, 11

Page 6: DataMapper on Infinispan

TorqueBox

The Power of JBoss

with the

Expressiveness of Ruby

6Thursday, September 22, 11

Page 7: DataMapper on Infinispan

7Thursday, September 22, 11

Page 8: DataMapper on Infinispan

TorqueBox•Ruby, baby!•Rack apps•Scheduled Jobs•Background Tasks•Message Queues & Topics•Message Processors•Long-running Services•Distributed / Replicated Cache

8Thursday, September 22, 11

Page 9: DataMapper on Infinispan

JRuby

•Healthy community •Real threads•Java libraries•Java tools•Fast runtime•Better memory management**

** for long running things like servers

9Thursday, September 22, 11

Page 10: DataMapper on Infinispan

CacheFactory.java

Java

public class CacheFactory {

  public CacheFactory() {    config = new Configuration();    store = new FileCacheStoreConfig();    store.purgeOnStartup( false );    config.fluent().loaders().addCacheLoader( store );    manager = new DefaultCacheManager( config.build() );  }

  public Cache getCache() { return manager.getCache(); }}

10Thursday, September 22, 11

Page 11: DataMapper on Infinispan

cache_factory.rb

JRuby

class CacheFactory  def initialize    @config = Configuration.new    @store = FileCacheStore.new    @store.purge_on_startup false    @config.fluent.loaders.add_cache_loader( @store )    @manager = DefaultCacheManager.new( @config.build )  end

  def get_cache ; @manager.get_cache endend

11Thursday, September 22, 11

Page 12: DataMapper on Infinispan

Infinispan

An extremely scalable, highly available data grid

http://www.jboss.org/infinispan

12Thursday, September 22, 11

Page 13: DataMapper on Infinispan

Infinispan

•Key / Value store•Highly concurrent core•Data Grid•Replicated•Distributed•Local

13Thursday, September 22, 11

Page 14: DataMapper on Infinispan

Hotrod

•Binary TCP protocol•Clients•Java•Python•Ruby•...

14Thursday, September 22, 11

Page 15: DataMapper on Infinispan

NoSQL?

•Non-relational•Scales out, not up•Big data•Low ceremony

15Thursday, September 22, 11

Page 16: DataMapper on Infinispan

Cache.java

Infinispan API

   cache.put(key, value, lifespan, timeUnit);

   cache.putIfAbsent(key, value, lifespan, timeUnit);

   cache.replace(key, oldVal, value, lifespan, timeUnit);

   cache.putAsync(key, value, lifespan, timeUnit);

   cache.keySet();

   cache.values();

   cache.entrySet();

16Thursday, September 22, 11

Page 17: DataMapper on Infinispan

Example.java

Hibernate Search

import org.hibernate.search.annotations.*;

@Indexed @ProvidedIdpublic class Book { @Field String title; @Field String description; @Field Date publicationYear;}

17Thursday, September 22, 11

Page 18: DataMapper on Infinispan

Search.java

Indexing: Lucene

org.apache.lucene.search.Query luceneQuery = queryBuilder.phrase() .onField( "description" ) .andField( "title" ) .sentence( "pat the bunny" ) .createQuery();

CacheQuery query = searchManager.getQuery( luceneQuery, Book.class );

18Thursday, September 22, 11

Page 19: DataMapper on Infinispan

DataMapper

•Object Relational Mapper•Alternative to ActiveRecord•Written in Ruby•http://datamapper.org

19Thursday, September 22, 11

Page 20: DataMapper on Infinispan

beer.rb

Resources

class Beer  include DataMapper::Resource  property :id, Serial  property :name, String  property :rating, Integer  property :notes, Text  belongs_to :userend

20Thursday, September 22, 11

Page 21: DataMapper on Infinispan

sample.rb

DataMapper Queries

Beer.all

Beer.get(1)

Beer.first( :name => 'Pisgah Pale' )

Beer.last( :name.like => 'IPA' )

Beer.all( :notes.like => 'hoppy' )

21Thursday, September 22, 11

Page 22: DataMapper on Infinispan

sample_adapter.rb

DataMapper Adapter SPI

module DataMapper::Adapters

  class SampleAdapter < AbstractAdapter    def initialize( name, options ) ; end    def create( resources ) ; end    def read( query ) ; end    def update( attributes, collection ) ; end    def delete( collection ) ; end  end

end

22Thursday, September 22, 11

Page 23: DataMapper on Infinispan

some_adapter.rb

DataMapper Filtering

    def read( query ) records = @search_manager.search( query )      query.filter_records( records )    end

23Thursday, September 22, 11

Page 24: DataMapper on Infinispan

adapter_spec.rb

Testing

require 'dm-core/spec/shared/adapter_spec'describe DataMapper::Adapters::InfinispanAdapter do

  before :all do    @adapter = DataMapper.setup(:default, :adapter => 'infinispan')  end

  it_should_behave_like 'An Adapter'

  describe "other important things to test" do # Your tests here  endend

24Thursday, September 22, 11

Page 25: DataMapper on Infinispan

torquebox-cache

•TorqueBox 2.0 gem

•dm-infinispan-adapter•TorqueBox::Infinispan::Cache •ActiveSupport::Cache::TorqueBoxStore

25Thursday, September 22, 11

Page 26: DataMapper on Infinispan

dm-infinispan-adapter

Use Infinispan as your object data store

26Thursday, September 22, 11

Page 27: DataMapper on Infinispan

dm-infinispan-adapterrequire 'dm-core'require 'dm-infinispan-adapter'

class Beer  include DataMapper::Resource  property :id, Serial  property :name, String  property :rating, Integer  property :notes, Text  belongs_to :userend

DataMapper.setup(:default, :adapter=>'infinispan', :persist=>true)

27Thursday, September 22, 11

Page 28: DataMapper on Infinispan

But How?

28Thursday, September 22, 11

Page 29: DataMapper on Infinispan

Hibernate Search

Annotated Java classes

29Thursday, September 22, 11

Page 30: DataMapper on Infinispan

Runtime Class Creation

How do we make Ruby’s Beer.class look like an annotated Java class at runtime?

30Thursday, September 22, 11

Page 31: DataMapper on Infinispan

dm-infinispan-adapter.rb

Metaprogramming!

require 'datamapper/model'

module DataMapper::Adapters

  class InfinispanAdapter < AbstractAdapter

    DataMapper::Model.append_inclusions( Infinispan::Model )

  endend

31Thursday, September 22, 11

Page 32: DataMapper on Infinispan

datamapper/model.rb

Metaprogramming!

module Infinispan  module Model

    def self.included(model)      model.extend(ClassMethods) model.before_class_method(:finalize, :configure_index)    end

endend

32Thursday, September 22, 11

Page 33: DataMapper on Infinispan

datamapper/model.rb

Annotations

require ‘jruby/core_ext’

annotation = {org.hibernate.search.annotations.Field => {}} add_method_annotation( “getName”, annotation )

33Thursday, September 22, 11

Page 34: DataMapper on Infinispan

datamapper/model.rb

Annotations

require ‘jruby/core_ext’

annotation = {  org.hibernate.search.annotations.Indexed => {},  org.hibernate.search.annotations.ProvidedId => {},  org.infinispan.marshall.SerializeWith => {"value" => org.torquebox.cache.marshalling.JsonExternalizer.java_class }}

add_class_annotation( annotation )

34Thursday, September 22, 11

Page 35: DataMapper on Infinispan

Become Java!

java_class = become_java!

35Thursday, September 22, 11

Page 36: DataMapper on Infinispan

JSON Externalizer

Forget

java.io.Serializable

36Thursday, September 22, 11

Page 37: DataMapper on Infinispan

JsonExternalizer.java

JSON Externalizer

public class JsonExternalizer implements Externalizer<IRubyObject> {

" @Override" public void writeObject(ObjectOutput output, IRubyObject object)" " " throws IOException {" " String theType = object.getType().getName();" " output.writeObject( theType );" " output.writeObject( toJSON(object) );" } }

37Thursday, September 22, 11

Page 38: DataMapper on Infinispan

JsonExternalizer.java

JSON Externalizer

public class JsonExternalizer implements Externalizer<IRubyObject> {

" @Override" public IRubyObject readObject(ObjectInput input) throws IOException, ClassNotFoundException {" " String theType = (String) input.readObject();" " String theJson = (String) input.readObject();" " return fromJSON(theJson, theType);"" } }

38Thursday, September 22, 11

Page 39: DataMapper on Infinispan

JsonExternalizer.java

JSON Externalizer

public class JsonExternalizer implements Externalizer<IRubyObject> {

    protected IRubyObject fromJSON(String json, String type) throws ClassNotFoundException {

        RubyModule objectClass = runtime.getClassFromPath( type );        return (IRubyObject) JavaEmbedUtils.invokeMethod( runtime, objectClass, "new", new Object[] { jsonHash }, IRubyObject.class);     } }

39Thursday, September 22, 11

Page 40: DataMapper on Infinispan

JsonExternalizer.java

JSON Externalizer

public class JsonExternalizer implements Externalizer<IRubyObject> {

    protected String toJSON(IRubyObject object) {        return (String) JavaEmbedUtils.invokeMethod( getCurrentRuntime(), object, "to_json", EMPTY_OBJECT_ARRAY, String.class );    } }

40Thursday, September 22, 11

Page 41: DataMapper on Infinispan

dm-core/property/serial.rb

Sequences

DataMapper::Property::Serial

41Thursday, September 22, 11

Page 42: DataMapper on Infinispan

dm-core/adapters/abstract_adapter.rb

Sequences

initialize_serial( resource, next_id )

42Thursday, September 22, 11

Page 43: DataMapper on Infinispan

cache.rb

Sequences

module TorqueBox  module Infinispan

    class Cache      def increment( sequence_name, amount = 1 ) # increment an integer      end      def decrement(name, amount = 1) # decrement an integer      end    end

  endend

43Thursday, September 22, 11

Page 44: DataMapper on Infinispan

dm-infinispan-adapter.rb

Sequences

@metadata = Cache.new( options )

initialize_serial( resource, @metadata.increment( “metadata/beers/index” ) )

44Thursday, September 22, 11

Page 45: DataMapper on Infinispan

cache_spec.rb

Transactions

  describe "with JTA transactions" do

    it "should behave like a transaction" do      @cache.transaction do |cache|        cache.put('Tommy', 'Dorsey')        raise "yikes!"        cache.put('Elvis', 'Presley')      end      @cache.get('Tommy').should be_nil      @cache.get('Elvis').should be_nil    end   end

45Thursday, September 22, 11

Page 46: DataMapper on Infinispan

dm-infinispan-adapter.rb

Transactions

    def delete( collection )      cache.transaction do        collection.each do |resource|          cache.remove( key(resource) )        end      end    end

46Thursday, September 22, 11

Page 47: DataMapper on Infinispan

TorqueBox::Infinispan::Cache

Use Infinispan for...

47Thursday, September 22, 11

Page 48: DataMapper on Infinispan

some_file.rb

Cache

include TorqueBox::Infinispan::Cache

cache = Cache.new(:name => 'MyCache', :mode => :replicated)

cache.put(key, value)cache.get(key)

48Thursday, September 22, 11

Page 49: DataMapper on Infinispan

ActiveSupport::Cache::TorqueBoxStore

Caching in Rails.

Replaces in-memory or memcached caches.

49Thursday, September 22, 11

Page 50: DataMapper on Infinispan

config/application.rb

TorqueBoxStore

module YourApp

  class Application < Rails::Application    config.cache_store = :torque_box_store end

end

50Thursday, September 22, 11

Page 51: DataMapper on Infinispan

my_app.rb

TorqueBoxStore

require 'sinatra'require 'torquebox'

class MyApp < Sinatra::Base

  use TorqueBox::Session::ServletStore

  get '/' do    session[:message] = 'Hello World!'    haml :index  end

end

51Thursday, September 22, 11

Page 52: DataMapper on Infinispan

Beer Catalogue!

http://www.flickr.com/photos/burnblue/308441464/

52Thursday, September 22, 11

Page 53: DataMapper on Infinispan

beer.rb

Model

require 'dm-core'require 'dm-infinispan-adapter'

class Beer  include DataMapper::Resource  property :id, Serial  property :name, String  property :rating, Integer  property :notes, Text  belongs_to :userend

DataMapper.setup(:default, :adapter=>'infinispan', :persist=>true)

53Thursday, September 22, 11

Page 54: DataMapper on Infinispan

application.rb

Sinatra

module BeerCatalogue  class Application < Sinatra::Base    get '/' do      @beers = Beer.all( :user_id => current_user.id )      haml :index    end

    post '/beer' do      Beer.create( :name=>params[:name], :notes=>params[:notes], :rating=>params[:rating], :user=>current_user)      redirect '/'    end  endend

54Thursday, September 22, 11

Page 55: DataMapper on Infinispan

views/index.haml

View

#welcome  Hello  =current_user.name

#body  #beer-list    %h2 Your Beers    - if @beers.empty?      %strong You haven't rated any beers yet. Do that now!    %ul      - @beers.each do |beer|        %li          =beer.name          =beer.rating =beer.notes

55Thursday, September 22, 11

Page 56: DataMapper on Infinispan

Source

http://github.com/torquebox/torqueboxhttp://github.com/torquebox/presentations

56Thursday, September 22, 11

Page 57: DataMapper on Infinispan

Installation$ gem install torquebox-server --pre \ --source http://torquebox.org/2x/builds/LATEST/gem-repo/

$ gem install bundler

$ bundle install

$ torquebox deploy .Deployed: beer.yml into: /path/to/jboss/standalone/deployments

$ torquebox run

57Thursday, September 22, 11

Page 58: DataMapper on Infinispan

http://www.flickr.com/photos/crystalflickr/2317183342/

58Thursday, September 22, 11

Page 59: DataMapper on Infinispan

TorqueBox 2.x

•Under development

•Continuous integration•TorqueBox::Infinispan::Cache•ActiveSupport::Cache::TorqueBoxStore•dm-infinispan-adapter

59Thursday, September 22, 11

Page 60: DataMapper on Infinispan

TorqueBox 1.x

•Version 1.1.1 released in August

•Continuous integration•ActiveSupport::Cache::TorqueBoxStore

60Thursday, September 22, 11

Page 61: DataMapper on Infinispan

Resources

•http://torquebox.org/•http://github.com/torquebox•#torquebox on FreeNode•@torquebox

61Thursday, September 22, 11

Page 62: DataMapper on Infinispan

Questions

http://www.flickr.com/photos/eleaf/2536358399/

62Thursday, September 22, 11