1 # -*- encoding: binary -*-
3 # this module is NOT thread-safe, all performance is dependent on the
4 # local machine so there is never anything that needs yielding to threads.
5 module Metropolis::TC::HDB
6 autoload :RO, 'metropolis/tc/hdb/ro'
7 autoload :EX, 'metropolis/tc/hdb/ex'
9 TCHDB = TokyoCabinet::HDB # :nodoc
10 include Metropolis::Common
14 @rd_flags = TCHDB::OREADER
15 @wr_flags = TCHDB::OWRITER
22 @rd_flags |= TCHDB::ONOLCK
24 raise ArgumentError, "'rdlock' must be 'true' or 'false'"
30 @wr_flags |= TCHDB::ONOLCK
32 raise ArgumentError, "'wrlock' must be 'true' or 'false'"
36 @optimize = %w(bnum apow fpow).map do |x|
41 case large = @query['large']
44 flags |= TCHDB::TLARGE
46 raise ArgumentError, "invalid 'large' value: #{large}"
49 case compress = @query['compress']
51 when 'deflate', 'bzip', 'tcbs'
52 flags |= TCHDB.const_get("T#{compress.upcase}")
54 raise ArgumentError, "invalid 'compress' value: #{compress}"
58 @nr_slots = 1 unless @path_pattern
59 @dbv = (0...@nr_slots).to_a.map do |slot|
60 path = @path_pattern ? sprintf(@path_pattern, slot) : @uri.path
63 hdb.open(path, TCHDB::OWRITER | TCHDB::OCREAT) or ex!(:open, hdb)
65 hdb.optimize(*@optimize) or ex!(:optimize, hdb)
67 hdb.close or ex!(:close, hdb)
71 @multi_hash ||= :digest_sha1
72 extend Metropolis::MultiHash
73 extend(RO) if @readonly
74 extend(EX) if @exclusive
78 raise "#{msg}: #{hdb.errmsg(hdb.ecode)}"
81 def writer(key, &block)
82 hdb, path = @dbv[multi_hash(key) % @nr_slots]
83 hdb.open(path, @wr_flags) or ex!(:open, hdb)
86 hdb.close or ex!(:close, hdb)
90 hdb, path = @dbv[multi_hash(key) % @nr_slots]
91 hdb.open(path, @rd_flags) or ex!(:open, hdb)
94 hdb.close or ex!(:close, hdb)
98 value = env["rack.input"].read
100 case env['HTTP_X_TT_PDMODE']
102 unless hdb.putkeep(key, value)
103 TCHDB::EKEEP == hdb.ecode and return r(409)
107 hdb.putcat(key, value) or ex!(:putcat, hdb)
109 # ttserver does not care for other PDMODE values, so we don't, either
110 hdb.put(key, value) or ex!(:put, hdb)
118 unless hdb.delete(key)
119 TCHDB::ENOREC == hdb.ecode and return r(404)
129 unless value = hdb.get(key)
130 TCHDB::ENOREC == hdb.ecode and return r(404)
134 [ 200, { 'Content-Length' => value.size.to_s }.merge!(@headers), [ value ] ]
138 @dbv.each { |(hdb,_)| hdb.close }