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