def defragmentize
      distance = 0
      new_file_size = 0
      deleted_blobs = 0
      corrupted_blobs = 0
      valid_blobs = 0

      # Iterate over all entries.
      @progressmeter.start('Defragmentizing blobs file', @f.size) do |pm|
        each_blob_header do |header|
          # If we have stumbled over a corrupted blob we treat it similar to a
          # deleted blob and reuse the space.
          if header.corruption_start
            distance += header.addr - header.corruption_start
            corrupted_blobs += 1
          end

          # Total size of the current entry
          entry_bytes = FlatFileBlobHeader::LENGTH + header.length
          if header.is_valid?
            # We have found a valid entry.
            valid_blobs += 1
            if distance > 0
              begin
                # Read current entry into a buffer
                @f.seek(header.addr)
                buf = @f.read(entry_bytes)
                # Write the buffer right after the end of the previous entry.
                @f.seek(header.addr - distance)
                @f.write(buf)
                # Mark the space between the relocated current entry and the
                # next valid entry as deleted space.
                FlatFileBlobHeader.new(@f, @f.pos, 0,
                                       distance - FlatFileBlobHeader::LENGTH,
                                       0, 0).write
                @f.flush
              rescue IOError => e
                PEROBS.log.fatal "Error while moving blob for ID " +
                  "#{header.id}: #{e.message}"
              end
            end
            new_file_size = header.addr - distance +
              FlatFileBlobHeader::LENGTH + header.length
          else
            deleted_blobs += 1
            distance += entry_bytes
          end

          pm.update(header.addr)
        end
      end

      PEROBS.log.info "#{distance / 1000} KiB/#{deleted_blobs} blobs of " +
        "#{@f.size / 1000} KiB/#{valid_blobs} blobs or " +
        "#{'%.1f' % (distance.to_f / @f.size * 100.0)}% reclaimed"
      if corrupted_blobs > 0
        PEROBS.log.info "#{corrupted_blobs} corrupted blob(s) found. Space " +
          "was recycled."
      end

      @f.flush
      @f.truncate(new_file_size)
      @f.flush

      sync
    end
def defragmentize
      distance = 0
      new_file_size = 0
      deleted_blobs = 0
      corrupted_blobs = 0
      valid_blobs = 0

      # Iterate over all entries.
      @progressmeter.start('Defragmentizing blobs file', @f.size) do |pm|
        each_blob_header do |header|
          # If we have stumbled over a corrupted blob we treat it similar to a
          # deleted blob and reuse the space.
          if header.corruption_start
            distance += header.addr - header.corruption_start
            corrupted_blobs += 1
          end

          # Total size of the current entry
          entry_bytes = FlatFileBlobHeader::LENGTH + header.length
          if header.is_valid?
            # We have found a valid entry.
            valid_blobs += 1
            if distance > 0
              begin
                # Read current entry into a buffer
                @f.seek(header.addr)
                buf = @f.read(entry_bytes)
                # Write the buffer right after the end of the previous entry.
                @f.seek(header.addr - distance)
                @f.write(buf)
                # Mark the space between the relocated current entry and the
                # next valid entry as deleted space.
                FlatFileBlobHeader.new(@f, @f.pos, 0,
                                       distance - FlatFileBlobHeader::LENGTH,
                                       0, 0).write
                @f.flush
              rescue IOError => e
                PEROBS.log.fatal "Error while moving blob for ID " +
                  "#{header.id}: #{e.message}"
              end
            end
            new_file_size = header.addr - distance +
              FlatFileBlobHeader::LENGTH + header.length
          else
            deleted_blobs += 1
            distance += entry_bytes
          end

          pm.update(header.addr)
        end
      end

      PEROBS.log.info "#{distance / 1000} KiB/#{deleted_blobs} blobs of " +
        "#{@f.size / 1000} KiB/#{valid_blobs} blobs or " +
        "#{'%.1f' % (distance.to_f / @f.size * 100.0)}% reclaimed"
      if corrupted_blobs > 0
        PEROBS.log.info "#{corrupted_blobs} corrupted blob(s) found. Space " +
          "was recycled."
      end

      @f.flush
      @f.truncate(new_file_size)
      @f.flush

      sync
    end
Eliminate all the holes in the file. This is an in-place
 implementation. No additional space will be needed on the file system.