From 0621370cec890c43f71cbf5d971f8ee4f69110fa Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Fri, 15 Jul 2011 10:03:38 +0200 Subject: [PATCH] -- --- lib/aodbm.rb | 103 +++++++++++++++++++++++++++ lib/plain.rb | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 295 insertions(+) create mode 100644 lib/aodbm.rb create mode 100644 lib/plain.rb diff --git a/lib/aodbm.rb b/lib/aodbm.rb new file mode 100644 index 0000000..cf98858 --- /dev/null +++ b/lib/aodbm.rb @@ -0,0 +1,103 @@ +require 'ffi' + +module AODBM + class DB + attr_reader :c + + def initialize name, flags = nil + flags ||= 0 + @c = Lib::open name, flags + end + + def open name, flags = nil + db = new name, flags + block_given? ? yield( db) : db + end + + def close + Lib::close @c + end + + def current + Version.new @c, Lib::current( @c) + end + + def commit version + Lib::commit @c, version + end + end + + class Version + attr_reader :db, :c + + def initialize db, c + @db, @c = db, c + end + + def previous + Version.new @db, Lib::previous( @db.c, @c) + end + + def has? data + Lib::has @db.c, @c, Lib::Data.new( data) + end + + def set key, val + Lib::set @db.c, @c, Lib::Data.new( key), Lib::Data.new( val) + end + end + + module Lib + extend FFI::Library + ffi_lib "libaodbm.so" + + typedef :pointer, :aodbm + typedef :uint64, :version + + class Data < FFI::Struct + def initialilze data + + end + + layout :dat, :buffer, :sz, :size_t + end + typedef :pointer, :data + + attach_function :open, :aodbm_open, [:string, :int], :aodbm + attach_function :close, :aodbm_close, [:aodbm], :void + + attach_function :current, :aodbm_current, [:aodbm], :version + attach_function :commit, :aodbm_commit, [:aodbm, :version], :bool + + attach_function :has, :aodbm_has, [:aodbm, :version, :data], :bool + attach_function :set, :aodbm_set, [:aodbm, :version, :data, :data], :version + attach_function :get, :aodbm_get, [:aodbm, :version, :data], :data + attach_function :del, :aodbm_del, [:aodbm, :version, :data], :version + + attach_function :is_based_on, :aodbm_is_based_on, [:aodbm, :version, :data], :bool + attach_function :previous, :aodbm_previous_version, [:aodbm, :version], :version + attach_function :common_ancestor, :aodbm_common_ancestor, [:aodbm, :version, :version], :version + + #typedef :changeset, :pointer + #attach_function :aodbm_diff_prev, [:aodbm, :version], :changeset + #attach_function :aodbm_diff_prev_rev, [:aodbm, :version], :changeset + #attach_function :aodbm_diff, [:aodbm, :version, :version], :changeset + #attach_function :aodbm_apply, [:aodbm, :version, :changeset], :version + #attach_function :aodbm_apply_di, [:aodbm, :version, :changeset], :version + #attach_function :aodbm_merge, [:aodbm, :version, :version], :version + + typedef :pointer, :iterator + class Record < FFI::Struct + layout :key, :data, :val, :data + end + typedef :pointer, :record + + attach_function :new_iterator, :aodbm_new_iterator, [:aodbm, :version], :iterator + attach_function :iterator_from, :aodbm_iterate_from, [:aodbm, :version, :data], :iterator + attach_function :iterate_next, :aodbm_iterator_next, [:aodbm, :iterator], :record + attach_function :iterate_goto, :aodbm_iterator_goto, [:aodbm, :iterator, :data], :void + attach_function :free_iterator, :aodbm_free_iterator, [:iterator], :void + + attach_function :free_data, :aodbm_free_data, [:data], :void + end +end diff --git a/lib/plain.rb b/lib/plain.rb new file mode 100644 index 0000000..edb4229 --- /dev/null +++ b/lib/plain.rb @@ -0,0 +1,192 @@ +require 'zlib' # Zlib::crc32 +require 'uuidtools' + +# Maximum Filesize: 4GB because #pack("N") + +class Plain < File + UUID_SIZE = 16 # Size of an key (UUID as raw 16byte string) + INT_SIZE = 4 + CRCR32_SIZE = INT_SIZE # Size of CRC32 (32Bit) + + KEY_SIZE = UUID_SIZE + IDX_SIZE = INT_SIZE # Size of an index (big-endian 32bit integer) + SIZE_SIZE = INT_SIZE # Size of size_t + CHK_SIZE = CRCR32_SIZE + IDXE_SIZE = KEY_SIZE + IDX_SIZE # Size of an entry in index-file + DBP_SIZE = KEY_SIZE + SIZE_SIZE + CHK_SIZE + + UUID_PACK = "a16" + INT_PACK = "N" + STR_PACK = "a*" + CRC32_PACK = INT_PACK + + KEY_PACK = UUID_PACK + IDX_PACK = INT_PACK + SIZE_PACK = INT_PACK + CHK_PACK = CRC32_PACK + IDXE_PACK = KEY_PACK + IDX_PACK + DBP_PACK = KEY_PACK + SIZE_PACK + CHK_PACK + VAL_PACK = STR_PACK + ENTRY_PACK = DBP_PACK + VAL_PACK + + class Corrupt < Exception + end + + module UUIDConv + class < 16-byte-String + # #cto_key # 16-byte-String => obj + attr_accessor :conv + attr_reader :idx + + def initialize *a + super *a + @conv = @@conv + @idx = File.open "#{path}.idx", a[1] + end + + class <>= 1 + end + end + idx >>= 1 + t = idx + p idx + + while t > 0 + t >>= 1 + i = yield idx + case i + when -1 then idx -= t + when 1 then idx += t + when 0 then return true + else return nil + end + end + end + + # Get the value. + # key must provide: #<=> uuid + def search_ key + idx = self.length + position = nil + self.class.binary_search( idx) do |idx| + p idx + idx *= IDXE_SIZE + if idx > size + size = @idx.size + break if idx > size + end + # Read entry i. p is position and k is key + @idx.seek idx + k, position = @idx.read( IDXE_SIZE).unpack IDXE_PACK + p pos: position, key: k + key <=> @conv.cto_key( k) + end ? position : nil + end + + def [] key + if position = search_( key) + self.pos = position+KEY_SIZE + length,_ = read( SIZE_SIZE).unpack( SIZE_PACK) + read( length)[2] + end + end + + def each + return Enumerator.new( self) unless block_given? + yield *get while !eof? + end + + # counts entries (size of the idx): O(1) + def length + @idx.size/IDXE_SIZE + end +end