* This file is part of the oGRAC project.
* Copyright (c) 2024 Huawei Technologies Co.,Ltd.
*
* oGRAC is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* dc_dump.c
*
*
* IDENTIFICATION
* src/kernel/catalog/dc_dump.c
*
* -------------------------------------------------------------------------
*/
#include "knl_dc_module.h"
#include "dc_dump.h"
#define MAX_DUMP_FILE_SIZE (10 * 1024 * 1024)
status_t dc_dump_prepare(cm_dump_t *dump, dc_dump_info_t *info, char *file_name, uint32 name_size)
{
if (!CM_IS_EMPTY(&info->dump_file)) {
errno_t ret = memset_sp(file_name, name_size, 0, name_size);
knl_securec_check(ret);
if (info->dump_file.len >= name_size) {
OG_THROW_ERROR(ERR_INVALID_FILE_NAME, T2S(&info->dump_file), name_size);
return OG_ERROR;
}
ret = memcpy_sp(file_name, name_size, info->dump_file.str, info->dump_file.len);
knl_securec_check(ret);
if (cm_file_exist(file_name)) {
OG_THROW_ERROR(ERR_FILE_ALREADY_EXIST, file_name, "failed to dump catalog");
return OG_ERROR;
} else if (cm_create_file(file_name, O_RDWR | O_BINARY | O_SYNC, &dump->handle) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
if (cm_open_file(file_name, O_RDWR | O_CREAT | O_APPEND, &dump->handle) != OG_SUCCESS) {
return OG_ERROR;
}
int64 file_size;
cm_get_filesize(file_name, &file_size);
if (file_size > MAX_DUMP_FILE_SIZE) {
OG_LOG_RUN_ERR("[DB] the size of dump file %s is more than %d, need delete first",
file_name, MAX_DUMP_FILE_SIZE);
OG_THROW_ERROR(ERR_DATAFILE_RESIZE_EXCEED, file_size, MAX_DUMP_FILE_SIZE);
cm_close_file(dump->handle);
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t dc_dump_index(cm_dump_t *dump, index_t *index)
{
cm_dump(dump, "*****INDEX %s*****\n", index->desc.name);
cm_dump(dump, "is_part: %d\n", index->desc.parted);
if (IS_PART_INDEX(index)) {
CM_DUMP_WRITE_FILE(dump);
return OG_SUCCESS;
}
btree_t *btree = &index->btree;
if (btree != NULL) {
cm_dump(dump, "entry: %d-%d\n", AS_PAGID(&btree->entry).file, AS_PAGID(&btree->entry).page);
cm_dump(dump, "extend_lock: %d\n", btree->extend_lock);
cm_dump(dump, "wait_recycle: %u\n", btree->wait_recycle);
cm_dump(dump, "is_recycling: %u\n", btree->is_recycling);
cm_dump(dump, "alloc_pages: %lld\n", btree->chg_stats.alloc_pages);
cm_dump(dump, "delete_size: %lld\n", btree->chg_stats.delete_size);
cm_dump(dump, "empty_size: %llu\n", btree->chg_stats.empty_size);
cm_dump(dump, "first_empty_size: %llu\n", btree->chg_stats.first_empty_size);
cm_dump(dump, "ow_del_scn: %llu\n", btree->chg_stats.ow_del_scn);
cm_dump(dump, "is_shadow: %d\n", btree->is_shadow);
cm_dump(dump, "is_splitting: %d\n\n", btree->is_splitting);
}
CM_DUMP_WRITE_FILE(dump);
return OG_SUCCESS;
}
static status_t dc_dump_table_entry(cm_dump_t *dump, dc_dump_info_t info, knl_dictionary_t dc)
{
dc_entry_t *entry = DC_ENTRY(&dc);
dc_entity_t *entity = DC_ENTITY(&dc);
char date[OG_MAX_TIME_STRLEN] = { 0 };
(void)cm_date2str(cm_now(), "yyyy-mm-dd hh24:mi:ss", date, OG_MAX_TIME_STRLEN);
cm_dump(dump, "%s\n", date);
cm_dump(dump, "------- Start Dump Table Dictionary Cache Info -------\n");
cm_dump(dump, "TABLE_NAME: %s\n", T2S(&info.table_name));
cm_dump(dump, "TABLE_ID: %d\n", entity->table.desc.id);
cm_dump(dump, "INDEX_COUNT: %d\n", entity->table.desc.index_count);
CM_DUMP_WRITE_FILE(dump);
cm_dump(dump, "----Entry info:\n");
cm_dump(dump, "lock: %d /* avoid load entity concurrently */\n", entry->lock);
cm_dump(dump, "serial_lock: %d /* avoid update serial value concurrently */\n", entry->serial_lock.lock);
cm_dump(dump, "sch_lock_mutex: %d /* avoid change lock status concurrently */\n", entry->sch_lock_mutex);
cm_dump(dump, "ref_lock: %d /* avoid change ref_count concurrently */\n", entry->ref_lock);
cm_dump(dump, "ref_count %d\n", entry->ref_count);
CM_DUMP_WRITE_FILE(dump);
cm_dump(dump, "recycled: %d /* TRUE when table has been dropped */\n", entry->recycled);
cm_dump(dump, "ready: %d /* TRUE when entry has been created */\n", entry->ready);
cm_dump(dump, "need_empty_entry: %d /* only valid for nologging table */\n", entry->need_empty_entry);
cm_dump(dump, "used: %d /* FALSE when entry in the freelist */\n", entry->used);
cm_dump(dump, "is_free: %d /* TRUE when table has been dropped */\n", entry->is_free);
CM_DUMP_WRITE_FILE(dump);
cm_dump(dump, "----Entity info:\n");
cm_dump(dump, "ref_lock: %d\n", entity->ref_lock);
cm_dump(dump, "ref_count %d\n", entity->ref_count);
cm_dump(dump, "stats_version: %d\n", entity->stats_version);
cm_dump(dump, "cbo_latch: %d\n", entity->cbo_latch.stat);
CM_DUMP_WRITE_FILE(dump);
cm_dump(dump, "contain_lob: %d /* TRUE when table has lob column */\n", entity->contain_lob);
cm_dump(dump, "corrupted: %d /* TRUE when segment has been broken */\n", entity->corrupted);
cm_dump(dump, "has_udef_col: %d /* TRUE when table has updated default column */\n", entity->has_udef_col);
cm_dump(dump, "valid: %d /* TRUE when table doing DDL concurrently */\n", entity->valid);
cm_dump(dump, "forbid_dml: %d /* TRUE when constraint has been disabled */\n", entity->forbid_dml);
cm_dump(dump, "has_serial_col: %d /* TRUE when table has serial/auto_increment column */\n", entity->has_serial_col);
cm_dump(dump, "is_analyzing: %d, stats_locked: %d, stat_exists: %d\n\n",
entity->is_analyzing, entity->stats_locked, entity->stat_exists);
CM_DUMP_WRITE_FILE(dump);
return OG_SUCCESS;
}
status_t dc_dump_table(knl_session_t *session, cm_dump_t *dump, dc_dump_info_t info)
{
knl_dictionary_t dc;
char file_name[OG_MAX_FILE_NAME_LEN];
if (knl_open_dc(session, &info.user_name, &info.table_name, &dc) != OG_SUCCESS) {
return OG_ERROR;
}
errno_t ret = memset_sp(file_name, OG_MAX_FILE_NAME_LEN, 0, OG_MAX_FILE_NAME_LEN);
knl_securec_check(ret);
ret = snprintf_s(file_name, OG_MAX_FILE_NAME_LEN, OG_MAX_FILE_NAME_LEN - 1, "%s/trc/%s_%s_DUMP.trc",
session->kernel->home, T2S(&info.user_name), T2S_EX(&info.table_name));
knl_securec_check_ss(ret);
if (dc_dump_prepare(dump, &info, file_name, OG_MAX_FILE_NAME_LEN) != OG_SUCCESS) {
knl_close_dc(&dc);
return OG_ERROR;
}
dc_entity_t *entity = DC_ENTITY(&dc);
dump->offset = 0;
if (dc_dump_table_entry(dump, info, dc) != OG_SUCCESS) {
knl_close_dc(&dc);
cm_close_file(dump->handle);
return OG_ERROR;
}
index_t *index = NULL;
for (uint32 i = 0; i < entity->table.index_set.total_count; i++) {
index = entity->table.index_set.items[i];
if (dc_dump_index(dump, index) != OG_SUCCESS) {
knl_close_dc(&dc);
cm_close_file(dump->handle);
return OG_ERROR;
}
}
cm_dump(dump, "-------- End of Dump Table ------\n\n");
if (cm_dump_flush(dump) != OG_SUCCESS) {
knl_close_dc(&dc);
cm_close_file(dump->handle);
return OG_ERROR;
}
knl_close_dc(&dc);
cm_close_file(dump->handle);
return OG_SUCCESS;
}
status_t dc_dump_user(knl_session_t *session, cm_dump_t *dump, dc_dump_info_t info)
{
char file_name[OG_MAX_FILE_NAME_LEN];
dc_user_t *user = NULL;
if (dc_open_user(session, &info.user_name, &user) != OG_SUCCESS) {
return OG_ERROR;
}
errno_t ret = memset_sp(file_name, OG_MAX_FILE_NAME_LEN, 0, OG_MAX_FILE_NAME_LEN);
knl_securec_check(ret);
ret = snprintf_s(file_name, OG_MAX_FILE_NAME_LEN, OG_MAX_FILE_NAME_LEN - 1, "%s/trc/USER_%s_DUMP.trc",
session->kernel->home, T2S(&info.user_name));
knl_securec_check_ss(ret);
if (dc_dump_prepare(dump, &info, file_name, OG_MAX_FILE_NAME_LEN) != OG_SUCCESS) {
return OG_ERROR;
}
dump->offset = 0;
char date[OG_MAX_TIME_STRLEN] = { 0 };
(void)cm_date2str(cm_now(), "yyyy-mm-dd hh24:mi:ss", date, OG_MAX_TIME_STRLEN);
cm_dump(dump, "%s\n", date);
cm_dump(dump, "------- Start Dump User Dictionary Cache Info -------\n");
cm_dump(dump, "user_name: %s\n", user->desc.name);
CM_DUMP_WRITE_FILE(dump);
cm_dump(dump, "----User spin_lock info:\n");
cm_dump(dump, "lock: %d /* avoid concurrent allocation of entry */\n", user->lock);
cm_dump(dump, "load_lock: %d /* for is_loaded flag */\n", user->load_lock);
cm_dump(dump, "s_lock: %d /* avoid changing user status concurrently */\n", user->s_lock);
cm_dump(dump, "user_latch: %d /* avoid concurrent execution of drop user and create/drop object */\n",
user->user_latch.latch.stat);
cm_dump(dump, "lib_latch: %d /* latch for pl */\n", user->lib_latch.latch.stat);
CM_DUMP_WRITE_FILE(dump);
cm_dump(dump, "----User flag info:\n");
cm_dump(dump, "status: %d /* 1-normal, 2-locked, 3-offline, 4-dropped*/\n", user->status);
cm_dump(dump, "is_loaded: %d, has_nologging: %d\n", user->is_loaded, user->has_nologging);
cm_dump(dump, "entry_lwm: %d, entry_hwm: %d\n", user->entry_lwm, user->entry_hwm);
cm_dump(dump, "-------- End of Dump User ------\n\n");
CM_DUMP_WRITE_FILE(dump);
cm_close_file(dump->handle);
return OG_SUCCESS;
}