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;
}