/* -------------------------------------------------------------------------
 *  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.
 * -------------------------------------------------------------------------
 *
 * srv_view_lock.c
 *
 *
 * IDENTIFICATION
 * src/server/srv_view_lock.c
 *
 * -------------------------------------------------------------------------
 */
#include "srv_module.h"
#include "srv_view_lock.h"
#include "srv_instance.h"
#include "knl_alck.h"
#include "pl_lock.h"
#include "dtc_database.h"
#include "dtc_dls.h"
#include "dtc_drc.h"

static knl_column_t g_lock_columns[] = {
    { 0, "SID",   0, 0, OG_TYPE_INTEGER, sizeof(uint32),        0, 0, OG_FALSE, 0, { 0 } },
    { 1, "TYPE",  0, 0, OG_TYPE_VARCHAR, OG_DYNVIEW_NORMAL_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 2, "ID1",   0, 0, OG_TYPE_BIGINT,  sizeof(uint64),        0, 0, OG_FALSE, 0, { 0 } },
    { 3, "ID2",   0, 0, OG_TYPE_BIGINT,  sizeof(uint64),        0, 0, OG_FALSE, 0, { 0 } },
    { 4, "LMODE", 0, 0, OG_TYPE_VARCHAR, OG_DYNVIEW_NORMAL_LEN, 0, 0, OG_TRUE,  0, { 0 } },
    { 5, "BLOCK", 0, 0, OG_TYPE_INTEGER, sizeof(uint32),        0, 0, OG_FALSE, 0, { 0 } },
    { 6, "RMID",  0, 0, OG_TYPE_INTEGER, sizeof(uint32),        0, 0, OG_FALSE, 0, { 0 } },
};

static knl_column_t g_spin_lock_columns[] = {
    { 0, "SID",    0, 0, OG_TYPE_INTEGER, sizeof(uint32), 0, 0, OG_FALSE, 0, { 0 } },
    { 1, "TYPE",   0, 0, OG_TYPE_VARCHAR, 128,            0, 0, OG_FALSE, 0, { 0 } },
    { 2, "SPINS",  0, 0, OG_TYPE_BIGINT,  sizeof(uint64), 0, 0, OG_FALSE, 0, { 0 } },
    { 3, "SLEEPS", 0, 0, OG_TYPE_BIGINT,  sizeof(uint64), 0, 0, OG_FALSE, 0, { 0 } },
    { 4, "FAILS",  0, 0, OG_TYPE_BIGINT,  sizeof(uint64), 0, 0, OG_FALSE, 0, { 0 } },
};

#define LOCK_VALUE_LMODE_NAME 10

static knl_column_t g_locked_object_columns[] = {
    { 0, "SESSION_ID",     0, 0, OG_TYPE_INTEGER, sizeof(uint32),           0, 0, OG_FALSE, 0, { 0 } },
    { 1, "XIDUSN",         0, 0, OG_TYPE_INTEGER, sizeof(uint32),           0, 0, OG_FALSE, 0, { 0 } },
    { 2, "XIDSLOT",        0, 0, OG_TYPE_INTEGER, sizeof(uint32),           0, 0, OG_FALSE, 0, { 0 } },
    { 3, "XIDSQN",         0, 0, OG_TYPE_INTEGER, sizeof(uint32),           0, 0, OG_FALSE, 0, { 0 } },
    { 4, "USER_NAME",      0, 0, OG_TYPE_CHAR,    OG_NAME_BUFFER_SIZE,      0, 0, OG_TRUE,  0, { 0 } },
    { 5, "OBJECT_ID",      0, 0, OG_TYPE_INTEGER, sizeof(uint32),           0, 0, OG_FALSE, 0, { 0 } },
    { 6, "OBJECT_NAME",    0, 0, OG_TYPE_CHAR,    OG_NAME_BUFFER_SIZE,      0, 0, OG_TRUE,  0, { 0 } },
    { 7, "CLIENT_OS_NAME", 0, 0, OG_TYPE_CHAR,    OG_HOST_NAME_BUFFER_SIZE, 0, 0, OG_FALSE, 0, { 0 } },
    { 8, "CLIENT_PROGREM", 0, 0, OG_TYPE_CHAR,    OG_FILE_NAME_BUFFER_SIZE, 0, 0, OG_FALSE, 0, { 0 } },
    { 9, "LMODE",          0, 0, OG_TYPE_CHAR,    LOCK_VALUE_LMODE_NAME,    0, 0, OG_TRUE,  0, { 0 } },
};

static knl_column_t g_sess_alocks[] = {
    { 0, "SID",        0, 0, OG_TYPE_INTEGER, sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
    { 1, "LOCK_NAME",  0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 2, "LOCK_TIMES", 0, 0, OG_TYPE_UINT32,  sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
    { 3, "LOCK_SCN",   0, 0, OG_TYPE_INTEGER, sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
};

static knl_column_t g_sess_shared_alocks[] = {
    { 0, "LOCK_NAME",          0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 1, "SID",                0, 0, OG_TYPE_INTEGER, sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
    { 2, "TOTAL_LOCKED_TIMES", 0, 0, OG_TYPE_UINT32,  sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
};

static knl_column_t g_xact_alocks[] = {
    { 0, "SID",        0, 0, OG_TYPE_INTEGER, sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
    { 1, "SERIAL#",    0, 0, OG_TYPE_INTEGER, sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
    { 2, "LOCK_NAME",  0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 3, "LOCK_TIMES", 0, 0, OG_TYPE_UINT32,  sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
};

static knl_column_t g_xact_shared_alocks[] = {
    { 0, "LOCK_NAME",          0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 1, "SID",                0, 0, OG_TYPE_INTEGER, sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
    { 2, "TOTAL_LOCKED_TIMES", 0, 0, OG_TYPE_UINT32,  sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
};

static knl_column_t g_plsql_alocks[] = {
    { 0, "USER",       0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 1, "PACKAGE",    0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN, 0, 0, OG_TRUE,  0, { 0 } },
    { 2, "OBJECT",     0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 3, "PL_TYPE",    0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 4, "SID",        0, 0, OG_TYPE_INTEGER, sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
    { 5, "LOCK_TIMES", 0, 0, OG_TYPE_UINT32,  sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
    { 6, "LOCK_SCN",   0, 0, OG_TYPE_INTEGER, sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
};


static knl_column_t g_plsql_shared_alocks[] = {
    { 0, "USER",               0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 1, "PACKAGE",            0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN, 0, 0, OG_TRUE,  0, { 0 } },
    { 2, "OBJECT",             0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 3, "PL_TYPE",            0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 4, "IX_SETTED",          0, 0, OG_TYPE_UINT32,  sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
    { 5, "TOTAL_LOCKED_TIMES", 0, 0, OG_TYPE_UINT32,  sizeof(uint32),  0, 0, OG_FALSE, 0, { 0 } },
};

static knl_column_t g_user_alocks[] = {
    { 0, "NAME",        0, 0, OG_TYPE_VARCHAR, OG_MAX_ALCK_USER_NAME_LEN,   0, 0, OG_FALSE, 0, { 0 } },
    { 1, "TYPE",        0, 0, OG_TYPE_VARCHAR, 2,                           0, 0, OG_FALSE, 0, { 0 } },
    { 2, "X_LOCKS",     0, 0, OG_TYPE_UINT32,  sizeof(uint32),              0, 0, OG_FALSE, 0, { 0 } },
    { 3, "MY_LOCKS",    0, 0, OG_TYPE_UINT32,  sizeof(uint32),              0, 0, OG_FALSE, 0, { 0 } },
    { 4, "TOTAL_LOCKS", 0, 0, OG_TYPE_UINT32,  sizeof(uint32),              0, 0, OG_FALSE, 0, { 0 } },
    { 5, "IX_SETTED",   0, 0, OG_TYPE_UINT32,  sizeof(uint32),              0, 0, OG_FALSE, 0, { 0 } },
    { 6, "LOCK_MODE",   0, 0, OG_TYPE_VARCHAR, OG_MAX_ALCK_MODE_STATUS_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 7, "IX_MAP",      0, 0, OG_TYPE_VARCHAR, OG_MAX_ALCK_IX_MAP_LEN,      0, 0, OG_TRUE,  0, { 0 } },
};

static knl_column_t g_all_alocks[] = {
    { 0, "NAME",        0, 0, OG_TYPE_VARCHAR, OG_MAX_ALCK_USER_NAME_LEN,   0, 0, OG_FALSE, 0, { 0 } },
    { 1, "TYPE",        0, 0, OG_TYPE_VARCHAR, 2,                           0, 0, OG_FALSE, 0, { 0 } },
    { 2, "X_LOCKS",     0, 0, OG_TYPE_UINT32,  sizeof(uint32),              0, 0, OG_FALSE, 0, { 0 } },
    { 3, "TOTAL_LOCKS", 0, 0, OG_TYPE_UINT32,  sizeof(uint32),              0, 0, OG_FALSE, 0, { 0 } },
    { 4, "IX_SETTED",   0, 0, OG_TYPE_UINT32,  sizeof(uint32),              0, 0, OG_FALSE, 0, { 0 } },
    { 5, "LOCK_DETAIL", 0, 0, OG_TYPE_VARCHAR, OG_MAX_COLUMN_SIZE,          0, 0, OG_FALSE, 0, { 0 } },
    { 6, "LOCK_MODE",   0, 0, OG_TYPE_VARCHAR, OG_MAX_ALCK_MODE_STATUS_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 7, "IX_MAP",      0, 0, OG_TYPE_VARCHAR, OG_MAX_ALCK_IX_MAP_LEN,      0, 0, OG_TRUE,  0, { 0 } },
};

static knl_column_t g_pl_locks[] = {
    { 0, "USER",             0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN,             0, 0, OG_FALSE, 0, { 0 } },
    { 1, "OBJECT",           0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN,             0, 0, OG_FALSE, 0, { 0 } },
    { 2, "TYPE",             0, 0, OG_TYPE_VARCHAR, OG_MAX_NAME_LEN,             0, 0, OG_FALSE, 0, { 0 } },
    { 3, "TOTAL_LOCK_TIMES", 0, 0, OG_TYPE_UINT32,  sizeof(uint32),              0, 0, OG_FALSE, 0, { 0 } },
    { 4, "X_LOCK_TIMES",     0, 0, OG_TYPE_UINT32,  sizeof(uint32),              0, 0, OG_FALSE, 0, { 0 } },
    { 5, "LOCK_MODE",        0, 0, OG_TYPE_VARCHAR, OG_MAX_ALCK_MODE_STATUS_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 6, "IX_MAP",           0, 0, OG_TYPE_UINT32,  sizeof(uint32),              0, 0, OG_TRUE,  0, { 0 } },
    { 7, "LOCK_DETAIL",      0, 0, OG_TYPE_VARCHAR, OG_MAX_COLUMN_SIZE,          0, 0, OG_FALSE, 0, { 0 } },
};

static knl_column_t g_dls_lock_columns[] = {
    { 0, "IDX", 0, 0, OG_TYPE_INTEGER, sizeof(uint32), 0, 0, OG_FALSE, 0, { 0 } },
    { 1, "DRID_TYPE", 0, 0, OG_TYPE_INTEGER, sizeof(uint32), 0, 0, OG_FALSE, 0, { 0 } },
    { 2, "DRID_UID", 0, 0, OG_TYPE_INTEGER, sizeof(uint32), 0, 0, OG_FALSE, 0, { 0 } },
    { 3, "DRID_ID", 0, 0, OG_TYPE_INTEGER, sizeof(uint32), 0, 0, OG_FALSE, 0, { 0 } },
    { 4, "DRID_IDX", 0, 0, OG_TYPE_INTEGER, sizeof(uint32), 0, 0, OG_FALSE, 0, { 0 } },
    { 5, "DRID_PART", 0, 0, OG_TYPE_INTEGER, sizeof(uint32), 0, 0, OG_FALSE, 0, { 0 } },
    { 6, "DRID_PARENTPART", 0, 0, OG_TYPE_INTEGER, sizeof(uint32), 0, 0, OG_FALSE, 0, { 0 } },
    { 7, "MODE", 0, 0, OG_TYPE_VARCHAR, OG_DYNVIEW_NORMAL_LEN, 0, 0, OG_FALSE, 0, { 0 } },
    { 8, "PART_ID", 0, 0, OG_TYPE_INTEGER, sizeof(uint32), 0, 0, OG_FALSE, 0, { 0 } },
    { 9, "GRANTED_MAP", 0, 0, OG_TYPE_BIGINT, sizeof(uint64), 0, 0, OG_FALSE, 0, { 0 } },
    { 10, "CONVERTQ_LEN", 0, 0, OG_TYPE_UINT32, sizeof(uint32), 0, 0, OG_FALSE, 0, { 0 } },
    { 11, "CONVERTING", 0, 0, OG_TYPE_INTEGER, sizeof(uint32), 0, 0, OG_FALSE, 0, { 0 } },
};

#define LOCK_COLS (ELEMENT_COUNT(g_lock_columns))
#define SPINLOCK_COLS (ELEMENT_COUNT(g_spin_lock_columns))
#define LOCKED_OBJECT_COLS (ELEMENT_COUNT(g_locked_object_columns))
#define SESS_ALOCKS (ELEMENT_COUNT(g_sess_alocks))
#define SESS_SHARED_ALOCKS (ELEMENT_COUNT(g_sess_shared_alocks))
#define XACT_ALOCKS (ELEMENT_COUNT(g_xact_alocks))
#define XACT_SHARED_ALOCKS (ELEMENT_COUNT(g_xact_shared_alocks))
#define PLSQL_ALOCKS (ELEMENT_COUNT(g_plsql_alocks))
#define PLSQL_SHARED_ALOCKS (ELEMENT_COUNT(g_plsql_shared_alocks))
#define ALL_ALOCKS (ELEMENT_COUNT(g_all_alocks))
#define USER_ALOCKS (ELEMENT_COUNT(g_user_alocks))
#define PL_LOCKS (ELEMENT_COUNT(g_pl_locks))
#define DLSLOCK_COLS (ELEMENT_COUNT(g_dls_lock_columns))

static void vw_lock_put_row(knl_handle_t session, lock_item_t *item, row_assist_t *ra, dc_entry_t *entry, uint16 sid)
{
    page_id_t page_id;
    uint16 rmid = item->rmid;
    (void)row_put_int32(ra, (int32)sid);
    (void)row_put_str(ra, lock_type_string(item->type));
    knl_session_t *ss = (knl_session_t *)session;
    if (item->type == LOCK_TYPE_TS || item->type == LOCK_TYPE_TX) {
        entry = item->dc_entry;
        if (entry != NULL) {
            (void)row_put_int64(ra, (int64)entry->uid);
            (void)row_put_int64(ra, (int64)entry->id);
            (void)row_put_str(ra, lock_mode_string(entry));
        } else {
            (void)row_put_int64(ra, OG_INVALID_INT64);
            (void)row_put_int64(ra, OG_INVALID_INT64);
            (void)row_put_null(ra);
        }

        if (entry == NULL || sid == OG_INVALID_ID16) {
            (void)row_put_int32(ra, OG_INVALID_INT32);
        } else {
            (void)row_put_int32(ra,
                (int32)(dc_locked_by_self(ss->kernel->sessions[sid], entry) ? 1 : 0));
        }
    } else {
        page_id = MAKE_PAGID(item->file, item->page);
        (void)row_put_int64(ra, *(int64 *)&page_id);
        (void)row_put_int64(ra, (int64)item->itl);
        (void)row_put_null(ra);
        (void)row_put_int32(ra, (int32)(1));
    }
    (void)row_put_int32(ra, (int32)rmid);
}

static status_t vw_lock_fetch(knl_handle_t session, knl_cursor_t *cursor)
{
    row_assist_t ra;
    uint16 sid;
    dc_entry_t *entry = NULL;
    knl_rm_t *rm = NULL;
    uint16 rmid;
    knl_session_t *ss = (knl_session_t *)session;
    if (cursor->rowid.vmid >= ss->kernel->lock_ctx.hwm) {
        cursor->eof = OG_TRUE;
        return OG_SUCCESS;
    }

    lock_item_t *item = lock_addr(&ss->kernel->lock_ctx, (uint32)cursor->rowid.vmid);
    rmid = item->rmid;
    sid = knl_get_rm_sid(session, rmid);

    while (item->type == LOCK_TYPE_FREE || item->type >= LOCK_TYPE_ALCK_TS || sid == OG_INVALID_ID16 ||
        item->dc_entry == NULL) {
        if (rmid != OG_INVALID_ID16) {
            rm = ss->kernel->rms[rmid];
        }

        if (rm != NULL && item->type != LOCK_TYPE_FREE && item->dc_entry != NULL && knl_xa_xid_valid(&rm->xa_xid)) {
            break;
        }

        cursor->rowid.vmid++;
        if (cursor->rowid.vmid >= ss->kernel->lock_ctx.hwm) {
            cursor->eof = OG_TRUE;
            return OG_SUCCESS;
        }

        item = lock_addr(&ss->kernel->lock_ctx, (uint32)cursor->rowid.vmid);
        rmid = item->rmid;
        rm = NULL;
        sid = knl_get_rm_sid(session, rmid);
    }

    row_init(&ra, (char *)cursor->row, ss->kernel->attr.max_row_size, LOCK_COLS);
    vw_lock_put_row(session, item, &ra, entry, sid);
    cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, &cursor->data_size);

    cursor->rowid.vmid++;
    return OG_SUCCESS;
}

typedef enum en_spin_type {
    SPIN_TXN = 0,
    SPIN_TXN_LIST,
    SPIN_INC_SCN,
    SPIN_SERI_COMMIT,
    SPIN_REDO_BUF,
    SPIN_COMMIT_QUEUE,
    SPIN_CKPT_QUEUE,
    SPIN_BUFFER,
    SPIN_BUCKET,
    SPIN_SPACE,
    SPIN_DC_ENTRY,
    SPIN_LOG_FLUSH,
    SPIN_SCH_LOCK,
    SPIN_CKPT,
    SPIN_PCR_POOL,
    SPIN_PCR_BUCKET,

    /* * must be the last one */
    SPIN_TYPE_COUNT
} spin_type_t;

typedef struct spin_mgr {
    spin_type_t type;
    const char *name;
} spin_mgr_t;

static spin_mgr_t g_spin_mgrs[] = {
    { SPIN_TXN,          "TXN" },
    { SPIN_TXN_LIST,     "TXN_LIST" },
    { SPIN_INC_SCN,      "INC_SCN" },
    { SPIN_SERI_COMMIT,  "SERIALIZED_COMMIT" },
    { SPIN_REDO_BUF,     "REDO_BUFFER" },
    { SPIN_COMMIT_QUEUE, "COMMIT_QUEUE" },
    { SPIN_CKPT_QUEUE,   "CKPT_QUEUE" },
    { SPIN_BUFFER,       "BUFFER" },
    { SPIN_BUCKET,       "BUCKET" },
    { SPIN_SPACE,        "SPACE" },
    { SPIN_DC_ENTRY,     "DC_ENTRY" },
    { SPIN_LOG_FLUSH,    "LOG_FLUSH" },
    { SPIN_SCH_LOCK,     "SCH_LOCK" },
    { SPIN_CKPT,         "CKPT" },
    { SPIN_PCR_POOL,    "PCR_POOL"},
    { SPIN_PCR_BUCKET,  "PCR_BUCKET"},
};

static spin_statis_t *vw_get_spin_info(knl_session_t *session, spin_type_t type)
{
    switch (type) {
        case SPIN_TXN:
            return &session->stat->spin_stat.stat_txn;
        case SPIN_TXN_LIST:
            return &session->stat->spin_stat.stat_txn_list;
        case SPIN_INC_SCN:
            return &session->stat->spin_stat.stat_inc_scn;
        case SPIN_SERI_COMMIT:
            return &session->stat->spin_stat.stat_seri_commit;
        case SPIN_REDO_BUF:
            return &session->stat->spin_stat.stat_redo_buf;
        case SPIN_COMMIT_QUEUE:
            return &session->stat->spin_stat.stat_commit_queue;
        case SPIN_CKPT_QUEUE:
            return &session->stat->spin_stat.stat_ckpt_queue;
        case SPIN_BUFFER:
            return &session->stat->spin_stat.stat_buffer;
        case SPIN_BUCKET:
            return &session->stat->spin_stat.stat_bucket;
        case SPIN_SPACE:
            return &session->stat->spin_stat.stat_space;
        case SPIN_DC_ENTRY:
            return &session->stat->spin_stat.stat_dc_entry;
        case SPIN_LOG_FLUSH:
            return &session->stat->spin_stat.stat_log_flush;
        case SPIN_SCH_LOCK:
            return &session->stat->spin_stat.stat_sch_lock;
        case SPIN_CKPT:
            return &session->stat->spin_stat.stat_ckpt;
        case SPIN_PCR_POOL:
            return &session->stat->spin_stat.stat_pcr_pool;
        case SPIN_PCR_BUCKET:
            return &session->stat->spin_stat.stat_pcr_bucket;
        case SPIN_TYPE_COUNT:
        default:
            return NULL;
    }
}

static status_t vw_spin_lock_fetch_core(knl_handle_t handle, knl_cursor_t *cursor)
{
    session_t *item = NULL;
    knl_session_t *session = NULL;
    spin_statis_t *stat = NULL;
    row_assist_t ra;

    while (1) {
        if (cursor->rowid.vmid >= g_instance->session_pool.hwm) {
            cursor->eof = OG_TRUE;
            return OG_SUCCESS;
        }

        item = g_instance->session_pool.sessions[cursor->rowid.vmid];
        if (!item->is_free) {
            break;
        }

        cursor->rowid.vmid++;
    }

    session = &item->knl_session;
    stat = vw_get_spin_info(session, g_spin_mgrs[cursor->rowid.vm_slot].type);
    OG_RETURN_IFERR(stat == NULL);

    cursor->tenant_id = item->curr_tenant_id;
    row_init(&ra, (char *)cursor->row, OG_MAX_ROW_SIZE, SPINLOCK_COLS);
    OG_RETURN_IFERR(row_put_int32(&ra, (int32)session->id));
    OG_RETURN_IFERR(row_put_str(&ra, g_spin_mgrs[cursor->rowid.vm_slot].name));
    OG_RETURN_IFERR(row_put_int64(&ra, (int64)stat->spins));
    OG_RETURN_IFERR(row_put_int64(&ra, (int64)stat->wait_usecs));
    OG_RETURN_IFERR(row_put_int64(&ra, (int64)stat->fails));

    cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, &cursor->data_size);
    cursor->rowid.vm_slot++;

    if (cursor->rowid.vm_slot == SPIN_TYPE_COUNT) {
        cursor->rowid.vmid++;
        cursor->rowid.vm_slot = 0;
    }

    return OG_SUCCESS;
}

static status_t vw_spin_lock_fetch(knl_handle_t handle, knl_cursor_t *cursor)
{
    return vw_fetch_for_tenant(vw_spin_lock_fetch_core, handle, cursor);
}

static status_t vw_locked_object_fetch(knl_handle_t session, knl_cursor_t *cursor)
{
    knl_session_t *sess = (knl_session_t *)session;
    lock_area_t *area = &sess->kernel->lock_ctx;
    lock_item_t item;
    row_assist_t ra;
    uint16 sid;

    if (cursor->rowid.vmid >= area->hwm) {
        cursor->eof = OG_TRUE;
        return OG_SUCCESS;
    }

    item = *lock_addr(area, (uint32)cursor->rowid.vmid);
    sid = knl_get_rm_sid(session, item.rmid);

    while ((item.type != LOCK_TYPE_TS && item.type != LOCK_TYPE_TX) || sid == OG_INVALID_ID16 ||
        item.dc_entry == NULL) {
        cursor->rowid.vmid++;
        if (cursor->rowid.vmid >= area->hwm) {
            cursor->eof = OG_TRUE;
            return OG_SUCCESS;
        }

        item = *lock_addr(area, (uint32)cursor->rowid.vmid);
        sid = knl_get_rm_sid(session, item.rmid);
    }

    session_t *se = g_instance->session_pool.sessions[sid];
    row_init(&ra, (char *)cursor->row,
             sess->kernel->attr.max_row_size, LOCKED_OBJECT_COLS);
    (void)row_put_int32(&ra, (int32)sid);
    (void)row_put_int32(&ra, (int32)se->knl_session.rm->xid.xmap.seg_id);
    (void)row_put_int32(&ra, (int32)se->knl_session.rm->xid.xmap.slot);
    (void)row_put_int32(&ra, (int32)se->knl_session.rm->xid.xnum);

    if (item.dc_entry == NULL) {
        (void)row_put_null(&ra);
        (void)row_put_int32(&ra, OG_INVALID_INT32);
        (void)row_put_null(&ra);
        (void)row_put_str(&ra, se->os_host); // CLIENT_OS_NAME
        (void)row_put_str(&ra, se->os_prog); // ClIENT_PROCESS
        (void)row_put_null(&ra);
    } else {
        (void)row_put_str(&ra, item.dc_entry->user->desc.name);
        (void)row_put_int32(&ra, (int32)item.dc_entry->id);
        (void)row_put_str(&ra, item.dc_entry->name);
        (void)row_put_str(&ra, se->os_host); // CLIENT_OS_NAME
        (void)row_put_str(&ra, se->os_prog); // ClIENT_PROCESS
        (void)row_put_str(&ra, lock_mode_string(item.dc_entry));
    }

    cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, &cursor->data_size);

    cursor->rowid.vmid++;
    return OG_SUCCESS;
}

static status_t vw_sess_alocks_fetch(knl_handle_t session, knl_cursor_t *cursor)
{
    row_assist_t ra;
    alck_item_pool_t *pool = &((knl_session_t *)session)->kernel->alck_ctx.se_ctx.item_pool;
    alck_map_pool_t *map_pool = &((knl_session_t *)session)->kernel->alck_ctx.se_ctx.map_pool;
    alck_item_t *alck_item;
    while (1) {
        if (cursor->rowid.vmid >= pool->count) {
            cursor->eof = OG_TRUE;
            return OG_SUCCESS;
        }

        alck_item = ALCK_ITEM_PTR(pool, (uint32)cursor->rowid.vmid);
        while (alck_item->lock_mode != ALCK_MODE_X || alck_item->x_times == 0) {
            cursor->rowid.vmid++;
            if (cursor->rowid.vmid >= pool->count) {
                cursor->eof = OG_TRUE;
                return OG_SUCCESS;
            }

            alck_item = ALCK_ITEM_PTR(pool, (uint32)cursor->rowid.vmid);
        }
        cm_spin_lock(&alck_item->lock, NULL);
        if (alck_item->lock_mode != ALCK_MODE_X || alck_item->x_times == 0) {
            cm_spin_unlock(&alck_item->lock);
            cursor->rowid.vmid++;
        } else {
            break;
        }
    }

    row_init(&ra, (char *)cursor->row, ((knl_session_t *)session)->kernel->attr.max_row_size, SESS_ALOCKS);
    (void)row_put_int32(&ra, (int32)alck_item->x_map_id);
    (void)row_put_str(&ra, alck_item->name);
    (void)row_put_int32(&ra, alck_get_locks(map_pool, alck_item, alck_item->x_map_id));
    (void)row_put_int32(&ra, alck_item->sn);
    cm_spin_unlock(&alck_item->lock);

    cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, &cursor->data_size);

    cursor->rowid.vmid++;
    return OG_SUCCESS;
}

static bool8 vw_shared_lock_loop(knl_cursor_t *cursor, alck_item_pool_t *pool)
{
    while (1) {
        if (cursor->rowid.vmid >= pool->count) {
            cursor->eof = OG_TRUE;
            return OG_FALSE;
        }
        
        alck_item_t *alck_item = ALCK_ITEM_PTR(pool, (uint32)cursor->rowid.vmid);
        while (alck_item->lock_mode != ALCK_MODE_S || alck_item->lock_times == 0) {
            cursor->rowid.vmid++;
            if (cursor->rowid.vmid >= pool->count) {
                cursor->eof = OG_TRUE;
                return OG_FALSE;
            }

            alck_item = ALCK_ITEM_PTR(pool, (uint32)cursor->rowid.vmid);
        }

        cm_spin_lock(&alck_item->lock, NULL);
        if (alck_item->lock_mode != ALCK_MODE_S || alck_item->lock_times == 0) {
            cm_spin_unlock(&alck_item->lock);
            cursor->rowid.vmid++;
            continue;
        }
        return OG_TRUE;
    }
}

static status_t vw_sess_shared_alocks_fetch(knl_handle_t session, knl_cursor_t *cursor)
{
    row_assist_t ra;
    alck_ctx_spec_t *ctx = &((knl_session_t *)session)->kernel->alck_ctx.se_ctx;
    alck_item_pool_t *pool = &((knl_session_t *)session)->kernel->alck_ctx.se_ctx.item_pool;
    while (OG_TRUE) {
        if (cursor->rowid.vmid >= pool->count) {
            cursor->eof = OG_TRUE;
            return OG_SUCCESS;
        }

        alck_item_t *alck_item = ALCK_ITEM_PTR(pool, (uint32)cursor->rowid.vmid);
        while (alck_item->lock_mode != ALCK_MODE_S || alck_item->lock_times == 0) {
            cursor->rowid.vmid++;
            if (cursor->rowid.vmid >= pool->count) {
                cursor->eof = OG_TRUE;
                return OG_SUCCESS;
            }
            alck_item = ALCK_ITEM_PTR(pool, (uint32)cursor->rowid.vmid);
        }

        cm_spin_lock(&alck_item->lock, NULL);
        if (alck_item->lock_mode != ALCK_MODE_S || alck_item->lock_times == 0) {
            cm_spin_unlock(&alck_item->lock);
            cursor->rowid.vmid++;
            continue;
        }

        alck_map_t *alck_map = ALCK_MAP_PTR(&ctx->map_pool, alck_item->first_map);

        row_init(&ra, (char *)cursor->row, ((knl_session_t *)session)->kernel->attr.max_row_size, SESS_SHARED_ALOCKS);
        (void)row_put_str(&ra, alck_item->name);
        (void)row_put_int32(&ra, (int32)alck_map->idx);
        (void)row_put_int32(&ra, (int32)alck_item->lock_times);
        cm_spin_unlock(&alck_item->lock);
        cursor->rowid.vmid++;
        return OG_SUCCESS;
    }

    return OG_ERROR;
}

static status_t vw_xact_locks_fetch(knl_handle_t session, knl_cursor_t *cursor)
{
    row_assist_t ra;
    alck_item_pool_t *pool = &((knl_session_t *)session)->kernel->alck_ctx.tx_ctx.item_pool;
    alck_item_t *alck_item;
    uint16 sid;
    while (1) {
        if (cursor->rowid.vmid >= pool->count) {
            cursor->eof = OG_TRUE;
            return OG_SUCCESS;
        }

        alck_item = ALCK_ITEM_PTR(pool, (uint32)cursor->rowid.vmid);
        while (alck_item->lock_mode != ALCK_MODE_X || alck_item->x_times == 0) {
            cursor->rowid.vmid++;
            if (cursor->rowid.vmid >= pool->count) {
                cursor->eof = OG_TRUE;
                return OG_SUCCESS;
            }

            alck_item = ALCK_ITEM_PTR(pool, (uint32)cursor->rowid.vmid);
        }
        cm_spin_lock(&alck_item->lock, NULL);
        sid = knl_get_rm_sid(session, alck_item->x_map_id);
        if (alck_item->lock_mode != ALCK_MODE_X || alck_item->x_times == 0 || sid == OG_INVALID_ID16) {
            cm_spin_unlock(&alck_item->lock);
            cursor->rowid.vmid++;
        } else {
            break;
        }
    }

    row_init(&ra, (char *)cursor->row, ((knl_session_t *)session)->kernel->attr.max_row_size, XACT_ALOCKS);
    (void)row_put_int32(&ra, (int32)sid);
    (void)row_put_int32(&ra, alck_item->sn);
    (void)row_put_str(&ra, alck_item->name);
    (void)row_put_int32(&ra, alck_item->lock_times);

    cm_spin_unlock(&alck_item->lock);

    cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, &cursor->data_size);

    cursor->rowid.vmid++;
    return OG_SUCCESS;
}

static status_t vw_xact_shared_locks_fetch(knl_handle_t session, knl_cursor_t *cursor)
{
    row_assist_t ra;
    alck_item_pool_t *pool = &((knl_session_t *)session)->kernel->alck_ctx.tx_ctx.item_pool;
    bool8 is_continue = vw_shared_lock_loop(cursor, pool);
    if (is_continue == OG_FALSE) {
        return OG_SUCCESS;
    }

    alck_item_t *alck_item = ALCK_ITEM_PTR(pool, (uint32)cursor->rowid.vmid);

    row_init(&ra, (char *)cursor->row,
             ((knl_session_t *)session)->kernel->attr.max_row_size, XACT_SHARED_ALOCKS);

    (void)row_put_str(&ra, alck_item->name);
    (void)row_put_int32(&ra, 0);
    (void)row_put_int32(&ra, alck_item->lock_times);

    cm_spin_unlock(&alck_item->lock);

    cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, &cursor->data_size);

    cursor->rowid.vmid++;
    return OG_SUCCESS;
}

static status_t vw_plsql_fetch_lock_ex(knl_handle_t session, knl_cursor_t *cursor, pl_entry_t *entry,
    bool8 *is_continue)
{
    row_assist_t ra;
    pl_lock_item_t *lock_item;
    status_t ret = OG_ERROR;
    dc_user_t *dc_user = NULL;
    *is_continue = OG_FALSE;

    lock_item = entry->meta_lock;
    if (lock_item->lock_mode != PL_MODE_X || lock_item->x_times == 0) {
        *is_continue = OG_TRUE;
        return OG_SUCCESS;
    }
    cm_spin_lock(&lock_item->lock, NULL);
    if (lock_item->lock_mode != PL_MODE_X || lock_item->x_times == 0) {
        *is_continue = OG_TRUE;
        cm_spin_unlock(&lock_item->lock);
        return OG_SUCCESS;
    }

    OG_RETURN_IFERR(dc_open_user_by_id(session, entry->desc.uid, &dc_user));
    row_init(&ra, (char *)cursor->row,
             ((knl_session_t *)session)->kernel->attr.max_row_size, PLSQL_ALOCKS);
    do {
        OG_BREAK_IF_ERROR(row_put_str(&ra, dc_user->desc.name));
        OG_BREAK_IF_ERROR(row_put_null(&ra));
        OG_BREAK_IF_ERROR(row_put_str(&ra, entry->desc.name));
        OG_BREAK_IF_ERROR(row_put_str(&ra, vw_pl_type_str(entry->desc.type)));
        OG_BREAK_IF_ERROR(row_put_int32(&ra, (int32)lock_item->x_map_id));
        OG_BREAK_IF_ERROR(row_put_int32(&ra, (int32)lock_item->lock_times));
        OG_BREAK_IF_ERROR(row_put_int32(&ra, (int32)lock_item->first_map));
        ret = OG_SUCCESS;
    } while (0);
    cm_spin_unlock(&lock_item->lock);
    return ret;
}

static status_t vw_plsql_fetch_lock_sh(knl_handle_t session, knl_cursor_t *cursor, pl_entry_t *entry,
    bool8 *is_continue)
{
    row_assist_t ra;
    uint32 ix_setted;
    pl_lock_item_t *lock_item;
    status_t ret = OG_ERROR;
    lock_item = entry->meta_lock;
    *is_continue = OG_FALSE;
    dc_user_t *dc_user = NULL;

    if (lock_item->lock_mode == PL_MODE_X || lock_item->lock_mode == PL_MODE_IDLE || lock_item->lock_times == 0) {
        *is_continue = OG_TRUE;
        return OG_SUCCESS;
    }
    cm_spin_lock(&lock_item->lock, NULL);
    if (lock_item->lock_mode == PL_MODE_X || lock_item->lock_mode == PL_MODE_IDLE || lock_item->lock_times == 0) {
        *is_continue = OG_TRUE;
        cm_spin_unlock(&lock_item->lock);
        return OG_SUCCESS;
    }
    ix_setted = (lock_item->lock_mode == PL_MODE_IX) ? 1 : 0;

    OG_RETURN_IFERR(dc_open_user_by_id(session, entry->desc.uid, &dc_user));
    knl_session_t *ss = (knl_session_t *)session;
    row_init(&ra, (char *)cursor->row, ss->kernel->attr.max_row_size, PLSQL_ALOCKS);
    do {
        OG_BREAK_IF_ERROR(row_put_str(&ra, dc_user->desc.name));
        OG_BREAK_IF_ERROR(row_put_null(&ra));
        OG_BREAK_IF_ERROR(row_put_str(&ra, entry->desc.name));
        OG_BREAK_IF_ERROR(row_put_str(&ra, vw_pl_type_str(entry->desc.type)));
        OG_BREAK_IF_ERROR(row_put_int32(&ra, ix_setted));
        OG_BREAK_IF_ERROR(row_put_int32(&ra, lock_item->lock_times));
        ret = OG_SUCCESS;
    } while (0);
    cm_spin_unlock(&lock_item->lock);
    return ret;
}


static status_t vw_plsql_alocks_fetch_core(knl_handle_t session, knl_cursor_t *cursor)
{
    uint32 bid = (uint32)cursor->rowid.vmid;
    uint32 bpos = (uint32)cursor->rowid.vm_tag;
    pl_manager_t *pl_mngr = GET_PL_MGR;
    pl_list_t *entry_list = NULL;
    bool8 is_continue = OG_FALSE;
    pl_entry_t *entry = NULL;
    bilist_node_t *entry_node = NULL;

    while (OG_TRUE) {
        if (bid >= PL_ENTRY_OID_BUCKET_SIZE) {
            cursor->eof = OG_TRUE;
            return OG_SUCCESS;
        }

        entry_list = &pl_mngr->entry_oid_buckets[bid];
        if (bpos >= entry_list->lst.count) {
            bpos = 0;
            bid++;
            continue;
        }

        cm_latch_s(&entry_list->latch, CM_THREAD_ID, OG_FALSE, NULL);
        entry_node = cm_bilist_get(&entry_list->lst, bpos);
        if (entry_node == NULL) {
            cm_unlatch(&entry_list->latch, NULL);
            bpos = 0;
            bid++;
            continue;
        }
        entry = BILIST_NODE_OF(pl_entry_t, entry_node, oid_link);
        status_t status = vw_plsql_fetch_lock_ex(session, cursor, entry, &is_continue);
        cm_unlatch(&entry_list->latch, NULL);
        OG_RETURN_IFERR(status);

        bpos++;
        if (is_continue) {
            continue;
        }
        break;
    }

    cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, &cursor->data_size);
    cursor->rowid.vmid = bid;
    cursor->rowid.vm_tag = bpos;
    return OG_SUCCESS;
}

static status_t vw_plsql_alocks_fetch(knl_handle_t session, knl_cursor_t *cursor)
{
    return vw_fetch_for_tenant(vw_plsql_alocks_fetch_core, session, cursor);
}

static status_t vw_plsql_shared_alocks_fetch_core(knl_handle_t session, knl_cursor_t *cursor)
{
    uint32 bid = (uint32)cursor->rowid.vmid;
    uint32 bpos = (uint32)cursor->rowid.vm_tag;
    pl_manager_t *pl_mngr = GET_PL_MGR;
    pl_list_t *entry_list = NULL;
    bool8 is_continue = OG_FALSE;
    pl_entry_t *entry = NULL;
    bilist_node_t *entry_node = NULL;

    while (OG_TRUE) {
        if (bid >= PL_ENTRY_OID_BUCKET_SIZE) {
            cursor->eof = OG_TRUE;
            return OG_SUCCESS;
        }

        entry_list = &pl_mngr->entry_oid_buckets[bid];
        if (bpos >= entry_list->lst.count) {
            bpos = 0;
            bid++;
            continue;
        }

        cm_latch_s(&entry_list->latch, CM_THREAD_ID, OG_FALSE, NULL);
        entry_node = cm_bilist_get(&entry_list->lst, bpos);
        if (entry_node == NULL) {
            cm_unlatch(&entry_list->latch, NULL);
            bpos = 0;
            bid++;
            continue;
        }
        entry = BILIST_NODE_OF(pl_entry_t, entry_node, oid_link);
        status_t status = vw_plsql_fetch_lock_sh(session, cursor, entry, &is_continue);
        cm_unlatch(&entry_list->latch, NULL);
        OG_RETURN_IFERR(status);

        bpos++;
        if (is_continue) {
            continue;
        }
        break;
    }

    cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, &cursor->data_size);
    cursor->rowid.vmid = bid;
    cursor->rowid.vm_tag = bpos;
    return OG_SUCCESS;
}

static status_t vw_plsql_shared_alocks_fetch(knl_handle_t session, knl_cursor_t *cursor)
{
    return vw_fetch_for_tenant(vw_plsql_shared_alocks_fetch_core, session, cursor);
}

static status_t vw_alocks_open(knl_handle_t session, knl_cursor_t *cursor)
{
    cursor->rowid.vmid = 0;
    cursor->rowid.vm_slot = 0;
    cursor->rowid.vm_tag = 0;
    vw_alocks_assist_t *assist = (vw_alocks_assist_t *)cursor->page_buf;
    assist->se_pool_itemcnts = ((knl_session_t *)session)->kernel->alck_ctx.se_ctx.item_pool.count;
    assist->tx_pool_itemcnts = ((knl_session_t *)session)->kernel->alck_ctx.tx_ctx.item_pool.count;
    return OG_SUCCESS;
}

static status_t vm_format_alck_se_detail(knl_handle_t session, alck_map_pool_t *map_pool, alck_item_t *alck_item,
    text_buf_t *txtbuf)
{
    uint32 map_id = alck_item->first_map;
    alck_map_t *alck_map = NULL;
    while (map_id != OG_INVALID_ID32) {
        alck_map = ALCK_MAP_PTR(map_pool, map_id);
        if (!cm_buf_append_fmt(txtbuf, "%u:%u ", alck_map->idx, alck_map->count)) {
            OG_RETURN_IFERR(cm_concat_string((text_t *)txtbuf, txtbuf->max_size, "..."));
            return OG_SUCCESS;
        }
        map_id = alck_map->next;
    }
    return OG_SUCCESS;
}

static status_t vm_format_alck_tx_detail(knl_handle_t session, alck_map_pool_t *map_pool, alck_item_t *alck_item,
    text_buf_t *txtbuf)
{
    uint32 map_id = alck_item->first_map;
    alck_map_t *alck_map = NULL;
    while (map_id != OG_INVALID_ID32) {
        alck_map = ALCK_MAP_PTR(map_pool, map_id);
        if (!cm_buf_append_fmt(txtbuf, "%u(%u):%u ", alck_map->idx, knl_get_rm_sid(session, alck_map->idx),
            alck_map->count)) {
            OG_RETURN_IFERR(cm_concat_string((text_t *)txtbuf, txtbuf->max_size, "..."));
            return OG_SUCCESS;
        }
        map_id = alck_map->next;
    }
    return OG_SUCCESS;
}

static status_t vm_format_alck_detail(knl_handle_t session, alck_map_pool_t *map_pool, alck_item_t *alck_item,
    text_buf_t *txtbuf, alck_lock_set_t lock_set)
{
    if (lock_set == SE_LOCK) {
        return vm_format_alck_se_detail(session, map_pool, alck_item, txtbuf);
    } else if (lock_set == TX_LOCK) {
        return vm_format_alck_tx_detail(session, map_pool, alck_item, txtbuf);
    }
    return OG_SUCCESS;
}

static char *vw_get_alck_mode(uint32 lock_mode)
{
    switch (lock_mode) {
        case ALCK_MODE_IDLE:
            return "IDLE";
        case ALCK_MODE_IX:
            return "IX";
        case ALCK_MODE_S:
            return "S";
        case ALCK_MODE_X:
            return "X";
        default:
            return "";
    }
    return "";
}

static status_t vw_alocks_rowput_ix_map(row_assist_t *ra, knl_handle_t session, alck_item_t *alck_item,
    alck_lock_set_t lock_set)
{
    char buffer[OG_MAX_ALCK_IX_MAP_LEN + 1];
    buffer[0] = '\0';
    if (alck_item->lock_mode != ALCK_MODE_IX) {
        return row_put_str(ra, "");
    }
    if (lock_set == SE_LOCK) {
        PRTS_RETURN_IFERR(sprintf_s(buffer, OG_MAX_ALCK_IX_MAP_LEN + 1, "%u", alck_item->ix_map_id));
    } else if (lock_set == TX_LOCK) {
        PRTS_RETURN_IFERR(sprintf_s(buffer, OG_MAX_ALCK_IX_MAP_LEN + 1, "%u(%u)", alck_item->ix_map_id,
            knl_get_rm_sid(session, alck_item->ix_map_id)));
    }
    return row_put_str(ra, buffer);
}

static status_t vw_all_alocks_rowput(knl_handle_t session, knl_cursor_t *cursor, alck_ctx_spec_t *ogx,
    alck_item_t *alck_item)
{
    row_assist_t ra;
    sql_stmt_t *stmt = ((session_t *)session)->current_stmt;
    text_buf_t lock_detail;

    OGSQL_SAVE_STACK(stmt);
    OG_RETURN_IFERR(sql_push_textbuf(stmt, OG_MAX_COLUMN_SIZE, &lock_detail));
    lock_detail.max_size -= ALCK_TEXTBUF_APPEND_RESERVE;
    if (vm_format_alck_detail(session, &ogx->map_pool, alck_item, &lock_detail, ogx->lock_set) != OG_SUCCESS) {
        OGSQL_RESTORE_STACK(stmt);
        return OG_ERROR;
    }
    row_init(&ra, (char *)cursor->row, ((knl_session_t *)session)->kernel->attr.max_row_size, ALL_ALOCKS);
    (void)row_put_str(&ra, alck_item->name);
    if (ogx->lock_set == SE_LOCK) {
        (void)row_put_str(&ra, "SE");
    } else {
        (void)row_put_str(&ra, "TX");
    }
    uint32 ix_setted = (alck_item->lock_mode == ALCK_MODE_IX) ? 1 : 0;
    (void)row_put_uint32(&ra, alck_item->x_times);
    (void)row_put_uint32(&ra, alck_item->lock_times);
    (void)row_put_uint32(&ra, ix_setted);
    (void)row_put_text(&ra, &lock_detail.value);
    (void)row_put_str(&ra, vw_get_alck_mode(alck_item->lock_mode));
    (void)vw_alocks_rowput_ix_map(&ra, session, alck_item, ogx->lock_set);
    OGSQL_RESTORE_STACK(stmt);
    return OG_SUCCESS;
}

static status_t vw_all_alocks_fetch(knl_handle_t session, knl_cursor_t *cursor)
{
    alck_ctx_spec_t *ogx = NULL;
    alck_item_pool_t *pool = NULL;
    alck_item_t *alck_item = NULL;
    vw_alocks_assist_t *assist = (vw_alocks_assist_t *)cursor->page_buf;
    status_t status;
    uint32 se_pool_count = assist->se_pool_itemcnts;
    uint32 tx_pool_count = assist->tx_pool_itemcnts;

    do {
        if (cursor->rowid.vmid >= se_pool_count + tx_pool_count) {
            cursor->eof = OG_TRUE;
            return OG_SUCCESS;
        } else if (cursor->rowid.vmid >= tx_pool_count) {
            ogx = &((knl_session_t *)session)->kernel->alck_ctx.se_ctx;
            pool = &ogx->item_pool;
            alck_item = ALCK_ITEM_PTR(pool, (uint32)cursor->rowid.vmid - tx_pool_count);
        } else {
            ogx = &((knl_session_t *)session)->kernel->alck_ctx.tx_ctx;
            pool = &ogx->item_pool;
            alck_item = ALCK_ITEM_PTR(pool, (uint32)cursor->rowid.vmid);
        }
        if (alck_item->lock_times == 0 || alck_item->lock_mode == ALCK_MODE_IDLE) {
            cursor->rowid.vmid++;
            continue;
        }

        cm_spin_lock(&alck_item->lock, NULL);
        if (alck_item->lock_times == 0 || alck_item->lock_mode == ALCK_MODE_IDLE) {
            cm_spin_unlock(&alck_item->lock);
            cursor->rowid.vmid++;
            continue;
        }
        break;
    } while (OG_TRUE);

    status = vw_all_alocks_rowput(session, cursor, ogx, alck_item);
    cm_spin_unlock(&alck_item->lock);
    OG_RETURN_IFERR(status);
    cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, &cursor->data_size);
    cursor->rowid.vmid++;
    return OG_SUCCESS;
}

static void vw_user_alck_rowput(knl_handle_t session, knl_cursor_t *cursor, alck_ctx_spec_t *ogx,
    alck_item_t *alck_item, alck_map_t *map)
{
    row_assist_t ra;
    row_init(&ra, (char *)cursor->row, ((knl_session_t *)session)->kernel->attr.max_row_size, USER_ALOCKS);
    (void)row_put_str(&ra, alck_item->name);
    if (ogx->lock_set == SE_LOCK) {
        (void)row_put_str(&ra, "SE");
    } else {
        (void)row_put_str(&ra, "TX");
    }
    uint32 ix_setted = (alck_item->lock_mode == ALCK_MODE_IX) ? 1 : 0;
    (void)row_put_uint32(&ra, alck_item->x_times);
    (void)row_put_uint32(&ra, map->count);
    (void)row_put_uint32(&ra, alck_item->lock_times);
    (void)row_put_uint32(&ra, ix_setted);
    (void)row_put_str(&ra, vw_get_alck_mode(alck_item->lock_mode));
    (void)vw_alocks_rowput_ix_map(&ra, session, alck_item, ogx->lock_set);
    cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, &cursor->data_size);
}

static status_t vw_user_alocks_fetch(knl_handle_t session, knl_cursor_t *cursor)
{
    alck_ctx_spec_t *ogx = NULL;
    alck_item_pool_t *pool = NULL;
    alck_map_pool_t *map_pool = NULL;
    alck_item_t *alck_item = NULL;
    vw_alocks_assist_t *assist = (vw_alocks_assist_t *)cursor->page_buf;
    uint32 se_pool_count = assist->se_pool_itemcnts;
    uint32 tx_pool_count = assist->tx_pool_itemcnts;
    knl_session_t *knl_sess = (knl_session_t *)session;
    uint32 match_idx;
    alck_map_t *map = NULL;

    do {
        if (cursor->rowid.vmid >= se_pool_count + tx_pool_count) {
            cursor->eof = OG_TRUE;
            return OG_SUCCESS;
        } else if (cursor->rowid.vmid >= tx_pool_count) {
            ogx = &knl_sess->kernel->alck_ctx.se_ctx;
            pool = &ogx->item_pool;
            alck_item = ALCK_ITEM_PTR(pool, (uint32)cursor->rowid.vmid - tx_pool_count);
            match_idx = knl_sess->id;
        } else {
            ogx = &knl_sess->kernel->alck_ctx.tx_ctx;
            pool = &ogx->item_pool;
            alck_item = ALCK_ITEM_PTR(pool, (uint32)cursor->rowid.vmid);
            match_idx = knl_sess->rmid;
        }
        map_pool = &ogx->map_pool;
        if (alck_item->lock_times == 0 || alck_item->lock_mode == ALCK_MODE_IDLE) {
            cursor->rowid.vmid++;
            continue;
        }

        cm_spin_lock(&alck_item->lock, NULL);
        if (alck_item->lock_times == 0 || alck_item->lock_mode == ALCK_MODE_IDLE ||
            (alck_item->lock_mode == ALCK_MODE_X && alck_item->x_map_id != match_idx)) {
            cm_spin_unlock(&alck_item->lock);
            cursor->rowid.vmid++;
            continue;
        }

        map = alck_get_map(map_pool, alck_item, match_idx);
        if (map == NULL) {
            cm_spin_unlock(&alck_item->lock);
            cursor->rowid.vmid++;
            continue;
        }
        break;
    } while (OG_TRUE);

    vw_user_alck_rowput(session, cursor, ogx, alck_item, map);
    cm_spin_unlock(&alck_item->lock);
    cursor->rowid.vmid++;
    return OG_SUCCESS;
}

static status_t vm_format_plsql_lock_detail(knl_handle_t session, pl_lock_item_t *lock_item, text_buf_t *txtbuf)
{
    pl_lock_pool_t *map_pool = &GET_PL_MGR->lock_map_pool;
    uint32 map_id = lock_item->first_map;
    pl_lock_map_t *lock_map = NULL;
    while (map_id != OG_INVALID_ID32) {
        lock_map = PL_LOCK_MAP_PTR(map_pool, map_id);
        if (!cm_buf_append_fmt(txtbuf, "%u:%u ", lock_map->idx, lock_map->count)) {
            OG_RETURN_IFERR(cm_concat_string((text_t *)txtbuf, txtbuf->max_size, "..."));
            return OG_SUCCESS;
        }
        map_id = lock_map->next;
    }
    return OG_SUCCESS;
}

static char *vw_get_plsql_lock_mode(uint32 lock_mode)
{
    switch (lock_mode) {
        case PL_MODE_IDLE:
            return "IDLE";
        case PL_MODE_IX:
            return "IX";
        case PL_MODE_S:
            return "S";
        case PL_MODE_X:
            return "X";
        default:
            return "";
    }
    return "";
}

static status_t vw_plsql_locks_rowput(knl_handle_t session, knl_cursor_t *cursor, pl_entry_t *entry,
    pl_lock_item_t *lock_item)
{
    row_assist_t ra;
    status_t ret = OG_ERROR;
    sql_stmt_t *stmt = ((session_t *)session)->current_stmt;
    text_buf_t lock_detail;
    dc_user_t *dc_user = NULL;
    OGSQL_SAVE_STACK(stmt);
    OG_RETURN_IFERR(dc_open_user_by_id(session, entry->desc.uid, &dc_user));
    OG_RETURN_IFERR(sql_push_textbuf(stmt, OG_MAX_COLUMN_SIZE, &lock_detail));
    lock_detail.max_size -= ALCK_TEXTBUF_APPEND_RESERVE;
    if (vm_format_plsql_lock_detail(session, lock_item, &lock_detail) != OG_SUCCESS) {
        OGSQL_RESTORE_STACK(stmt);
        return OG_ERROR;
    }
    row_init(&ra, (char *)cursor->row, ((knl_session_t *)session)->kernel->attr.max_row_size, PL_LOCKS);
    do {
        OG_BREAK_IF_ERROR(row_put_str(&ra, dc_user->desc.name));
        OG_BREAK_IF_ERROR(row_put_str(&ra, entry->desc.name));
        OG_BREAK_IF_ERROR(row_put_str(&ra, vw_pl_type_str(entry->desc.type)));
        OG_BREAK_IF_ERROR(row_put_uint32(&ra, lock_item->lock_times));
        OG_BREAK_IF_ERROR(row_put_uint32(&ra, lock_item->x_times));
        OG_BREAK_IF_ERROR(row_put_str(&ra, vw_get_plsql_lock_mode(lock_item->lock_mode)));
        if (lock_item->lock_mode == PL_MODE_IX) {
            OG_BREAK_IF_ERROR(row_put_uint32(&ra, lock_item->ix_map_id));
        } else {
            OG_BREAK_IF_ERROR(row_put_null(&ra));
        }
        OG_BREAK_IF_ERROR(row_put_text(&ra, &lock_detail.value));
        ret = OG_SUCCESS;
    } while (0);
    OGSQL_RESTORE_STACK(stmt);
    return ret;
}

static status_t vw_fetch_plsql_fetch_lock_info(knl_handle_t session, knl_cursor_t *cursor, pl_entry_t *entry,
    bool8 *is_continue)
{
    pl_lock_item_t *lock_item = entry->meta_lock;
    *is_continue = OG_FALSE;
    status_t status;
    if (lock_item->lock_mode == PL_MODE_IDLE || lock_item->lock_times == 0) {
        *is_continue = OG_TRUE;
        return OG_SUCCESS;
    }
    cm_spin_lock(&lock_item->lock, NULL);
    if (lock_item->lock_mode == PL_MODE_IDLE || lock_item->lock_times == 0) {
        *is_continue = OG_TRUE;
        cm_spin_unlock(&lock_item->lock);
        return OG_SUCCESS;
    }
    status = vw_plsql_locks_rowput(session, cursor, entry, lock_item);
    cm_spin_unlock(&lock_item->lock);
    return status;
}

static status_t vw_plsql_locks_fetch_core(knl_handle_t session, knl_cursor_t *cursor)
{
    uint32 bid = (uint32)cursor->rowid.vmid;
    uint32 bpos = (uint32)cursor->rowid.vm_tag;
    pl_manager_t *pl_mngr = GET_PL_MGR;
    pl_list_t *entry_list = NULL;
    bool8 is_continue = OG_FALSE;
    pl_entry_t *entry = NULL;
    bilist_node_t *entry_node = NULL;

    while (OG_TRUE) {
        if (bid >= PL_ENTRY_OID_BUCKET_SIZE) {
            cursor->eof = OG_TRUE;
            return OG_SUCCESS;
        }

        entry_list = &pl_mngr->entry_oid_buckets[bid];
        if (bpos >= entry_list->lst.count) {
            bpos = 0;
            bid++;
            continue;
        }

        cm_latch_s(&entry_list->latch, CM_THREAD_ID, OG_FALSE, NULL);
        entry_node = cm_bilist_get(&entry_list->lst, bpos);
        if (entry_node == NULL) {
            cm_unlatch(&entry_list->latch, NULL);
            bpos = 0;
            bid++;
            continue;
        }
        entry = BILIST_NODE_OF(pl_entry_t, entry_node, oid_link);
        status_t status = vw_fetch_plsql_fetch_lock_info(session, cursor, entry, &is_continue);
        cm_unlatch(&entry_list->latch, NULL);
        OG_RETURN_IFERR(status);

        bpos++;
        if (is_continue) {
            continue;
        }
        break;
    }

    cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, &cursor->data_size);
    cursor->rowid.vmid = bid;
    cursor->rowid.vm_tag = bpos;
    return OG_SUCCESS;
}

static status_t vw_plsql_locks_fetch(knl_handle_t session, knl_cursor_t *cursor)
{
    return vw_fetch_for_tenant(vw_plsql_locks_fetch_core, session, cursor);
}

static status_t get_lock_res_view(row_assist_t *ra, drc_master_res_t *lock_res)
{
    OG_RETURN_IFERR(row_put_uint32(ra, (uint32)lock_res->idx));
    OG_RETURN_IFERR(row_put_uint32(ra, (uint32)lock_res->res_id.type));
    OG_RETURN_IFERR(row_put_uint32(ra, (uint32)lock_res->res_id.uid));
    OG_RETURN_IFERR(row_put_uint32(ra, (uint32)lock_res->res_id.id));
    OG_RETURN_IFERR(row_put_uint32(ra, (uint32)lock_res->res_id.idx));
    OG_RETURN_IFERR(row_put_uint32(ra, (uint32)lock_res->res_id.part));
    OG_RETURN_IFERR(row_put_uint32(ra, (uint32)lock_res->res_id.parentpart));
    OG_RETURN_IFERR(row_put_str(ra, drc_get_lock_mode_str(lock_res)));
    OG_RETURN_IFERR(row_put_int32(ra, (int32)lock_res->part_id));
    OG_RETURN_IFERR(row_put_int64(ra, (int64)lock_res->granted_map));
    OG_RETURN_IFERR(row_put_uint32(ra, (uint32)lock_res->convert_q.count));
    OG_RETURN_IFERR(row_put_int32(ra, (int32)lock_res->converting.req_info.inst_id));
    return OG_SUCCESS;
}

static status_t vw_dls_lock_fetch(knl_handle_t handle, knl_cursor_t *cursor)
{
    row_assist_t ra;
    drc_list_t *part_list = NULL;
    drc_master_res_t *lock_res = NULL;
    uint64 index;
    uint32 i;
    uint32 lock_idx;

    if (cursor->rowid.vm_slot >= DRC_MAX_PART_NUM) {
        cursor->eof = OG_TRUE;
        return OG_SUCCESS;
    }

    drc_get_global_lock_res_parts(cursor->rowid.vm_slot, &part_list);
    while (part_list->count == 0 && cursor->rowid.vm_slot < DRC_MAX_PART_NUM) {
        cursor->rowid.vm_slot++;
        cursor->rowid.vmid = 0;
        drc_get_global_lock_res_parts(cursor->rowid.vm_slot, &part_list);
    }

    if (cursor->rowid.vm_slot >= DRC_MAX_PART_NUM) {
        cursor->eof = OG_TRUE;
        return OG_SUCCESS;
    }

    drc_lock_remaster_mngr();
    index = cursor->rowid.vmid;
    lock_idx = part_list->first;
    for (i = 0; i < part_list->count; i++) {
        lock_res = drc_get_global_lock_resx_by_id(lock_idx);
        if (index == 0) {
            break;
        } else {
            index--;
            lock_idx = lock_res->node.next;
        }
    }
    drc_unlock_remaster_mngr();

    row_init(&ra, (char *)cursor->row, OG_MAX_ROW_SIZE, DLSLOCK_COLS);
    status_t ret = get_lock_res_view(&ra, lock_res);
    if (ret != OG_SUCCESS) {
        return ret;
    }
    cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, &cursor->data_size);
    cursor->rowid.vmid++;

    if (i == part_list->count - 1) {
        cursor->rowid.vm_slot++;
        cursor->rowid.vmid = 0;
    }

    return OG_SUCCESS;
}

VW_DECL dv_lock = { "SYS", "DV_LOCKS", LOCK_COLS, g_lock_columns, vw_common_open, vw_lock_fetch };
VW_DECL dv_spinlock = { "SYS", "DV_SPINLOCKS", SPINLOCK_COLS, g_spin_lock_columns, vw_common_open, vw_spin_lock_fetch };
VW_DECL dv_locked_object = { "SYS",          "DV_LOCKED_OBJECTS",   LOCKED_OBJECT_COLS, g_locked_object_columns,
                             vw_common_open, vw_locked_object_fetch };
VW_DECL dv_sess_alocks = { "SYS",         "DV_USER_ADVISORY_LOCKS", SESS_ALOCKS,
                           g_sess_alocks, vw_common_open,           vw_sess_alocks_fetch };
VW_DECL dv_sess_shared_alocks = { "SYS",          "DV_SESSION_SHARED_LOCKS",  SESS_SHARED_ALOCKS, g_sess_shared_alocks,
                                  vw_common_open, vw_sess_shared_alocks_fetch };
VW_DECL dv_xact_alocks = { "SYS", "DV_XACT_LOCKS", XACT_ALOCKS, g_xact_alocks, vw_common_open, vw_xact_locks_fetch };
VW_DECL dv_xact_shared_alocks = { "SYS",          "DV_XACT_SHARED_LOCKS",    XACT_SHARED_ALOCKS, g_xact_shared_alocks,
                                  vw_common_open, vw_xact_shared_locks_fetch };
VW_DECL dv_plsql_alocks = {
    "SYS", "DV_PLSQL_LOCKS", PLSQL_ALOCKS, g_plsql_alocks, vw_common_open, vw_plsql_alocks_fetch
};
VW_DECL dv_plsql_shared_alocks = {
    "SYS",          "DV_PLSQL_SHARED_LOCKS",     PLSQL_SHARED_ALOCKS, g_plsql_shared_alocks,
    vw_common_open, vw_plsql_shared_alocks_fetch
};
VW_DECL dv_user_alocks = { "SYS", "DV_USER_ALOCKS", USER_ALOCKS, g_user_alocks, vw_alocks_open, vw_user_alocks_fetch };
VW_DECL dv_all_alocks = { "SYS", "DV_ALL_ALOCKS", ALL_ALOCKS, g_all_alocks, vw_alocks_open, vw_all_alocks_fetch };
VW_DECL dv_pl_locks = { "SYS", "DV_PL_LOCKS", PL_LOCKS, g_pl_locks, vw_common_open, vw_plsql_locks_fetch };
VW_DECL dv_dlslock = { "SYS", "DV_DLSLOCKS", DLSLOCK_COLS, g_dls_lock_columns, vw_common_open, vw_dls_lock_fetch };

dynview_desc_t *vw_describe_lock(uint32 id)
{
    switch ((dynview_id_t)id) {
        case DYN_VIEW_LOCK:
            return &dv_lock;

        case DYN_VIEW_LOCKED_OBJECT:
            return &dv_locked_object;

        case DYN_VIEW_SPINLOCK:
            return &dv_spinlock;

        case DYN_VIEW_SESS_ALOCK:
            return &dv_sess_alocks;

        case DYN_VIEW_SESS_SHARED_ALOCK:
            return &dv_sess_shared_alocks;

        case DYN_VIEW_XACT_ALOCK:
            return &dv_xact_alocks;

        case DYN_VIEW_XACT_SHARED_ALOCK:
            return &dv_xact_shared_alocks;

        case DYN_VIEW_PLSQL_ALOCK:
            return &dv_plsql_alocks;

        case DYN_VIEW_PLSQL_SHARED_ALOCK:
            return &dv_plsql_shared_alocks;

        case DYN_VIEW_ALL_ALOCK:
            return &dv_all_alocks;

        case DYN_VIEW_USER_ALOCK:
            return &dv_user_alocks;

        case DYN_VIEW_PL_LOCKS:
            return &dv_pl_locks;

        case DYN_VIEW_DLSLOCK:
            return &dv_dlslock;

        default:
            return NULL;
    }
}