/**
   * Parameter write indicates either an orderly close, or a fast close without backup.
   *
   * <p>When false, just closes the file.
   *
   * <p>When true, writes out all cached rows that have been modified and the free position pointer
   * for the *.data file and then closes the file.
   */
  public void close(boolean write) throws HsqlException {

    SimpleLog appLog = database.logger.appLog;

    try {
      if (cacheReadonly) {
        if (dataFile != null) {
          dataFile.close();
        }

        return;
      }

      StopWatch sw = new StopWatch();

      appLog.sendLine(SimpleLog.LOG_NORMAL, "DataFileCache.close(" + write + ") : start");

      if (write) {
        cache.saveAll();
        Trace.printSystemOut("saveAll: " + sw.elapsedTime());
        appLog.sendLine(SimpleLog.LOG_NORMAL, "DataFileCache.close() : save data");

        if (fileModified || freeBlocks.isModified()) {

          // set empty
          dataFile.seek(LONG_EMPTY_SIZE);
          dataFile.writeLong(freeBlocks.getLostBlocksSize());

          // set end
          dataFile.seek(LONG_FREE_POS_POS);
          dataFile.writeLong(fileFreePosition);

          // set saved flag;
          dataFile.seek(FLAGS_POS);

          int flag = BitMap.set(0, FLAG_ISSAVED);

          if (hasRowInfo) {
            flag = BitMap.set(flag, FLAG_ROWINFO);
          }

          dataFile.writeInt(flag);
          appLog.sendLine(SimpleLog.LOG_NORMAL, "DataFileCache.close() : flags");

          //
          if (dataFile.length() != fileFreePosition) {
            dataFile.seek(fileFreePosition);
          }

          appLog.sendLine(SimpleLog.LOG_NORMAL, "DataFileCache.close() : seek end");
          Trace.printSystemOut("pos and flags: " + sw.elapsedTime());
        }
      }

      if (dataFile != null) {
        dataFile.close();
        appLog.sendLine(SimpleLog.LOG_NORMAL, "DataFileCache.close() : close");

        dataFile = null;

        Trace.printSystemOut("close: " + sw.elapsedTime());
      }

      boolean empty = fileFreePosition == INITIAL_FREE_POS;

      if (empty) {
        fa.removeElement(fileName);
        fa.removeElement(backupFileName);
      }
    } catch (Throwable e) {
      appLog.logContext(e);

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