diff options
author | Eric Wong <normalperson@yhbt.net> | 2010-12-01 10:34:32 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2010-12-01 10:47:53 +0000 |
commit | f7387cd8d1af627e5919da371cac923bbc59ef6a (patch) | |
tree | f18212e18ce20cedbc734bbac05c0c40825bd02c /lib/metropolis/tdb.rb | |
parent | 27eb2d7ebd29239a5043a528c97c6dd218d03217 (diff) | |
download | metropolis-f7387cd8d1af627e5919da371cac923bbc59ef6a.tar.gz |
add basic support for the Trivial Database (TDB)
TDB supports multiple simultaneous readers and writer *processes*, not just threads.
Diffstat (limited to 'lib/metropolis/tdb.rb')
-rw-r--r-- | lib/metropolis/tdb.rb | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/lib/metropolis/tdb.rb b/lib/metropolis/tdb.rb new file mode 100644 index 0000000..14aa3aa --- /dev/null +++ b/lib/metropolis/tdb.rb @@ -0,0 +1,74 @@ +# -*- encoding: binary -*- + +require 'tdb' + +module Metropolis::TDB + include Metropolis::Common + + def setup(opts) + super + path_pattern = opts[:path_pattern] + path_pattern.scan(/%\d*x/).size == 1 or + raise ArgumentError, "only one '/%\d*x/' may appear in #{path_pattern}" + @tdb_opts = { :tdb_flags => 0 } + if @readonly + @tdb_opts[:open_flags] = IO::RDONLY + extend Metropolis::Common::RO + end + if query = opts[:query] + size = query['hash_size'] and @tdb_opts[:hash_size] = size.to_i + hash = query['hash'] and @tdb_opts[:hash] = hash.to_sym + + case query['volatile'] + when 'true'; @tdb_opts[:tdb_flags] |= TDB::VOLATILE + when 'false', nil + else + raise ArgumentError, "'volatile' must be 'true' or 'false'" + end + + case query['sync'] + when 'true', nil + when 'false'; @tdb_opts[:tdb_flags] |= TDB::NOSYNC + else + raise ArgumentError, "'sync' must be 'true' or 'false'" + end + end + + @dbv = (0...@nr_slots).to_a.map do |slot| + path = sprintf(path_pattern, slot) + ::TDB.new(path, @tdb_opts) + end + end + + def db(key, &block) + yield @dbv[key.hash % @nr_slots] + end + + def put(key, env) + value = env["rack.input"].read + db(key) do |tdb| + case env['HTTP_X_TT_PDMODE'] + when '1' + # TODO: make this atomic + return r(409) if tdb.include?(key) + when '2' + value = (tdb.get(key) || "") << value + end + tdb.store(key, value) + end + r(201) + end + + def delete(key) + r(db(key) { |tdb| tdb.nuke!(key) } ? 200 : 404) + end + + def get(key, env) + value = db(key) { |tdb| tdb.fetch(key) } or return r(404) + [ 200, { 'Content-Length' => value.size.to_s }.merge!(@headers), [ value ] ] + end + + def close! + @dbv.each { |tdb| tdb.close } + end +end |