lib/daybreak/record.rb in daybreak-0.1.1 vs lib/daybreak/record.rb in daybreak-0.1.2
- old
+ new
@@ -1,87 +1,67 @@
module Daybreak
# Records define how data is serialized and read from disk.
- class Record
+ module Record
# Thrown when either key or data is missing
class UnnacceptableDataError < Exception; end
# Thrown when there is a CRC mismatch between the data from the disk
# and what was written to disk previously.
class CorruptDataError < Exception; end
- include Locking
+ extend self
+ extend Locking
+
# The mask a record uses to check for deletion.
- DELETION_MASK = (1 << 31)
+ DELETION_MASK = 1 << 31
- attr_accessor :key, :data
-
- def initialize(key = nil, data = nil, deleted = false)
- @key = key
- @data = data
- if deleted
- @deleted = DELETION_MASK
- else
- @deleted = 0
- end
- end
-
# Read a record from an open io source, check the CRC, and set <tt>@key</tt>
# and <tt>@data</tt>.
# @param [#read] io an IO instance to read from
- def read(io)
- lock io do
- @key = read_key(io)
- @data = read_data(io)
- crc = io.read(4)
- raise CorruptDataError, "CRC mismatch #{crc} should be #{crc_string}" unless crc == crc_string
- end
- self
- end
# The serialized representation of the key value pair plus the CRC.
# @return [String]
- def representation
- raise UnnacceptableDataError, "key and data must be defined" if @key.nil? || @data.nil?
- byte_string + crc_string
+ def serialize(record)
+ raise UnnacceptableDataError, 'key and data must be defined' unless record[0] && record[1]
+ s = key_data_string(record)
+ s << crc_string(s)
end
# Create a new record to read from IO.
# @param [#read] io an IO instance to read from
- def self.read(io)
- new.read(io)
+ def read(io)
+ lock io do
+ record = []
+ masked = read32(io)
+ # Read the record's key bytes
+ record << io.read(masked & (DELETION_MASK - 1)) <<
+ # Read the record's value bytes
+ io.read(read32(io)) <<
+ # Set the deletion flag
+ ((masked & DELETION_MASK) != 0)
+ crc = io.read(4)
+ raise CorruptDataError, 'CRC mismatch' unless crc == crc_string(key_data_string(record))
+ record
+ end
end
- def deleted?
- @deleted > 0
- end
-
private
- def byte_string
- @byte_string ||= part(@key, @key.bytesize + @deleted) + part(@data, @data.bytesize)
+ # Return the deletion flag plus two length prefixed cells
+ def key_data_string(record)
+ part(record[0], record[0].bytesize + (record[2] ? DELETION_MASK : 0)) << part(record[1], record[1].bytesize)
end
- def crc_string
- [Zlib.crc32(byte_string, 0)].pack('N')
+ def crc_string(s)
+ [Zlib.crc32(s, 0)].pack('N')
end
- def read_data(io)
- io.read read32(io)
+ def part(data, length)
+ [length].pack('N') << data
end
- def read_key(io)
- masked = read32 io
- @deleted = masked & DELETION_MASK
- length = masked & (DELETION_MASK - 1)
- io.read length
- end
-
def read32(io)
raw = io.read(4)
raw.unpack('N')[0]
- end
-
- def part(data, length)
- [length].pack('N') + data
end
end
end