Using transactions with secondary indexes in bdb

I'm having trouble figuring out how to do transactions. I'm using db
4.5.40 from Oracle and bdb 0.6.0. Here's a code snippet:

require 'bdb'

BDB::Hash.open('models.db', nil, BDB::TRUNCATE) {}
BDB::Hash.open('makes.db', nil, BDB::TRUNCATE) {}

BDB::Env.open('db', BDB::CREATE | BDB::INIT_TRANSACTION) do |env|
  models = makes = nil
  env.begin(BDB::TXN_COMMIT) do |tx|
    models = tx.open_db(BDB::HASH, 'models.db', nil, BDB::CREATE)
    makes = tx.open_db(BDB::HASH, 'makes.db', nil, BDB::CREATE | BDB::DUPSORT)
    models.associate(makes) { |sdb, key, value| value }
  end

  env.begin(BDB::TXN_COMMIT) do |tx|
    tx.assoc(models, makes)
    puts '===== Before'
    puts '----- models'
    models.each { |key, value| puts "#{key} = #{value}" }
    puts '----- makes'
    makes.each { |key, value| puts "#{key} = #{value}" }
  end

  env.begin(BDB::TXN_COMMIT) do |tx|
    tx.assoc(models, makes)
    models['Civic'] = 'Honda'
    models['Accord'] = 'Honda' # this is line 26 where the error is occurring
    models['S2000'] = 'Honda'
    models['Camry'] = 'Toyota'
    models['Solara'] = 'Toyota'
  end

  env.begin do |tx|
    tx.assoc(models, makes)
    puts '===== After'
    puts '----- models'
    models.each { |key, value| puts "#{key} = #{value}" }
    puts '----- makes'
    makes.each { |key, value| puts "#{key} = #{value}" }
  end

  makes.close
  models.close
end

Now I have no idea if I'm using transactions properly, not to mention
any of the other various features, but I suspect I'm not since I get
this output:

===== Before
----- models
----- makes
/home/jim/eclipse/testRuby/test.rb:26:in `close': BUG : current_env
not set (BDB::Fatal)
        from /home/jim/eclipse/testRuby/test.rb:26:in `open'
        from /home/jim/eclipse/testRuby/test.rb:6
/home/jim/eclipse/testRuby/test.rb:26: [BUG] Segmentation fault
ruby 1.8.5 (2007-03-13) [i386-linux]

I would greatly appreciate any help that anyone can provide.

Cheers,
Jim

OK, I figured out that a lot of my previous code was wrong, not even
considering the transactions, so I removed the transactional stuff and
got down to this:

require 'bdb'

BDB::Hash.open('models.db', nil, BDB::CREATE | BDB::TRUNCATE) {}
BDB::Hash.open('makes.db', nil, BDB::CREATE | BDB::TRUNCATE,
:set_flags => BDB::DUP | BDB::DUPSORT) {}

BDB::Hash.open('models.db', nil, BDB::CREATE) do |models|
  BDB::Hash.open('makes.db', nil, BDB::CREATE, :set_flags => BDB::DUP

BDB::DUPSORT) do |makes|

    models.associate(makes) { |sdb, key, value| value }

    puts '===== Before'
    puts '----- models'
    models.each { |key, value| puts "#{key} = #{value}" }
    puts '----- makes'
    makes.each_primary { |skey, pkey, pvalue| p [skey, pkey, pvalue] }

    models['Civic'] = 'Honda'
    models['Accord'] = 'Honda'
    models['S2000'] = 'Honda'
    models['Camry'] = 'Toyota'
    models['Solara'] = 'Toyota'

    puts '===== After'
    puts '----- models'
    models.each { |key, value| puts "#{key} = #{value}" }
    puts '----- makes'
    makes.each_primary { |skey, pkey, pvalue| p [skey, pkey, pvalue] }
  end
end

And here is the output, which looks right to me:

===== Before
----- models
----- makes
===== After
----- models
Civic = Honda
Accord = Honda
Camry = Toyota
Solara = Toyota
S2000 = Honda
----- makes
["Honda", "Accord", "Honda"]
["Honda", "Civic", "Honda"]
["Honda", "S2000", "Honda"]
["Toyota", "Camry", "Toyota"]
["Toyota", "Solara", "Toyota"]

Now I just have to figure out the transactional part. I'll follow up
on the list once I do.

Cheers,
Jim

there are transaction examples in the bdb src - have you looked at that?

-a

···

On Tue, 3 Apr 2007, Jim Cain wrote:

OK, I figured out that a lot of my previous code was wrong, not even
considering the transactions, so I removed the transactional stuff and
got down to this:

require 'bdb'

BDB::Hash.open('models.db', nil, BDB::CREATE | BDB::TRUNCATE) {}
BDB::Hash.open('makes.db', nil, BDB::CREATE | BDB::TRUNCATE,
:set_flags => BDB::DUP | BDB::DUPSORT) {}

BDB::Hash.open('models.db', nil, BDB::CREATE) do |models|
BDB::Hash.open('makes.db', nil, BDB::CREATE, :set_flags => BDB::DUP
> BDB::DUPSORT) do |makes|
  models.associate(makes) { |sdb, key, value| value }

  puts '===== Before'
  puts '----- models'
  models.each { |key, value| puts "#{key} = #{value}" }
  puts '----- makes'
  makes.each_primary { |skey, pkey, pvalue| p [skey, pkey, pvalue] }

  models['Civic'] = 'Honda'
  models['Accord'] = 'Honda'
  models['S2000'] = 'Honda'
  models['Camry'] = 'Toyota'
  models['Solara'] = 'Toyota'

  puts '===== After'
  puts '----- models'
  models.each { |key, value| puts "#{key} = #{value}" }
  puts '----- makes'
  makes.each_primary { |skey, pkey, pvalue| p [skey, pkey, pvalue] }
end

And here is the output, which looks right to me:

===== Before
----- models
----- makes
===== After
----- models
Civic = Honda
Accord = Honda
Camry = Toyota
Solara = Toyota
S2000 = Honda
----- makes
["Honda", "Accord", "Honda"]
["Honda", "Civic", "Honda"]
["Honda", "S2000", "Honda"]
["Toyota", "Camry", "Toyota"]
["Toyota", "Solara", "Toyota"]

Now I just have to figure out the transactional part. I'll follow up
on the list once I do.

--
be kind whenever possible... it is always possible.
- the dalai lama

I looked at the one example file "txn.rb" originally, but I didn't put
it all together then. Upon a second look, it's making a bit more
sense. In that example, he has:

module BDB
   class ThreadHash < Hash
      def start(val, num)
         Thread.start do
            self.env.begin(self) do |txn, b1|
               b1.delete_if do |k, v|
                  print "\t#{num} #{k} -- #{v}\n"
                  k == val
               end
               p "Thread #{num} Pass"
               Thread.pass
               b1.each do |k, v|
                  print "\t#{num} #{k} -- #{v}\n"
               end
               if num == 1
                  txn.abort
               else
                  txn.commit
               end
            end
            p "End Thread #{num}"
         end
      end
   end
end

And then later on he calls #start for each ThreadHash object. I
suppose the business part of that is:

self.env.begin(self) do |txn, b1|
# ...
end

So he's passing in the ThreadHash object as the only argument to
#begin, but the docs have this for Env#begin:

begin(flags = 0, db, ...) { |txn, db, ...| ...}

This says that "flags" is the first argument. Maybe that's where my
confusion started.

Cheers,
Jim

···

On 4/2/07, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:

there are transaction examples in the bdb src - have you looked at that?

I've updated my previous example to include transactions:

  BDB::Hash.open('models.db', nil, BDB::CREATE | BDB::TRUNCATE) {}
  BDB::Hash.open('makes.db', nil, BDB::CREATE | BDB::TRUNCATE,
:set_flags => BDB::DUP | BDB::DUPSORT) {}

  env = BDB::Env.new('/home/jim/eclipse/testRuby',
BDB::CREATE|BDB::INIT_TRANSACTION)
  models = env.open_db(BDB::HASH, 'models.db', nil, BDB::CREATE)
  makes = env.open_db(BDB::HASH, 'makes.db', nil, BDB::CREATE,
:set_flags => BDB::DUP | BDB::DUPSORT)

  env.begin(models, makes) do |tx, tx_models, tx_makes|
    tx_models.associate(tx_makes) { |sdb, key, value| value }
    tx.commit
  end

  puts '===== Before'
  puts '----- models'
  models.each { |key, value| puts "#{key} = #{value}" }
  puts '----- makes'
  makes.each_primary { |skey, pkey, pvalue| p [skey, pkey, pvalue] }

  env.begin(BDB::TXN_COMMIT, models, makes) do |tx, tx_models, tx_makes|
    tx_models['Civic'] = 'Honda'
    tx_models['Accord'] = 'Honda'
    tx_models['S2000'] = 'Honda'
    tx_models['Camry'] = 'Toyota'
    tx_models['Solara'] = 'Toyota'
  end

  env.begin(models, makes) do |tx, tx_models, tx_makes|
    puts '===== After'
    puts '----- models'
    tx_models.each { |key, value| puts "#{key} = #{value}" }
    puts '----- makes'
    tx_makes.each_primary { |skey, pkey, pvalue| p [skey, pkey, pvalue] }
  end

  env.begin(BDB::TXN_COMMIT, models, makes) do |tx, tx_models, tx_makes|
    tx_makes.close
    tx_models.close
  end

  env.close

Here is the output:

===== Before
----- models
----- makes
===== After
----- models
Civic = Honda
Accord = Honda
Camry = Toyota
Solara = Toyota
S2000 = Honda
----- makes

It doesn't appear to be updating the secondary index. What have I done wrong?

Cheers,
Jim