1 # -*- encoding: binary -*-
4 # use a Ruby hash as a plain data store
5 # It can unmarshal a hash from disk
6 module Metropolis::Hash
7 include Metropolis::Common
11 if @path = opts[:path]
13 @db = Marshal.load(File.open(@path, "rb") { |fp| fp.read })
14 Hash === @db or raise ArgumentError, "#@path is not a marshaled Hash"
22 extend Metropolis::Common::RO
24 args = [ @db, @path, !!opts[:fsync] ]
25 @clean_proc = Metropolis::Hash.finalizer_callback(args)
26 ObjectSpace.define_finalizer(self, @clean_proc)
33 ObjectSpace.undefine_finalizer(self)
39 value = @db[key] or return r(404)
40 [ 200, { 'Content-Length' => value.size.to_s }.merge!(@headers), [ value ] ]
44 value = env["rack.input"].read
45 case env['HTTP_X_TT_PDMODE']
47 @db.exists?(key) and r(409)
50 (tmp = @db[key] ||= "") << value
58 r(@db.delete(key) ? 200 : 404)
61 def self.finalizer_callback(data)
63 db, path, fsync = data
64 dir = File.dirname(path)
65 tmp = Tempfile.new('hash_save', dir)
68 tmp.write(Marshal.dump(db))
70 File.rename(tmp.path, path)
71 File.open(dir) { |d| d.fsync } if fsync