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|