[Nitro] Multiple databases?

Aleksi Niemela Aleksi.Niemela at cs.helsinki.fi
Mon Jun 20 15:49:13 EDT 2005


Sorry, this mail is perhaps longer than it should.

Timothy Brown wrote:

>Hi:
>
>I'd like to create multiple databases with Nitro - e.g., I want some
>objects to reside in one database, others to reside in a separate
>database, and have both of them accessible by the same application.
>
>
This code should work in theory. There're no design barriers I'm aware 
of against this. You have to be careful not to let Og find automatically 
which classes to manage. Or it will get [A,B] for both DB managers and 
creates tables for both but objects will be created only for the manager 
instantiated first. The current version of Og::setup doesn't allow 
pointing out which classes to manage, so here's a bit modified version.

George, I guess you should change Og code to something like this method 
setup.

    require 'rubygems'
    require_gem 'postgres-pr'
    require_gem 'og'

    $DBG = true

    class A
      property :name, String  
      def initialize(name)
        @name = name
      end
    end

    class B
      property :name, String
      def initialize(name)
        @name = name
      end
    end

    def setup(options = {}, managed_classes = [])
      m = @@manager = Og::Manager.new(options)
      m.manage_classes managed_classes
      return m
    end

    config1 = {
      :address => "localhost",
      :destroy => true,
      :name => "testing",
      :store => "psql",
      :user => "tester1",
      :password => "tester1password",
      :connection_count => 1
    }

    config2 = {
      :address => "localhost",
      :destroy => true,
      :name => "testing2",             # note different database
      :store => "psql",
      :user => "tester2",              # and user
      :password => "tester2password",
      :connection_count => 1
    }


    db1 = setup(config1, [A])
    db2 = setup(config2, [B])

    a_objects = (0..2).map {|i| A.create "foo #{i}" }
    puts "creating B"
    b = B.create "bar"

    puts "finding"

    p A.all.to_ary
    p B.all.to_ary


But in practise that code doesn't work. I get this error message. I 
guess George needs to look into this as at least I wasn't able to 
decipher the origin of the problem.

/usr/lib/ruby/gems/1.8/gems/postgres-pr-0.4.0/lib/postgres-pr/connection.rb:115:in 
`query': ERROR       C42P01  Mrelatio
n "ogb_oid_seq" does not exist  Fnamespace.c    L201    
RRangeVarGetRelid (RuntimeError)
        from 
/usr/lib/ruby/gems/1.8/gems/postgres-pr-0.4.0/lib/postgres-pr/postgres-compat.rb:33:in 
`exec'
        from (eval):4:in `og_insert'
        from 
/usr/lib/ruby/gems/1.8/gems/og-0.18.1/lib/og/store.rb:119:in `save'
        from 
/usr/lib/ruby/gems/1.8/gems/og-0.18.1/lib/og/entity.rb:58:in `create'
        from test_multiple_databases.rb:53

To be more precise, my guess is that after this bug has been fixed you 
can say.

    db1 = Og::setup(config, [A,B])   # and create tables for both
    db2 = Og::setup(config2, [A,B])  # classes for both databases

    a = A.create        # goes to db2 as A.ogmanager is pointing to db2
    A.ogmanager = db1
    a2 = A.create       # now goes to db1

and maybe there's no need to change any code and it will work right away 
to set manager per object basis

    a3 = A.new          # not created, so not saved yet
    def a3.ogmanager    # while normal A objects would go
      db2               # to current manager, that is db1, this object
    end                
                            
    a3.name = "foo"   
    a3.save             # goes to db2



But I'm diverting from bug hunting. I can't say what is really the 
problem as strategically placed "pp ogmanager" at entity.rb 
ClassMethod::create does show both classes have their own manager with 
their own connections (as you can verify from this output, sorry it's 
longish). But there are couple of odd things here:

1) with first run there really was no ogb_oid_seq in testing2 database, 
but after I dropped it and rerun I got it there, so it really exists, 
and testing database is all ok, all of sequence, table and data in it.

2) as the following output shows, first A.create has correct 
connections, but in second call the pool is empty (but the creation 
still succeeds). This leads me to wonder if Glue::Pool is still one to 
blame, but I can't put my finger on the bug there should it have one.

    - Aleksi


$ ruby test_multiple_databases.rb
DEBUG: Table already exists
DEBUG: Table already exists
#<Og::Manager:0x102eb9f8
 @entities=
  {A=>
    #<Og::Manager::EntityInfo:0x1047b7c0
     @enchanted=false,
     @klass=A,
     @options={}>},
 @options=
  {:address=>"localhost",
   :destroy=>true,
   :user=>"tester1",
   :password=>"tester1password",
   :connection_count=>1,
   :store=>"psql",
   :name=>"testing"},
 @pool=
  [#<Og::PsqlStore:0x1047e568
    @conn=
     #<PGconn:0x1047e2b0
      @conn=
       #<PostgresPR::Connection:0x1047e148
        @conn=#<TCPSocket:0x1047df68>,
        @params=
         {"integer_datetimes"=>"off",
          "TimeZone"=>"Europe/Helsinki",
          "server_encoding"=>"LATIN1",
          "DateStyle"=>"ISO, MDY",
          "client_encoding"=>"LATIN1",
          "session_authorization"=>"tester1",
          "server_version"=>"8.0.1",
          "is_superuser"=>"off"}>,
      @db="testing",
      @host="localhost",
      @user="tester1">,
    @options=
     {:address=>"localhost",
      :destroy=>true,
      :user=>"tester1",
      :password=>"tester1password",
      :connection_count=>1,
      :store=>"psql",
      :name=>"testing"},
    @transaction_nesting=0,
    @typemap=
     {TrueClass=>"boolean",
      Time=>"timestamp",
      Array=>"text",
      Float=>"float",
      Integer=>"integer",
      Date=>"date",
      Fixnum=>"integer",
      Hash=>"text",
      String=>"text",
      Object=>"text"}>]>
#<Og::Manager:0x102eb9f8
 @entities=
  {A=>
    #<Og::Manager::EntityInfo:0x1047b7c0
     @enchanted=false,
     @klass=A,
     @options={}>},
 @options=
  {:address=>"localhost",
   :destroy=>true,
   :user=>"tester1",
   :password=>"tester1password",
   :connection_count=>1,
   :store=>"psql",
   :name=>"testing"},
 @pool=[]>
#<Og::Manager:0x102eb9f8
 @entities=
  {A=>
    #<Og::Manager::EntityInfo:0x1047b7c0
     @enchanted=false,
     @klass=A,
     @options={}>},
 @options=
  {:address=>"localhost",
   :destroy=>true,
   :user=>"tester1",
   :password=>"tester1password",
   :connection_count=>1,
   :store=>"psql",
   :name=>"testing"},
 @pool=[]>
creating B
#<Og::Manager:0x10471e78
 @entities=
  {B=>
    #<Og::Manager::EntityInfo:0x1046fbc8
     @enchanted=false,
     @klass=B,
     @options={}>},
 @options=
  {:address=>"localhost",
   :destroy=>true,
   :user=>"tester2",
   :password=>"tester2password",
   :connection_count=>1,
   :store=>"psql",
   :name=>"testing2"},
 @pool=
  [#<Og::PsqlStore:0x10471bd8
    @conn=
     #<PGconn:0x10471b48
      @conn=
       #<PostgresPR::Connection:0x104719e0
        @conn=#<TCPSocket:0x10471818>,
        @params=
         {"integer_datetimes"=>"off",
          "TimeZone"=>"Europe/Helsinki",
          "server_encoding"=>"LATIN1",
          "DateStyle"=>"ISO, MDY",
          "client_encoding"=>"LATIN1",
          "session_authorization"=>"tester2",
          "server_version"=>"8.0.1",
          "is_superuser"=>"off"}>,
      @db="testing2",
      @host="localhost",
      @user="tester2">,
    @options=
     {:address=>"localhost",
      :destroy=>true,
      :user=>"tester2",
      :password=>"tester2password",
      :connection_count=>1,
      :store=>"psql",
      :name=>"testing2"},
    @transaction_nesting=0,
    @typemap=
     {TrueClass=>"boolean",
      Time=>"timestamp",
      Array=>"text",
      Float=>"float",
      Integer=>"integer",
      Date=>"date",
      Fixnum=>"integer",
      Hash=>"text",
      String=>"text",
      Object=>"text"}>]>





More information about the Nitro-general mailing list