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
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
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))
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
end
def DBTree.cleanup_env()
- # no-op
+ DBTree.close_bot_registries
end
end
# 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)
}
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
# debug "closing registry #{registry}"
return if !@registry
registry.close
+ @registry = nil
end
# convert value to string form for storing in the registry
# 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
# 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
# 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