/**
   * Closes this Database using the specified mode.
   *
   * <p>
   *
   * <ol>
   *   <LI>closemode -1 performs SHUTDOWN IMMEDIATELY, equivalent to a poweroff or crash.
   *   <LI>closemode 0 performs a normal SHUTDOWN that checkpoints the database normally.
   *   <LI>closemode 1 performs a shutdown compact that scripts out the contents of any CACHED
   *       tables to the log then deletes the existing *.data file that contains the data for all
   *       CACHED table before the normal checkpoint process which in turn creates a new, compact
   *       *.data file.
   * </ol>
   */
  public void close(int closemode) {

    HsqlException he = null;

    setState(DATABASE_CLOSING);
    sessionManager.closeAllSessions();
    sessionManager.clearAll();

    if (filesReadOnly) {
      closemode = CLOSEMODE_IMMEDIATELY;
    }

    /**
     * @todo fredt - impact of possible error conditions in closing the log should be investigated
     *     for the CLOSEMODE_COMPACT mode
     */
    logger.closePersistence(closemode);
    lobManager.close();

    try {
      if (closemode == CLOSEMODE_COMPACT) {
        clearStructures();
        reopen();
        setState(DATABASE_CLOSING);
        logger.closePersistence(CLOSEMODE_NORMAL);
      }
    } catch (Throwable t) {
      if (t instanceof HsqlException) {
        he = (HsqlException) t;
      } else {
        he = Error.error(ErrorCode.GENERAL_ERROR, t.toString());
      }
    }

    logger.releaseLock();
    setState(DATABASE_SHUTDOWN);
    clearStructures();

    // fredt - this could change to avoid removing a db from the
    // DatabaseManager repository if there are pending getDatabase()
    // calls
    DatabaseManager.removeDatabase(this);

    if (he != null) {
      throw he;
    }
  }
  /**
   * Opens this database. The database should be opened after construction. or reopened by the
   * close(int closemode) method during a "shutdown compact". Closes the log if there is an error.
   */
  void reopen() {

    boolean isNew = false;

    setState(DATABASE_OPENING);

    try {
      nameManager = new HsqlNameManager(this);
      granteeManager = new GranteeManager(this);
      userManager = new UserManager(this);
      schemaManager = new SchemaManager(this);
      persistentStoreCollection = new PersistentStoreCollectionDatabase();
      isReferentialIntegrity = true;
      sessionManager = new SessionManager(this);
      collation = collation.getDefaultInstance();
      dbInfo = DatabaseInformation.newDatabaseInformation(this);
      txManager = new TransactionManager2PL(this);

      lobManager.createSchema();
      logger.openPersistence();

      isNew = logger.isNewDatabase;

      if (isNew) {
        userManager.createSAUser();
        schemaManager.createPublicSchema();
        lobManager.initialiseLobSpace();
        logger.checkpoint(false);
      }

      lobManager.open();
      dbInfo.setWithContent(true);
    } catch (Throwable e) {
      logger.closePersistence(Database.CLOSEMODE_IMMEDIATELY);
      logger.releaseLock();
      setState(DATABASE_SHUTDOWN);
      clearStructures();
      DatabaseManager.removeDatabase(this);

      if (!(e instanceof HsqlException)) {
        e = Error.error(ErrorCode.GENERAL_ERROR, e);
      }

      logger.logSevereEvent("could not reopen database", e);

      throw (HsqlException) e;
    }

    setState(DATABASE_ONLINE);
  }