Skip to content

File boot_sr.c

File List > cubrid > src > transaction > boot_sr.c

Go to the documentation of this file

/*
 * Copyright 2008 Search Solution Corporation
 * Copyright 2016 CUBRID Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

/*
 * boot_sr.c - Boot management (at server)
 */

#ident "$Id$"

#include "config.h"

#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#if defined(SOLARIS)
#include <netdb.h>
#endif /* SOLARIS */

/* for getcwd, possibly a candidate for the os_ library ? */
#if defined(WINDOWS)
#include <direct.h>
#else /* WINDOWS */
#include <unistd.h>
#endif /* WINDOWS */
#include <assert.h>

#include "boot_sr.h"

#include "area_alloc.h"
#include "btree.h"
#include "chartype.h"
#include "dbtran_def.h"
#include "error_manager.h"
#include "system_parameter.h"
#include "object_primitive.h"
#include "locator_sr.h"
#include "heap_file.h"
#include "system_catalog.h"
#include "transform.h"
#include "databases_file.h"
#include "language_support.h"
#include "message_catalog.h"
#include "perf_monitor.h"
#include "porting_inline.hpp"
#include "set_object.h"
#include "util_func.h"
#include "intl_support.h"
#include "serial.h"
#include "server_interface.h"
#include "jansson.h"
#include "pl_sr.h"
#include "xserver_interface.h"
#include "session.h"
#include "event_log.h"
#include "trace_log.h"
#include "tz_support.h"
#include "filter_pred_cache.h"
#include "scan_manager.h"
#include "slotted_page.h"
#include "thread_manager.hpp"
#include "double_write_buffer.hpp"
#include "xasl_cache.h"
#include "log_volids.hpp"
#include "vacuum.h"
#include "tde.h"
#include "porting.h"
#include "log_manager.h"
#include "catalog_class.h"

#if defined(SERVER_MODE)
#include "connection_sr.h"
#include "server_support.h"
#include "pl_sr.h"
#include "px_worker_manager_global.hpp"
#endif /* SERVER_MODE */

#if defined(WINDOWS)
#include "wintcp.h"
#else
#include "tcp.h"
#endif /* WINDOWS */

#if defined(ENABLE_SYSTEMTAP)
#include "probes.h"
#endif /* ENABLE_SYSTEMTAP */
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"

#define BOOT_LEAVE_SAFE_OSDISK_PARTITION_FREE_SPACE  \
  (1250 * (IO_DEFAULT_PAGE_SIZE / IO_PAGESIZE)) /* 5 Mbytes */

#define BOOT_FORMAT_MAX_LENGTH  500
#define BOOTSR_MAX_LINE  500

#define BOOT_LOB_TEMP_DIR_KEYWORD "ces"

typedef struct boot_dbparm BOOT_DB_PARM;
struct boot_dbparm
{
  VFID trk_vfid;        /* Tracker of files */
  HFID hfid;            /* Heap file where this information is stored. It is only used for validation purposes */
  HFID rootclass_hfid;      /* Heap file where classes are stored */
  EHID classname_table;     /* The hash file of class names */
  CTID ctid;            /* The catalog file */
  /* TODO: Remove me */
  VFID query_vfid;      /* Query file */
  char rootclass_name[10];  /* Name of the root class */
  OID rootclass_oid;        /* OID of the root class */
  VOLID nvols;          /* Number of volumes that have been created */
  VOLID temp_nvols;     /* Number of temporary volumes that have been created */
  VOLID last_volid;     /* Next volume identifier */
  VOLID temp_last_volid;    /* Next temporary volume identifier. This goes from a higher number to a lower number */
  int vacuum_log_block_npages;  /* Number of pages for vacuum data file */
  VFID vacuum_data_vfid;    /* Vacuum data file identifier */
  VFID dropped_files_vfid;  /* Vacuum dropped files file identifier */
  HFID tde_keyinfo_hfid;    /* Heap file where tde key info (TDE_KEYINFO) is stored */
};

enum remove_temp_vol_action
{ REMOVE_TEMP_VOL_DEFAULT_ACTION, ONLY_PHYSICAL_REMOVE_TEMP_VOL_ACTION };
typedef enum remove_temp_vol_action REMOVE_TEMP_VOL_ACTION;

#if defined(SA_MODE)
extern void boot_client_all_finalize (int final_level);
#endif /* SA_MODE */


BOOT_SERVER_STATUS boot_Server_status = BOOT_SERVER_DOWN;

#if defined(SERVER_MODE)
bool boot_Enabled_flush_daemons = false;
#endif /* SERVER_MODE */

#if defined(SERVER_MODE)
/* boot_cl.c:boot_Host_name[] if CS_MODE and SA_MODE */
char boot_Host_name[CUB_MAXHOSTNAMELEN] = "";
#endif /* SERVER_MODE */

/*
 * database parameter variables that do not change over time
 */
static char boot_Db_full_name[PATH_MAX];
static OID boot_Header_oid; /* Location of parameters */
static BOOT_DB_PARM boot_Struct_db_parm;    /* The structure */
static BOOT_DB_PARM *boot_Db_parm = &boot_Struct_db_parm;
static OID *boot_Db_parm_oid = &boot_Header_oid;
static char boot_Lob_path[PATH_MAX + LOB_PATH_PREFIX_MAX] = "";
static bool skip_to_check_ct_classes_for_rebuild = false;
static char boot_Server_session_key[SERVER_SESSION_KEY_SIZE];

#if defined(SERVER_MODE)
static bool boot_Set_server_at_exit = false;
static int boot_Server_process_id = 1;
#endif /* SERVER_MODE */


/* Functions */
static int boot_get_db_parm (THREAD_ENTRY * thread_p, BOOT_DB_PARM * dbparm, OID * dbparm_oid);
static int boot_remove_temp_volume (THREAD_ENTRY * thread_p, VOLID volid, const char *vlabel);

static int boot_remove_all_temp_volumes (THREAD_ENTRY * thread_p, REMOVE_TEMP_VOL_ACTION delete_action);
static void boot_make_temp_volume_fullname (char *temp_vol_fullname, VOLID temp_volid);
static void boot_remove_unknown_temp_volumes (THREAD_ENTRY * thread_p);
static int boot_parse_add_volume_extensions (THREAD_ENTRY * thread_p, const char *filename_addmore_vols);
static int boot_find_rest_volumes (THREAD_ENTRY * thread_p, BO_RESTART_ARG * r_args, VOLID volid,
                   int (*fun) (THREAD_ENTRY * thread_p, VOLID xvolid, const char *vlabel, void *args),
                   void *args);
static int boot_find_rest_permanent_volumes (THREAD_ENTRY * thread_p, bool newvolpath, bool use_volinfo, VOLID volid,
                         int (*fun) (THREAD_ENTRY * thread_p, VOLID xvolid, const char *vlabel,
                             void *args), void *args);

static void boot_remove_temp_volumes (THREAD_ENTRY * thread_p);
static int boot_check_permanent_volumes (THREAD_ENTRY * thread_p);
static int boot_mount (THREAD_ENTRY * thread_p, VOLID volid, const char *vlabel, void *ignore_arg);
static char *boot_find_new_db_path (char *db_pathbuf, const char *fileof_vols_and_wherepaths);
static int boot_create_all_volumes (THREAD_ENTRY * thread_p, const BOOT_CLIENT_CREDENTIAL * client_credential,
                    const char *db_comments, DKNPAGES db_npages, const char *file_addmore_vols,
                    const char *log_path, const char *log_prefix, DKNPAGES log_npages,
                    int client_lock_wait, TRAN_ISOLATION client_isolation);
static int boot_remove_all_volumes (THREAD_ENTRY * thread_p, const char *db_fullname, const char *log_path,
                    const char *log_prefix, bool dirty_rem, bool force_delete);
static char *boot_volume_info_log_path (char *log_path);
static void boot_remove_useless_path_separator (const char *path, char *new_path);
static void boot_ctrl_c_in_init_server (int ignore_signo);

#if defined(CUBRID_DEBUG)
static void boot_check_db_at_num_shutdowns (bool force_nshutdowns);
#endif /* CUBRID_DEBUG */

#if defined(SERVER_MODE)
static void boot_shutdown_server_at_exit (void);
#endif /* SERVER_MODE */

static INTL_CODESET boot_get_db_charset_from_header (THREAD_ENTRY * thread_p, const char *log_path,
                             const char *log_prefix);
STATIC_INLINE int boot_db_parm_update_heap (THREAD_ENTRY * thread_p) __attribute__ ((ALWAYS_INLINE));

static int boot_after_copydb (THREAD_ENTRY * thread_p);

static int boot_generate_tde_keys (THREAD_ENTRY * thread_p);

/*
 * bo_server) -set server's status, UP or DOWN
 *   return: void
 *   status(in) :
 */
void
boot_server_status (BOOT_SERVER_STATUS status)
{
  static const char *status_str[] = { "UNKNOWN", "UP", "DOWN", "MAINTENANCE" };
  if (status >= BOOT_SERVER_UP && status <= BOOT_SERVER_MAINTENANCE)
    {
      boot_Server_status = status;
      er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_BO_SERVER_STATUS, 1, status_str[status]);
#if defined(SERVER_MODE)
      if (boot_Set_server_at_exit == false)
    {
      boot_Set_server_at_exit = true;
      boot_Server_process_id = getpid ();
      (void) atexit (boot_shutdown_server_at_exit);
    }
#endif /* SERVER_MODE */
    }
}

#if defined(SERVER_MODE)
/*
 * bo_shutdown_server_at_exit () - make sure that the server is shutdown at exit
 *
 * return : nothing
 *
 * Note: This function is called when the invoked program terminates normally.
 *       This function make sure that the server is shutdown gracefully.
 */
static void
boot_shutdown_server_at_exit (void)
{
  if (BO_IS_SERVER_RESTARTED () && boot_Server_process_id == getpid ())
    {
      /* Avoid infinite looping if someone calls exit during shutdown */
      boot_Server_process_id++;
      THREAD_ENTRY *thread_p = thread_get_thread_entry_info ();
      (void) xboot_shutdown_server (thread_p, ER_ALL_FINAL);
    }
}

/*
 * boot_donot_shutdown_server_at_exit () - do not shutdown server at exist.
 *
 * return : nothing
 *
 * Note: This function must be called when the system needs to exit without
 *       shutting down the system (e.g., in case of fatal failure).
 */
void
boot_donot_shutdown_server_at_exit (void)
{
  if (BO_IS_SERVER_RESTARTED () && boot_Server_process_id == getpid ())
    {
      boot_Server_process_id++;
    }
}
#endif /* SERVER_MODE */

/*
 * boot_get_db_parm () - retrieve database parameters from disk
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 *   dbparm(out): database parameter structure
 *   dbparm_oid(in): oid of parameter object
 *
 * Note: Retrieve the database boot/restart parameters from disk.
 */
static int
boot_get_db_parm (THREAD_ENTRY * thread_p, BOOT_DB_PARM * dbparm, OID * dbparm_oid)
{
  RECDES recdes;
  HEAP_SCANCACHE scan_cache;
  SCAN_CODE scan = S_SUCCESS;

  recdes.area_size = recdes.length = DB_SIZEOF (*dbparm);
  recdes.data = (char *) dbparm;

  heap_scancache_quick_start_with_class_hfid (thread_p, &scan_cache, &boot_Db_parm->hfid);
  scan = heap_first (thread_p, &boot_Db_parm->hfid, NULL, dbparm_oid, &recdes, &scan_cache, COPY);
  heap_scancache_end (thread_p, &scan_cache);

  if (scan != S_SUCCESS)
    {
      assert (false);
      return ER_FAILED;
    }

  return NO_ERROR;
}

/*
 * boot_find_root_heap () - find the root heap
 *
 * return: NO_ERROR
 *
 * Note: Find the heap where the classes are stored.
 */
int
boot_find_root_heap (HFID * root_hfid_p)
{
  assert (root_hfid_p != NULL);
  assert (!HFID_IS_NULL (&boot_Db_parm->rootclass_hfid));

  HFID_COPY (root_hfid_p, &boot_Db_parm->rootclass_hfid);

  return NO_ERROR;
}

/*
 * xboot_find_number_permanent_volumes () - find the number of permanent volumes
 *
 * return : number of permanent volumes
 */
int
xboot_find_number_permanent_volumes (THREAD_ENTRY * thread_p)
{
  int nvols;

  /* wait for disk extensions to finish. */
  disk_lock_extend ();
  nvols = boot_Db_parm->nvols;
  disk_unlock_extend ();

  return nvols;
}

/*
 * xboot_find_number_temp_volumes () - find the number of temporary volumes
 *
 * return : number of temporary volumes
 */
int
xboot_find_number_temp_volumes (THREAD_ENTRY * thread_p)
{
  int nvols;

  /* wait for disk extensions to finish. */
  disk_lock_extend ();
  nvols = boot_Db_parm->temp_nvols;
  disk_unlock_extend ();

  return nvols;
}

/*
 * xboot_find_last_permanent () - find the volid of last permanent volume
 *
 * return : volid of last permanent volume
 */
VOLID
xboot_find_last_permanent (THREAD_ENTRY * thread_p)
{
  VOLID volid;

  /* wait for disk extensions to finish. */
  disk_lock_extend ();
  volid = boot_Db_parm->last_volid;
  disk_unlock_extend ();

  return volid;
}

/*
 * xboot_peek_last_permanent () - peek the volid of last permanent volume
 *
 * return : volid of last permanent volume
 * NOTE: this function does not wait for extensions to finish
 */
VOLID
xboot_peek_last_permanent (THREAD_ENTRY * thread_p)
{
  return boot_Db_parm->last_volid;
}

/*
 * xboot_find_last_temp () - find the volid of next temporary volume
 *
 * return : volid of next temporary volume
 */
VOLID
xboot_find_last_temp (THREAD_ENTRY * thread_p)
{
  VOLID volid;

  /* wait for disk extensions to finish. */
  disk_lock_extend ();
  volid = boot_Db_parm->temp_last_volid;
  disk_unlock_extend ();

  return volid;
}

/*
 * boot_find_next_permanent_volid () - find next volid for a permanent volume
 *
 * return : next volid for a permanent volume
 */
VOLID
boot_find_next_permanent_volid (THREAD_ENTRY * thread_p)
{
  VOLID volid;

  /* wait for disk extensions to finish. */
  disk_lock_extend ();
  volid = boot_Db_parm->last_volid + 1;
  disk_unlock_extend ();

  return volid;
}

/*
 * boot_reset_db_parm () - reset database initialization parameters
 *                      (must be used only be log/recovery manager)
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 * Note: Reset database initialization parameters. It is used only during
 *       recovery of the database.
 */
int
boot_reset_db_parm (THREAD_ENTRY * thread_p)
{
  return boot_get_db_parm (thread_p, boot_Db_parm, boot_Db_parm_oid);
}

/*
 * boot_db_name () - find the name of the database
 *
 * return : name of the database
 *
 */
const char *
boot_db_name (void)
{
  return fileio_get_base_file_name (boot_Db_full_name);
}

/*
 * boot_db_full_name () - return current database full name.
 *
 * return : database full name
 */
const char *
boot_db_full_name ()
{
  return boot_Db_full_name;
}

/*
 * boot_get_lob_path - return the lob path which is read from databases.txt
 */
const char *
boot_get_lob_path (void)
{
  return boot_Lob_path;
}

/*
 * boot_remove_temp_volume () - remove a volume from the database
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 *   volid(in): Volume identifier to remove
 *
 * Note: Remove a volume from the database. The deletion of the volume is done
 *       independently of the destiny of the current transaction. That is,
 *       if this function finishes successfully the removal is made permanent,
 *       if the function fails, whatever was done is aborted.
 *       Currently, we do not allow to remove permanent volumes. In the future
 *       we may allow the removal of any volume but the primary volume
 *       (LOG_DBFIRST_VOLID).
 */
static int
boot_remove_temp_volume (THREAD_ENTRY * thread_p, VOLID volid, const char *vlabel)
{
  /* Make sure that this is a temporary volume */
  if (volid < boot_Db_parm->temp_last_volid)
    {
      if (volid >= LOG_DBFIRST_VOLID && volid <= boot_Db_parm->last_volid)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_TRYING_TO_REMOVE_PERMANENT_VOLUME, 1,
          fileio_get_volume_label (volid, PEEK));
      return ER_BO_TRYING_TO_REMOVE_PERMANENT_VOLUME;
    }
      else
    {
      er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_FILE_UNKNOWN_VOLID, 1, volid);
      return ER_FILE_UNKNOWN_VOLID;
    }
    }

  /* Do the following for temporary volumes */
  boot_Db_parm->temp_nvols--;
  if (boot_Db_parm->temp_nvols <= 0)
    {
      boot_Db_parm->temp_last_volid = NULL_VOLID;
    }
  else if (boot_Db_parm->temp_last_volid == volid)
    {
      boot_Db_parm->temp_last_volid = volid + 1;
    }

  /* The volume is not known by the system any longer. */
  (void) pgbuf_invalidate_all (thread_p, volid);

  fileio_unformat (thread_p, vlabel);

  return NO_ERROR;
}

/*
 * xboot_add_volume_extension () - add a volume extension to the database
 *
 * return : volid or NULL_VOLID (in case of failure)
 *
 *   ext_info(in): volume info
 *
 * Note: Add a volume extension to the database. The addition of the volume
 *       is a system operation that will be either aborted in case of failure
 *       or committed in case of success, independently on the destiny of the
 *       current transaction. The volume becomes immediately available to other
 *       transactions.
 */
VOLID
xboot_add_volume_extension (THREAD_ENTRY * thread_p, DBDEF_VOL_EXT_INFO * ext_info)
{
  VOLID volid;

  if (disk_add_volume_extension
      (thread_p, ext_info->purpose, ext_info->voltype, ext_info->max_npages, ext_info->path, ext_info->name,
       ext_info->comments, ext_info->max_writesize_in_sec, ext_info->overwrite, &volid) != NO_ERROR)
    {
      ASSERT_ERROR ();
      return NULL_VOLID;
    }
  assert (volid != NULL_VOLID);
  return volid;
}

/*
 * boot_remove_useless_path_separator () - Remove useless PATH_SEPARATOR in path string
 *
 * return : true or false(in case of fail)
 *
 *   path(in): Original path.
 *   new_path(out): Transformed path.
 *
 * Note: This function removes useless PATH_SEPARATOR in path string.
 *       For example,
 *       /home3/CUBRID/DB/               -->  /home3/CUBRID/DB
 *       C:\CUBRID\\\Databases\\         -->  C:\CUBRID\Databases
 *       \\pooh\user\                    -->  \\pooh\user
 *
 *       After transform..
 *       If new path string is "/" or "\", don't remove the last slash.
 *       It is survived.
 */
static void
boot_remove_useless_path_separator (const char *path, char *new_path)
{
  int slash_num = 0;        /* path separator counter */

  /* path must be not null */
  assert (path != NULL);
  assert (new_path != NULL);

  /*
   * Before transform.
   *   / h o m e 3 / / w o r k / c u b r i d / / / w o r k /
   *
   * After transform.
   *   / h o m e 3   / w o r k / c u b r i d     / w o r k
   */

  /* Consume the preceding continuous slash chars. */
  while (*path == PATH_SEPARATOR)
    {
      slash_num++;
      path++;
    }

  /* If there is preceding consumed slash, append PATH_SEPARATOR */
  if (slash_num)
    {
      *new_path++ = PATH_SEPARATOR;
#if defined(WINDOWS)
      /*
       * In Windows/NT,
       * If first duplicated PATH_SEPARATORs are appeared, they are survived.
       * For example,
       * \\pooh\user\ -> \\pooh\user(don't touch the first duplicated PATH_SEPARATORs)
       */
      if (slash_num > 1)
    {
      *new_path++ = PATH_SEPARATOR;
    }
#endif /* WINDOWS */
    }

  /* Initialize separator counter again. */
  slash_num = 0;

  /*
   * If current character is PATH_SEPARATOR,
   *    skip after increasing separator counter.
   * If current character is normal character, copy to new_path.
   */
  while (*path)
    {
      if (*path == PATH_SEPARATOR)
    {
      slash_num++;
    }
      else
    {
      /*
       * If there is consumed slash, append PATH_SEPARATOR.
       * Initialize separator counter.
       */
      if (slash_num)
        {
          *new_path++ = PATH_SEPARATOR;
          slash_num = 0;
        }
      *new_path++ = *path;
    }
      path++;
    }

  /* Assure null terminated string */
  *new_path = '\0';
}

/*
 * boot_parse_add_volume_extensions () - add a set of volume extensions
 *                                       to the database
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 *   filename_addmore_vols(in): File name where the volume specifications are
 *                              found
 *
 * Note: A set of volume extensions are added to the database. The given
 *       parameter is a file which indicates the specifications for all
 *       the volumes to be created. A volume is specified by ONE LINE which
 *       can contain the following parameters:
 *       [NAME volname] [PATH volpath] [COMMENTS volcomments]
 *                      [PURPOSE volpurpose] PAGES volnpages
 *
 *       The additions of the volumes is a system operations that will be either
 *       aborted in case of failure or committed in case of success,
 *       independently on the destiny of the current transaction. The volume
 *       becomes immediately available to other transactions.
 */
static int
boot_parse_add_volume_extensions (THREAD_ENTRY * thread_p, const char *filename_addmore_vols)
{
  FILE *fp;
  char input_buffer[BOOTSR_MAX_LINE + 1];
  char *line;
  char *token;
  char *token_value;
  char *ext_name;
  char *ext_path;
  char *ext_comments;
  DKNPAGES ext_npages;
  DISK_VOLPURPOSE ext_purpose;
  int line_num = 0;
  int error_code = NO_ERROR;
  VOLID volid = NULL_VOLID;

  fp = fopen (filename_addmore_vols, "r");
  if (fp == NULL)
    {
      er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_USER_FILE_UNKNOWN, 1, filename_addmore_vols);
      return ER_LOG_USER_FILE_UNKNOWN;
    }

  /*
   * Get a line
   * Continue parsing even in case of error, so that we can indicate as
   * many errors as possible.
   */

  while ((line = fgets (input_buffer, BOOTSR_MAX_LINE, fp)) != NULL)
    {
      line_num++;

      /* Ignore lines with comments */

      if (line[0] == '\0' || line[0] == '#')
    {
      continue;
    }

      ext_npages = (DKNPAGES) strlen (line);
      if (line[ext_npages - 1] != '\n')
    {
      line[ext_npages] = '\n';
      line[ext_npages + 1] = '\0';
    }

      /*
       * Parse the line
       */

      ext_name = NULL;
      ext_path = NULL;
      ext_comments = NULL;
      ext_npages = 0;
      ext_purpose = DB_PERMANENT_DATA_PURPOSE;

      while (true)
    {
      /*
       * Read token.. skip leading whitespace and comments
       */
      while (char_isspace (line[0]))
        {
          line++;
        }

      if (line[0] == '\0')
        {
          break;
        }

      token = line;

      do
        {
          line++;
        }
      while (!char_isspace (line[0]));
      line[0] = '\0';
      line++;

      /*
       * Skip any whitespace before the value.
       */

      while (char_isspace (line[0]))
        {
          line++;
        }

      token_value = line;

      /*
       * If string in " xxx " or ' xxxx ' find its delimiter
       */

      if (token_value[0] == '"' || token_value[0] == '\'')
        {
          int delim;

          delim = token_value[0];
          token_value++;
          do
        {
          line++;
        }
          while (line[0] != delim);
          line[0] = '\0';
          line++;
        }
      else
        {
          do
        {
          line++;
        }
          while (!char_isspace (line[0]));
          line[0] = '\0';
          line++;
        }

      if (intl_mbs_casecmp (token, "NAME") == 0)
        {
          /* Name of volume */
          ext_name = token_value;
        }
      else if (intl_mbs_casecmp (token, "PATH") == 0)
        {
          ext_path = token_value;
        }
      else if (intl_mbs_casecmp (token, "COMMENTS") == 0)
        {
          ext_comments = token_value;
        }
      else if (intl_mbs_casecmp (token, "PURPOSE") == 0)
        {
          if (intl_mbs_casecmp (token_value, "DATA") == 0)
        {
          ext_purpose = DB_PERMANENT_DATA_PURPOSE;
        }
          else if (intl_mbs_casecmp (token_value, "INDEX") == 0)
        {
          ext_purpose = DB_PERMANENT_DATA_PURPOSE;
        }
          else if (intl_mbs_casecmp (token_value, "TEMP") == 0)
        {
          ext_purpose = DB_TEMPORARY_DATA_PURPOSE;
        }
          else if (intl_mbs_casecmp (token_value, "GENERIC") == 0)
        {
          ext_purpose = DB_PERMANENT_DATA_PURPOSE;
        }
          else
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_PARSE_ADDVOLS_UNKNOWN_PURPOSE, 2, token_value,
              line_num);
          error_code = ER_BO_PARSE_ADDVOLS_UNKNOWN_PURPOSE;
          break;
        }
        }
      else if (intl_mbs_casecmp (token, "NPAGES") == 0)
        {
          if (sscanf (token_value, "%i", (int *) &ext_npages) != 1)
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_PARSE_ADDVOLS_NOGIVEN_NPAGES, 1, line_num);
          error_code = ER_BO_PARSE_ADDVOLS_NOGIVEN_NPAGES;
          break;
        }
          else if (ext_npages <= 0)
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_PARSE_ADDVOLS_BAD_NPAGES, 2, ext_npages, line_num);
          break;
        }
        }
      else
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_PARSE_ADDVOLS_UNKNOWN_TOKEN, 2, token, line_num);
        }
    }

      /*
       * Add the volume
       */
      if (error_code != NO_ERROR || (ext_name == NULL && ext_path == NULL && ext_comments == NULL && ext_npages == 0))
    {
      continue;
    }

      if (ext_npages <= 0)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_PARSE_ADDVOLS_NOGIVEN_NPAGES, 1, line_num);
      error_code = ER_BO_PARSE_ADDVOLS_NOGIVEN_NPAGES;
      continue;
    }

      error_code =
    disk_add_volume_extension (thread_p, ext_purpose, DB_PERMANENT_VOLTYPE, ext_npages, ext_path, ext_name,
                   ext_comments, 0, false, &volid);
      if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      break;
    }
      assert (volid != NULL_VOLID);
    }
  fclose (fp);

  return error_code;
}

/*
 * boot_remove_all_temp_volumes () - remove all temporary volumes from the database
 *
 * return: NO_ERROR if all OK, ER_ status otherwise
 */
static int
boot_remove_all_temp_volumes (THREAD_ENTRY * thread_p, REMOVE_TEMP_VOL_ACTION delete_action)
{
  int error_code = NO_ERROR;

  /* if volumes exist beyond bo_Dbparm.temp_last_volid, we remove the volumes.
   * there is no logging to add or remove a temporary temp volume, but logging to update bo_Dbparm.
   * so, unknown volumes can be possible to exist.
   */
  if (!BO_IS_SERVER_RESTARTED ())
    {
      boot_remove_unknown_temp_volumes (thread_p);
    }

  if (boot_Db_parm->temp_nvols == 0)
    {
      assert (boot_Db_parm->temp_last_volid == NULL_VOLID);
      return NO_ERROR;
    }

  boot_remove_temp_volumes (thread_p);

  if (delete_action == ONLY_PHYSICAL_REMOVE_TEMP_VOL_ACTION)
    {
      return NO_ERROR;
    }

  if (boot_Db_parm->temp_nvols != 0 || boot_Db_parm->temp_last_volid != NULL_VOLID)
    {
      /* something bad happened. Reset it anyway. */
      boot_Db_parm->temp_nvols = 0;
      boot_Db_parm->temp_last_volid = NULL_VOLID;
    }

  error_code = boot_db_parm_update_heap (thread_p);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      return error_code;
    }

  return error_code;
}

static void
boot_make_temp_volume_fullname (char *temp_vol_fullname, VOLID temp_volid)
{
  const char *temp_path;
  const char *temp_name;
  char *alloc_tempath = NULL;

  assert (temp_vol_fullname != NULL);

  temp_vol_fullname[0] = '\0';

  alloc_tempath = (char *) malloc (strlen (boot_Db_full_name) + 1);
  if (alloc_tempath == NULL)
    {
      return;
    }
  temp_path = (char *) prm_get_string_value (PRM_ID_IO_TEMP_VOLUME_PATH);
  if (temp_path == NULL || temp_path[0] == '\0')
    {
      temp_path = fileio_get_directory_path (alloc_tempath, boot_Db_full_name);
    }
  temp_name = fileio_get_base_file_name (boot_Db_full_name);

  fileio_make_volume_temp_name (temp_vol_fullname, temp_path, temp_name, temp_volid);

  if (alloc_tempath)
    {
      free_and_init (alloc_tempath);
    }
}

/*
 * boot_remove_unknown_temp_volumes () -
 *
 * return: none
 */
static void
boot_remove_unknown_temp_volumes (THREAD_ENTRY * thread_p)
{
  VOLID temp_volid;
  char temp_vol_fullname[PATH_MAX];

  if (boot_Db_parm->temp_last_volid == NULL_VOLID)
    {
      temp_volid = LOG_MAX_DBVOLID;
    }
  else
    {
      temp_volid = boot_Db_parm->temp_last_volid - 1;
    }

  for (; temp_volid > boot_Db_parm->last_volid; temp_volid--)
    {
      boot_make_temp_volume_fullname (temp_vol_fullname, temp_volid);
      if (!fileio_is_volume_exist (temp_vol_fullname))
    {
      break;
    }
      er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_BO_UNKNOWN_VOLUME, 1, temp_vol_fullname);
      fileio_unformat (thread_p, temp_vol_fullname);
    }
}

/*
 * boot_find_rest_volumes () - call function on the rest of vols
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 *   r_args(in): restart argument structure contains various options
 *   volid(in): Volume identifier
 *   fun(in): Function to call on volid, vlabel, and arguments
 *   args(in): Extra arguments for function to call
 *
 * Note: The given function is called for every single volume which is different from the given one.
 */
static int
boot_find_rest_volumes (THREAD_ENTRY * thread_p, BO_RESTART_ARG * r_args, VOLID volid,
            int (*fun) (THREAD_ENTRY * thread_p, VOLID xvolid, const char *vlabel, void *args), void *args)
{
  int error_code = NO_ERROR;
  bool check;

  if (r_args != NULL)
    {
      check = r_args->newvolpath;
    }
  else
    {
      check = false;
    }

  error_code = boot_find_rest_permanent_volumes (thread_p, check, true, volid, fun, args);
  if (error_code != NO_ERROR)
    {
      return error_code;
    }

  /* We don't want to mount temp vols during bootstrapping,
   * since temp vols might be inaccessible for a crash case and will be removed soon.
   */

  return error_code;
}

/*
 * boot_find_rest_permanent_volumes () - call function on the rest of permanent vols of database
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 *   newvolpath(in): restore the database and log volumes to the path specified in the database-loc-file.
 *   use_volinfo(in): use volinfo indicator
 *   volid(in): Volume identifier
 *   fun(in): Function to call on volid, vlabel, and arguments
 *   args(in): Extra arguments for function to call
 *
 * Note: The given function is called for every single permanent volume which is different from the given one.
 */
static int
boot_find_rest_permanent_volumes (THREAD_ENTRY * thread_p, bool newvolpath, bool use_volinfo, VOLID volid,
                  int (*fun) (THREAD_ENTRY * thread_p, VOLID xvolid, const char *vlabel, void *args),
                  void *args)
{
  DKNVOLS num_vols = 0;
  int error_code = NO_ERROR;

  if (newvolpath || !use_volinfo
      || (num_vols = logpb_scan_volume_info (thread_p, NULL, volid, LOG_DBFIRST_VOLID, fun, args)) == -1)
    {
      /* Don't use volume info .. or could not find volume info .. or it was bad */
      VOLID next_volid = LOG_DBFIRST_VOLID; /* Next volume identifier */
      char next_vol_fullname[PATH_MAX]; /* Next volume name */

      num_vols = 0;

      /* First the primary volume, then the rest of the volumes */
      /*
       * Do not assume that all the volumes are mounted. This function may be called to mount the volumes.
       * Thus, request to current volume for the next volume instead of going directly through the volume identifier.
       */
      strcpy (next_vol_fullname, boot_Db_full_name);
      for (next_volid = LOG_DBFIRST_VOLID; next_volid != NULL_VOLID;)
    {
      num_vols++;
      if (next_volid != volid)
        {
          error_code = (*fun) (thread_p, next_volid, next_vol_fullname, args);
          if (error_code != NO_ERROR)
        {
          return error_code;
        }
        }
      /* update next_volid and next_vol_fullname */
      if (disk_get_link (thread_p, next_volid, &next_volid, next_vol_fullname) == NULL)
        {
          return ER_FAILED;
        }
    }

      if (use_volinfo == true)
    {
      /* The volume info was not found.. Recreate it with the current information */
      (void) logpb_recreate_volume_info (thread_p);
    }
    }
  else
    {
      /* Add the volume that was ignored, as long as it is in the range of a valid one */
      if (volid != NULL_VOLID && volid >= LOG_DBFIRST_VOLID && volid <= boot_Db_parm->last_volid)
    {
      num_vols++;
    }

      if (num_vols != boot_Db_parm->nvols)
    {
      error_code = boot_find_rest_permanent_volumes (thread_p, newvolpath, false, volid, fun, args);
      if (error_code != NO_ERROR)
        {
          /* Still could not mount or find all necessary volumes */
          er_set (ER_SYNTAX_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_INCONSISTENT_NPERM_VOLUMES, 2, num_vols,
              boot_Db_parm->nvols);
          return error_code;
        }

      (void) logpb_recreate_volume_info (thread_p);
      return NO_ERROR;
    }
    }

  if (num_vols < boot_Db_parm->nvols)
    {
      return ER_FAILED;
    }

  return error_code;
}

/*
 * boot_remove_temp_volumes () - Find temporary volumes and remove them
 *
 * Note: The given function is called for every single temporary volume which is different from the given one.
 */
static void
boot_remove_temp_volumes (THREAD_ENTRY * thread_p)
{
  VOLID temp_volid;
  char temp_vol_fullname[PATH_MAX];
  const char *temp_path;
  const char *temp_name;
  char *alloc_tempath = NULL;

  /*
   * Get the name of the extension: ext_path|dbname|"ext"|volid
   */

  /* Use the directory where the primary volume is located */
  alloc_tempath = (char *) malloc (strlen (boot_Db_full_name) + 1);
  if (alloc_tempath == NULL)
    {
      return;
    }
  temp_path = (char *) prm_get_string_value (PRM_ID_IO_TEMP_VOLUME_PATH);
  if (temp_path == NULL || temp_path[0] == '\0')
    {
      temp_path = fileio_get_directory_path (alloc_tempath, boot_Db_full_name);
    }
  temp_name = fileio_get_base_file_name (boot_Db_full_name);

  for (temp_volid = boot_Db_parm->temp_last_volid; temp_volid <= LOG_MAX_DBVOLID; temp_volid++)
    {
      fileio_make_volume_temp_name (temp_vol_fullname, temp_path, temp_name, temp_volid);
      if (fileio_is_volume_exist (temp_vol_fullname) == true)
    {
      (void) boot_remove_temp_volume (thread_p, temp_volid, temp_vol_fullname);
    }
    }

  if (alloc_tempath)
    {
      free_and_init (alloc_tempath);
    }
}

/*
 * boot_check_permanent_volumes () - check consistency of permanent volume names and number
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 * Note: Make sure that we can reach the expected number of volumes
 *       using the internal link list of permananet volumes.
 */
static int
boot_check_permanent_volumes (THREAD_ENTRY * thread_p)
{
  VOLID num_vols = 0;
  VOLID volid = LOG_DBFIRST_VOLID;  /* Current volume identifier */
  VOLID next_volid = LOG_DBFIRST_VOLID; /* Next volume identifier */
  char next_vol_fullname[PATH_MAX]; /* Next volume name */
  const char *vlabel;

  /*
   * Don't use volinfo .. or could not find volinfo
   */

  /* First the primary volume, then the rest of the volumes */
  num_vols = 0;
  strcpy (next_vol_fullname, boot_Db_full_name);

  /*
   * Do not assume that all the volumes are mounted. This function may be
   * called to mount the volumes. Thus, request to current volume for the
   * next volume instead of going directly through the volume identifier.
   */
  do
    {
      num_vols++;
      /* Have to make sure a label exists, before we try to use it below */
      vlabel = fileio_get_volume_label (volid, PEEK);
      if (vlabel == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
      return ER_GENERIC_ERROR;
    }

      if (util_compare_filepath (next_vol_fullname, vlabel) != 0)
    {
      /*
       * Names are different. The database was renamed outside the domain of
       * the database (e.g., in Unix), or this is not a database.
       * If volume information is not present, assume that this is not a
       * database
       */
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_BO_NOT_A_VOLUME, 1, vlabel);
    }
      if (disk_get_link (thread_p, volid, &next_volid, next_vol_fullname) == NULL)
    {
      return ER_GENERIC_ERROR;
    }

      volid = next_volid;
    }
  while (volid != NULL_VOLID);

  if (num_vols != boot_Db_parm->nvols)
    {
      er_set (ER_SYNTAX_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_INCONSISTENT_NPERM_VOLUMES, 2, num_vols,
          boot_Db_parm->nvols);
      return ER_BO_INCONSISTENT_NPERM_VOLUMES;
    }

  return NO_ERROR;
}

/*
 * boot_mount () - mount given volume
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 *   volid(in): Volume identifier
 *   vlabel(in): Volume label
 *   arg_ignore: Unused
 */
static int
boot_mount (THREAD_ENTRY * thread_p, VOLID volid, const char *vlabel, void *ignore_arg)
{
  char check_vlabel[PATH_MAX];
  int vdes;

  vdes = fileio_mount (thread_p, boot_Db_full_name, vlabel, volid, false, false);
  if (vdes == NULL_VOLDES)
    {
      return ER_FAILED;
    }

  /* Check the label and give a warning if labels are not the same */
  if (xdisk_get_fullname (thread_p, volid, check_vlabel) == NULL)
    {
      fileio_dismount (thread_p, vdes);
      return ER_FAILED;
    }

  if (util_compare_filepath (check_vlabel, vlabel) != 0)
    {
      /*
       * Names are different. The database was renamed outside the domain of
       * the database (e.g., in Unix), or this is not a database.
       * If volume information is not present, assume that this is not a
       * database
       */
      if (!logpb_find_volume_info_exist ())
    {
      er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_NOT_A_VOLUME, 1, vlabel);
      return ER_BO_NOT_A_VOLUME;
    }
      er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_BO_NOT_A_VOLUME, 1, vlabel);
    }

  return NO_ERROR;
}

#if !defined(WINDOWS)
static jmp_buf boot_Init_server_jmpbuf;
#endif

static bool boot_Init_server_is_canceled = false;

/*
 * boot_ctrl_c_in_init_server () -
 *
 * return:
 */
static void
boot_ctrl_c_in_init_server (int ignore_signo)
{
#if !defined(WINDOWS)
  _longjmp (boot_Init_server_jmpbuf, 1);
#else
  boot_Init_server_is_canceled = true;
#endif
}

/*
 * xboot_initialize_server () - initialize server
 *
 * return : transaction index or NULL_TRAN_INDEX in the case of
 *          error.
 *
 *   print_version(in): Flag which indicates if the version of CUBRID server
 *          is printed at the end of the initialization process.
 *   db_name(in): Database Name
 *   db_path(in): Directory where the database is created. It allows you
 *          to specify the exact pathname of a directory in which
 *          to create the new database. A NULL value is invalid.
 *   db_comments(in): Database creation comments such as name of the user who
 *          created the database, the date of the creation,the name
 *          of the intended application, or nothing at all. NULL
 *          can be passed if no comments are desired.
 *   db_npages(in): Total number of pages to allocate for the database.
 *   db_overwrite(in): Wheater to overwrite the database if it already exists.
 *   file_addmore_vols(in): More volumes are created during the initialization
 *          process.
 *   log_path(in): Directory where the log and backups of the database are
 *          created. We recommend placing log and backup in a
 *          different directory and disk device from the directory
 *          and disk device of the data volumes. A NULL value is
 *          invalid.
 *   db_server_host(in): Server host where the database will reside. The host is
 *          needed in a client/server environment to identify the
 *          server which will maintain (e.g., restart) the database
 *          A NULL is invalid.
 *   rootclass_oid(in): OID of root class (Set as a side effect)
 *   rootclass_hfid(in): Heap for classes  (Set as a side effect)
 *   client_prog_name(in): Name of the client program or NULL
 *   client_user_name(in): Name of the client user or NULL
 *   client_host_name(in): Name of the client host or NULL
 *   client_process_id(in): Identifier of the process of the host where the client
 *          client transaction runs.
 *   client_lock_wait(in): Wait for at least this number of milliseconds to acquire a
 *          lock. Negative value is infinite
 *   client_isolation(in): Isolation level. One of the following:
 *                         TRAN_REPEATABLE_READ
 *                         TRAN_READ_COMMITTED
 *                         TRAN_SERIALIZABLE
 * db_desired_pagesize(in): Desired pagesize for the new database. The given size
 *          must be power of 2 and greater or equal than 512.
 *
 * Note: The first step of any CUBRID application is to initialize a
 *       database. A database is composed of data volumes (or Unix file
 *       system files), database backup files, and log files. A data
 *       volume contains information on attributes, classes, indexes,
 *       and objects created in the database. A database backup is a
 *       fuzzy snapshot of the entire database. The backup is fuzzy
 *       since it can be taken online when other transactions are
 *       updating the database. The logs contain records that reflects
 *       changes to the database. The log and backup files are used by
 *       the system to recover committed and uncommitted transactions
 *       in the event of system and media crashes. Logs are also used
 *       to support user-initiated rollbacks.
 *
 *       The rest of this function is identical to the restart. A
 *       transaction for the current client session is automatically
 *       started.
 */
int
xboot_initialize_server (const BOOT_CLIENT_CREDENTIAL * client_credential, BOOT_DB_PATH_INFO * db_path_info,
             bool db_overwrite, const char *file_addmore_vols, volatile DKNPAGES db_npages,
             PGLENGTH db_desired_pagesize, volatile DKNPAGES log_npages, PGLENGTH db_desired_log_page_size,
             OID * rootclass_oid, HFID * rootclass_hfid, int client_lock_wait,
             TRAN_ISOLATION client_isolation)
{
  volatile int tran_index = NULL_TRAN_INDEX;
  const char *log_prefix = NULL;
  DB_INFO *db = NULL;
  DB_INFO *dir = NULL;
  volatile int dbtxt_vdes = NULL_VOLDES;
  char db_pathbuf[PATH_MAX];
  char vol_real_path[PATH_MAX];
  char log_pathbuf[PATH_MAX];
  char lob_pathbuf[LOB_PATH_PREFIX_MAX + PATH_MAX];
  char dbtxt_label[PATH_MAX];
  char fixed_pathbuf[PATH_MAX];
  char original_namebuf[PATH_MAX];
#if defined (NDEBUG)
  char format[BOOT_FORMAT_MAX_LENGTH];
#endif
  int error_code;
  void (*volatile old_ctrl_c_handler) (int sig_no) = SIG_ERR;
  struct stat stat_buf;
  bool is_exist_volume;
  const char *db_path, *log_path, *lob_path;
  char *p;
  THREAD_ENTRY *thread_p = NULL;

  assert (client_credential != NULL);
  assert (db_path_info != NULL);

#if defined(SERVER_MODE)
  if (lang_init () != NO_ERROR)
    {
      if (er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOC_INIT, 1, "Failed to initialize language module");
    }
      goto exit_on_error;
    }

  /* initialize time zone data, optional module */
  if (tz_load () != NO_ERROR)
    {
      if (er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_TZ_LOAD_ERROR, 1, "Failed to initialize timezone module");
    }
      goto exit_on_error;
    }

  /* open the system message catalog, before prm_ ? */
  if (msgcat_init () != NO_ERROR)
    {
      /* need an appropriate error */
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_ACCESS_MESSAGE_CATALOG, 0);
      goto exit_on_error;
    }

  if (sysprm_load_and_init (NULL, NULL, SYSPRM_LOAD_ALL) != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANT_LOAD_SYSPRM, 0);
      goto exit_on_error;
    }

  area_init ();
  error_code = set_area_init ();
  if (error_code != NO_ERROR)
    {
      goto exit_on_error;
    }
  error_code = pr_area_init ();
  if (error_code != NO_ERROR)
    {
      goto exit_on_error;
    }
  error_code = tp_init ();
  if (error_code != NO_ERROR)
    {
      goto exit_on_error;
    }

  /* Initialize tsc-timer */
  tsc_init ();

  /* Clear error structure */
  er_clear ();
#endif /* SERVER_MODE */

#if defined(CUBRID_DEBUG)
  if ((int) strlen (ROOTCLASS_NAME) > DB_SIZEOF (boot_Db_parm->rootclass_name))
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNABLE_TO_RESTART_SERVER, 1, ROOTCLASS_NAME);
      er_log_debug (ARG_FILE_LINE,
            "xboot_initialize_server: ** SYSTEM COMPILATION ERROR **"
            " Length (i.e., %d) of ROOTCLASS_NAME(i.e, %s) is bigger than"
            " length (i.e., %d) of bo_Dbparm->rootclass_name field", strlen (ROOTCLASS_NAME) + 1,
            ROOTCLASS_NAME, DB_SIZEOF (boot_Db_parm->rootclass_name));
      /* Destroy everything */
      goto exit_on_error;
    }
#endif /* CUBRID_DEBUG */

  if (client_credential->db_name.empty ())
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNKNOWN_DATABASE, 1, client_credential->get_db_name ());
      goto exit_on_error;
    }

  /*
   * Make sure that the db_path and log_path and lob_path are the canonicalized
   * absolute pathnames
   */

  memset (db_pathbuf, 0, sizeof (db_pathbuf));
  memset (log_pathbuf, 0, sizeof (log_pathbuf));
  memset (lob_pathbuf, 0, sizeof (lob_pathbuf));

  /*
   * for db path,
   * convert to absolute path, remove useless PATH_SEPARATOR
   */
  db_path = db_path_info->db_path;
  if (realpath (db_path, fixed_pathbuf) != NULL)
    {
      db_path = fixed_pathbuf;
    }
  else
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_DIRECTORY_DOESNOT_EXIST, 1, db_path);
      goto exit_on_error;
    }
  boot_remove_useless_path_separator (db_path, db_pathbuf);
  db_path = db_pathbuf;

  /*
   * for log path,
   * convert to absolute path, remove useless PATH_SEPARATOR
   */
  log_path = db_path_info->log_path;
  if (realpath (log_path, fixed_pathbuf) != NULL)
    {
      log_path = fixed_pathbuf;
    }
  else
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_DIRECTORY_DOESNOT_EXIST, 1, log_path);
      goto exit_on_error;
    }
  boot_remove_useless_path_separator (log_path, log_pathbuf);

  /*
   * for lob path,
   * convert to absolute path, remove useless PATH_SEPARATOR
   */
  lob_path = db_path_info->lob_path;
  if (es_get_type (lob_path) == ES_NONE)
    {
      snprintf (lob_pathbuf, sizeof (lob_pathbuf), "%s%s", LOB_PATH_DEFAULT_PREFIX, lob_path);
      p = strchr (lob_pathbuf, ':') + 1;
    }
  else
    {
      p = strchr (strcpy (lob_pathbuf, lob_path), ':') + 1;
    }
  lob_path = p;

  if (lob_path == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_INVALID_PATH, 1, lob_pathbuf);
      return NULL_TRAN_INDEX;
    }

  if (es_get_type (lob_pathbuf) == ES_POSIX)
    {
#if defined (WINDOWS)
      if (realpath (lob_path, fixed_pathbuf) != NULL
      && (stat (fixed_pathbuf, &stat_buf) == 0 && S_ISDIR (stat_buf.st_mode)))
#else
      if (realpath (lob_path, fixed_pathbuf) != NULL)
#endif
    {
      lob_path = fixed_pathbuf;
    }
      else
    {
      er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_BO_DIRECTORY_DOESNOT_EXIST, 1, lob_path);
      if (mkdir (lob_path, 0700) < 0)
        {
          cub_dirname_r (lob_path, fixed_pathbuf, PATH_MAX);
          er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", fixed_pathbuf);
          goto exit_on_error;
        }
    }
      boot_remove_useless_path_separator (lob_path, p);
    }

  /*
   * Compose the full name of the database
   */
  if (snprintf (boot_Db_full_name, sizeof (boot_Db_full_name), "%s%c%s", db_pathbuf, PATH_SEPARATOR,
        client_credential->get_db_name ()) < 0)
    {
      assert_release (false);
    }

  /*
   * Initialize error structure, critical section, slotted page, heap, and
   * recovery managers
   */

#if defined(SERVER_MODE)
  sysprm_load_and_init (boot_Db_full_name, NULL, SYSPRM_LOAD_ALL);
#endif /* SERVER_MODE */

  /* If the server is already restarted, shutdown the server */
  if (BO_IS_SERVER_RESTARTED ())
    {
      // not sure this can be true
      if (thread_p == NULL)
    {
      thread_p = thread_get_thread_entry_info ();
    }
      (void) xboot_shutdown_server (thread_p, ER_ALL_FINAL);
      assert (thread_p == NULL);
    }

  log_prefix = fileio_get_base_file_name (client_credential->get_db_name ());

  /*
   * Find logging information to create the log volume. If the page size is
   * not the same as the one in production mode, adjust the number of pages
   * allocated.
   */

  if (db_npages <= 0)
    {
      db_npages = (DKNPAGES) (prm_get_bigint_value (PRM_ID_DB_VOLUME_SIZE) / db_desired_pagesize);
    }

  if (log_npages <= 0)
    {
      log_npages = (DKNPAGES) (prm_get_bigint_value (PRM_ID_LOG_VOLUME_SIZE) / db_desired_log_page_size);
    }

  if (log_npages < 10)
    {
      log_npages = 10;
    }

  /* *INDENT-OFF* */
  cubthread::initialize (thread_p);
  error_code = cubthread::initialize_thread_entries ();
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto exit_on_error;
    }
  /* *INDENT-ON* */

  /*
   * get the database directory information in write mode.
   */

  if (cfg_maycreate_get_directory_filename (dbtxt_label) == NULL
#if !defined(WINDOWS) || !defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
/* Temporary fix for NT file locking problem */
      || (dbtxt_vdes = fileio_mount (thread_p, dbtxt_label, dbtxt_label, LOG_DBTXT_VOLID, 2, true)) == NULL_VOLDES
#endif /* !WINDOWS || DONT_USE_MANDATORY_LOCK_IN_WINDOWS */
    )
    {
      goto exit_on_error;
    }

  if (dbtxt_vdes != NULL_VOLDES)
    {
      if (cfg_read_directory_ex (dbtxt_vdes, &dir, true) != NO_ERROR)
    {
      goto exit_on_error;
    }
    }
  else
    {
      if (cfg_read_directory (&dir, true) != NO_ERROR)
    {
      goto exit_on_error;
    }
    }

  if (dir != NULL && ((db = cfg_find_db_list (dir, client_credential->get_db_name ())) != NULL))
    {
      if (db_overwrite == false)
    {
      /* There is a database with the same name and we cannot overwrite it */
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_DATABASE_EXISTS, 1, client_credential->get_db_name ());
      goto exit_on_error;
    }
      else
    {
      /*
       * Delete the database.. to make sure that all backups, log archives, and
       * so on are removed... then continue...
       *
       * Note: we do not call xboot_delete since it shuttdown the system and
       *       update database.txt that we have a read copy of its content.
       */

      /* Note: for database replacement, we need to remove the old database with its original path! */
      memset (original_namebuf, 0, sizeof (original_namebuf));

      /* Compose the original full name of the database */
      snprintf (original_namebuf, sizeof (original_namebuf), "%s%c%s", db->pathname, PATH_SEPARATOR, db->name);

      error_code = boot_remove_all_volumes (thread_p, original_namebuf, db->logpath, log_prefix, false, true);
      if (error_code != NO_ERROR)
        {
          goto exit_on_error;
        }
    }
    }

  if (dbtxt_vdes != NULL_VOLDES)
    {
      fileio_dismount (thread_p, dbtxt_vdes);   /* unlock the directory file */
      dbtxt_vdes = NULL_VOLDES;
      cfg_free_directory (dir);
      dir = NULL;
    }

  error_code =
    logpb_check_exist_any_volumes (thread_p, boot_Db_full_name, log_pathbuf, log_prefix, vol_real_path,
                   &is_exist_volume);
  if (error_code != NO_ERROR || is_exist_volume)
    {
      goto exit_on_error;
    }

#if !defined(WINDOWS)
  if (db_path_info->vol_path != NULL)
    {
      if (realpath ((char *) db_path_info->vol_path, vol_real_path) == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_CREATE_LINK, 2, vol_real_path, boot_Db_full_name);
      goto exit_on_error;
    }
      else
    {
      if (stat (vol_real_path, &stat_buf) != 0  /* file not exist */
          || S_ISDIR (stat_buf.st_mode))
        {           /* is directory */
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_CREATE_LINK, 2, vol_real_path, boot_Db_full_name);
          goto exit_on_error;
        }
      (void) unlink (boot_Db_full_name);
      if (symlink (vol_real_path, boot_Db_full_name) != 0)
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_CREATE_LINK, 2, vol_real_path, boot_Db_full_name);
          goto exit_on_error;
        }
    }
    }
#endif /* !WINDOWS */

  (void) db_set_page_size (db_desired_pagesize, db_desired_log_page_size);

  if ((int) strlen (boot_Db_full_name) > DB_MAX_PATH_LENGTH - 1)
    {
      /* db_path + db_name is too long */
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_FULL_DATABASE_NAME_IS_TOO_LONG, 4, db_pathbuf,
          client_credential->get_db_name (), strlen (boot_Db_full_name), DB_MAX_PATH_LENGTH - 1);
      goto exit_on_error;
    }

  old_ctrl_c_handler = os_set_signal_handler (SIGINT, boot_ctrl_c_in_init_server);

#if !defined(WINDOWS)
  boot_Init_server_is_canceled = (_setjmp (boot_Init_server_jmpbuf) != 0);
#endif

  if (!boot_Init_server_is_canceled)
    {
      tran_index =
    boot_create_all_volumes (thread_p, client_credential, db_path_info->db_comments, db_npages, file_addmore_vols,
                 log_pathbuf, (const char *) log_prefix, log_npages, client_lock_wait,
                 client_isolation);

      if (tran_index != NULL_TRAN_INDEX && !boot_Init_server_is_canceled)
    {
#if !defined(WINDOWS) || !defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
      dbtxt_vdes = fileio_mount (thread_p, dbtxt_label, dbtxt_label, LOG_DBTXT_VOLID, 2, true);
      if (dbtxt_vdes == NULL_VOLDES)
        {
          goto exit_on_error;
        }
#endif /* !WINDOWS || !DONT_USE_MANDATORY_LOCK_IN_WINDOWS */

      if (dbtxt_vdes != NULL_VOLDES)
        {
          if (cfg_read_directory_ex (dbtxt_vdes, &dir, true) != NO_ERROR)
        {
          goto exit_on_error;
        }
        }
      else
        {
          if (cfg_read_directory (&dir, true) != NO_ERROR)
        {
          goto exit_on_error;
        }
        }

      db = cfg_find_db_list (dir, client_credential->get_db_name ());

      /* Now create the entry in the database table */
      if (db == NULL)
        {
          db =
        cfg_add_db (&dir, client_credential->get_db_name (), db_pathbuf, log_pathbuf, lob_pathbuf,
                db_path_info->db_host);
        }
      else
        {
          cfg_update_db (db, db_pathbuf, log_pathbuf, lob_pathbuf, db_path_info->db_host);
        }

      if (db == NULL || db->name == NULL || db->pathname == NULL || db->logpath == NULL || db->lobpath == NULL
          || db->hosts == NULL)
        {
          goto exit_on_error;
        }

#if defined(WINDOWS) && !defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
      /* Under Windows/NT, it appears that locking a file prevents a subsequent open for write by the same process.
       * The cfg_write_directory will never succeed as long as the file is "mounted" by fileio_mount().  To allow
       * the cubrid.db file to be updated, dismount before calling cfg_.  Note that this leaves an extremely small
       * windows where another process could steal our lock. */
      if (dbtxt_vdes != NULL_VOLDES)
        {
          fileio_dismount (thread_p, dbtxt_vdes);
          dbtxt_vdes = NULL_VOLDES;
        }
#endif /* WINDOWS && !DONT_USE_MANDATORY_LOCK_IN_WINDOWS */

      if (dbtxt_vdes != NULL_VOLDES)
        {
          cfg_write_directory_ex (dbtxt_vdes, dir);
        }
      else
        {
          cfg_write_directory (dir);
        }
      cfg_free_directory (dir);
      dir = NULL;

      if (dbtxt_vdes != NULL_VOLDES)
        {
          fileio_dismount (thread_p, dbtxt_vdes);
          dbtxt_vdes = NULL_VOLDES;
        }
    }
    }

  if (tran_index == NULL_TRAN_INDEX || boot_Init_server_is_canceled)
    {
      (void) boot_remove_all_volumes (thread_p, boot_Db_full_name, log_pathbuf, (const char *) log_prefix, true, true);
      if (boot_Init_server_is_canceled)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INTERRUPTED, 0);
    }
      else
    {
      if (db_path_info->vol_path != NULL)
        {
          (void) unlink (boot_Db_full_name);
        }
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_CREATE_VOL, 3, "volumes",
          client_credential->get_db_name (), er_get_msglog_filename ());
    }

      goto exit_on_error;
    }

  rootclass_oid->volid = boot_Db_parm->rootclass_oid.volid;
  rootclass_oid->pageid = boot_Db_parm->rootclass_oid.pageid;
  rootclass_oid->slotid = boot_Db_parm->rootclass_oid.slotid;
  if (boot_find_root_heap (rootclass_hfid) != NO_ERROR || HFID_IS_NULL (rootclass_hfid))
    {
      goto exit_on_error;
    }

  // sessions state is required to continue
  session_states_init (thread_p);

  /* print_version string */
#if defined (NDEBUG)
  strncpy_size (format, msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_GENERAL, MSGCAT_GENERAL_DATABASE_INIT),
        BOOT_FORMAT_MAX_LENGTH);
  fprintf (stdout, format, rel_name (), rel_build_number ());
#else /* NDEBUG */
  fprintf (stdout, "\n%s (%s) (%d %s build)\n\n", rel_name (), rel_build_number (), rel_bit_platform (),
       rel_build_type ());
#endif /* !NDEBUG */

  if (old_ctrl_c_handler != SIG_ERR)
    {
      (void) os_set_signal_handler (SIGINT, old_ctrl_c_handler);
    }

  return tran_index;

exit_on_error:

  if (old_ctrl_c_handler != SIG_ERR)
    {
      (void) os_set_signal_handler (SIGINT, old_ctrl_c_handler);
    }

  /* Destroy everything */
  if (dir)
    {
      cfg_free_directory (dir);
    }

  if (dbtxt_vdes != NULL_VOLDES)
    {
      fileio_dismount (thread_p, dbtxt_vdes);
    }

  if (tran_index != NULL_TRAN_INDEX)
    {
      logtb_release_tran_index (thread_p, tran_index);
      log_final (thread_p);
    }

  er_stack_push ();
  boot_server_all_finalize (thread_p, ER_THREAD_FINAL, BOOT_SHUTDOWN_EXCEPT_COMMON_MODULES);
  er_stack_pop ();

  // and now finalize thread entry
  cubthread::finalize ();

  return NULL_TRAN_INDEX;
}

static int
boot_make_session_server_key (void)
{
  int err;
  UINT32 t;
  unsigned char ip[4];

  t = (UINT32) time (NULL);
  memcpy (boot_Server_session_key, &t, sizeof (UINT32));
  err = css_hostname_to_ip (boot_Host_name, ip);
  if (err != NO_ERROR)
    {
      ASSERT_ERROR ();
      return err;
    }
  boot_Server_session_key[4] = ip[0];
  boot_Server_session_key[5] = ip[1];
  boot_Server_session_key[6] = ip[2];
  boot_Server_session_key[7] = ip[3];
  return NO_ERROR;
}

/*
 * boot_restart_server () - restart server
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 *   print_restart(in): Flag which indicates if the version of CUBRID server
 *                      is printed at the end of the restart process.
 *   db_name(in): Database Name
 *   from_backup(in): Execute the restart from a backup..
 *   check_db_coll(in): True if check DB collations with system collations
 *   r_args(in): restart argument structure contains various options
 *
 * Note: The CUBRID server is restarted. Recovery process, no
 *       related to media failures (i.e., disk crashes), takes place
 *       during the restart process.
 */
int
boot_restart_server (THREAD_ENTRY * thread_p, bool print_restart, const char *db_name, bool from_backup,
             CHECK_ARGS * check_coll_and_timezone, BO_RESTART_ARG * r_args, bool skip_vacuum)
{
  char log_path[PATH_MAX];
  const char *log_prefix;
  DB_INFO *db = NULL;
  DB_INFO *dir = NULL;
#if defined (NDEBUG)
  char format[BOOT_FORMAT_MAX_LENGTH];
#endif
  int tran_index = NULL_TRAN_INDEX;
  int dbtxt_vdes = NULL_VOLDES;
  char dbtxt_label[PATH_MAX];
#if defined(SERVER_MODE)
  HA_MODE common_ha_mode;
#endif
  int error_code = NO_ERROR;
  char *prev_err_msg;
  INTL_CODESET db_charset_db_header = INTL_CODESET_NONE;
  INTL_CODESET db_charset_db_root = INTL_CODESET_NONE;
  char db_lang[LANG_MAX_LANGNAME + 1];
  char timezone_checksum[32 + 1];
  const TZ_DATA *tzd;
  char *mk_path;

  /* language data is loaded in context of server */
  if (lang_init () != NO_ERROR)
    {
      if (er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOC_INIT, 1, "Failed to initialize language module");
    }
      error_code = ER_LOC_INIT;
      goto error;
    }

  /* initialize time zone data, optional module */
  if (tz_load () != NO_ERROR)
    {
      if (er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_TZ_LOAD_ERROR, 1, "Failed to initialize timezone module");
    }
      error_code = ER_TZ_LOAD_ERROR;
      goto error;
    }

  if (msgcat_init () != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_ACCESS_MESSAGE_CATALOG, 0);
      error_code = ER_BO_CANNOT_ACCESS_MESSAGE_CATALOG;
      goto error;
    }

#if defined(SERVER_MODE)
  if (sysprm_load_and_init (db_name, NULL, SYSPRM_LOAD_ALL) != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANT_LOAD_SYSPRM, 0);
      error_code = ER_BO_CANT_LOAD_SYSPRM;
      goto error;
    }

  common_ha_mode = HA_GET_MODE ();
#endif /* SERVER_MODE */

  if (db_name == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNKNOWN_DATABASE, 1, db_name);
      error_code = ER_BO_UNKNOWN_DATABASE;
      goto error;
    }

  /*
   * Make sure that there is a database.txt and that the desired database
   * exists. We do not want to lock the database.txt at this point since we
   * are only reading it. However, if we do not find the desired database,
   * we must lock the file to make sure that we got a consistent view of
   * database.txt (database.txt is written from scratch when it is updated).
   * That is, don't complain that a database does not exist until we have
   * a lock of database.txt
   */

  if (cfg_read_directory (&dir, false) != NO_ERROR)
    {
      if (er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CFG_NO_FILE, 1, DATABASES_FILENAME);
    }
      error_code = ER_CFG_NO_FILE;
      goto error;
    }

  if (dir == NULL || ((db = cfg_find_db_list (dir, db_name)) == NULL))
    {
      /*
       * Make sure that nobody was in the process of writing the
       * database.txt when we got a snapshot of it.
       */
      if (dir != NULL)
    {
      cfg_free_directory (dir);
      dir = NULL;
    }

      if (cfg_maycreate_get_directory_filename (dbtxt_label) != NULL
#if !defined(WINDOWS) || !defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
/* Temporary fix for NT file locking problem */
      && (dbtxt_vdes = fileio_mount (thread_p, dbtxt_label, dbtxt_label, LOG_DBTXT_VOLID, 2, true)) != NULL_VOLDES
#endif /* !WINDOWS || !DONT_USE_MANDATORY_LOCK_IN_WINDOWS */
    )
    {
      if (dbtxt_vdes != NULL_VOLDES)
        {
          if (cfg_read_directory_ex (dbtxt_vdes, &dir, false) == NO_ERROR)
        {
          db = cfg_find_db_list (dir, db_name);
        }
        }
      else
        {
          if (cfg_read_directory (&dir, false) == NO_ERROR)
        {
          db = cfg_find_db_list (dir, db_name);
        }
        }

      fileio_dismount (thread_p, dbtxt_vdes);
      dbtxt_vdes = NULL_VOLDES;
    }
      if (db == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNKNOWN_DATABASE, 1, db_name);
      error_code = ER_BO_UNKNOWN_DATABASE;
      goto error;
    }
    }

  if (GETHOSTNAME (boot_Host_name, CUB_MAXHOSTNAMELEN) != 0)
    {
      if (strcmp (boot_Host_name, "") == 0)
    {
      strcpy (boot_Host_name, "(unknown)");
    }
    }
  boot_Host_name[CUB_MAXHOSTNAMELEN - 1] = '\0';    /* bullet proof */

  COMPOSE_FULL_NAME (boot_Db_full_name, sizeof (boot_Db_full_name), db->pathname, db_name);
  error_code = boot_make_session_server_key ();
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

  if (boot_volume_info_log_path (log_path) == NULL)
    {
      strcpy (log_path, db->logpath);
    }

  if (db->lobpath != NULL)
    {
      strlcpy (boot_Lob_path, db->lobpath, sizeof (boot_Lob_path));
    }
  else
    {
      boot_Lob_path[0] = '\0';
    }

  /*
   * Initialize error structure, critical section, slotted page, heap, and
   * recovery managers
   */
#if defined(SERVER_MODE)
  if (common_ha_mode != prm_get_integer_value (PRM_ID_HA_MODE) && !HA_DISABLED ())
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_PRM_CONFLICT_EXISTS_ON_MULTIPLE_SECTIONS, 6, "cubrid.conf", "common",
          prm_get_name (PRM_ID_HA_MODE), css_ha_mode_string (common_ha_mode), db_name,
          css_ha_mode_string (HA_GET_MODE ()));
      error_code = ER_PRM_CONFLICT_EXISTS_ON_MULTIPLE_SECTIONS;
      goto error;
    }

  /* reinit msg catalog to reflect PRM_MAX_THREADS */
  msgcat_final ();
  if (msgcat_init () != NO_ERROR)
    {
      error_code = ER_BO_CANNOT_ACCESS_MESSAGE_CATALOG;
      goto error;
    }

  error_code = css_init_conn_list ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  error_code = perfmon_initialize (MAX_NTRANS);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

  /* note that thread entry was re-initialized */
  thread_p = thread_get_thread_entry_info ();
  assert (thread_p != NULL);

  if (er_init (prm_get_string_value (PRM_ID_ER_LOG_FILE), prm_get_integer_value (PRM_ID_ER_EXIT_ASK)) != NO_ERROR)
    {
      error_code = ER_FAILED;
      goto error;
    }
  er_clear ();

  event_log_init (db_name);
  trace_log_init (db_name);

  /* initialize allocations areas for things we need, on the client, most of this is done inside ws_init(). */
  area_init ();
  error_code = set_area_init ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }
  error_code = pr_area_init ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  locator_initialize_areas ();

  /* initialize the type/doain module (also sets up an area) */
  error_code = tp_init ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  /* Initialize tsc-timer */
  tsc_init ();
#endif /* !SERVER_MODE */

#if defined (SA_MODE)
  /* *INDENT-OFF* */
  // thread_manager was not initialized
  assert (thread_p == NULL);
  cubthread::initialize (thread_p);
  assert (thread_p == thread_get_thread_entry_info ());
#endif // SA_MODE
  error_code = cubthread::initialize_thread_entries ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }
  /* *INDENT-ON* */

  /*
   * Call pl_server_init() before log_initialize() to avoid potential issues
   * with large memory allocations impacting fork() system calls.
   *
   * Context:
   * 1. During log_initialize(), large data buffer allocations might cause fork()
   *    system call failures. To prevent this, pl_server_init() is invoked earlier.
   *
   * 2. In cases with large-scale databases such as those used for YCSB testing, 
   *    the time taken by log_initialize() is nearly identical to the time taken 
   *    to reach it via boot_start_server(). This suggests that other modules 
   *    during server startup consume significant system resources, although the 
   *    specifics are yet to be analyzed.
   *
   * 3. To enhance PL server initialization reliability, pl_server_init() is called 
   *    before other modules’ initialization.
   */
  error_code = pl_server_init (db_name);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  pr_Enable_string_compression = prm_get_bool_value (PRM_ID_ENABLE_STRING_COMPRESSION);

  /*
   * Compose the full name of the database and find location of logs
   */

  log_prefix = fileio_get_base_file_name (db_name);

  /* The database pagesize is set by log_get_io_page_size */

  if (log_get_io_page_size (thread_p, boot_Db_full_name, log_path, log_prefix) == -1)
    {
      if (from_backup == false || er_errid () == ER_IO_MOUNT_LOCKED)
    {
      error_code = ER_FAILED;
      goto error;
    }
    }

  /* Initialize the transaction table */
  logtb_define_trantable (thread_p, -1, -1);

  /*
   * How to restart the system ?
   */
  if (from_backup != false)
    {
      /*
       * RESTART FROM BACKUP
       */
#if defined(SA_MODE)
      if (r_args->restore_slave)
    {
      (void) logpb_remove_all_in_log_path (thread_p, boot_Db_full_name, log_path, log_prefix);
    }
#endif /* SA_MODE */
      error_code = logpb_restore (thread_p, boot_Db_full_name, log_path, log_prefix, r_args);
      if (error_code != NO_ERROR)
    {
      goto error;
    }
    }

  spage_boot (thread_p);
  error_code = heap_manager_initialize ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  /*
   * Now continue the normal restart process. At this point the data volumes
   * are ok. However, some recovery may need to take place
   */

  /* Mount the data volume */
  error_code = boot_mount (thread_p, LOG_DBFIRST_VOLID, boot_Db_full_name, NULL);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  /* Find the location of the database parameters and read them */
  if (disk_get_boot_hfid (thread_p, LOG_DBFIRST_VOLID, &boot_Db_parm->hfid) == NULL)
    {
      error_code = ER_FAILED;
      goto error;
    }

  error_code = boot_get_db_parm (thread_p, boot_Db_parm, boot_Db_parm_oid);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  error_code = tde_cipher_initialize (thread_p, &boot_Db_parm->tde_keyinfo_hfid,
                      r_args == NULL ? NULL : r_args->keys_file_path);
  if (error_code != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_TDE_CIPHER_LOAD_FAIL, 0);
      error_code = NO_ERROR;
    }

  /* we need to manually add root class HFID to cache */
  error_code =
    heap_cache_class_info (thread_p, &boot_Db_parm->rootclass_oid, &boot_Db_parm->rootclass_hfid, FILE_HEAP,
               boot_Db_parm->rootclass_name);
  if (error_code != NO_ERROR)
    {
      assert_release (false);
      goto error;
    }

  db_charset_db_header = boot_get_db_charset_from_header (thread_p, log_path, log_prefix);
  if (db_charset_db_header <= INTL_CODESET_NONE || INTL_CODESET_LAST < db_charset_db_header)
    {
      char er_msg[ERR_MSG_SIZE];
      snprintf (er_msg, sizeof (er_msg) - 1,
        "Cannot find a valid charset in log header or first volume header or different values have "
        "been found");
      er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOC_INIT, 1, er_msg);
      error_code = ER_LOC_INIT;
      goto error;
    }
  else
    {
      lang_set_charset (db_charset_db_header);
    }

  /* Find the rest of the volumes and mount them */

  error_code = boot_find_rest_volumes (thread_p, from_backup ? r_args : NULL, LOG_DBFIRST_VOLID, boot_mount, NULL);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  /* initialize disk manager */
  error_code = disk_manager_init (thread_p, true);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

  error_code = logtb_initialize_global_unique_stats_table (thread_p);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  error_code = file_tracker_load (thread_p, &boot_Db_parm->trk_vfid);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }
  catalog_initialize (&boot_Db_parm->ctid);

  if (prm_get_bool_value (PRM_ID_DISABLE_VACUUM) == false)
    {
      /* We need to load vacuum data and initialize vacuum routine before recovery. */
      error_code =
    vacuum_initialize (thread_p, boot_Db_parm->vacuum_log_block_npages, &boot_Db_parm->vacuum_data_vfid,
               &boot_Db_parm->dropped_files_vfid, r_args != NULL && r_args->is_restore_from_backup);
      if (error_code != NO_ERROR)
    {
      goto error;
    }
    }

  oid_set_root (&boot_Db_parm->rootclass_oid);

  /* Load and recover data pages before log recovery */
  error_code = dwb_load_and_recover_pages (thread_p, log_path, log_prefix);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

#if defined(SERVER_MODE)
  pgbuf_daemons_init ();
  dwb_daemons_init ();
  parallel_query::worker_manager_global::get_manager ().init ();
#endif /* SERVER_MODE */

  /*
   * Now restart the recovery manager and execute any recovery actions
   */

  log_initialize (thread_p, boot_Db_full_name, log_path, log_prefix, from_backup, r_args);

  error_code = boot_after_copydb (thread_p);    // only does something if this is first boot after copydb
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

#if defined(SERVER_MODE)
  BO_ENABLE_FLUSH_DAEMONS ();

  cdc_daemons_init ();
#endif /* SERVER_MODE */

  // after recovery we can boot vacuum
  error_code = vacuum_boot (thread_p);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

  /*
   * Initialize the catalog manager, the query evaluator, and install meta
   * classes
   */

  error_code = locator_initialize (thread_p);
  if (error_code != NO_ERROR)
    {
      error_code = ER_FAILED;
      goto error;
    }

  error_code = catcls_find_and_set_cached_class_oid (thread_p);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  error_code = xcache_initialize (thread_p);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

  if (qmgr_initialize (thread_p) != NO_ERROR)
    {
      error_code = ER_FAILED;
      goto error;
    }

  error_code = qfile_initialize_list_cache (thread_p);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  error_code = fpcache_initialize (thread_p);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

  /*
   * Initialize system locale using values from db_root system table
   */
  error_code =
    catcls_get_server_compat_info (thread_p, &db_charset_db_root, db_lang, sizeof (db_lang) - 1, timezone_checksum);

  if (error_code != NO_ERROR)
    {
      goto error;
    }

  if (db_charset_db_header != db_charset_db_root)
    {
      char er_msg[ERR_MSG_SIZE];
      snprintf (er_msg, sizeof (er_msg) - 1, "Invalid charset in db_root system table: expecting %s, found %s",
        lang_charset_cubrid_name (db_charset_db_header), lang_charset_cubrid_name (db_charset_db_root));
      er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOC_INIT, 1, er_msg);
      error_code = ER_LOC_INIT;
      goto error;
    }

  error_code = lang_set_language (db_lang);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  /* Check server timezone checksum versus database checksum */
  if (check_coll_and_timezone->check_timezone == true)
    {
      tzd = tz_get_data ();
      assert (tzd != NULL);

      error_code = check_timezone_compat (tzd->checksum, timezone_checksum, "server", "database");
      if (error_code != NO_ERROR)
    {
      goto error;
    }
    }

#if defined (SERVER_MODE)
  /* Cache serial index BTID. */
  /* Note that workspace manager is unavailable when restarting from backup. It is possible to allow SA_MODE
   * executables except restoredb to use the function, however, it is better not to use it in SA_MODE for clarity. */
  error_code = serial_cache_index_btid (thread_p);
  if (error_code != NO_ERROR)
    {
      goto error;
    }
#endif /* SERVER_MODE */

  /*
   * Allocate a temporary transaction index to finish further system related
   * changes such as removal of temporary volumes and modifications of
   * system parameter
   */

  /* todo: I am not sure we really need a transaction here. but since we are hurrying to release 10.1 and we don't have
   *       time to do changes that may have a significant impact on database behavior, I'd rather keep this for now.
   *       We should rethink the boot_Db_parm implementation altogether and we can come back to this when we do it. */
  tran_index =
    logtb_assign_tran_index (thread_p, NULL_TRANID, TRAN_ACTIVE, NULL, NULL, TRAN_LOCK_INFINITE_WAIT,
                 TRAN_DEFAULT_ISOLATION_LEVEL ());
  if (tran_index == NULL_TRAN_INDEX)
    {
      error_code = ER_FAILED;
      goto error;
    }

  /*
   * Remove any database temporary volumes
   */

  (void) boot_remove_all_temp_volumes (thread_p, REMOVE_TEMP_VOL_DEFAULT_ACTION);

  if (boot_Lob_path[0] != '\0')
    {
      error_code = es_init (boot_Lob_path);

      if (error_code != NO_ERROR)
    {
      goto error;
    }

      /* remove lob ces temp dir */
      error_code = fileio_lob_remove_matching_dir (BOOT_LOB_TEMP_DIR_KEYWORD);

      if (error_code != NO_ERROR)
    {
      goto error;
    }
    }
  else
    {
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_ES_NO_LOB_PATH, 0);
    }

  if (xtran_server_commit (thread_p, false) != TRAN_UNACTIVE_COMMITTED)
    {
      assert_release (false);
      error_code = ER_FAILED;
      goto error;
    }
  logtb_free_tran_index (thread_p, tran_index);
  tran_index = NULL_TRAN_INDEX;
  logtb_set_to_system_tran_index (thread_p);

  if (!tf_Metaclass_class.mc_n_variable)
    {
      tf_compile_meta_classes ();
    }

  if (skip_to_check_ct_classes_for_rebuild == false)
    {
      if (catcls_Enable != true)
    {
      error_code = catcls_compile_catalog_classes (thread_p);
      if (error_code != NO_ERROR)
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_MISSING_OR_INVALID_CATALOG, 0);
          goto error;
        }
    }
    }

  /* check server collations with database collations */
  if (check_coll_and_timezone->check_db_coll == true)
    {
      LANG_COLL_COMPAT *db_collations = NULL;
      int db_coll_cnt;

      error_code = catcls_get_db_collation (thread_p, &db_collations, &db_coll_cnt);
      if (error_code != NO_ERROR)
    {
      if (db_collations != NULL)
        {
          db_private_free (thread_p, db_collations);
        }
      goto error;
    }

      if (db_collations != NULL)
    {
      error_code = lang_check_coll_compat (db_collations, db_coll_cnt, "server", "database");
      db_private_free (thread_p, db_collations);
      if (error_code != NO_ERROR)
        {
          goto error;
        }
    }
    }

#if defined (SA_MODE)
  /* Completely vacuum database. */
  if (r_args == NULL || r_args->is_restore_from_backup == false)
    {
      er_clear ();      /* forget any warning or error to start vacuumming */
      if (!skip_vacuum)
    {
      xvacuum (thread_p);
    }
    }
#endif

  /* read only mode ? */
  if (prm_get_bool_value (PRM_ID_READ_ONLY_MODE))
    {
      logtb_disable_update (NULL);
    }

  error_code = serial_initialize_cache_pool (thread_p);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  error_code = pl_server_wait_for_ready ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  session_states_init (thread_p);

#if defined (SERVER_MODE)
  if (prm_get_bool_value (PRM_ID_ACCESS_IP_CONTROL) == true && from_backup == false)
    {
      error_code = css_set_accessible_ip_info ();
      if (error_code != NO_ERROR)
    {
      goto error;
    }
    }
#endif

#if defined (SERVER_MODE)
  /* set number of hosts */
  css_set_ha_num_of_hosts (db->num_hosts);
  /* set server's starting mode for HA according to the 'ha_mode' parameter */
  css_change_ha_server_state (thread_p, (HA_SERVER_STATE) prm_get_integer_value (PRM_ID_HA_SERVER_STATE), false,
                  HA_CHANGE_MODE_IMMEDIATELY, true);
#endif

  /* initialize partitions cache */
  error_code = partition_cache_init (thread_p);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  cfg_free_directory (dir);

  if (print_restart)
    {
#if defined (NDEBUG)
      strncpy_size (format, msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_GENERAL, MSGCAT_GENERAL_DATABASE_INIT),
            BOOT_FORMAT_MAX_LENGTH);
      fprintf (stdout, format, rel_name ());
#else /* NDEBUG */
      fprintf (stdout, "\n%s (%s) (%d %s build)\n\n", rel_name (), rel_build_number (), rel_bit_platform (),
           rel_build_type ());
#endif /* !NDEBUG */
      fflush (stdout);
    }

  if (from_backup == true)
    {
      log_set_ha_promotion_time (thread_p, 0);
      log_set_db_restore_time (thread_p, (INT64) (time (0)));
    }

  /* server status could be changed by css_change_ha_server_state */
  if (boot_Server_status == BOOT_SERVER_DOWN)
    {
      /* server is up! */
      boot_server_status (BOOT_SERVER_UP);
    }
#if !defined(SA_MODE)
  json_set_alloc_funcs (malloc, free);
#endif

  return NO_ERROR;

error:
  if (dir != NULL)
    {
      cfg_free_directory (dir);
      dir = NULL;
    }
  prev_err_msg = (char *) er_msg ();
  if (prev_err_msg != NULL)
    {
      prev_err_msg = strdup (prev_err_msg);
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNABLE_TO_RESTART_SERVER, 1, prev_err_msg);
      free_and_init (prev_err_msg);
    }
  else
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNABLE_TO_RESTART_SERVER, 1, "");
    }

  if (tran_index != NULL_TRAN_INDEX)
    {
      logtb_free_tran_index (thread_p, tran_index);
    }

  session_states_finalize (thread_p);
  logtb_finalize_global_unique_stats_table (thread_p);


  vacuum_stop_workers (thread_p);
  vacuum_stop_master (thread_p);

#if defined(SERVER_MODE)
  pl_server_destroy ();

  cdc_daemons_destroy ();

  BO_DISABLE_FLUSH_DAEMONS ();
  pgbuf_daemons_destroy ();
  dwb_daemons_destroy ();
  parallel_query::worker_manager_global::get_manager ().destroy ();
#endif

  log_final (thread_p);
  fpcache_finalize (thread_p);
  qfile_finalize_list_cache (thread_p);
  xcache_finalize (thread_p);

#if defined(SERVER_MODE)
  css_final_conn_list ();
#endif

  er_stack_push ();
  boot_server_all_finalize (thread_p, ER_THREAD_FINAL, BOOT_SHUTDOWN_EXCEPT_COMMON_MODULES);
  er_stack_pop ();

#if defined (SA_MODE)
  cubthread::finalize ();
#endif /* SA_MODE */

  return error_code;
}

/*
 * xboot_restart_from_backup () - restore the database system from backup.
 *                             used for media crash recovery
 *
 * return : Transaction index
 *
 *   print_restart(in): Flag which indicates if the version of CUBRID server
 *                      is printed at the end of the restart process.
 *   db_name(in): Database Name
 *   r_args(in): restart argument structure contains various options
 *
 * Note: The database is restored from its backup and from all archive
 *       and active logs with information recoded since the backup. If
 *       these files are not actually placed in the location of the log
 *       files, the system will request those files.
 */
int
xboot_restart_from_backup (THREAD_ENTRY * thread_p, int print_restart, const char *db_name, BO_RESTART_ARG * r_args)
{
  CHECK_ARGS check_coll_and_timezone = { true, true };

  if (lang_init () != NO_ERROR)
    {
      if (er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOC_INIT, 1, "Failed to initialize language module");
    }
      return NULL_TRAN_INDEX;
    }

  /* initialize time zone data, optional module */
  if (tz_load () != NO_ERROR)
    {
      if (er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_TZ_LOAD_ERROR, 1, "Failed to initialize timezone module");
    }
      return NULL_TRAN_INDEX;
    }

  /* open the system message catalog, before prm_ ? */
  if (msgcat_init () != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_ACCESS_MESSAGE_CATALOG, 0);
      return NULL_TRAN_INDEX;
    }

  /* initialize system parameters */
  if (sysprm_load_and_init (NULL, NULL, SYSPRM_LOAD_ALL) != NO_ERROR)
    {
      return NULL_TRAN_INDEX;
    }

  prm_set_bool_value (PRM_ID_DBFILES_PROTECT, false);

  /*
   *  We need to do some initialization that normally happens in
   *  boot_restart_server(), but only if the SERVER_MODE CPP variable is
   *  defined.  Unfortunately, if we're here, then SERVER_MODE is not defined
   *  so call the important initializers ourselves.
   *
   *  Initialize allocations areas for things we need
   *  Initialize the type/doain module (also sets up an area)
   */

  area_init ();

  if (tp_init () != NO_ERROR)
    {
      return NULL_TRAN_INDEX;
    }

  if (boot_restart_server (thread_p, print_restart, db_name, true, &check_coll_and_timezone, r_args, false) != NO_ERROR)
    {
      return NULL_TRAN_INDEX;
    }
  else
    {
      if (tde_is_loaded ())
    {
      if (boot_reset_mk_after_restart_from_backup (thread_p, r_args) != NO_ERROR)
        {
          return NULL_TRAN_INDEX;
        }
    }
      return LOG_FIND_THREAD_TRAN_INDEX (thread_p);
    }
}

/*
 * boot_reset_mk_after_restart_from_backup () - Reset after restarting from a backup volume
 *
 *  return          : Error code
 *  thread_p (in)   : Thread entry
 *  r_args(in)      : Restart argument structure contains various options
 *
 * There might be no proper master key after restoring database 
 * even if we have a server mk file and the backup mk file (in the case of timed restore).
 * 
 * There are several cases but we simplify it into two case:
 * (1) The master key set on the database can be found in the server _keys file
 * (2) not (1), which means no server mk file or no master key in the server mk file.
 *
 * For (1), we do nothing.
 * For (2), we copy backup mk file as the server mk file and set the first key in the key file
 * as the master key for database.
 */
int
boot_reset_mk_after_restart_from_backup (THREAD_ENTRY * thread_p, BO_RESTART_ARG * r_args)
{
  TDE_KEYINFO keyinfo;
  char mk_path[PATH_MAX] = { 0, };
  char mk_path_old[PATH_MAX] = { 0, };
  char ctime_buf[CTIME_MAX];
  int time_str_len;
  unsigned char master_key[TDE_MASTER_KEY_LENGTH];
  time_t created_time;
  int mk_index;
  int server_mk_vdes = NULL_VOLDES;
  int backup_mk_vdes = NULL_VOLDES;
  int err = NO_ERROR;

  assert (tde_is_loaded ());

  if (thread_p == NULL)
    {
      thread_p = thread_get_thread_entry_info ();
    }

  err = tde_get_keyinfo (thread_p, &keyinfo);
  if (err != NO_ERROR)
    {
      goto exit;
    }

  /* Check the mk file on the server */
  tde_make_keys_file_fullname (mk_path, boot_db_full_name (), false);

  server_mk_vdes = fileio_mount (thread_p, boot_db_full_name (), mk_path, LOG_DBTDE_KEYS_VOLID, 2, false);
  if (server_mk_vdes != NULL_VOLDES && tde_validate_keys_file (server_mk_vdes))
    {
      err = tde_load_mk (server_mk_vdes, &keyinfo, master_key);
      if (err == NO_ERROR)
    {
      /* case (1): There is the master key in the server key file:
       * Nothing to do */
      goto exit;
    }
    }

  /* 
   * case (2):
   * There isn't the key set on the database in the server key file,
   * So we just copy the backup file as a new server key file 
   * and set the first key in the file as the master key.
   */

  /* No need to mount. The mk file from backup is not accessed by others */
  backup_mk_vdes = fileio_open (r_args->keys_file_path, O_RDWR, 0600);
  if (backup_mk_vdes == NULL_VOLDES)
    {
      /* not expected. if it doens't exist, loading tde must have failed and this function shoudn't have been called. */
      assert (false);
      ASSERT_ERROR_AND_SET (err);
      goto exit;
    }

  if (tde_validate_keys_file (backup_mk_vdes) == false)
    {
      /* not expected. if it is not valid, loading tde must have failed and this function shoudn't have been called. */
      assert (false);
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_TDE_INVALID_KEYS_FILE, 1, mk_path);
      err = ER_TDE_INVALID_KEYS_FILE;
      goto exit;
    }

  err = tde_find_first_mk (backup_mk_vdes, &mk_index, master_key, &created_time);
  if (err != NO_ERROR)
    {
      goto exit;
    }

  fileio_close (backup_mk_vdes);
  backup_mk_vdes = NULL_VOLDES;

  /* if a server key file exists, move it */
  if (server_mk_vdes != NULL_VOLDES)
    {
      er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_TDE_RESTORE_KEY_FOUND_ONLY_FROM_BACKUP, 1, mk_path);

      strcpy (mk_path_old, mk_path);
      strcat (mk_path_old, "_old");
      fileio_unformat_and_rename (thread_p, mk_path, mk_path_old);
      server_mk_vdes = NULL_VOLDES;

      er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_TDE_RESTORE_MAKE_KEYS_FILE_OLD, 2, mk_path, mk_path_old);
    }

  err = tde_copy_keys_file (thread_p, mk_path, r_args->keys_file_path, false, false);
  if (err != NO_ERROR)
    {
      goto exit;
    }

  er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_TDE_RESTORE_COPY_KEYS_FILE, 2, r_args->keys_file_path, mk_path);

  err = tde_change_mk (thread_p, mk_index, master_key, created_time);
  if (err != NO_ERROR)
    {
      goto exit;
    }

  ctime_r (&created_time, ctime_buf);

  time_str_len = strlen (ctime_buf);
  if (time_str_len > 0 && ctime_buf[time_str_len - 1] == '\n')
    {
      ctime_buf[time_str_len - 1] = '\0';
    }
  er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_TDE_RESTORE_CHANGE_MASTER_KEY, 2, mk_index, ctime_buf);

  if (xtran_server_commit (thread_p, false) != TRAN_UNACTIVE_COMMITTED)
    {
      ASSERT_ERROR ();
      err = er_errid ();
      goto exit;
    }

exit:
  if (server_mk_vdes != NULL_VOLDES)
    {
      fileio_dismount (thread_p, server_mk_vdes);
    }
  if (backup_mk_vdes != NULL_VOLDES)
    {
      fileio_close (backup_mk_vdes);
    }
  return err;
}

/*
 * xboot_shutdown_server () - shutdown CUBRID server
 *
 * return : true
 *
 *   thread_p (in/out) : input thread entry; outputs NULL if thread is finalized (SA_MODE)
 *   is_er_final(in): Terminate the error module..
 *
 * Note: All active transactions of all clients are aborted and the
 *       CUBRID server is terminated. Any database temporarily volume
 *       is destroyed.
 */
bool
xboot_shutdown_server (REFPTR (THREAD_ENTRY, thread_p), ER_FINAL_CODE is_er_final)
{
  if (!BO_IS_SERVER_RESTARTED ())
    {
      return true;
    }

#if defined(CUBRID_DEBUG)
  boot_check_db_at_num_shutdowns (true);
#endif /* CUBRID_DEBUG */

  sysprm_set_force (PRM_ID_SUPPRESS_FSYNC, "0");

  /* Shutdown the system with the system transaction */
  logtb_set_to_system_tran_index (thread_p);
  log_abort_all_active_transaction (thread_p);
  vacuum_stop_workers (thread_p);

  /* before removing temp vols */
  (void) logtb_reflect_global_unique_stats_to_btree (thread_p);
  qfile_finalize_list_cache (thread_p);
  xcache_finalize (thread_p);
  fpcache_finalize (thread_p);
  session_states_finalize (thread_p);

  (void) boot_remove_all_temp_volumes (thread_p, REMOVE_TEMP_VOL_DEFAULT_ACTION);

  /* remove lob ces temp dir */
  (void) fileio_lob_remove_matching_dir (BOOT_LOB_TEMP_DIR_KEYWORD);

  // ha delays are registered and logged, and must be stopped before vacuum master
  log_stop_ha_delay_registration ();

  // only after all logging is finished can this vacuum master be stopped; boot_remove_all_temp_volumes may add a final
  // log entry
  // hopefully, nothing else follows
  vacuum_stop_master (thread_p);

#if defined(SERVER_MODE)
  pgbuf_daemons_destroy ();
  cdc_daemons_destroy ();
  pl_server_destroy ();
  parallel_query::worker_manager_global::get_manager ().destroy ();
#endif

#if defined (SA_MODE)
  vacuum_sa_reflect_last_blockid (thread_p);
#endif // SA_MODE
  log_final (thread_p);

  /* Since all pages were flushed, now it's safe to destroy DWB. */
  (void) dwb_destroy (thread_p);

  if (is_er_final == ER_ALL_FINAL)
    {
      boot_server_all_finalize (thread_p, is_er_final, BOOT_SHUTDOWN_EXCEPT_COMMON_MODULES);
    }
  else
    {
      er_stack_push ();
      boot_server_all_finalize (thread_p, is_er_final, BOOT_SHUTDOWN_EXCEPT_COMMON_MODULES);
      er_stack_pop ();
    }

#if defined (SA_MODE)
  // stop thread module
  cubthread::finalize ();
  thread_p = NULL;
#endif // SA_MODE

  return true;
}

/*
 * xboot_get_server_session_key ()
 */
const char *
xboot_get_server_session_key (void)
{
  return boot_Server_session_key;
}

/*
 * xboot_register_client () - register a client
 *
 * return : transaction index or NULL_TRAN_INDEX in the case of error.
 *
 *   client_credential(in): Client's credential (see boot.h)
 *   client_lock_wait(in): Wait for at least this number of milliseconds to acquire
 *                         a lock. Negative value is infinite
 *   client_isolation(in): Isolation level. One of the following:
 *                         TRAN_REPEATABLE_READ
 *                         TRAN_READ_COMMITTED
 *                         TRAN_SERIALIZABLE
 *   tran_state(out): State of transaction
 *   server_credential(out): Server's credential (see boot.h)
 *
 * Note: If the CUBRID server is not already restarted, it is
 *       restarted. The calling client is registered and a transaction
 *       index is assigned to the client. If the last transaction
 *       executed on behalf of the client has client loose ends
 *       recovery tasks, such transaction is assigned to the client and
 *       and the transaction state is returned as a side effect.
 */
int
xboot_register_client (THREAD_ENTRY * thread_p, BOOT_CLIENT_CREDENTIAL * client_credential, int client_lock_wait,
               TRAN_ISOLATION client_isolation, TRAN_STATE * tran_state,
               BOOT_SERVER_CREDENTIAL * server_credential)
{
  // *INDENT-OFF*
  int tran_index;
  std::string db_user_save;
  char db_user_upper[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  bool skip_vacuum = false;
#if defined(SA_MODE)
  std::string adm_prg_file_name;
  CHECK_ARGS check_coll_and_timezone = { true, true };
#endif /* SA_MODE */
  // *INDENT-ON*

#if defined(SA_MODE)
  if (client_credential != NULL && !client_credential->program_name.empty ()
      && client_credential->client_type == DB_CLIENT_TYPE_ADMIN_UTILITY)
    {
      auto const sep_index = client_credential->program_name.find_last_of (PATH_SEPARATOR);
      if (sep_index != client_credential->program_name.npos)
    {
      adm_prg_file_name = client_credential->program_name.substr (sep_index + 1);
    }
      else
    {
      adm_prg_file_name = client_credential->program_name;
    }
    }
  if (!adm_prg_file_name.empty ())
    {
      if (strncasecmp (adm_prg_file_name.c_str (), "synccolldb", strlen ("synccolldb")) == 0
      || strncasecmp (adm_prg_file_name.c_str (), "migrate_", strlen ("migrate_")) == 0)
    {
      check_coll_and_timezone.check_db_coll = false;
    }
      if (strncasecmp (adm_prg_file_name.c_str (), "gen_tz", strlen ("gen_tz")) == 0)
    {
      check_coll_and_timezone.check_timezone = false;
    }
    }

  if (client_credential->client_type == DB_CLIENT_TYPE_SKIP_VACUUM_CSQL
      || client_credential->client_type == DB_CLIENT_TYPE_SKIP_VACUUM_ADMIN_CSQL)
    {
      skip_vacuum = true;
    }

  /* If the server is not restarted, restart the server at this moment */
  if (!BO_IS_SERVER_RESTARTED ()
      && boot_restart_server (thread_p, false, client_credential->get_db_name (), false, &check_coll_and_timezone,
                  NULL, skip_vacuum) != NO_ERROR)
    {
      *tran_state = TRAN_UNACTIVE_UNKNOWN;
      return NULL_TRAN_INDEX;
    }
#else /* SA_MODE */
  /* If the server is not restarted, returns an error */
  if (!BO_IS_SERVER_RESTARTED ())
    {
      *tran_state = TRAN_UNACTIVE_UNKNOWN;
      return NULL_TRAN_INDEX;
    }
#endif /* SA_MODE */

  /* Initialize scan function pointers of show statements */
  showstmt_scan_init ();

  db_user_save = client_credential->get_db_user ();
  if (!client_credential->db_user.empty ())
    {
      intl_identifier_upper (client_credential->get_db_user (), db_user_upper);
      client_credential->db_user = db_user_upper;
    }

  /* Assign a transaction index to the client */
  tran_index =
    logtb_assign_tran_index (thread_p, NULL_TRANID, TRAN_ACTIVE, client_credential, tran_state, client_lock_wait,
                 client_isolation);
#if defined (SERVER_MODE)
  if (thread_p->conn_entry->status != CONN_OPEN)
    {
      /* the connection is going down. stop it */
      logtb_release_tran_index (thread_p, tran_index);
      tran_index = NULL_TRAN_INDEX;
    }
#endif /* SERVER_MODE */

  if (tran_index != NULL_TRAN_INDEX)
    {
#if defined (SERVER_MODE)
      thread_p->conn_entry->set_tran_index (tran_index);
#endif /* SERVER_MODE */
      server_credential->db_full_name = boot_Db_full_name;
      server_credential->host_name = boot_Host_name;
      server_credential->lob_path = boot_Lob_path;
      server_credential->process_id = getpid ();
      COPY_OID (&server_credential->root_class_oid, &boot_Db_parm->rootclass_oid);
      if (boot_find_root_heap (&(server_credential->root_class_hfid)) != NO_ERROR
      || HFID_IS_NULL (&(server_credential->root_class_hfid)))
    {
      *tran_state = TRAN_UNACTIVE_UNKNOWN;
      return NULL_TRAN_INDEX;
    }

      server_credential->page_size = IO_PAGESIZE;
      server_credential->log_page_size = LOG_PAGESIZE;
      server_credential->disk_compatibility = rel_disk_compatible ();
#if defined (SERVER_MODE)
      server_credential->ha_server_state = css_ha_server_state ();
#else
      server_credential->ha_server_state = (HA_SERVER_STATE) prm_get_integer_value (PRM_ID_HA_SERVER_STATE);
#endif
      memcpy (server_credential->server_session_key, boot_Server_session_key, SERVER_SESSION_KEY_SIZE);
      server_credential->db_charset = lang_charset ();
      server_credential->db_lang = (char *) lang_get_Lang_name ();

#if defined(SERVER_MODE)
      /* Check the server's state for HA action for this client */
      if (BOOT_NORMAL_CLIENT_TYPE (client_credential->client_type))
    {
      if (css_check_ha_server_state_for_client (thread_p, 1) != NO_ERROR)
        {
          logtb_release_tran_index (thread_p, tran_index);
          er_log_debug (ARG_FILE_LINE, "xboot_register_client: css_check_ha_server_state_for_client() error\n");
          *tran_state = TRAN_UNACTIVE_UNKNOWN;
          client_credential->db_user = db_user_save;
          return NULL_TRAN_INDEX;
        }
    }
      if (client_credential->client_type == DB_CLIENT_TYPE_LOG_APPLIER)
    {
      css_notify_ha_log_applier_state (thread_p, HA_LOG_APPLIER_STATE_UNREGISTERED);
    }
#endif /* SERVER_MODE */

      er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_BO_CLIENT_CONNECTED, 4,
          client_credential->get_program_name (),
          client_credential->process_id, client_credential->get_host_name (), tran_index);
    }

#if defined(ENABLE_SYSTEMTAP) && defined(SERVER_MODE)
  CUBRID_CONN_START (thread_p->conn_entry->client_id, client_credential->get_db_user ());
#endif /* ENABLE_SYSTEMTAP */

  client_credential->db_user = db_user_save;
  return tran_index;
}

/*
 * xboot_unregister_client () - unregister a client
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 *   thread_p (in/out) : input thread entry; outputs NULL if thread is finalized (SA_MODE)
 *   tran_index(in): Client transaction index
 *
 * Note: A client is unregistered. Any active transactions on that
 *       client are aborted. This function is called when a client is
 *       disconnected or when a crash of the client is detected by the
 *       CUBRID server, to release resources acquired such as locks,
 *       and allocated memory, on behalf of the client.
 */
int
xboot_unregister_client (REFPTR (THREAD_ENTRY, thread_p), int tran_index)
{
  int save_index;
  LOG_TDES *tdes;
#if defined(SERVER_MODE)
  int client_id;
  CSS_CONN_ENTRY *conn;
#endif /* SERVER_MODE */

  if (BO_IS_SERVER_RESTARTED () && tran_index != NULL_TRAN_INDEX)
    {
      save_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);

      LOG_SET_CURRENT_TRAN_INDEX (thread_p, tran_index);
      tdes = LOG_FIND_TDES (tran_index);
#if defined(SERVER_MODE)
      conn = thread_p->conn_entry;
      client_id = (conn != NULL) ? conn->client_id : -1;
      if (tdes == NULL || tdes->client_id != client_id)
    {
      thread_p->tran_index = save_index;

#if defined(ENABLE_SYSTEMTAP)
      CUBRID_CONN_END (-1, "NULL");
#endif /* ENABLE_SYSTEMTAP */

      return NO_ERROR;
    }

      /* check if the client was a log applier */
      if (tdes->client.client_type == DB_CLIENT_TYPE_LOG_APPLIER)
    {
      css_notify_ha_log_applier_state (thread_p, HA_LOG_APPLIER_STATE_UNREGISTERED);
    }
      /* Check the server's state for HA action for this client */
      if (BOOT_NORMAL_CLIENT_TYPE (tdes->client.client_type))
    {
      if (css_check_ha_server_state_for_client (thread_p, 2) != NO_ERROR)
        {
          er_log_debug (ARG_FILE_LINE, "xboot_unregister_client: css_check_ha_server_state_for_client() error\n");
        }
    }
#else
      if (tdes == NULL)
    {
#if defined(ENABLE_SYSTEMTAP)
      CUBRID_CONN_END (-1, "NULL");
#endif /* ENABLE_SYSTEMTAP */

      return NO_ERROR;
    }
#endif /* SERVER_MODE */

      /*
       * If the transaction is active only abort it.
       * Don't abort transactions in LOG_ISTRAN_2PC_PREPARE arbitrarily.
       */
#ifdef CCI_XA
      if (LOG_ISTRAN_ACTIVE (tdes))
#else
      if (LOG_ISTRAN_ACTIVE (tdes) || LOG_ISTRAN_2PC_PREPARE (tdes))    /* logtb_is_current_active (thread_p) */
#endif
    {
      (void) xtran_server_abort (thread_p);
    }

      perfmon_stop_watch (thread_p);

#if defined(ENABLE_SYSTEMTAP) && defined(SERVER_MODE)
      CUBRID_CONN_END (client_id, tdes->client.get_db_user ());
#endif /* ENABLE_SYSTEMTAP */

      /* Release the transaction index */
      logtb_release_tran_index (thread_p, tran_index);

      LOG_SET_CURRENT_TRAN_INDEX (thread_p, save_index);
    }

#if defined(CUBRID_DEBUG)
  boot_check_db_at_num_shutdowns (false);
#endif /* CUBRID_DEBUG */

#if defined(SA_MODE)
  (void) xboot_shutdown_server (thread_p, ER_ALL_FINAL);
#endif /* SA_MODE */

  return NO_ERROR;
}

#if defined(SERVER_MODE)
/*
 * xboot_notify_unregister_client () -
 *
 * return :
 *
 *   tran_index(in) :
 *
 * Note:
 */
void
xboot_notify_unregister_client (THREAD_ENTRY * thread_p, int tran_index)
{
  CSS_CONN_ENTRY *conn;
  LOG_TDES *tdes;
  int client_id;

  conn = thread_p->conn_entry;

  /* sboot_notify_unregister_client should hold conn->rmutex.
   * Please see the comment of sboot_notify_unregister_client.
   */

  client_id = conn->client_id;
  tdes = LOG_FIND_TDES (tran_index);
  if (tdes != NULL && tdes->client_id == client_id)
    {
      if (conn->status == CONN_OPEN)
    {
      conn->status = CONN_CLOSING;
    }
    }
}
#endif /* SERVER_MODE */

#if defined(CUBRID_DEBUG)
/*
 * boot_check_db_at_num_shutdowns () - run checkdb when a number of client
 *                                       shutdowns has been executed.
 *                                       This is a debugging function.
 *
 *   force_nshutdowns(in): true if only forcing is desired.
 *
 * Note: Run checkdb when a number of client shutdowns has been
 *       executed (at the same or across several server sessions) and
 *       the env variable CUBRID_CHECKDB_ATNUM_SHUTDOWNS has a value
 *       greater than zero at the server process. The environment value
 *       indicates when to execute the checkdb.
 *
 * Side-effect: A file with the name ".checkdb_num_shutdowns" is created to
 *              to save the number of client shutdowns. This file is removed
 *              once the above env variable is not set.
 *              Note this file is not associated with a particular database.
 *              Therefore, the file could be modified (and removed) by several
 *              servers (databases). This will work OK, for most practical
 *              purposes. No a good reason, why it was implemented this way.
 *              The author was lazy and it was for debugging only.
 */
static void
boot_check_db_at_num_shutdowns (bool force_nshutdowns)
{
  const char *env_value;
  const char *checkdb_file_num_shutdowns = ".checkdb_num_shutdowns";
  FILE *fp;
  static int checkdb_every_nshutdowns = -1;
  static int num_current_shutdowns = -1;

  if (force_nshutdowns == true)
    {
      if (checkdb_every_nshutdowns > 0 && (fp = fopen (checkdb_file_num_shutdowns, "w")) != NULL)
    {
      fprintf (fp, "%d", num_current_shutdowns);
      fclose (fp);
    }
      return;
    }

  /*
   * Check the consistency of the database when the client is unregister
   */

  if (checkdb_every_nshutdowns == -1)
    {
      env_value = envvar_get ("CHECKDB_EVERY_NSHUTDOWNS");
      if (env_value != NULL)
    {
      checkdb_every_nshutdowns = atoi (env_value);
    }
      else
    {
      checkdb_every_nshutdowns = 0;
    }

      if (checkdb_every_nshutdowns <= 0)
    {
      checkdb_every_nshutdowns = 0; /* Don't check at all */
      (void) remove (checkdb_file_num_shutdowns);
      return;
    }

      fp = fopen (checkdb_file_num_shutdowns, "r");
      if (fp != NULL)
    {
      if (fscanf (fp, "%d", &num_current_shutdowns) != 1)
        {
          num_current_shutdowns = 0;
        }
    }
      else
    {
      num_current_shutdowns = 0;
    }
    }

  if (checkdb_every_nshutdowns > 0)
    {
      num_current_shutdowns++;

      if (num_current_shutdowns == checkdb_every_nshutdowns)
    {
      num_current_shutdowns = 0;
      if (xboot_check_db_consistency () != NO_ERROR)
        {
          const char *tmpname;
          fflush (stderr);
          fflush (stdout);
          tmpname = er_get_msglog_filename ();
          if (tmpname == NULL)
        {
          tmpname = "/dev/null";
        }
          fprintf (stdout,
               "Some inconsistencies were detected in your database.\n Please consult error_log file = %s"
               " for additional information\n", tmpname);
          fflush (stdout);
          /*
           * The following is added so we can attach to the debugger on
           * a fatal error. It is of great help to stop execution when
           * running a set of sql scripts. (That is, find the script that
           * leave the DB inconsistent).
           */
          er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
        }
    }
    }
}
#endif /* CUBRID_DEBUG */

enum
{
  CHECK_ONLY = 0,
  REPAIR_ALL = 1
};

/*
 * xboot_checkdb_table () - check consistency of table
 *                              as much as possible
 *
 * return :
 *
 */
DISK_ISVALID
xboot_checkdb_table (THREAD_ENTRY * thread_p, int check_flag, OID * oid, BTID * index_btid)
{
  int error_code;
  HFID hfid;
  bool repair = check_flag & CHECKDB_REPAIR;
  DISK_ISVALID allvalid, valid;
  HEAP_SCANCACHE scan_cache;
  RECDES peek_recdes;

  allvalid = DISK_VALID;

  if (check_flag & CHECKDB_CHECK_PREV_LINK)
    {
      valid = btree_repair_prev_link (thread_p, oid, index_btid, CHECK_ONLY);
      if (valid == DISK_ERROR)
    {
      return DISK_ERROR;
    }
      if (valid != DISK_VALID)
    {
      allvalid = valid;
    }
    }

  if (check_flag & CHECKDB_REPAIR_PREV_LINK)
    {
      valid = btree_repair_prev_link (thread_p, oid, index_btid, REPAIR_ALL);
      if (valid == DISK_ERROR)
    {
      return DISK_ERROR;
    }
      if (valid != DISK_VALID)
    {
      allvalid = valid;
    }
    }

  if (heap_get_class_info (thread_p, oid, &hfid, NULL, NULL) != NO_ERROR || HFID_IS_NULL (&hfid))
    {
      return DISK_ERROR;
    }

  if (index_btid == NULL)
    {
      /* if index name was specified, skip checking heap file */
      if (lock_object (thread_p, oid, oid_Root_class_oid, IS_LOCK, LK_UNCOND_LOCK) != LK_GRANTED)
    {
      return DISK_ERROR;
    }
      error_code = heap_scancache_quick_start_root_hfid (thread_p, &scan_cache);
      if (error_code != NO_ERROR)
    {
      lock_unlock_object (thread_p, oid, oid_Root_class_oid, IS_LOCK, true);
      return DISK_ERROR;
    }
      /* Check heap file is really exist. It can be removed. */
      if (heap_get_class_record (thread_p, oid, &peek_recdes, &scan_cache, PEEK) != S_SUCCESS)
    {
      heap_scancache_end (thread_p, &scan_cache);
      lock_unlock_object (thread_p, oid, oid_Root_class_oid, IS_LOCK, true);
      return DISK_ERROR;
    }
      heap_scancache_end (thread_p, &scan_cache);

      valid = heap_check_heap_file (thread_p, &hfid);
      if (valid == DISK_ERROR)
    {
      lock_unlock_object (thread_p, oid, oid_Root_class_oid, IS_LOCK, true);
      return DISK_ERROR;
    }
      if (valid != DISK_VALID)
    {
      allvalid = valid;
    }

      lock_unlock_object (thread_p, oid, oid_Root_class_oid, IS_LOCK, true);
    }

  valid = btree_check_by_class_oid (thread_p, oid, index_btid);
  if (valid == DISK_ERROR)
    {
      return DISK_ERROR;
    }
  if (valid != DISK_VALID)
    {
      allvalid = valid;
    }

  valid = locator_check_by_class_oid (thread_p, oid, &hfid, index_btid, repair);
  if (valid == DISK_ERROR)
    {
      return DISK_ERROR;
    }
  if (valid != DISK_VALID)
    {
      allvalid = valid;
    }

  return allvalid;
}

/*
 * xcallback_console_print -
 *
 * return:
 *
 *   print_str(in):
 */
#if defined (SA_MODE)
int
xcallback_console_print (THREAD_ENTRY * thread_p, char *print_str)
{
  fprintf (stdout, print_str);

  return NO_ERROR;
}
#endif

/*
 * xboot_check_db_consistency () - check consistency of database
 *                              as much as possible
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 */
int
xboot_check_db_consistency (THREAD_ENTRY * thread_p, int check_flag, OID * oids, int num_oids, BTID * index_btid)
{
  DISK_ISVALID isvalid = DISK_VALID;
  int i;
  bool repair = check_flag & CHECKDB_REPAIR;
  int error_code = NO_ERROR;

  disk_lock_extend ();
  error_code = boot_check_permanent_volumes (thread_p);
  disk_unlock_extend ();

  isvalid = disk_check (thread_p, repair);
  if (isvalid != DISK_VALID)
    {
      ASSERT_ERROR_AND_SET (error_code);
    }

  if (index_btid != NULL && BTID_IS_NULL (index_btid))
    {
      index_btid = NULL;
    }

  if (num_oids > 0)
    {
      for (i = 0; i < num_oids; i++)
    {
      if (OID_ISNULL (&oids[i]))
        {
          continue;
        }
      isvalid = xboot_checkdb_table (thread_p, check_flag, &oids[i], index_btid);

      if (isvalid != DISK_VALID)
        {
          error_code = ER_FAILED;
        }
    }
      return error_code;
    }

  if (check_flag & CHECKDB_CHECK_PREV_LINK)
    {
      if (isvalid != DISK_ERROR)
    {
      isvalid = btree_repair_prev_link (thread_p, NULL, NULL, CHECK_ONLY);
      if (isvalid != DISK_VALID)
        {
          error_code = ER_FAILED;
        }
    }
    }

  if (check_flag & CHECKDB_REPAIR_PREV_LINK)
    {
      if (isvalid != DISK_ERROR)
    {
      isvalid = btree_repair_prev_link (thread_p, NULL, NULL, REPAIR_ALL);
      if (isvalid != DISK_VALID)
        {
          error_code = ER_FAILED;
        }
    }
    }

  if (check_flag & CHECKDB_FILE_TRACKER_CHECK)
    {
      if (isvalid != DISK_ERROR)
    {
      isvalid = file_tracker_check (thread_p);
      if (isvalid != DISK_VALID)
        {
          assert (isvalid != DISK_INVALID);
          ASSERT_ERROR_AND_SET (error_code);
        }
    }
    }

  if (check_flag & CHECKDB_HEAP_CHECK_ALLHEAPS)
    {
      if (isvalid != DISK_ERROR)
    {
      isvalid = heap_check_all_heaps (thread_p);
      if (isvalid != DISK_VALID)
        {
          error_code = ER_FAILED;
        }
    }
    }

  if (check_flag & CHECKDB_CT_CHECK_CAT_CONSISTENCY)
    {
      if (isvalid != DISK_ERROR)
    {
      isvalid = catalog_check_consistency (thread_p);
      if (isvalid != DISK_VALID)
        {
          error_code = ER_FAILED;
        }
    }
    }

  if (check_flag & CHECKDB_BTREE_CHECK_ALL_BTREES)
    {
      if (isvalid != DISK_ERROR)
    {
      isvalid = btree_check_all (thread_p);
      if (isvalid != DISK_VALID)
        {
          error_code = ER_FAILED;
        }
    }
    }

  if (check_flag & CHECKDB_LC_CHECK_CLASSNAMES)
    {
      if (isvalid != DISK_ERROR)
    {
      isvalid = locator_check_class_names (thread_p);
      if (isvalid != DISK_VALID)
        {
          error_code = ER_FAILED;
        }
    }
    }

  if (check_flag & CHECKDB_LC_CHECK_ALLENTRIES_OF_ALLBTREES)
    {
      if (isvalid != DISK_ERROR)
    {
      isvalid = locator_check_all_entries_of_all_btrees (thread_p, repair);
      if (isvalid != DISK_VALID)
        {
          error_code = ER_FAILED;
        }
    }
    }

  return error_code;
}

/*
 * boot_server_all_finalize () - terminate every single module
 *               except the log/recovery manager
 *   is_er_final(in): Terminate the error module..
 *   shutdown_common_modules(in): Terminate all common modules (for SA mode)
 *                if SERVER_MODE, this is implied BOOT_SHUTDOWN_ALL_MODULES.
 *
 * Note: Every single module except the log/recovery manager are
 *       uninitialized. All data volumes are unmounted.
 */
void
boot_server_all_finalize (THREAD_ENTRY * thread_p, ER_FINAL_CODE is_er_final,
              BOOT_SERVER_SHUTDOWN_MODE shutdown_common_modules)
{
  logtb_finalize_global_unique_stats_table (thread_p);
  locator_finalize (thread_p);
  spage_finalize (thread_p);
  catalog_finalize ();
  qmgr_finalize (thread_p);
  (void) heap_manager_finalize ();
  fileio_dismount_all (thread_p);
  disk_manager_final ();
  boot_server_status (BOOT_SERVER_DOWN);

  catcls_finalize_class_oid_to_oid_hash_table (thread_p);
  serial_finalize_cache_pool ();
  partition_cache_finalize (thread_p);

  // return lock-free transaction and destroy the system.
  thread_return_lock_free_transaction_entries ();
  lf_destroy_transaction_systems ();

  perfmon_finalize ();

#if defined(SERVER_MODE)
  /* server mode shuts down all modules */
  shutdown_common_modules = BOOT_SHUTDOWN_ALL_MODULES;
#endif /* SERVER_MODE */

  if (shutdown_common_modules == BOOT_SHUTDOWN_ALL_MODULES)
    {
      es_final ();
      tp_final ();
      locator_free_areas ();
      set_final ();
      sysprm_final ();
      area_final ();
      msgcat_final ();
      if (is_er_final == ER_ALL_FINAL)
    {
      er_final (ER_ALL_FINAL);
    }
      lang_final ();
      tz_unload ();
    }

#if defined(SERVER_MODE)
  css_free_accessible_ip_info ();
  event_log_final ();
  trace_log_final ();
#endif
}

/*
 * xboot_backup () - a fuzzy backup of the database
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 *   backup_path(in): Location where information volumes are backed up. If NULL is given, the following defaults
 *                are assumed to back up each information volume:
 *                    - If file "fileof_vols_and_backup_paths" is given, the path to backup each volume is found in
 *                      this file.
 *                    - All information volumes are backed up on the same location where the log files are located.
 *   backup_level(in): backup levels allowed: 0 - Full (default),
 *                     1 - Incremental1, 2 - Incremental
 *   deleted_unneeded_logarchives(in): Whether to remove log archives that are not needed any longer to recovery from
 *                         crashes when the backup just created is used.
 *   backup_verbose_file(in): verbose mode file path
 *   num_threads: number of threads
 *   zip_method: compression method
 *   zip_level: compression level
 *   sleep_msecs(in):
 *
 * Note: A fuzzy backup of the database is taken. The backup is written into the given backup_path location.
 *       If the backup_path location is omitted (i.e, NULL is given), the log path location which was specified at
 *       database creation is used to store the backup.
 */
int
xboot_backup (THREAD_ENTRY * thread_p, const char *backup_path, FILEIO_BACKUP_LEVEL backup_level,
          bool delete_unneeded_logarchives, const char *backup_verbose_file, int num_threads,
          FILEIO_ZIP_METHOD zip_method, FILEIO_ZIP_LEVEL zip_level, int skip_activelog, int sleep_msecs,
          bool separate_keys)
{
  int error_code;

  error_code =
    logpb_backup (thread_p, boot_Db_parm->nvols, backup_path, backup_level, delete_unneeded_logarchives,
          backup_verbose_file, num_threads, zip_method, zip_level, skip_activelog, sleep_msecs, separate_keys);
  return error_code;
}

/*
 * xboot_copy () - copy the database to a new destination
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 *   thread_p (in/out) : input thread entry; outputs NULL if thread is finalized (SA_MODE)
 *   fromdb_name(in): The database from where the copy is made.
 *   newdb_name(in): Name of new database
 *   newdb_path(in): Directory where the new database will reside
 *   newlog_path(in): Directory where the log volumes of the new database will reside
 *   newlob_path(in): Directory where the lob volumes of the new database will reside
 *   newdb_server_host(in): Server host where the new database reside
 *   new_volext_path(in): A path is included if all volumes are placed in one place/directory. If NULL is given,
 *                        - If file "fileof_vols_and_wherepaths" is given, the path is found in this file.
 *                        - Each volume is copied to same place where the volume resides.
 *                      Note: This parameter should be NULL, if the above file is given.
 *   fileof_vols_and_wherepaths(in): A file is given when the user decides to control the copy/rename of the volume by
 *                               individual bases. That is, user decides to spread the volumes over several locations
 *                               and or to label the volumes with specific names.
 *                               Each volume entry consists of: volid from_fullvolname to_fullvolname
 *   newdb_overwrite(in): Whether to overwrite the new database if it already exist.
 */
int
xboot_copy (REFPTR (THREAD_ENTRY, thread_p), const char *from_dbname, const char *new_db_name, const char *new_db_path,
        const char *new_log_path, const char *new_lob_path, const char *new_db_server_host,
        const char *new_volext_path, const char *fileof_vols_and_copypaths, bool new_db_overwrite)
{
  DB_INFO *dir = NULL;
  DB_INFO *db = NULL;
  const char *new_log_prefix;
  char new_db_fullname[PATH_MAX];
  char new_db_pathbuf[PATH_MAX];
  char new_db_pathbuf2[PATH_MAX];
  char new_log_pathbuf[PATH_MAX];
  char new_lob_pathbuf2[PATH_MAX];
  char new_lob_pathbuf[PATH_MAX];
  char new_volext_pathbuf[PATH_MAX];
  char fixed_pathbuf[PATH_MAX];
  char new_db_server_host_buf[CUB_MAXHOSTNAMELEN + 1];
  char dbtxt_label[PATH_MAX];
  int dbtxt_vdes = NULL_VOLDES;
  int error_code = NO_ERROR;
#if defined (WINDOWS)
  struct stat stat_buf;
#endif

  assert (thread_p != NULL);

  /* If db_path and/or log_path are NULL find the defaults */

  if (new_db_path == NULL || fileof_vols_and_copypaths != NULL)
    {
      /*
       * If a newdb path was given, it is ignored since only one option must
       * be specified
       */
      new_db_path = boot_find_new_db_path (new_db_pathbuf, fileof_vols_and_copypaths);
      if (new_db_path == NULL)
    {
      error_code = ER_FAILED;
      goto error;
    }
    }

  /*
   * Make sure that the db_path and log_path are the canonicalized absolute
   * pathnames
   */

  if (new_db_path == NULL)
    {
      new_db_path = "";
    }
  else if (realpath ((char *) new_db_path, new_db_pathbuf2) != NULL)
    {
      new_db_path = new_db_pathbuf2;
    }

  if (new_log_path != NULL && realpath ((char *) new_log_path, new_log_pathbuf) != NULL)
    {
      new_log_path = new_log_pathbuf;
    }

  if (new_log_path == NULL)
    {
      /* Assign the data volume directory */
      strcpy (new_log_pathbuf, new_db_path);
      new_log_path = new_log_pathbuf;
    }

  if (new_lob_path == NULL)
    {
      assert_release (new_db_path != NULL);
      if (snprintf (new_lob_pathbuf2, sizeof (new_lob_pathbuf2), "%s%s/lob", LOB_PATH_DEFAULT_PREFIX, new_db_path) < 0)
    {
      assert_release (false);
    }
      new_lob_path = new_lob_pathbuf2;
    }

  if (new_lob_path != NULL)
    {
      ES_TYPE es_type = es_get_type (new_lob_path);
      char *p = NULL;

      switch (es_type)
    {
    case ES_NONE:
      /* prepend default prefix */
      if (snprintf (new_lob_pathbuf, sizeof (new_lob_pathbuf), "%s%s", LOB_PATH_DEFAULT_PREFIX, new_lob_path) < 0)
        {
          assert_release (false);
        }
      new_lob_path = new_lob_pathbuf;
      es_type = ES_POSIX;
      p = (char *) strchr (new_lob_path, ':') + 1;
      break;
    case ES_POSIX:
      p = strchr (strcpy (new_lob_pathbuf, new_lob_path), ':') + 1;
      break;
    case ES_OWFS:
#if !defined (CUBRID_OWFS)
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_INVALID_PATH, 1, new_lob_path);
      error_code = ER_ES_INVALID_PATH;
      goto error;
#endif /* !CUBRID_OWFS */
    case ES_LOCAL:
    default:
      break;
    }

      if (es_type == ES_POSIX && p != NULL)
    {
#if defined (WINDOWS)
      if (realpath (p, fixed_pathbuf) != NULL
          && (stat (fixed_pathbuf, &stat_buf) == 0 && S_ISDIR (stat_buf.st_mode)))
#else
      if (realpath (p, fixed_pathbuf) != NULL)
#endif
        {
          strcpy (p, fixed_pathbuf);
        }
      else
        {
          er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_BO_DIRECTORY_DOESNOT_EXIST, 1, p);
          if (mkdir (p, 0700) < 0)
        {
          cub_dirname_r (p, fixed_pathbuf, PATH_MAX);
          er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", fixed_pathbuf);
          error_code = ER_BO_DIRECTORY_DOESNOT_EXIST;
          goto error;
        }
        }
    }
    }

  if (new_volext_path != NULL && realpath ((char *) new_volext_path, new_volext_pathbuf) != NULL)
    {
      new_volext_path = new_volext_pathbuf;
    }

  /* If a host was not given, assume the current host */

  if (new_db_server_host == NULL)
    {
      strcpy (new_db_server_host_buf, "localhost");
      new_db_server_host = new_db_server_host_buf;
    }

  /* Make sure that the full path for the new database is not too long */
  if ((int) (strlen (new_db_name) + strlen (new_db_path) + 2) > DB_MAX_PATH_LENGTH)
    {
      /*
       * db_path + db_name is too long
       */
      er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_FULL_DATABASE_NAME_IS_TOO_LONG, 3, new_db_path, new_db_name,
          strlen (new_db_name) + strlen (new_db_path) + 2, DB_MAX_PATH_LENGTH);
      error_code = ER_BO_FULL_DATABASE_NAME_IS_TOO_LONG;
      goto error;
    }

  /* Get the log prefix */
  new_log_prefix = fileio_get_base_file_name (new_db_name);

  /*
   * get the database directory information in write mode
   */
  if (cfg_maycreate_get_directory_filename (dbtxt_label) == NULL
#if !defined(WINDOWS) || !defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
/* Temporary fix for NT file locking problem */
      || (dbtxt_vdes = fileio_mount (thread_p, dbtxt_label, dbtxt_label, LOG_DBTXT_VOLID, 2, true)) == NULL_VOLDES
#endif /* !WINDOWS || !DONT_USE_MANDATORY_LOCK_IN_WINDOWS */
    )
    {
      error_code = ER_FAILED;
      goto error;
    }

  if (dbtxt_vdes != NULL_VOLDES)
    {
      error_code = cfg_read_directory_ex (dbtxt_vdes, &dir, true);
      if (error_code != NO_ERROR)
    {
      goto error;
    }
    }
  else
    {
      error_code = cfg_read_directory (&dir, true);
      if (error_code != NO_ERROR)
    {
      goto error;
    }
    }

  if (dir != NULL && ((db = cfg_find_db_list (dir, new_db_name)) != NULL))
    {
      if (new_db_overwrite == false)
    {
      /* There is a database with the same name and we cannot overwrite it */
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_DATABASE_EXISTS, 1, new_db_name);
      {
        error_code = ER_BO_DATABASE_EXISTS;
        goto error;
      }
    }
      else
    {
      /*
       * Delete the database.. to make sure that all backups, log archives, and
       * so on are removed... then continue...
       * Note: we do not call xboot_delete since it reverts a bunch of stuff.
       */
      CHECK_ARGS check_col_and_timezone = { true, true };
      cfg_free_directory (dir);
      dir = NULL;

      if (dbtxt_vdes != NULL_VOLDES)
        {
          fileio_dismount (thread_p, dbtxt_vdes);
          dbtxt_vdes = NULL_VOLDES;
        }
      (void) xboot_shutdown_server (thread_p, ER_THREAD_FINAL);

      error_code = xboot_delete (new_db_name, true, BOOT_SHUTDOWN_EXCEPT_COMMON_MODULES);
      if (error_code != NO_ERROR)
        {
          goto error;
        }
      check_col_and_timezone.check_db_coll = false;
      error_code = boot_restart_server (thread_p, false, from_dbname, false, &check_col_and_timezone, NULL, false);
      if (error_code != NO_ERROR)
        {
          goto error;
        }

      // get current thread entry
      thread_p = thread_get_thread_entry_info ();
      error_code =
        xboot_copy (thread_p, from_dbname, new_db_name, new_db_path, new_log_path, new_lob_path, new_db_server_host,
            new_volext_path, fileof_vols_and_copypaths, false);
      assert (thread_p == NULL);

      return error_code;
    }
    }

  if (dbtxt_vdes != NULL_VOLDES)
    {
      fileio_dismount (thread_p, dbtxt_vdes);   /* unlock the directory file */
      dbtxt_vdes = NULL_VOLDES;
      cfg_free_directory (dir);
      dir = NULL;
    }

  /*
   * Compose the full name of the new database
   */

  COMPOSE_FULL_NAME (new_db_fullname, sizeof (new_db_fullname), new_db_path, new_db_name);

  /*
   * Copy the database
   */

  error_code =
    logpb_copy_database (thread_p, boot_Db_parm->nvols, new_db_fullname, new_log_path, new_log_prefix, new_volext_path,
             fileof_vols_and_copypaths);
  if (error_code != NO_ERROR)
    {
      (void) xtran_server_abort (NULL);
    }
  else
    {
      /* Now create the entry in the database table */

      if (xtran_server_commit (thread_p, false) != TRAN_UNACTIVE_COMMITTED)
    {
      error_code = ER_FAILED;
      goto error;
    }

#if !defined(WINDOWS) || !defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
      dbtxt_vdes = fileio_mount (thread_p, dbtxt_label, dbtxt_label, LOG_DBTXT_VOLID, 2, true);
      if (dbtxt_vdes == NULL_VOLDES)
    {
      error_code = ER_FAILED;
      goto error;
    }
#endif /* !WINDOWS || !DONT_USE_MANDATORY_LOCK_IN_WINDOWS */

      if (dbtxt_vdes != NULL_VOLDES)
    {
      error_code = cfg_read_directory_ex (dbtxt_vdes, &dir, true);
      if (error_code != NO_ERROR)
        {
          goto error;
        }
    }
      else
    {
      error_code = cfg_read_directory (&dir, true);
      if (error_code != NO_ERROR)
        {
          goto error;
        }
    }
      db = cfg_find_db_list (dir, new_db_name);

      if (db == NULL)
    {
      db = cfg_add_db (&dir, new_db_name, new_db_path, new_log_path, new_lob_path, new_db_server_host);
    }
      else
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_DATABASE_EXISTS, 1, new_db_name);
      error_code = ER_BO_DATABASE_EXISTS;
      goto error;
    }

      if (dbtxt_vdes != NULL_VOLDES)
    {
      cfg_write_directory_ex (dbtxt_vdes, dir);
    }
      else
    {
      cfg_write_directory (dir);
    }

#if defined(WINDOWS) && !defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
      if (dbtxt_vdes != NULL_VOLDES)
    {
      fileio_dismount (thread_p, dbtxt_vdes);
      dbtxt_vdes = NULL_VOLDES;
    }
#endif /* WINDOWS && !DONT_USE_MANDATORY_LOCK_IN_WINDOWS */
    }

  cfg_free_directory (dir);
  if (dbtxt_vdes != NULL_VOLDES)
    {
      fileio_dismount (thread_p, dbtxt_vdes);
    }

  (void) xboot_shutdown_server (thread_p, ER_THREAD_FINAL);
  return error_code;

error:
  if (dir != NULL)
    {
      cfg_free_directory (dir);
    }

  if (dbtxt_vdes != NULL_VOLDES)
    {
      fileio_dismount (thread_p, dbtxt_vdes);
    }

  (void) xboot_shutdown_server (thread_p, ER_THREAD_FINAL);

  return error_code;
}

/*
 * xboot_soft_rename () - a soft rename of a database on the same disk partitions
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 *   olddb_name(in): Name of new database
 *   newdb_name(in): Directory where the new database will reside
 *   newdb_path(in): Directory where the log volumes of the new database
 *                        will reside
 *   newlog_path(in): Server host where the new database reside
 *   newdb_server_host(in): Wheater to overwrite the new database if it already
 *                        exist.
 *   new_volext_path(in): A path is included if all volumes are placed in one
 *                        place/directory. If NULL is given,
 *                        - If file "fileof_vols_and_wherepaths" is given, the
 *                          path is found in this file.
 *                        - Each volume is copied to same place where the
 *                          volume resides.
 *                      Note: This parameter should be NULL, if the above file
 *                            is given.
 *   fileof_vols_and_renamepaths(in):A file is given when the user decides to
 *                               control the rename of the volume by
 *                               individual bases. That is, user decides to
 *                               spread the volumes over several locations and
 *                               or to label the volumes with specific names.
 *                               Each volume entry consists of:
 *                                 volid from_fullvolname to_fullvolname
 *   newdb_overwrite(in):Rename the volumes/files at OS too. If it is true,
 *                        the enw database cannot exist in database.txt
 *   extern_rename(in): Rename the volumes/files at OS too. If it is true,
 *                        the enw database cannot exist in database.txt
 *   force_delete(in): Force delete backup volumes and information file
 *
 */
int
xboot_soft_rename (THREAD_ENTRY * thread_p, const char *old_db_name, const char *new_db_name, const char *new_db_path,
           const char *new_log_path, const char *new_db_server_host, const char *new_volext_path,
           const char *fileof_vols_and_renamepaths, bool new_db_overwrite, bool extern_rename,
           bool force_delete)
{
  DB_INFO *dir = NULL;
  DB_INFO *db = NULL;
  const char *newlog_prefix;
  char new_db_server_host_buf[CUB_MAXHOSTNAMELEN + 1];
  char new_db_fullname[PATH_MAX];
  char new_db_pathbuf[PATH_MAX];
  char new_log_pathbuf[PATH_MAX];
  int dbtxt_vdes = NULL_VOLDES;
  char dbtxt_label[PATH_MAX];
  char allocdb_path[PATH_MAX];
  char alloclog_path[PATH_MAX];
  int error_code = NO_ERROR;

  if (fileof_vols_and_renamepaths != NULL)
    {
      /*
       * If a newdb path was given, it is ignored since only one option must
       * be specified
       */
      new_db_path = boot_find_new_db_path (allocdb_path, fileof_vols_and_renamepaths);
      if (new_db_path == NULL)
    {
      error_code = ER_FAILED;
      goto end;
    }
    }

  if (new_db_path == NULL)
    {
      /*
       * Use the same location as the source database
       */
      new_db_path = fileio_get_directory_path (allocdb_path, boot_Db_full_name);
      if (new_db_path == NULL)
    {
      if (getcwd (allocdb_path, PATH_MAX) == NULL)
        {
          er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CWD_FAIL, 0);
          error_code = ER_BO_CWD_FAIL;
          goto end;
        }
      new_db_path = allocdb_path;
    }
    }

  if (new_log_path == NULL)
    {
      /*
       * Use the same log location as the source database
       */
      new_log_path = fileio_get_directory_path (alloclog_path, log_Name_active);
      if (new_log_path == NULL)
    {
      if (getcwd (alloclog_path, PATH_MAX) == NULL)
        {
          er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CWD_FAIL, 0);
          error_code = ER_BO_CWD_FAIL;
          goto end;
        }
      new_log_path = alloclog_path;
    }
    }

  /*
   * Make sure that the db_path and log_path are the canonicalized absolute
   * pathnames
   */

  if (realpath ((char *) new_db_path, new_db_pathbuf) != NULL)
    {
      new_db_path = new_db_pathbuf;
    }

  if (new_log_path != NULL && realpath ((char *) new_log_path, new_log_pathbuf) != NULL)
    {
      new_log_path = new_log_pathbuf;
    }

  /* If db_path and/or log_path are NULL find the defaults */

  if (new_log_path == NULL)
    {
      /* Assign the data volume directory */
      strncpy (new_log_pathbuf, new_db_path, PATH_MAX);
      new_log_path = new_log_pathbuf;
    }

  /* If a host was not given, assume the current host */

  if (new_db_server_host == NULL)
    {
      strcpy (new_db_server_host_buf, "localhost");
      new_db_server_host = new_db_server_host_buf;
    }

  /* Make sure that the full path for the new database is not too long */
  if ((int) (strlen (new_db_name) + strlen (new_db_path) + 2) > DB_MAX_PATH_LENGTH)
    {
      /*
       * db_path + db_name is too long
       */
      er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_FULL_DATABASE_NAME_IS_TOO_LONG, 3, new_db_path, new_db_name,
          strlen (new_db_name) + strlen (new_db_path) + 2, DB_MAX_PATH_LENGTH);
      error_code = ER_BO_FULL_DATABASE_NAME_IS_TOO_LONG;
      goto end;
    }

  /* Get the log prefix */
  newlog_prefix = fileio_get_base_file_name (new_db_name);

  /*
   * get the database directory information in write mode
   */
  if (cfg_maycreate_get_directory_filename (dbtxt_label) == NULL
#if !defined(WINDOWS) || !defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
/* Temporary fix for NT file locking problem */
      || (dbtxt_vdes = fileio_mount (thread_p, dbtxt_label, dbtxt_label, LOG_DBTXT_VOLID, 2, true)) == NULL_VOLDES
#endif /* !WINDOWS || !DONT_USE_MANDATORY_LOCK_IN_WINDOWS */
    )
    {
      error_code = ER_FAILED;
      goto end;
    }

  if (dbtxt_vdes != NULL_VOLDES)
    {
      error_code = cfg_read_directory_ex (dbtxt_vdes, &dir, true);
      if (error_code != NO_ERROR)
    {
      goto end;
    }
    }
  else
    {
      error_code = cfg_read_directory (&dir, true);
      if (error_code != NO_ERROR)
    {
      goto end;
    }
    }

  if (dir != NULL && (db = cfg_find_db_list (dir, new_db_name)) == NULL && extern_rename != true)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNKNOWN_DATABASE, 1, new_db_name);
      error_code = ER_BO_UNKNOWN_DATABASE;
      goto end;
    }

  if (dir != NULL && db != NULL && extern_rename == true && new_db_overwrite == false)
    {
      /* There is a database with the same name and we cannot overwrite it */
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_DATABASE_EXISTS, 1, new_db_name);
      error_code = ER_BO_DATABASE_EXISTS;
      goto end;
    }

  /*
   * Compose the full name of the new database
   */

  COMPOSE_FULL_NAME (new_db_fullname, sizeof (new_db_fullname), new_db_path, new_db_name);

  /*
   * Rename the database
   */

  error_code =
    logpb_rename_all_volumes_files (thread_p, boot_Db_parm->nvols, new_db_fullname, new_log_path, newlog_prefix,
                    new_volext_path, fileof_vols_and_renamepaths, extern_rename, force_delete);
  if (error_code != NO_ERROR)
    {
      goto end;
    }

  /* Now create the entry in the database table */
  if (extern_rename == true)
    {
      if (db == NULL)
    {
      const char *old_lob_path = NULL;
      char new_lob_pathbuf[PATH_MAX] = { '\0' };
      char *new_lob_path = NULL;

      old_lob_path = boot_get_lob_path ();
      if (*old_lob_path != '\0')
        {
          new_lob_path = strncpy_bufsize (new_lob_pathbuf, old_lob_path);
        }

      cfg_delete_db (&dir, old_db_name);
      db = cfg_add_db (&dir, new_db_name, new_db_path, new_log_path, new_lob_path, new_db_server_host);
    }
      else
    {
      cfg_update_db (db, new_db_path, new_log_path, NULL, new_db_server_host);
    }

      if (db == NULL || db->name == NULL || db->pathname == NULL || db->logpath == NULL || db->hosts == NULL)
    {
      error_code = ER_FAILED;
      goto end;
    }
    }
#if defined(WINDOWS) && !defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
  /* must unlock this before we can open it again for writing */
  if (dbtxt_vdes != NULL_VOLDES)
    {
      fileio_dismount (thread_p, dbtxt_vdes);
      dbtxt_vdes = NULL_VOLDES;
    }
#endif /* WINDOWS && !DONT_USE_MANDATORY_LOCK_IN_WINDOWS */
  if (dbtxt_vdes != NULL_VOLDES)
    {
      cfg_write_directory_ex (dbtxt_vdes, dir);
    }
  else
    {
      cfg_write_directory (dir);
    }

end:
  if (dir != NULL)
    {
      cfg_free_directory (dir);
    }

  if (dbtxt_vdes != NULL_VOLDES)
    {
      fileio_dismount (thread_p, dbtxt_vdes);
    }

  return error_code;
}

/*
 * xboot_delete () - delete all log files and database backups
 *
 * return: NO_ERROR if all OK, ER_ status otherwise
 *
 *   db_name(in):
 *   force_delete(in):
 *
 * Note: All data, log, and backup files associated with the current
 *              database are removed from the system.
 *              This is a very dangerous operation since the database cannot
 *              be recovered after this operation is executed. We strongly
 *              recommend that you backup the database and put the backup on
 *              tape or outside the log and backup directories before this
 *              operation is done. After this operation is executed the system
 *              is unavailable, that is, the system is shutdown by this
 *              operation.
 *
 * Note: This function must be run offline, that is, it should not be
 *              run when there are multiusers in the system.
 */
int
xboot_delete (const char *db_name, bool force_delete, BOOT_SERVER_SHUTDOWN_MODE shutdown_common_modules)
{
  char log_path[PATH_MAX];
  const char *log_prefix = NULL;
  DB_INFO *db;
  DB_INFO *dir = NULL;
  int dbtxt_vdes = NULL_VOLDES;
  char dbtxt_label[PATH_MAX];
  int error_code = NO_ERROR;
  THREAD_ENTRY *thread_p = NULL;

  if (!BO_IS_SERVER_RESTARTED ())
    {
      /*
       * Compose the full name of the database and find location of logs
       */
      if (msgcat_init () != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_ACCESS_MESSAGE_CATALOG, 0);
      return ER_FAILED;
    }

      if (sysprm_load_and_init (NULL, NULL, SYSPRM_LOAD_ALL) != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANT_LOAD_SYSPRM, 0);
      return ER_FAILED;
    }

      er_clear ();
    }

  /* *INDENT-OFF* */
  cubthread::initialize (thread_p);
  error_code = cubthread::initialize_thread_entries ();
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      return error_code;
    }
  /* *INDENT-ON* */

  error_code = perfmon_initialize (1);  /* 1 transaction for SA_MDOE */
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      return error_code;
    }

  /* Find the prefix for the database */
  log_prefix = fileio_get_base_file_name (db_name);

  /*
   * get the database directory information in write mode.
   */
  if (cfg_maycreate_get_directory_filename (dbtxt_label) == NULL)
    {
      goto error_dirty_delete;
    }

#if !defined(WINDOWS) || !defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
  /* Temporary solution to NT file locking problem */
  dbtxt_vdes = fileio_mount (thread_p, dbtxt_label, dbtxt_label, LOG_DBTXT_VOLID, 2, true);
  if (dbtxt_vdes == NULL_VOLDES)
    {
      return ER_FAILED;
    }
#endif /* !WINDOWS || !DONT_USE_MANDATORY_LOCK_IN_WINDOWS */

  if (dbtxt_vdes != NULL_VOLDES)
    {
      error_code = cfg_read_directory_ex (dbtxt_vdes, &dir, true);
    }
  else
    {
      error_code = cfg_read_directory (&dir, true);
    }

  if (error_code != NO_ERROR)
    {
      /*
       * If I cannot obtain a Lock on database.txt, it is better to quite at
       * this moment. We will not even perform a dirty delete.
       */
      if (dbtxt_vdes != NULL_VOLDES)
    {
      fileio_dismount (thread_p, dbtxt_vdes);
    }
      return error_code;
    }

  if (dir == NULL || (db = cfg_find_db_list (dir, db_name)) == NULL)
    {
      if (dbtxt_vdes != NULL_VOLDES)
    {
      fileio_dismount (thread_p, dbtxt_vdes);
    }
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNKNOWN_DATABASE, 1, db_name);
      if (dir)
    {
      cfg_free_directory (dir);
    }
      goto error_dirty_delete;
    }

  /*
   * How can we perform the delete operation..without restarting the system
   * or restarted the system.
   */

  if (!BO_IS_SERVER_RESTARTED ())
    {
      /*
       * Compose the full name of the database and find location of logs
       */
      COMPOSE_FULL_NAME (boot_Db_full_name, sizeof (boot_Db_full_name), db->pathname, db_name);
    }

  if (boot_volume_info_log_path (log_path) == NULL)
    {
      strcpy (log_path, db->logpath);
    }

  if (dbtxt_vdes != NULL_VOLDES)
    {
      fileio_dismount (thread_p, dbtxt_vdes);
      dbtxt_vdes = NULL_VOLDES;
      cfg_free_directory (dir);
      dir = NULL;
    }

  /* Now delete the database. Normally, DWB was already removed at database shutdown. */
  error_code = boot_remove_all_volumes (thread_p, boot_Db_full_name, log_path, log_prefix, false, force_delete);
  if (error_code == NO_ERROR)
    {
#if defined(WINDOWS) && !defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
      dbtxt_vdes = fileio_mount (thread_p, dbtxt_label, dbtxt_label, LOG_DBTXT_VOLID, 2, true);
      if (dbtxt_vdes == NULL_VOLDES)
    {
      goto error_dirty_delete;
    }
#endif /* WINDOWS && !DONT_USE_MANDATORY_LOCK_IN_WINDOWS */

      if (dbtxt_vdes != NULL_VOLDES)
    {
      if (cfg_read_directory_ex (dbtxt_vdes, &dir, true) != NO_ERROR)
        {
          goto error_dirty_delete;
        }
    }
      else
    {
      if (cfg_read_directory (&dir, true) != NO_ERROR)
        {
          goto error_dirty_delete;
        }
    }

      db = cfg_find_db_list (dir, db_name);

      if (db && cfg_delete_db (&dir, db_name))
    {
#if defined(WINDOWS) && !defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
      /* must unlock it before opening it for write again */
      if (dbtxt_vdes != NULL_VOLDES)
        {
          fileio_dismount (thread_p, dbtxt_vdes);
          dbtxt_vdes = NULL_VOLDES;
        }
#endif /* WINDOWS && !DONT_USE_MANDATORY_LOCK_IN_WINDOWS */
      if (dbtxt_vdes != NULL_VOLDES)
        {
          cfg_write_directory_ex (dbtxt_vdes, dir);
        }
      else
        {
          cfg_write_directory (dir);
        }
    }
      cfg_free_directory (dir);
    }

  if (dbtxt_vdes != NULL_VOLDES)
    {
      fileio_dismount (thread_p, dbtxt_vdes);
    }

  /* Shutdown the server */
  if (error_code == NO_ERROR)
    {
      boot_server_all_finalize (thread_p, ER_THREAD_FINAL, shutdown_common_modules);
    }
  else
    {
      er_stack_push ();
#if defined (SERVER_MODE)
      boot_server_all_finalize (thread_p, ER_THREAD_FINAL, BOOT_SHUTDOWN_ALL_MODULES);
#else
      boot_server_all_finalize (thread_p, ER_THREAD_FINAL, shutdown_common_modules);
#endif
      er_stack_pop ();
    }

#if defined (SA_MODE)
  cubthread::finalize ();
  thread_p = NULL;
#endif // SA_MODE

  return error_code;

error_dirty_delete:

  error_code = ER_FAILED;

  /* Shutdown the server */
  er_stack_push ();
#if defined (SERVER_MODE)
  boot_server_all_finalize (thread_p, ER_THREAD_FINAL, BOOT_SHUTDOWN_ALL_MODULES);
#else
  boot_server_all_finalize (thread_p, ER_THREAD_FINAL, shutdown_common_modules);
#endif
  er_stack_pop ();

#if defined (SA_MODE)
  cubthread::finalize ();
  thread_p = NULL;
#endif // SA_MODE

  return error_code;
}

/*
 * boot_create_all_volumes () -
 *
 * return:
 *
 *   db_comments(in):
 *   db_npages(in):
 *   file_addmore_vols(in):
 *   log_path(in):
 *   log_prefix(in):
 *   log_npages(in):
 *   client_prog_name(in):
 *   client_user_name(in):
 *   client_host_name(in):
 *   client_process_id(in):
 *   client_lock_wait(in):
 *   client_isolation(in):
 */
static int
boot_create_all_volumes (THREAD_ENTRY * thread_p, const BOOT_CLIENT_CREDENTIAL * client_credential,
             const char *db_comments, DKNPAGES db_npages, const char *file_addmore_vols,
             const char *log_path, const char *log_prefix, DKNPAGES log_npages,
             int client_lock_wait, TRAN_ISOLATION client_isolation)
{
  int tran_index = NULL_TRAN_INDEX;
  VOLID db_volid = NULL_VOLID;
  RECDES recdes;
  int error_code;
  DBDEF_VOL_EXT_INFO ext_info;
  HEAP_OPERATION_CONTEXT heapop_context;

  assert (client_credential != NULL);

  spage_boot (thread_p);
  error_code = heap_manager_initialize ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  /* Create the active log and initialize the log and recovery manager */
  error_code = log_create (thread_p, boot_Db_full_name, log_path, log_prefix, log_npages);
  if (error_code != NO_ERROR || boot_Init_server_is_canceled)
    {
      goto error;
    }
  log_initialize (thread_p, boot_Db_full_name, log_path, log_prefix, false, NULL);

  /* Assign an index to current thread of execution (i.e., a client id) */

  tran_index =
    logtb_assign_tran_index (thread_p, NULL_TRANID, TRAN_ACTIVE, client_credential, NULL, client_lock_wait,
                 client_isolation);
  if (tran_index == NULL_TRAN_INDEX)
    {
      goto error;
    }

  ext_info.name = boot_Db_full_name;
  ext_info.comments = db_comments;
  ext_info.max_npages = db_npages;
  ext_info.max_writesize_in_sec = 0;
  ext_info.purpose = DB_PERMANENT_DATA_PURPOSE;
  ext_info.extend_npages = db_npages;

  /* Create double write buffer if not already created. DWB creation must be done before first volume.
   * DWB file is created on log_path.
   */
  if (dwb_create (thread_p, log_path, log_prefix) != NO_ERROR)
    {
      goto error;
    }

  /* Format the first database volume */
  error_code = disk_format_first_volume (thread_p, boot_Db_full_name, db_comments, db_npages);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

  if (logpb_add_volume (NULL, LOG_DBFIRST_VOLID, boot_Db_full_name, DB_PERMANENT_DATA_PURPOSE) != LOG_DBFIRST_VOLID)
    {
      goto error;
    }

  /*
   * Initialize the database parameter table
   */

  boot_Db_parm->trk_vfid.volid = LOG_DBFIRST_VOLID;
  boot_Db_parm->hfid.vfid.volid = LOG_DBFIRST_VOLID;
  boot_Db_parm->rootclass_hfid.vfid.volid = LOG_DBFIRST_VOLID;
  boot_Db_parm->classname_table.vfid.volid = LOG_DBFIRST_VOLID;
  boot_Db_parm->ctid.vfid.volid = LOG_DBFIRST_VOLID;
  boot_Db_parm->ctid.xhid.vfid.volid = LOG_DBFIRST_VOLID;

  (void) strncpy (boot_Db_parm->rootclass_name, ROOTCLASS_NAME, DB_SIZEOF (boot_Db_parm->rootclass_name));
  boot_Db_parm->nvols = 1;
  boot_Db_parm->last_volid = LOG_DBFIRST_VOLID;
  boot_Db_parm->temp_nvols = 0;
  boot_Db_parm->temp_last_volid = NULL_VOLID;

  /* The query area has been removed */
  boot_Db_parm->query_vfid.volid = NULL_VOLID;
  boot_Db_parm->query_vfid.fileid = NULL_FILEID;

  OID_SET_NULL (&boot_Db_parm->rootclass_oid);
  oid_set_root (&boot_Db_parm->rootclass_oid);

  /* Get parameter value for vacuum data file size. Save it to boot_Db_parm to keep the value persistent even if the
   * server is restarted and the value in config file is changed. */
  boot_Db_parm->vacuum_log_block_npages = prm_get_integer_value (PRM_ID_VACUUM_LOG_BLOCK_PAGES);
  VFID_SET_NULL (&boot_Db_parm->vacuum_data_vfid);
  VFID_SET_NULL (&boot_Db_parm->dropped_files_vfid);

  /* Create the needed files */
  error_code = file_tracker_create (thread_p, &boot_Db_parm->trk_vfid);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }
  error_code = xheap_create (thread_p, &boot_Db_parm->hfid, NULL, false);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }
  error_code = xheap_create (thread_p, &boot_Db_parm->rootclass_hfid, NULL, false);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

  error_code = xheap_create (thread_p, &boot_Db_parm->tde_keyinfo_hfid, NULL, false);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

  error_code = heap_assign_address (thread_p, &boot_Db_parm->rootclass_hfid, NULL, &boot_Db_parm->rootclass_oid, 0);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

  oid_set_root (&boot_Db_parm->rootclass_oid);
  /* we need to manually add root class HFID to cache */
  error_code =
    heap_cache_class_info (thread_p, &boot_Db_parm->rootclass_oid, &boot_Db_parm->rootclass_hfid, FILE_HEAP,
               boot_Db_parm->rootclass_name);
  if (error_code != NO_ERROR)
    {
      assert_release (false);
      goto error;
    }

  if (xehash_create (thread_p, &boot_Db_parm->classname_table, DB_TYPE_STRING, -1, &boot_Db_parm->rootclass_oid, -1,
             false) == NULL)
    {
      goto error;
    }

  /* Initialize structures for global unique statistics */
  error_code = logtb_initialize_global_unique_stats_table (thread_p);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  if (catalog_create (thread_p, &boot_Db_parm->ctid) == NULL)
    {
      goto error;
    }

  error_code = disk_set_boot_hfid (thread_p, LOG_DBFIRST_VOLID, &boot_Db_parm->hfid);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  /* Store the parameter table */
  recdes.area_size = recdes.length = DB_SIZEOF (*boot_Db_parm);
  recdes.type = REC_HOME;
  recdes.data = (char *) boot_Db_parm;

  /* Prepare context */
  heap_create_insert_context (&heapop_context, &boot_Db_parm->hfid, &boot_Db_parm->rootclass_oid, &recdes, NULL);

  /* Insert and fetch location */
  if (heap_insert_logical (thread_p, &heapop_context, NULL) != NO_ERROR)
    {
      goto error;
    }
  COPY_OID (boot_Db_parm_oid, &heapop_context.res_oid);

  /* Create file for vacuum data */
  if (vacuum_create_file_for_vacuum_data (thread_p, &boot_Db_parm->vacuum_data_vfid) != NO_ERROR)
    {
      goto error;
    }

  /* Create file for dropped files (tracked by vacuum) */
  if (vacuum_create_file_for_dropped_files (thread_p, &boot_Db_parm->dropped_files_vfid) != NO_ERROR)
    {
      goto error;
    }

  /* Update boot_Db_parm */
  error_code = boot_db_parm_update_heap (thread_p);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

  /*
   * Create the rest of the other volumes if any
   */

  if (file_addmore_vols != NULL)
    {
      error_code = boot_parse_add_volume_extensions (thread_p, file_addmore_vols);
      if (error_code != NO_ERROR)
    {
      goto error;
    }
    }

  error_code = locator_initialize (thread_p);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  error_code = pgbuf_flush_all (thread_p, NULL_VOLID);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  /*
   * Initialize the catalog manager, the query evaluator, and install meta
   * classes
   */

  oid_set_root (&boot_Db_parm->rootclass_oid);
  catalog_initialize (&boot_Db_parm->ctid);

  if (qmgr_initialize (thread_p) != NO_ERROR)
    {
      goto error;
    }

  error_code = tf_install_meta_classes ();
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  error_code = tde_initialize (thread_p, &boot_Db_parm->tde_keyinfo_hfid);
  if (error_code != NO_ERROR)
    {
      goto error;
    }

  logpb_force_flush_pages (thread_p);
  (void) pgbuf_flush_all (thread_p, NULL_VOLID);
  (void) fileio_synchronize_all (thread_p);

  (void) logpb_checkpoint (thread_p);
  boot_server_status (BOOT_SERVER_UP);

  return tran_index;

  /* An error was found */
error:

  if (db_volid != NULL_VOLID)
    {
      (void) logpb_delete (thread_p, boot_Db_parm->nvols, boot_Db_full_name, log_path, log_prefix, true);
    }
  else
    {
      if (tran_index != NULL_TRAN_INDEX)
    {
      logtb_release_tran_index (thread_p, tran_index);
      log_final (thread_p);
    }
    }

  er_stack_push ();
  boot_server_all_finalize (thread_p, ER_THREAD_FINAL, BOOT_SHUTDOWN_EXCEPT_COMMON_MODULES);
  er_stack_pop ();

  return NULL_TRAN_INDEX;
}

/*
 * boot_remove_all_volumes () - remove all log files, information volumes, and backups
 *                     of given full database name
 *
 * return:  NO_ERROR if all OK, ER_ status otherwise
 *
 *   db_fullname(in):Full name of the database (A path)
 *   log_path(in): Path of log (cannot be NULL)
 *   log_prefix(in): Prefix of log (cannot be NULL)
 *   dirty_rem(in):
 *   force_delete(in):
 *
 * Note: All data, log, and backup files associated with the given
 *              database are removed from the system. However, the database is
 *              not unregistered from the database.txt. That is, this function
 *              does not know anything about database.txt.
 *              See xboot_delete for deletion of database instead of volumes.
 */
static int
boot_remove_all_volumes (THREAD_ENTRY * thread_p, const char *db_fullname, const char *log_path, const char *log_prefix,
             bool dirty_rem, bool force_delete)
{
  int error_code = NO_ERROR;

  if (dirty_rem)
    {
      goto error_rem_allvols;
    }

  /*
   * How can we perform the delete operation..without restarting the system
   * or restarted the system.
   */

  if (!BO_IS_SERVER_RESTARTED ())
    {
      /* System is not restarted. Read the system parameters */
      if (msgcat_init () != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_ACCESS_MESSAGE_CATALOG, 0);
      return ER_FAILED;
    }

      if (sysprm_load_and_init (NULL, NULL, SYSPRM_LOAD_ALL) != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANT_LOAD_SYSPRM, 0);
      return ER_FAILED;
    }

      /*
       * Initialize error structure, critical section, slotted page, heap, and
       * recovery managers
       */

      er_clear ();

      /* Initialize the transaction table */
      logtb_define_trantable (thread_p, -1, -1);

      /* The database pagesize is set by log_get_io_page_size */

      if (log_get_io_page_size (thread_p, db_fullname, log_path, log_prefix) == -1)
    {
      /*
       * There is something wrong with this database... We will only remove
       * as much as we can
       */
      goto error_rem_allvols;
    }
      if (!fileio_is_volume_exist (db_fullname))
    {
      goto error_rem_allvols;
    }
      if (!logpb_exist_log (thread_p, db_fullname, log_path, log_prefix))
    {
      goto error_rem_allvols;
    }
      error_code = boot_mount (thread_p, LOG_DBFIRST_VOLID, db_fullname, NULL);
      if (error_code != NO_ERROR)
    {
      goto error_rem_allvols;
    }
      if (disk_get_boot_hfid (thread_p, LOG_DBFIRST_VOLID, &boot_Db_parm->hfid) == NULL)
    {
      goto error_rem_allvols;
    }
      error_code = boot_get_db_parm (thread_p, boot_Db_parm, boot_Db_parm_oid);
      if (error_code != NO_ERROR)
    {
      goto error_rem_allvols;
    }
      error_code = tde_cipher_initialize (thread_p, &boot_Db_parm->tde_keyinfo_hfid, NULL);
      if (error_code != NO_ERROR)
    {
      goto error_rem_allvols;
    }

      /* Find the rest of the volumes and mount them */
      error_code = boot_find_rest_volumes (thread_p, NULL, LOG_DBFIRST_VOLID, boot_mount, NULL);
      if (error_code != NO_ERROR)
    {
      goto error_rem_allvols;
    }
      error_code = disk_manager_init (thread_p, true);
      if (error_code != NO_ERROR)
    {
      goto error_rem_allvols;
    }

      log_restart_emergency (thread_p, db_fullname, log_path, log_prefix);

      (void) boot_remove_all_temp_volumes (thread_p, ONLY_PHYSICAL_REMOVE_TEMP_VOL_ACTION);
      boot_server_status (BOOT_SERVER_UP);
      log_final (thread_p);

      /* remove lob ces temp dir */
      error_code = fileio_lob_remove_matching_dir (BOOT_LOB_TEMP_DIR_KEYWORD);
      if (error_code != NO_ERROR)
    {
      goto error_rem_allvols;
    }
    }

  /* Now delete the database */
  error_code = logpb_delete (thread_p, boot_Db_parm->nvols, db_fullname, log_path, log_prefix, force_delete);
  return error_code;

error_rem_allvols:

  error_code = logpb_delete (thread_p, -1, db_fullname, log_path, log_prefix, force_delete);

  return error_code;
}

/*
 * xboot_emergency_patch () - patch the database for emergency restart
 *
 * return:  NO_ERROR if all OK, ER_ status otherwise
 *
 *   db_name(in): Database Name
 *   recreate_log(in): true if the log is missing
 *   log_npages(in):
 *   user_db_charset(in): charset to use when recreating log
 *   out_fp(in):
 *
 * Note: The database is patched for future restarts. The patch will
 *              remove any indication of recovery to be performed. If a log
 *              is not available, the recreate_flag must be given
 */
int
xboot_emergency_patch (const char *db_name, bool recreate_log, DKNPAGES log_npages, const char *db_locale,
               FILE * out_fp)
{
  char log_path[PATH_MAX];
  const char *log_prefix;
  DB_INFO *db = NULL;
  DB_INFO *dir = NULL;
  int dbtxt_vdes = NULL_VOLDES;
  char dbtxt_label[PATH_MAX];
  int error_code = NO_ERROR;
  INTL_CODESET db_charset_db_header = INTL_CODESET_ERROR;
  INTL_CODESET db_charset_db_root = INTL_CODESET_ERROR;
  char dummy_timezone_checksum[32 + 1];
  char db_lang[LANG_MAX_LANGNAME];
  THREAD_ENTRY *thread_p = NULL;

  if (lang_init () != NO_ERROR)
    {
      if (er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOC_INIT, 1, "Failed to initialize language module");
    }
      error_code = ER_LOC_INIT;
      goto error_exit;
    }

  (void) msgcat_init ();
  if (sysprm_load_and_init (NULL, NULL, SYSPRM_LOAD_ALL) != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANT_LOAD_SYSPRM, 0);
      error_code = ER_BO_CANT_LOAD_SYSPRM;
      goto error_exit;
    }

  if (db_name == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNKNOWN_DATABASE, 1, db_name);
      error_code = ER_BO_UNKNOWN_DATABASE;
      goto error_exit;
    }

  /* *INDENT-OFF* */
  cubthread::initialize (thread_p);
  error_code = cubthread::initialize_thread_entries ();
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error_exit;
    }
  /* *INDENT-ON* */

  /*
   * Compose the full name of the database and find location of logs
   */
  if (cfg_read_directory (&dir, false) != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CFG_NO_FILE, 1, DATABASES_FILENAME);
      error_code = ER_CFG_NO_FILE;
      goto error_exit;
    }

  if (dir == NULL || ((db = cfg_find_db_list (dir, db_name)) == NULL))
    {
      /*
       * Make sure that nobody was in the process of writing the
       * database.txt when we got a snapshot of it.
       */
      if (dir != NULL)
    {
      cfg_free_directory (dir);
      dir = NULL;
    }

      if (cfg_maycreate_get_directory_filename (dbtxt_label) != NULL
#if !defined(WINDOWS) || !defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
      /* Temporary solution to NT file locking problem. */
      && (dbtxt_vdes = fileio_mount (thread_p, dbtxt_label, dbtxt_label, LOG_DBTXT_VOLID, 2, true)) != NULL_VOLDES
#endif /* !WINDOWS || !DONT_USE_MANDATORY_LOCK_IN_WINDOWS */
    )
    {
      if (dbtxt_vdes != NULL_VOLDES)
        {
          if (cfg_read_directory_ex (dbtxt_vdes, &dir, false) == NO_ERROR)
        {
          db = cfg_find_db_list (dir, db_name);
        }
        }
      else
        {
          if (cfg_read_directory (&dir, false) == NO_ERROR)
        {
          db = cfg_find_db_list (dir, db_name);
        }
        }

      fileio_dismount (thread_p, dbtxt_vdes);
      dbtxt_vdes = NULL_VOLDES;
    }
      if (db == NULL)
    {
      if (dir != NULL)
        {
          cfg_free_directory (dir);
        }
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_UNKNOWN_DATABASE, 1, db_name);
      error_code = ER_BO_UNKNOWN_DATABASE;
      goto error_exit;
    }
    }

  COMPOSE_FULL_NAME (boot_Db_full_name, sizeof (boot_Db_full_name), db->pathname, db_name);

  if (boot_volume_info_log_path (log_path) == NULL)
    {
      strcpy (log_path, db->logpath);
    }

  cfg_free_directory (dir);

  log_prefix = fileio_get_base_file_name (db_name);

  if (sysprm_load_and_init (boot_Db_full_name, NULL, SYSPRM_LOAD_ALL) != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANT_LOAD_SYSPRM, 0);
      error_code = ER_BO_CANT_LOAD_SYSPRM;
      goto error_exit;
    }

  /*
   * Initialize error structure, critical section, slotted page, heap, and
   * recovery managers
   */

  /* The database pagesize is set by log_get_io_page_size */

  if (log_get_io_page_size (thread_p, boot_Db_full_name, log_path, log_prefix) == -1)
    {
      if (recreate_log != 0)
    {
      /*
       * User must indicate the database pagesize through its own environment
       */
      (void) db_set_page_size (IO_DEFAULT_PAGE_SIZE, IO_DEFAULT_PAGE_SIZE);
    }
      else
    {
      error_code = ER_FAILED;
      goto error_exit;
    }
    }

  /* Initialize the transaction table */
  logtb_define_trantable (thread_p, -1, -1);

  spage_boot (thread_p);
  error_code = heap_manager_initialize ();
  if (error_code != NO_ERROR)
    {
      goto error_exit;
    }

  /* Mount the data volume */
  error_code = boot_mount (thread_p, LOG_DBFIRST_VOLID, boot_Db_full_name, NULL);
  if (error_code != NO_ERROR)
    {
      goto error_exit;
    }

  /* Find the location of the database parameters and read them */
  if (disk_get_boot_hfid (thread_p, LOG_DBFIRST_VOLID, &boot_Db_parm->hfid) == NULL)
    {
      error_code = ER_FAILED;
      goto error_exit;
    }
  error_code = boot_get_db_parm (thread_p, boot_Db_parm, boot_Db_parm_oid);
  if (error_code != NO_ERROR)
    {
      error_code = ER_FAILED;
      goto error_exit;
    }

  if (recreate_log == false)
    {
      db_charset_db_header = boot_get_db_charset_from_header (thread_p, log_path, log_prefix);
      if (db_charset_db_header <= INTL_CODESET_NONE || INTL_CODESET_LAST < db_charset_db_header)
    {
      char er_msg[ERR_MSG_SIZE];
      snprintf (er_msg, sizeof (er_msg) - 1,
            "Cannot found a valid charset in volumes header or there is a missmatch.");
      er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOC_INIT, 1, er_msg);
      error_code = ER_LOC_INIT;
      goto error_exit;
    }
      else
    {
      lang_set_charset (db_charset_db_header);
    }
    }
  else
    {
      error_code = lang_set_charset_lang (db_locale);
      if (error_code != NO_ERROR)
    {
      goto error_exit;
    }
      db_charset_db_header = lang_charset ();
    }

  /* Find the rest of the volumes and mount them */

  error_code = boot_find_rest_volumes (thread_p, NULL, LOG_DBFIRST_VOLID, boot_mount, NULL);
  if (error_code != NO_ERROR)
    {
      goto error_exit;
    }
  error_code = disk_manager_init (thread_p, true);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error_exit;
    }

  error_code = logtb_initialize_global_unique_stats_table (thread_p);
  if (error_code != NO_ERROR)
    {
      goto error_exit;
    }

  error_code = file_tracker_load (thread_p, &boot_Db_parm->trk_vfid);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error_exit;
    }
  catalog_initialize (&boot_Db_parm->ctid);

  if (prm_get_bool_value (PRM_ID_DISABLE_VACUUM) == false)
    {
      /* We need initialize vacuum routine before recovery. */
      error_code =
    vacuum_initialize (thread_p, boot_Db_parm->vacuum_log_block_npages, &boot_Db_parm->vacuum_data_vfid,
               &boot_Db_parm->dropped_files_vfid, false);
      if (error_code != NO_ERROR)
    {
      goto error_exit;
    }
    }

  error_code = tp_init ();
  if (error_code != NO_ERROR)
    {
      goto error_exit;
    }

  if (recreate_log == false)
    {
      log_restart_emergency (thread_p, boot_Db_full_name, log_path, log_prefix);
    }

  /*
   * Initialize the catalog manager, the query evaluator, and install meta
   * classes
   */

  error_code = locator_initialize (thread_p);
  if (error_code != NO_ERROR)
    {
      goto error_exit;
    }

  oid_set_root (&boot_Db_parm->rootclass_oid);

  /* Initialize tsc-timer */
  tsc_init ();

  error_code =
    catcls_get_server_compat_info (thread_p, &db_charset_db_root, db_lang, sizeof (db_lang) - 1,
                   dummy_timezone_checksum);
  if (error_code != NO_ERROR)
    {
      goto error_exit;
    }

  if (db_charset_db_header != db_charset_db_root)
    {
      char er_msg[ERR_MSG_SIZE];
      snprintf (er_msg, sizeof (er_msg) - 1, "Invalid charset in db_root system table: expecting %s, found %s",
        lang_charset_cubrid_name (db_charset_db_header), lang_charset_cubrid_name (db_charset_db_root));
      er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOC_INIT, 1, er_msg);
      error_code = ER_LOC_INIT;
      goto error_exit;
    }

  if (recreate_log == true)
    {
      if (log_is_active_log_sane (thread_p, boot_Db_full_name, log_path, log_prefix))
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_TOO_SANE_TO_RECREATE, 1, log_path);
      error_code = ER_LOG_TOO_SANE_TO_RECREATE;
      goto error_exit;
    }

      if (log_npages <= 0)
    {
      /* Use the default that is the size of the database */
      log_npages = xdisk_get_total_numpages (thread_p, LOG_DBFIRST_VOLID);

      if (log_npages < 10)
        {
          log_npages = 10;
        }
    }

      error_code = log_recreate (thread_p, boot_Db_full_name, log_path, log_prefix, log_npages, out_fp);
      if (error_code != NO_ERROR)
    {
      goto error_exit;
    }
    }

  boot_server_status (BOOT_SERVER_UP);

  (void) xtran_server_commit (thread_p, false);
  (void) xboot_shutdown_server (thread_p, ER_ALL_FINAL);

  return error_code;

error_exit:

  if (error_code != NO_ERROR)
    {
      error_code = ER_FAILED;
    }

  boot_server_all_finalize (thread_p, ER_THREAD_FINAL, BOOT_SHUTDOWN_ALL_MODULES);

  return error_code;
}

/*
 * boot_find_new_db_path () - find the new path of database
 *
 * return: db_pathbuf or NULL
 *
 *   db_pathbuf(in): The database path buffer (Set as a side effect)
 *                The size of this buffer muts be at least PATH_MAX
 *   fileof_vols_and_wherepaths(in):A file of volumes and path or NULL.
 *                Each volume entry consists of:
 *                 volid from_fullvolname to_fullvolname
 *
 * Note: Find the new database path from either the given wherepath
 *              file or the current working directory.
 */
static char *
boot_find_new_db_path (char *db_pathbuf, const char *fileof_vols_and_wherepaths)
{
  FILE *where_paths_fp;
  char from_volname[PATH_MAX];  /* Name of new volume */
  int from_volid;
  char *name;
  char format_string[32];
#if !defined(WINDOWS)
  struct stat stat_buf;
#endif

  if (fileof_vols_and_wherepaths != NULL)
    {
      /*
       * Obtain the new database path from where paths file
       */
      where_paths_fp = fopen (fileof_vols_and_wherepaths, "r");
      if (where_paths_fp == NULL)
    {
      er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_USER_FILE_UNKNOWN, 1,
                   fileof_vols_and_wherepaths);
      return NULL;
    }

      *db_pathbuf = '\0';
      *from_volname = '\0';

      sprintf (format_string, "%%d %%%ds %%%ds", PATH_MAX - 1, PATH_MAX - 1);
      if (fscanf (where_paths_fp, format_string, &from_volid, from_volname, db_pathbuf) != 3
      || from_volid != LOG_DBFIRST_VOLID)
    {
      fclose (where_paths_fp);
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_LOG_USER_FILE_UNORDERED_ENTRIES, 7, fileof_vols_and_wherepaths,
          0, from_volid, from_volname, db_pathbuf, LOG_DBFIRST_VOLID, boot_Db_full_name);
      return NULL;
    }
      fclose (where_paths_fp);

#if !defined(WINDOWS)
      if (stat (db_pathbuf, &stat_buf) != -1 && S_ISCHR (stat_buf.st_mode))
    {
      if (getcwd (db_pathbuf, PATH_MAX) == NULL)
        {
          er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CWD_FAIL, 0);
          *db_pathbuf = '0';
          return NULL;
        }

      return db_pathbuf;
    }
#endif /* !WINDOWS */

      name = strrchr (db_pathbuf, PATH_SEPARATOR);
#if defined(WINDOWS)
      {
    char *name_tmp = strrchr (db_pathbuf, '/');

    if (name < name_tmp)
      {
        name = name_tmp;
      }
      }
#endif /* WINDOWS */
      if (name == NULL)
    {
      /* It does not look like a path name. Use working directory */
      if (getcwd (db_pathbuf, PATH_MAX) == NULL)
        {
          er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CWD_FAIL, 0);
          *db_pathbuf = '\0';
          return NULL;
        }
    }
      else
    {
      *name = '\0';
    }
    }
  else
    {
      /* Use current working directory */
      if (getcwd (db_pathbuf, PATH_MAX) == NULL)
    {
      er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CWD_FAIL, 0);
      *db_pathbuf = '\0';
      return NULL;
    }
    }

  return db_pathbuf;
}

/*
 * boot_volume_info_log_path () - find path for log in volinfo
 *
 * return: log_path or NULL
 *
 *   log_path(in): Storage for log path
 *
 * Note: Find path for the log in the volume information.
 */
static char *
boot_volume_info_log_path (char *log_path)
{
  int read_int_volid = NULL_VOLID;
  char *slash;
  FILE *volinfo_fp = NULL;  /* Pointer to new volinfo */
  char format_string[32];

  fileio_make_volume_info_name (log_path, boot_Db_full_name);
  volinfo_fp = fopen (log_path, "r");
  if (volinfo_fp == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_CANNOT_FINE_VOLINFO, 1, log_path);
      return NULL;
    }

  sprintf (format_string, "%%d %%%ds", PATH_MAX - 1);
  while (true)
    {
      if (fscanf (volinfo_fp, format_string, &read_int_volid, log_path) != 2)
    {
      read_int_volid = NULL_VOLID;
      break;
    }
      if (LOG_DBLOG_ACTIVE_VOLID == (VOLID) read_int_volid)
    {
      break;
    }
    }
  fclose (volinfo_fp);

  if (LOG_DBLOG_ACTIVE_VOLID == (VOLID) read_int_volid)
    {
      slash = strrchr (log_path, PATH_SEPARATOR);
#if defined(WINDOWS)
      {
    char *r_slash = strrchr (log_path, '/');

    if (slash < r_slash)
      {
        slash = r_slash;
      }
      }
#endif /* WINDOWS */
      if (slash != NULL)
    {
      *slash = '\0';
    }
      return log_path;
    }

  return NULL;
}

/*
 * xboot_compact_db () - compact the database
 *
 * return : NO_ERROR if all OK, ER_ status otherwise
 *
 *   class_oids(in): the class oids list to process
 *   n_classes(in): the length of class_oids
 *   space_to_process(in): the maximum space to process
 *   instance_lock_timeout(in): the lock timeout for instances
 *   class_lock_timeout(in): the lock timeout for classes
 *   delete_old_repr(in): drop old class representations
 *   last_processed_class_oid(in,out): last processed class oid
 *   last_processed_oid(in,out): last processed oid
 *   total_objects(in,out): count processed objects for each class
 *   failed_objects(in,out): count failed objects for each class
 *   modified_objects(in,out): count modified objects for each class
 *   big_objects(in,out): count big objects for each class
 *   initial_last_repr_id(in,out): the list of last class representation
 *
 * Note:
 */

int
xboot_compact_db (THREAD_ENTRY * thread_p, OID * class_oids, int n_classes, int space_to_process,
          int instance_lock_timeout, int class_lock_timeout, bool delete_old_repr,
          OID * last_processed_class_oid, OID * last_processed_oid, int *total_objects, int *failed_objects,
          int *modified_objects, int *big_objects, int *initial_last_repr_id)
{
  return boot_compact_db (thread_p, class_oids, n_classes, space_to_process, instance_lock_timeout, class_lock_timeout,
              delete_old_repr, last_processed_class_oid, last_processed_oid, total_objects, failed_objects,
              modified_objects, big_objects, initial_last_repr_id);
}

/*
 * xboot_heap_compact () - compact all pages from hfid of specified class OID
 *   return: error_code
 *   class_oid(in):  the class oid
 */
int
xboot_heap_compact (THREAD_ENTRY * thread_p, OID * class_oid)
{
  return boot_heap_compact_pages (thread_p, class_oid);
}

/*
 * xboot_compact_start () - start database compaction
 *   return: error_code
 */
int
xboot_compact_start (THREAD_ENTRY * thread_p)
{
  return boot_compact_start (thread_p);
}

/*
 * xboot_compact_stop () - stop database compaction
 *   return: error_code
 */
int
xboot_compact_stop (THREAD_ENTRY * thread_p)
{
  return boot_compact_stop (thread_p);
}

bool
boot_set_skip_check_ct_classes (bool val)
{
  bool old_val = skip_to_check_ct_classes_for_rebuild;
  skip_to_check_ct_classes_for_rebuild = val;
  return old_val;
}

/*
 * boot_get_db_charset_from_header () - Get DB charset from volumes
 *                      (log or generic)
 *   return: charset
 *   thread_p(in):
 *   log_path(in):
 *   log_prefix(in):
 */
static INTL_CODESET
boot_get_db_charset_from_header (THREAD_ENTRY * thread_p, const char *log_path, const char *log_prefix)
{
  INTL_CODESET vol_header_db_charset = INTL_CODESET_ERROR;
  INTL_CODESET log_header_db_charset = INTL_CODESET_ERROR;

  log_header_db_charset =
    (INTL_CODESET) log_get_charset_from_header_page (thread_p, boot_Db_full_name, log_path, log_prefix);

  if (disk_get_boot_db_charset (thread_p, LOG_DBFIRST_VOLID, &vol_header_db_charset) != NO_ERROR)
    {
      vol_header_db_charset = INTL_CODESET_ERROR;
    }

  if (log_header_db_charset == INTL_CODESET_ERROR)
    {
      return vol_header_db_charset;
    }
  else if (vol_header_db_charset == INTL_CODESET_ERROR)
    {
      return log_header_db_charset;
    }
  else if (vol_header_db_charset != log_header_db_charset)
    {
      return INTL_CODESET_ERROR;
    }

  assert (vol_header_db_charset == log_header_db_charset);

  return vol_header_db_charset;
}

const char *
boot_client_type_to_string (BOOT_CLIENT_TYPE type)
{
  switch (type)
    {
    case DB_CLIENT_TYPE_SYSTEM_INTERNAL:
      return "SYSTEM_INTERNAL";
    case DB_CLIENT_TYPE_DEFAULT:
      return "DEFAULT";
    case DB_CLIENT_TYPE_CSQL:
      return "CSQL";
    case DB_CLIENT_TYPE_READ_ONLY_CSQL:
      return "READ_ONLY_CSQL";
    case DB_CLIENT_TYPE_BROKER:
      return "BROKER";
    case DB_CLIENT_TYPE_READ_ONLY_BROKER:
      return "READ_ONLY_BROKER";
    case DB_CLIENT_TYPE_SLAVE_ONLY_BROKER:
      return "SLAVE_ONLY_BROKER";
    case DB_CLIENT_TYPE_ADMIN_UTILITY:
      return "ADMIN_UTILITY";
    case DB_CLIENT_TYPE_ADMIN_CSQL:
      return "ADMIN_CSQL";
    case DB_CLIENT_TYPE_ADMIN_CSQL_REBUILD_CATALOG:
      return "ADMIN_CSQL_REBUILD_CATALOG";
    case DB_CLIENT_TYPE_LOG_COPIER:
      return "LOG_COPIER";
    case DB_CLIENT_TYPE_LOG_APPLIER:
      return "LOG_APPLIER";
    case DB_CLIENT_TYPE_RW_BROKER_REPLICA_ONLY:
      return "RW_BROKER_REPLICA_ONLY";
    case DB_CLIENT_TYPE_RO_BROKER_REPLICA_ONLY:
      return "RO_BROKER_REPLICA_ONLY";
    case DB_CLIENT_TYPE_SO_BROKER_REPLICA_ONLY:
      return "SO_BROKER_REPLICA_ONLY";
    case DB_CLIENT_TYPE_ADMIN_CSQL_WOS:
      return "ADMIN_CSQL_WOS";
    case DB_CLIENT_TYPE_SKIP_VACUUM_CSQL:
      return "SKIP_VACUUM_CSQL";
    case DB_CLIENT_TYPE_SKIP_VACUUM_ADMIN_CSQL:
      return "SKIP_VACUUM_ADMIN_CSQL";
    case DB_CLIENT_TYPE_ADMIN_COMPACTDB_WOS:
      return "ADMIN_COMPACTDB_WOS";
    case DB_CLIENT_TYPE_ADMIN_LOADDB_COMPAT_UNDER_11_2:
      return "ADMIN_LOADDB_COMPAT_UNDER_11_2";
    case DB_CLIENT_TYPE_ADMIN_LOADDB_COMPAT_UNDER_11_4:
      return "ADMIN_LOADDB_COMPAT_UNDER_11_4";
    case DB_CLIENT_TYPE_LOADDB_UTILITY:
      return "LOADDB_UTILITY";
    case DB_CLIENT_TYPE_UNKNOWN:
    default:
      return "UNKNOWN";
    }
}

int
boot_get_new_volume_name_and_id (THREAD_ENTRY * thread_p, DB_VOLTYPE voltype, const char *given_path,
                 const char *given_name, char *fullname_newvol_out, VOLID * volid_newvol_out)
{
  char buf_temp_path[PATH_MAX];
  const char *temp_path = NULL;
  const char *temp_name = NULL;

  if (voltype == DB_PERMANENT_VOLTYPE)
    {
      *volid_newvol_out = boot_Db_parm->last_volid + 1;
      if (*volid_newvol_out > LOG_MAX_DBVOLID
      || (boot_Db_parm->temp_nvols > 0 && *volid_newvol_out >= boot_Db_parm->temp_last_volid))
    {
      /* should be caught early */
      assert (false);
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_MAXNUM_VOLS_HAS_BEEN_EXCEEDED, 1, LOG_MAX_DBVOLID);
      return ER_BO_MAXNUM_VOLS_HAS_BEEN_EXCEEDED;
    }

      if (given_path != NULL)
    {
      temp_path = given_path;
    }
      else
    {
      temp_path = prm_get_string_value (PRM_ID_IO_VOLUME_EXT_PATH);
      if (temp_path == NULL)
        {
          temp_path = fileio_get_directory_path (buf_temp_path, boot_Db_full_name);
          if (temp_path == NULL)
        {
          buf_temp_path[0] = '\0';
          temp_path = buf_temp_path;
        }
        }

    }
      if (given_name != NULL)
    {
      temp_name = given_name;

      fileio_make_volume_ext_given_name (fullname_newvol_out, temp_path, given_name);
    }
      else
    {
      temp_name = fileio_get_base_file_name (boot_Db_full_name);
      fileio_make_volume_ext_name (fullname_newvol_out, temp_path, temp_name, *volid_newvol_out);
    }
    }
  else
    {
      *volid_newvol_out = boot_Db_parm->temp_nvols > 0 ? boot_Db_parm->temp_last_volid - 1 : LOG_MAX_DBVOLID;
      if (*volid_newvol_out <= boot_Db_parm->last_volid)
    {
      /* should be caught early */
      assert (false);
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BO_MAXNUM_VOLS_HAS_BEEN_EXCEEDED, 1, LOG_MAX_DBVOLID);
      return ER_BO_MAXNUM_VOLS_HAS_BEEN_EXCEEDED;
    }
      assert (given_path == NULL && given_name == NULL);

      temp_path = (char *) prm_get_string_value (PRM_ID_IO_TEMP_VOLUME_PATH);
      if (temp_path == NULL || temp_path[0] == '\0')
    {
      temp_path = fileio_get_directory_path (buf_temp_path, boot_Db_full_name);
    }
      temp_name = fileio_get_base_file_name (boot_Db_full_name);
      fileio_make_volume_temp_name (fullname_newvol_out, temp_path, temp_name, *volid_newvol_out);
    }

  return NO_ERROR;
}

int
boot_dbparm_save_volume (THREAD_ENTRY * thread_p, DB_VOLTYPE voltype, VOLID volid)
{
  VPID vpid_boot_bp_parm;
  BOOT_DB_PARM save_boot_db_parm = *boot_Db_parm;

  int error_code = NO_ERROR;

  assert (log_check_system_op_is_started (thread_p));

  if (voltype == DB_PERMANENT_VOLTYPE)
    {
      assert (boot_Db_parm->nvols >= 0);
      if (volid != boot_Db_parm->last_volid + 1)
    {
      assert_release (false);
      error_code = ER_FAILED;
      goto error;
    }
      boot_Db_parm->last_volid = volid;
      boot_Db_parm->nvols++;

      VPID_GET_FROM_OID (&vpid_boot_bp_parm, boot_Db_parm_oid);
      log_append_undo_data2 (thread_p, RVPGBUF_FLUSH_PAGE, NULL, NULL, 0, sizeof (vpid_boot_bp_parm),
                 &vpid_boot_bp_parm);

      error_code = boot_db_parm_update_heap (thread_p);

      if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

      /* flush the boot_Db_parm object. this is not necessary but it is recommended in order to mount every known volume
       * during restart. that may not be possible during media crash though. */
      heap_flush (thread_p, boot_Db_parm_oid);
      dwb_synchronize (thread_p, fileio_get_volume_descriptor (boot_Db_parm_oid->volid), NULL); /* label? */
    }
  else
    {
      if (boot_Db_parm->temp_nvols < 0 || (boot_Db_parm->temp_nvols == 0 && volid != LOG_MAX_DBVOLID)
      || (boot_Db_parm->temp_nvols > 0 && boot_Db_parm->temp_last_volid - 1 != volid))
    {
      /* invalid volid */
      assert_release (false);
      error_code = ER_FAILED;
      goto error;
    }
      boot_Db_parm->temp_nvols++;
      boot_Db_parm->temp_last_volid = volid;
    }

  return NO_ERROR;

error:

  *boot_Db_parm = save_boot_db_parm;

  return error_code;
}

/*
 * boot_db_parm_update_heap () - update heap record for boot_Db_parm
 *
 * return        : error code
 * thread_p (in) : thread entry
 */
STATIC_INLINE int
boot_db_parm_update_heap (THREAD_ENTRY * thread_p)
{
  HEAP_SCANCACHE scan_cache;
  HEAP_OPERATION_CONTEXT update_context;
  RECDES recdes;

  int error_code = NO_ERROR;

  recdes.length = recdes.area_size = sizeof (*boot_Db_parm);
  recdes.data = (char *) boot_Db_parm;

  /* note that we start a scan cache with NULL class_oid. That's because boot_Db_parm_oid doesn't really have a class!
   * we have to start the scan cache this way so it can cache also cache file type for heap_update_logical.
   * otherwise it will try to read it from cache using root class OID. which actually has its own heap file and its own
   * heap file type.
   */
  error_code = heap_scancache_start_modify (thread_p, &scan_cache, &boot_Db_parm->hfid, NULL, SINGLE_ROW_UPDATE, NULL);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      return error_code;
    }

  /* hack the class to avoid heap_scancache_check_with_hfid. */
  scan_cache.node.class_oid = *oid_Root_class_oid;
  heap_create_update_context (&update_context, &boot_Db_parm->hfid, boot_Db_parm_oid, &boot_Db_parm->rootclass_oid,
                  &recdes, &scan_cache, UPDATE_INPLACE_CURRENT_MVCCID);
  error_code = heap_update_logical (thread_p, &update_context);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
    }
  heap_scancache_end (thread_p, &scan_cache);
  return error_code;
}

//
// boot_after_copydb - do whatever checks and changes necessary on first boot of copied database.
//                     copydb is quite rudimentary; it will just copy page by page as is, and then reset the LSA's.
//                     some of database stuff may be contextual (e.g. stuff that depend on log like vacuum), and
//                     here that stuff must be handled
//
static int
boot_after_copydb (THREAD_ENTRY * thread_p)
{
  if (!log_Gl.hdr.was_copied)
    {
      // this is not after copydb
      return NO_ERROR;
    }

  int error_code = vacuum_reset_data_after_copydb (thread_p);
  if (error_code != NO_ERROR)
    {
      ASSERT_ERROR ();
      return error_code;
    }

  // finished booting after copydb
  log_Gl.hdr.was_copied = false;

  // flush log and header to disk to make sure everything is saved
  logpb_force_flush_header_and_pages (thread_p);

  er_log_debug (ARG_FILE_LINE, "Complete boot_after_copydb \n");

  return NO_ERROR;
}