lib/perobs/FlatFile.rb in perobs-3.0.1 vs lib/perobs/FlatFile.rb in perobs-3.0.2
- old
+ new
@@ -114,10 +114,11 @@
@f.flush
rescue IOError => e
PEROBS.log.fatal "Cannot sync flat file database: #{e.message}"
end
@index.sync
+ @space_list.sync
end
# Delete the blob for the specified ID.
# @param id [Integer] ID of the object to be deleted
# @return [Boolean] True if object was deleted, false otherwise
@@ -193,22 +194,29 @@
if length != -1
# Just a safeguard so we don't overwrite current data.
header = FlatFileBlobHeader.read_at(@f, addr)
if header.length != length
PEROBS.log.fatal "Length in free list (#{length}) and header " +
- "(#{header.length}) don't match."
+ "(#{header.length}) for address #{addr} don't match."
end
if raw_obj.length > header.length
PEROBS.log.fatal "Object (#{raw_obj.length}) is longer than " +
"blob space (#{header.length})."
end
if header.is_valid?
- PEROBS.log.fatal "Entry (flags: #{header.flags}) is already used."
+ PEROBS.log.fatal "Entry at address #{addr} with flags: " +
+ "#{header.flags} is already used for ID #{header.id}."
end
end
flags = 1 << FlatFileBlobHeader::VALID_FLAG_BIT
flags |= (1 << FlatFileBlobHeader::COMPRESSED_FLAG_BIT) if compressed
+ if old_addr && old_header.is_marked?
+ # This method might be called in the middle of an operation that
+ # uses the mark flag. We must ensure that the flag is carried over
+ # to the new header.
+ flags |= (1 << FlatFileBlobHeader::MARK_FLAG_BIT)
+ end
FlatFileBlobHeader.new(@f, addr, flags, raw_obj.length, id, crc).write
@f.write(raw_obj)
if length != -1 && raw_obj.length < length
# The new object was not appended and it did not completely fill the
# free space. So we have to write a new header to mark the remaining
@@ -223,19 +231,23 @@
FlatFileBlobHeader.new(@f, space_address, 0, space_length,
0, 0).write
# Register the new space with the space list.
@space_list.add_space(space_address, space_length) if space_length > 0
end
+
+ # Once the blob has been written we can update the index as well.
+ @index.insert(id, addr)
+
if old_addr
# If we had an existing object stored for the ID we have to mark
# this entry as deleted now.
old_header.clear_flags
+ # And register the newly freed space with the space list.
+ @space_list.add_space(old_addr, old_header.length)
else
@f.flush
end
- # Once the blob has been written we can update the index as well.
- @index.insert(id, addr)
rescue IOError => e
PEROBS.log.fatal "Cannot write blob for ID #{id} to FlatFileDB: " +
e.message
end
@@ -547,24 +559,34 @@
@index.clear
@space_list.clear
each_blob_header do |pos, header|
if header.is_valid?
- @index.insert(header.id, pos)
+ if (duplicate_pos = @index.get(header.id))
+ PEROBS.log.error "FlatFile contains multiple blobs for ID " +
+ "#{header.id}. First blob is at address #{duplicate_pos}. " +
+ "Other blob found at address #{pos}."
+ @space_list.add_space(pos, header.length) if header.length > 0
+ discard_damaged_blob(header)
+ else
+ @index.insert(header.id, pos)
+ end
else
@space_list.add_space(pos, header.length) if header.length > 0
end
end
+
+ sync
end
def has_space?(address, size)
header = FlatFileBlobHeader.read_at(@f, address)
- header.length == size
+ !header.is_valid? && header.length == size
end
def has_id_at?(id, address)
header = FlatFileBlobHeader.read_at(@f, address)
- header.id == id
+ header.is_valid? && header.id == id
end
def inspect
s = '['
each_blob_header do |pos, header|