def write_obj_by_id(id, raw_obj)
      # Check if we have already an object with the given ID. We'll mark it as
      # outdated and save the header for later deletion. In case this
      # operation is aborted or interrupted we ensure that we either have the
      # old or the new version available.
      if (old_addr = find_obj_addr_by_id(id))
        old_header = FlatFileBlobHeader.read(@f, old_addr)
        old_header.set_outdated_flag
      end

      crc = checksum(raw_obj)

      # If the raw_obj is larger then 256 characters we will compress it to
      # safe some space in the database file. For smaller strings the
      # performance impact of compression is not compensated by writing
      # less data to the storage.
      compressed = false
      if raw_obj.bytesize > 256
        raw_obj = Zlib.deflate(raw_obj)
        compressed = true
      end

      addr, length = find_free_blob(raw_obj.bytesize)
      begin
        if length != -1
          # Just a safeguard so we don't overwrite current data.
          header = FlatFileBlobHeader.read(@f, addr)
          if header.length != length
            PEROBS.log.fatal "Length in free list (#{length}) and header " +
              "(#{header.length}) for address #{addr} don't match."
          end
          if raw_obj.bytesize > header.length
            PEROBS.log.fatal "Object (#{raw_obj.bytesize}) is longer than " +
              "blob space (#{header.length})."
          end
          if header.is_valid?
            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
        FlatFileBlobHeader.new(@f, addr, flags, raw_obj.bytesize, id, crc).write
        @f.write(raw_obj)
        if length != -1 && raw_obj.bytesize < 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
          # empty space.
          unless length - raw_obj.bytesize >= FlatFileBlobHeader::LENGTH
            PEROBS.log.fatal "Not enough space to append the empty space " +
              "header (space: #{length} bytes, object: #{raw_obj.bytesize} " +
              "bytes)."
          end
          space_address = @f.pos
          space_length = length - FlatFileBlobHeader::LENGTH - raw_obj.bytesize
          FlatFileBlobHeader.new(@f, space_address, 0, space_length,
                                 0, 0).write
          # Register the new space with the space list.
          if @space_list.is_open? && space_length > 0
            @space_list.add_space(space_address, space_length)
          end
        end

        # Once the blob has been written we can update the index as well.
        @index.insert(id, addr) if @index.is_open?

        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.
          if @space_list.is_open?
            @space_list.add_space(old_addr, old_header.length)
          end
        else
          @f.flush
        end
      rescue IOError => e
        PEROBS.log.fatal "Cannot write blob for ID #{id} to FlatFileDB: " +
          e.message
      end

      addr
    end
def write_obj_by_id(id, raw_obj)
      # Check if we have already an object with the given ID. We'll mark it as
      # outdated and save the header for later deletion. In case this
      # operation is aborted or interrupted we ensure that we either have the
      # old or the new version available.
      if (old_addr = find_obj_addr_by_id(id))
        old_header = FlatFileBlobHeader.read(@f, old_addr)
        old_header.set_outdated_flag
      end

      crc = checksum(raw_obj)

      # If the raw_obj is larger then 256 characters we will compress it to
      # safe some space in the database file. For smaller strings the
      # performance impact of compression is not compensated by writing
      # less data to the storage.
      compressed = false
      if raw_obj.bytesize > 256
        raw_obj = Zlib.deflate(raw_obj)
        compressed = true
      end

      addr, length = find_free_blob(raw_obj.bytesize)
      begin
        if length != -1
          # Just a safeguard so we don't overwrite current data.
          header = FlatFileBlobHeader.read(@f, addr)
          if header.length != length
            PEROBS.log.fatal "Length in free list (#{length}) and header " +
              "(#{header.length}) for address #{addr} don't match."
          end
          if raw_obj.bytesize > header.length
            PEROBS.log.fatal "Object (#{raw_obj.bytesize}) is longer than " +
              "blob space (#{header.length})."
          end
          if header.is_valid?
            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
        FlatFileBlobHeader.new(@f, addr, flags, raw_obj.bytesize, id, crc).write
        @f.write(raw_obj)
        if length != -1 && raw_obj.bytesize < 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
          # empty space.
          unless length - raw_obj.bytesize >= FlatFileBlobHeader::LENGTH
            PEROBS.log.fatal "Not enough space to append the empty space " +
              "header (space: #{length} bytes, object: #{raw_obj.bytesize} " +
              "bytes)."
          end
          space_address = @f.pos
          space_length = length - FlatFileBlobHeader::LENGTH - raw_obj.bytesize
          FlatFileBlobHeader.new(@f, space_address, 0, space_length,
                                 0, 0).write
          # Register the new space with the space list.
          if @space_list.is_open? && space_length > 0
            @space_list.add_space(space_address, space_length)
          end
        end

        # Once the blob has been written we can update the index as well.
        @index.insert(id, addr) if @index.is_open?

        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.
          if @space_list.is_open?
            @space_list.add_space(old_addr, old_header.length)
          end
        else
          @f.flush
        end
      rescue IOError => e
        PEROBS.log.fatal "Cannot write blob for ID #{id} to FlatFileDB: " +
          e.message
      end

      addr
    end
Write the given object into the file. This method never uses in-place
 updates for existing objects. A new copy is inserted first and only when
 the insert was successful, the old copy is deleted and the index
 updated.
 @param id [Integer] ID of the object
 @param raw_obj [String] Raw object as String
 @return [Integer] position of the written blob in the blob file