allow easier, single-file options for TC and TDB
[metropolis.git] / lib / metropolis / tdb.rb
blobd734443ee5b3c8fb052d7cbe2a703e49b429f401
1 # -*- encoding: binary -*-
3 require 'tdb'
5 module Metropolis::TDB
6   include Metropolis::Common
7   autoload :Single, 'metropolis/tdb/single'
8   autoload :Multi, 'metropolis/tdb/multi'
10   def setup(opts)
11     super
12     @tdb_opts = { :tdb_flags => 0 }
13     if @readonly
14       @tdb_opts[:open_flags] = IO::RDONLY
15       extend Metropolis::Common::RO
16     end
17     if @query
18       size = @query['hash_size'] and @tdb_opts[:hash_size] = size.to_i
19       hash = @query['hash'] and @tdb_opts[:hash] = hash.to_sym
21       case @query['volatile']
22       when 'true'; @tdb_opts[:tdb_flags] |= TDB::VOLATILE
23       when 'false', nil
24       else
25         raise ArgumentError, "'volatile' must be 'true' or 'false'"
26       end
28       case @query['sync']
29       when 'true', nil
30       when 'false'; @tdb_opts[:tdb_flags] |= TDB::NOSYNC
31       else
32         raise ArgumentError, "'sync' must be 'true' or 'false'"
33       end
34     end
35     extend(@path_pattern ? Metropolis::TDB::Multi : Metropolis::TDB::Single)
36   end
38   def put(key, env)
39     value = env["rack.input"].read
40     db(key) do |tdb|
41       case env['HTTP_X_TT_PDMODE']
42       when '1'
43         # TODO: make this atomic
44         return r(409) if tdb.include?(key)
45       when '2'
46         value = (tdb.get(key) || "") << value
47       end
48       tdb.store(key, value)
49     end
50     r(201)
51   end
53   def delete(key)
54     r(db(key) { |tdb| tdb.nuke!(key) } ? 200 : 404)
55   end
57   def get(key, env)
58     value = db(key) { |tdb| tdb.fetch(key) } or return r(404)
59     [ 200, { 'Content-Length' => value.size.to_s }.merge!(@headers), [ value ] ]
60   end
61 end