/**
   * Allocates file space for the row.
   *
   * <p>A Row is added by walking the list of CacheFree objects to see if there is available space
   * to store it, reusing space if it exists. Otherwise the file is grown to accommodate it.
   */
  private int setFilePos(CachedObject r) throws IOException {

    int rowSize = r.getStorageSize();
    int i = freeBlocks == null ? -1 : freeBlocks.get(rowSize);

    if (i == -1) {
      i = (int) (fileFreePosition / cacheFileScale);

      long newFreePosition = fileFreePosition + rowSize;

      if (newFreePosition > maxDataFileSize) {
        throw new IOException(Trace.getMessage(Trace.DATA_FILE_IS_FULL));
      }

      fileFreePosition = newFreePosition;
    }

    r.setPos(i);

    return i;
  }
  public synchronized CachedObject get(int i, PersistentStore store, boolean keep)
      throws HsqlException {

    if (i < 0) {
      return null;
    }

    try {
      CachedObject value = cache.get(i);

      if (value == null) {
        boolean result = readObject(i);

        if (!result) {
          return null;
        }

        value = store.get(rowIn);

        value.setPos(i);
        cache.put(i, value);
      }

      if (keep) {
        value.keepInMemory(true);
      }

      return value;
    } catch (IOException e) {
      database.logger.appLog.logContext("" + cache + " pos: " + i);
      database.logger.appLog.logContext(e);

      throw Trace.error(
          Trace.DATA_FILE_ERROR, Trace.DataFileCache_makeRow, new Object[] {e, fileName});
    }
  }