def check(repair = false)
      errors = 0
      return errors unless @f

      t = Time.now
      PEROBS.log.info "Checking FlatFile database" +
        "#{repair ? ' in repair mode' : ''}..."

      # First check the database blob file. Each entry should be readable and
      # correct and all IDs must be unique. We use a shadow index to keep
      # track of the already found IDs.
      new_index = BTree.new(@db_dir, 'new-index', INDEX_BTREE_ORDER,
                            @progressmeter)
      new_index.erase
      new_index.open

      corrupted_blobs = 0
      @progressmeter.start('Checking blobs file', @f.size) do |pm|
        corrupted_blobs = each_blob_header do |header|
          if header.is_valid?
            # We have a non-deleted entry.
            begin
              @f.seek(header.addr + FlatFileBlobHeader::LENGTH)
              buf = @f.read(header.length)
              if buf.bytesize != header.length
                PEROBS.log.error "Premature end of file in blob with ID " +
                  "#{header.id}."
                discard_damaged_blob(header) if repair
                errors += 1
                next
              end

              # Uncompress the data if the compression bit is set in the mark
              # byte.
              if header.is_compressed?
                begin
                  buf = Zlib.inflate(buf)
                rescue Zlib::BufError, Zlib::DataError
                  PEROBS.log.error "Corrupted compressed block with ID " +
                    "#{header.id} found."
                  discard_damaged_blob(header) if repair
                  errors += 1
                  next
                end
              end

              if header.crc && checksum(buf) != header.crc
                PEROBS.log.error "Checksum failure while checking blob " +
                  "with ID #{header.id}"
                discard_damaged_blob(header) if repair
                errors += 1
                next
              end
            rescue IOError => e
              PEROBS.log.fatal "Check of blob with ID #{header.id} failed: " +
                e.message
            end

            # Check if the ID has already been found in the file.
            if (previous_address = new_index.get(header.id))
              PEROBS.log.error "Multiple blobs for ID #{header.id} found. " +
                "Addresses: #{previous_address}, #{header.addr}"
              errors += 1
              previous_header = FlatFileBlobHeader.read(@f, previous_address,
                                                        header.id)
              if repair
                # We have two blobs with the same ID and we must discard one of
                # them.
                if header.is_outdated?
                  discard_damaged_blob(header)
                elsif previous_header.is_outdated?
                  discard_damaged_blob(previous_header)
                else
                  PEROBS.log.error "None of the blobs with same ID have " +
                    "the outdated flag set. Deleting the smaller one."
                  errors += 1
                  discard_damaged_blob(header.length < previous_header.length ?
                                       header : previous_header)
                end
                next
              end
            else
              # ID is unique so far. Add it to the shadow index.
              new_index.insert(header.id, header.addr)
            end

          end

          pm.update(header.addr)
        end

        errors += corrupted_blobs
      end

      # We no longer need the new index.
      new_index.close
      new_index.erase

      if repair && corrupted_blobs > 0
        erase_index_files
        defragmentize
        regenerate_index_and_spaces
      else
        # Now we check the index data. It must be correct and the entries must
        # match the blob file. All entries in the index must be in the blob file
        # and vise versa.
        begin
          index_ok = @index.check do |id, address|
            has_id_at?(id, address)
          end
          x_check_errs = 0
          space_check_ok = true
          unless index_ok && (space_check_ok = @space_list.check(self)) &&
            (x_check_errs = cross_check_entries) == 0
            errors += 1 unless index_ok && space_check_ok
            errors += x_check_errs
            regenerate_index_and_spaces if repair
          end
        rescue PEROBS::FatalError
          errors += 1
          regenerate_index_and_spaces if repair
        end
      end

      sync if repair
      PEROBS.log.info "check_db completed in #{Time.now - t} seconds. " +
        "#{errors} errors found."

      errors
    end
def check(repair = false)
      errors = 0
      return errors unless @f

      t = Time.now
      PEROBS.log.info "Checking FlatFile database" +
        "#{repair ? ' in repair mode' : ''}..."

      # First check the database blob file. Each entry should be readable and
      # correct and all IDs must be unique. We use a shadow index to keep
      # track of the already found IDs.
      new_index = BTree.new(@db_dir, 'new-index', INDEX_BTREE_ORDER,
                            @progressmeter)
      new_index.erase
      new_index.open

      corrupted_blobs = 0
      @progressmeter.start('Checking blobs file', @f.size) do |pm|
        corrupted_blobs = each_blob_header do |header|
          if header.is_valid?
            # We have a non-deleted entry.
            begin
              @f.seek(header.addr + FlatFileBlobHeader::LENGTH)
              buf = @f.read(header.length)
              if buf.bytesize != header.length
                PEROBS.log.error "Premature end of file in blob with ID " +
                  "#{header.id}."
                discard_damaged_blob(header) if repair
                errors += 1
                next
              end

              # Uncompress the data if the compression bit is set in the mark
              # byte.
              if header.is_compressed?
                begin
                  buf = Zlib.inflate(buf)
                rescue Zlib::BufError, Zlib::DataError
                  PEROBS.log.error "Corrupted compressed block with ID " +
                    "#{header.id} found."
                  discard_damaged_blob(header) if repair
                  errors += 1
                  next
                end
              end

              if header.crc && checksum(buf) != header.crc
                PEROBS.log.error "Checksum failure while checking blob " +
                  "with ID #{header.id}"
                discard_damaged_blob(header) if repair
                errors += 1
                next
              end
            rescue IOError => e
              PEROBS.log.fatal "Check of blob with ID #{header.id} failed: " +
                e.message
            end

            # Check if the ID has already been found in the file.
            if (previous_address = new_index.get(header.id))
              PEROBS.log.error "Multiple blobs for ID #{header.id} found. " +
                "Addresses: #{previous_address}, #{header.addr}"
              errors += 1
              previous_header = FlatFileBlobHeader.read(@f, previous_address,
                                                        header.id)
              if repair
                # We have two blobs with the same ID and we must discard one of
                # them.
                if header.is_outdated?
                  discard_damaged_blob(header)
                elsif previous_header.is_outdated?
                  discard_damaged_blob(previous_header)
                else
                  PEROBS.log.error "None of the blobs with same ID have " +
                    "the outdated flag set. Deleting the smaller one."
                  errors += 1
                  discard_damaged_blob(header.length < previous_header.length ?
                                       header : previous_header)
                end
                next
              end
            else
              # ID is unique so far. Add it to the shadow index.
              new_index.insert(header.id, header.addr)
            end

          end

          pm.update(header.addr)
        end

        errors += corrupted_blobs
      end

      # We no longer need the new index.
      new_index.close
      new_index.erase

      if repair && corrupted_blobs > 0
        erase_index_files
        defragmentize
        regenerate_index_and_spaces
      else
        # Now we check the index data. It must be correct and the entries must
        # match the blob file. All entries in the index must be in the blob file
        # and vise versa.
        begin
          index_ok = @index.check do |id, address|
            has_id_at?(id, address)
          end
          x_check_errs = 0
          space_check_ok = true
          unless index_ok && (space_check_ok = @space_list.check(self)) &&
            (x_check_errs = cross_check_entries) == 0
            errors += 1 unless index_ok && space_check_ok
            errors += x_check_errs
            regenerate_index_and_spaces if repair
          end
        rescue PEROBS::FatalError
          errors += 1
          regenerate_index_and_spaces if repair
        end
      end

      sync if repair
      PEROBS.log.info "check_db completed in #{Time.now - t} seconds. " +
        "#{errors} errors found."

      errors
    end
Check (and repair) the FlatFile.
 @param repair [Boolean] True if errors should be fixed.
 @return [Integer] Number of errors found