lib/perobs/FlatFileBlobHeader.rb in perobs-2.5.0 vs lib/perobs/FlatFileBlobHeader.rb in perobs-3.0.0
- old
+ new
@@ -29,55 +29,72 @@
module PEROBS
# The FlatFile blob header has the following structure:
#
- # 1 Byte: Mark byte.
+ # 1 Byte: Flags byte.
# Bit 0: 0 deleted entry, 1 valid entry
# Bit 1: 0 unmarked, 1 marked
# Bit 2: 0 uncompressed data, 1 compressed data
- # Bit 3 - 7: reserved, must be 0
+ # Bit 3: 0 current entry, 1 outdated entry
+ # Bit 4 - 7: reserved, must be 0
# 8 bytes: Length of the data blob in bytes
# 8 bytes: ID of the value in the data blob
# 4 bytes: CRC32 checksum of the data blob
#
- # If the bit 0 of the mark byte is 0, only the length is valid. The blob is
+ # If the bit 0 of the flags byte is 0, only the length is valid. The blob is
# empty. Only of bit 0 is set then entry is valid.
class FlatFileBlobHeader
# The 'pack()' format of the header.
FORMAT = 'CQQL'
# The length of the header in bytes.
LENGTH = 21
+ VALID_FLAG_BIT = 0
+ MARK_FLAG_BIT = 1
+ COMPRESSED_FLAG_BIT = 2
+ OUTDATED_FLAG_BIT = 3
- attr_reader :mark, :length, :id, :crc
+ attr_reader :addr, :flags, :length, :id, :crc
- # Create a new FlatFileBlobHeader with the given mark, length, id and crc.
- # @param mark [Fixnum] 8 bit number, see above
+ # Create a new FlatFileBlobHeader with the given flags, length, id and crc.
+ # @param file [File] the FlatFile that contains the header
+ # @param addr [Integer] the offset address of the header in the file
+ # @param flags [Fixnum] 8 bit number, see above
# @param length [Fixnum] length of the header in bytes
# @param id [Integer] ID of the blob entry
# @param crc [Fixnum] CRC32 checksum of the blob entry
- def initialize(mark, length, id, crc)
- @mark = mark
+ def initialize(file, addr, flags, length, id, crc)
+ @file = file
+ @addr = addr
+ @flags = flags
@length = length
@id = id
@crc = crc
end
# Read the header from the given File.
# @param file [File]
# @return FlatFileBlobHeader
def FlatFileBlobHeader::read(file)
begin
+ addr = file.pos
buf = file.read(LENGTH)
rescue IOError => e
- PEROBS.log.fatal "Cannot read blob header in flat file DB: #{e.message}"
+ PEROBS.log.error "Cannot read blob header in flat file DB: #{e.message}"
+ return nil
end
return nil unless buf
- FlatFileBlobHeader.new(*buf.unpack(FORMAT))
+ if buf.length != LENGTH
+ PEROBS.log.error "Incomplete FlatFileBlobHeader: Only #{buf.length} " +
+ "bytes of #{LENGTH} could be read"
+ return nil
+ end
+
+ FlatFileBlobHeader.new(file, addr, *buf.unpack(FORMAT))
end
# Read the header from the given File.
# @param file [File]
# @param addr [Integer] address in the file to start reading
@@ -94,49 +111,107 @@
if buf.nil? || buf.length != LENGTH
PEROBS.log.fatal "Cannot read blob header " +
"#{id ? "for ID #{id} " : ''}at address " +
"#{addr}"
end
- header = FlatFileBlobHeader.new(*buf.unpack(FORMAT))
+ header = FlatFileBlobHeader.new(file, addr, *buf.unpack(FORMAT))
if id && header.id != id
PEROBS.log.fatal "Mismatch between FlatFile index and blob file " +
"found for entry with ID #{id}/#{header.id}"
end
return header
end
# Write the header to a given File.
# @param file [File]
- def write(file)
+ def write
begin
- file.write([ @mark, @length, @id, @crc].pack(FORMAT))
+ @file.seek(@addr)
+ @file.write([ @flags, @length, @id, @crc].pack(FORMAT))
rescue IOError => e
PEROBS.log.fatal "Cannot write blob header into flat file DB: " +
e.message
end
end
+ # Reset all the flags bit to 0. This marks the blob as invalid.
+ # @param file [File] The file handle of the blob file.
+ # @param addr [Integer] The address of the header
+ def clear_flags
+ begin
+ @file.seek(@addr)
+ @file.write([ 0 ].pack('C'))
+ @file.flush
+ rescue IOError => e
+ PEROBS.log.fatal "Clearing flags of FlatFileBlobHeader with ID " +
+ "#{@id} failed: #{e.message}"
+ end
+ end
+
# Return true if the header is for a non-empty blob.
def is_valid?
- bit_set?(0)
+ bit_set?(VALID_FLAG_BIT)
end
# Return true if the blob has been marked.
def is_marked?
- bit_set?(1)
+ bit_set?(MARK_FLAG_BIT)
end
+ # Set the mark bit.
+ def set_mark_flag
+ set_flag(MARK_FLAG_BIT)
+ write_flags
+ end
+
+ # Clear the mark bit.
+ def clear_mark_flag
+ clear_flag(MARK_FLAG_BIT)
+ write_flags
+ end
+
# Return true if the blob contains compressed data.
def is_compressed?
- bit_set?(2)
+ bit_set?(COMPRESSED_FLAG_BIT)
end
+ # Set the outdated bit. The entry will be invalid as soon as the current
+ # transaction has been completed.
+ def set_outdated_flag
+ set_flag(OUTDATED_FLAG_BIT)
+ write_flags
+ end
+
+ # Return true if the blob contains outdated data.
+ def is_outdated?
+ bit_set?(OUTDATED_FLAG_BIT)
+ end
+
private
+ def write_flags
+ begin
+ @file.seek(@addr)
+ @file.write([ @flags ].pack('C'))
+ @file.flush
+ rescue IOError => e
+ PEROBS.log.fatal "Writing flags of FlatFileBlobHeader with ID #{@id} " +
+ "failed: #{e.message}"
+ end
+ end
+
def bit_set?(n)
mask = 1 << n
- @mark & mask == mask
+ @flags & mask == mask
+ end
+
+ def set_flag(n)
+ @flags |= (1 << n)
+ end
+
+ def clear_flag(n)
+ @flags &= ~(1 << n) & 0xFF
end
end
end