]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blobdiff - lib/rbot/registry/tc.rb
db adaptors: nil internal variable when closing
[user/henk/code/ruby/rbot.git] / lib / rbot / registry / tc.rb
index 8279f63a7fea25193f64b0ebe571618ba7112918..06013f8f796749aa2f2e751a1a179c6208218393 100644 (file)
@@ -5,6 +5,17 @@
 
 begin
   require 'bdb'
+  if BDB::VERSION_MAJOR < 4
+    fatal "Your bdb (Berkeley DB) version #{BDB::VERSION} is too old!"
+    fatal "rbot will only run with bdb version 4 or higher, please upgrade."
+    fatal "For maximum reliability, upgrade to version 4.2 or higher."
+    raise BDB::Fatal, BDB::VERSION + " is too old"
+  end
+
+  if BDB::VERSION_MAJOR == 4 and BDB::VERSION_MINOR < 2
+    warning "Your bdb (Berkeley DB) version #{BDB::VERSION} may not be reliable."
+    warning "If possible, try upgrade version 4.2 or later."
+  end
 rescue LoadError
   warning "rbot couldn't load the bdb module. Old registries won't be upgraded"
 rescue Exception => e
@@ -12,22 +23,14 @@ rescue Exception => e
 end
 
 
-if BDB::VERSION_MAJOR < 4
-  fatal "Your bdb (Berkeley DB) version #{BDB::VERSION} is too old!"
-  fatal "rbot will only run with bdb version 4 or higher, please upgrade."
-  fatal "For maximum reliability, upgrade to version 4.2 or higher."
-  raise BDB::Fatal, BDB::VERSION + " is too old"
-end
 
-if BDB::VERSION_MAJOR == 4 and BDB::VERSION_MINOR < 2
-  warning "Your bdb (Berkeley DB) version #{BDB::VERSION} may not be reliable."
-  warning "If possible, try upgrade version 4.2 or later."
-end
 
 require 'tokyocabinet'
 
 module Irc
 
+  class DBFatal < Exception ; end
+
   if defined? BDB
   # DBHash is for tying a hash to disk (using bdb).
   # Call it with an identifier, for example "mydata". It'll look for
@@ -114,21 +117,25 @@ module Irc
       if absfilename && File.exist?(key)
         # db already exists, use it
         @db = DBTree.open_db(key)
+        @fname = key.dup
       elsif absfilename
         # create empty db
         @db = DBTree.create_db(key)
+        @fname = key.dup
       elsif File.exist? relfilename
         # db already exists, use it
         @db = DBTree.open_db relfilename
+        @fname = relfilename.dup
       else
         # create empty db
         @db = DBTree.create_db relfilename
+        @fname = relfilename.dup
       end
       oldbasename = (absfilename ? key : relfilename).gsub(/\.tdb$/, ".db")
       if File.exists? oldbasename and defined? BDB
         # upgrading
         warning "Upgrading old database #{oldbasename}..."
-        oldb = ::BDB::Btree.open(oldbasename, nil, "r", 0600)
+        oldb = ::BDB::CIBtree.open(oldbasename, nil, "r", 0600)
         oldb.each_key do |k|
           @db.outlist k
           @db.putlist k, (oldb.duplicates(k, false))
@@ -143,19 +150,51 @@ module Irc
       return @db.send(method, *args, &block)
     end
 
+    # Since TokyoCabinet does not have the concept of an environment, we have to do the
+    # database management ourselves. In particular, we have to keep a list of open
+    # registries to be sure we to close all of them on exit
+    @@bot_registries={ }
+    def self.close_bot_registries
+      @@bot_registries.each { |name, reg| reg.close }
+      @@bot_registries.clear
+    end
+
+    def close
+      db = @@bot_registries.delete(@fname)
+      if db != @db
+        error "We think we have #{@db} from #{@fname}, TC pseudo-env gives us #{db}"
+      end
+      @db.close
+    end
+
     def DBTree.create_db(name)
       debug "DBTree: creating empty db #{name}"
+      if @@bot_registries.key? name
+        error "DBTree: creating assumingly allocated db #{name}?!"
+        return @@bot_registries[name]
+      end
       db = TokyoCabinet::CIBDB.new
       res = db.open(name, TokyoCabinet::CIBDB::OREADER | TokyoCabinet::CIBDB::OCREAT | TokyoCabinet::CIBDB::OWRITER)
-       warning "DBTree: creating empty db #{name}: #{db.errmsg(db.ecode) unless res}"
+      if res
+        @@bot_registries[name] = db
+      else
+        error "DBTree: creating empty db #{name}: #{db.errmsg(db.ecode)}"
+      end
       return db
     end
 
     def DBTree.open_db(name)
       debug "DBTree: opening existing db #{name}"
+      if @@bot_registries.key? name
+        return @@bot_registries[name]
+      end
       db = TokyoCabinet::CIBDB.new
       res = db.open(name, TokyoCabinet::CIBDB::OREADER | TokyoCabinet::CIBDB::OWRITER)
-       warning "DBTree:opening db #{name}: #{db.errmsg(db.ecode) unless res}"
+      if res
+        @@bot_registries[name] = db
+      else
+        error "DBTree: opening db #{name}: #{db.errmsg(db.ecode)}"
+      end
       return db
     end
 
@@ -168,7 +207,7 @@ module Irc
     end
 
     def DBTree.cleanup_env()
-      # no-op
+      DBTree.close_bot_registries
     end
 
   end
@@ -191,29 +230,31 @@ class Bot
     # NB this function is called _early_ in init(), pretty much all you have to
     # work with is @bot.botclass.
     def upgrade_data
+      oldreg = @bot.path 'registry.db'
       if defined? DBHash
-        oldreg = @bot.path 'registry.db'
         newreg = @bot.path 'plugin_registry.db'
         if File.exist?(oldreg)
           log _("upgrading old-style (rbot 0.9.5 or earlier) plugin registry to new format")
           old = ::BDB::Hash.open(oldreg, nil, "r+", 0600)
-          new = TokyoCabinet::CIBDB.new
-          new.open(name, TokyoCabinet::CIBDB::OREADER | TokyoCabinet::CIBDB::OCREAT | TokyoCabinet::CIBDB::OWRITER)
-          old.each_key do |k|
-            new.outlist k
-            new.putlist k, (old.duplicates(k, false))
-          end
+          new = ::BDB::CIBtree.open(newreg, nil, ::BDB::CREATE | ::BDB::EXCL, 0600)
+          old.each {|k,v|
+            new[k] = v
+          }
           old.close
           new.close
           File.rename(oldreg, oldreg + ".old")
         end
       else
-        warning "Won't upgrade data: BDB not installed"
+        warning "Won't upgrade data: BDB not installed" if File.exist? oldreg
       end
     end
 
     def upgrade_data2
       oldreg = @bot.path 'plugin_registry.db'
+      if not defined? BDB
+        warning "Won't upgrade data: BDB not installed" if File.exist? oldreg
+        return
+      end
       newdir = @bot.path 'registry'
       if File.exist?(oldreg)
         Dir.mkdir(newdir) unless File.exist?(newdir)
@@ -237,8 +278,8 @@ class Bot
             }
           end
           unless dbs.has_key?(prefix)
-            log _("creating db #{@bot.botclass}/registry/#{prefix}.db")
-            dbs[prefix] = TokyoCabinet::CIBDB.open("#{@bot.botclass}/registry/#{prefix}.db",
+            log _("creating db #{@bot.botclass}/registry/#{prefix}.tdb")
+            dbs[prefix] = TokyoCabinet::CIBDB.open("#{@bot.botclass}/registry/#{prefix}.tdb",
              TokyoCabinet::CIBDB::OREADER | TokyoCabinet::CIBDB::OCREAT | TokyoCabinet::CIBDB::OWRITER)
           end
           dbs[prefix][key] = v
@@ -335,6 +376,7 @@ class Bot
       # debug "closing registry #{registry}"
       return if !@registry
       registry.close
+      @registry = nil
     end
 
     # convert value to string form for storing in the registry
@@ -400,7 +442,7 @@ class Bot
     # just like Hash#each
     def each(set=nil, bulk=0, &block)
       return nil unless File.exist?(@filename)
-      registry.fwmkeys(set).each {|key|
+      registry.fwmkeys(set.to_s).each {|key|
         block.call(key, restore(registry[key]))
       }
     end
@@ -408,7 +450,7 @@ class Bot
     # just like Hash#each_key
     def each_key(set=nil, bulk=0, &block)
       return nil unless File.exist?(@filename)
-      registry.fwmkeys(set).each do |key|
+      registry.fwmkeys(set.to_s).each do |key|
         block.call(key)
       end
     end
@@ -416,7 +458,7 @@ class Bot
     # just like Hash#each_value
     def each_value(set=nil, bulk=0, &block)
       return nil unless File.exist?(@filename)
-      registry.fwmkeys(set).each do |key|
+      registry.fwmkeys(set.to_s).each do |key|
         block.call(restore(registry[key]))
       end
     end