* 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.
* -------------------------------------------------------------------------
*
* knl_lob.h
*
*
* IDENTIFICATION
* src/kernel/lob/knl_lob.h
*
* -------------------------------------------------------------------------
*/
#ifndef __KNL_LOB_H
#define __KNL_LOB_H
#include "cm_defs.h"
#include "knl_session.h"
#include "knl_heap.h"
#include "knl_interface.h"
#include "rb_purge.h"
#include "knl_lob_persistent.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LOB_MAX_INLIINE_SIZE (OG_LOB_LOCATOR_BUF_SIZE - OFFSET_OF(lob_locator_t, data))
#define COLUMN_IS_LOB(c) \
(((c)->datatype == OG_TYPE_CLOB) || ((c)->datatype == OG_TYPE_BLOB) || \
((c)->datatype == OG_TYPE_IMAGE) || KNL_COLUMN_IS_ARRAY(c))
#define LOB_SEG_HEAD(session) (lob_segment_t *)((session)->curr_page + PAGE_HEAD_SIZE)
#define MAX_LOB_ITEMS_PAGES 1024
#define LOB_ITEM_PAGE_CAPACITY (OG_SHARED_PAGE_SIZE / sizeof(lob_item_t))
#define MAX_LOB_ITEMS (MAX_LOB_ITEMS_PAGES * LOB_ITEM_PAGE_CAPACITY)
#define KNL_LOB_LOCATOR_SIZE sizeof(lob_locator_t)
#define LOB_CHECK_ORG_SCN(locator, data) \
((data)->head.type == PAGE_TYPE_LOB_DATA && (data)->chunk.org_scn == (locator)->org_scn)
#define LOB_CHECK_XID(locator, chunk) ((locator)->xid.value == (chunk)->ins_xid.value)
#define LOB_IS_INLINE(locator) (!(locator)->head.is_outline)
#define LOB_INLINE_DATA(locator) (char *)((locator)->data)
#define KNL_LOB_LOCATOR_OFFSERT(cursor, id) ((cursor)->offsets[id] - sizeof(uint16))
#define KNL_LOB_INLINE_SIZE(lob_len) CM_ALIGN4(sizeof(uint16) + sizeof(lob_head_t) + (lob_len))
#define KNL_LOB_OUTLINE_SIZE CM_ALIGN4(sizeof(uint16) + sizeof(lob_locator_t))
#define DEFAULT_LOB_CHUNK_SIZE 4096
#define LOB_MAX_CHUNK_SIZE(session) (DEFAULT_PAGE_SIZE(session) - sizeof(lob_data_page_t) - sizeof(page_tail_t))
#define LOB_GET_LOCATOR(locator) (lob_locator_t *)(locator)
#define LOB_GET_CHUNK_COUNT(session, locator) \
(((locator)->head.size + LOB_MAX_CHUNK_SIZE(session) - 1) / LOB_MAX_CHUNK_SIZE(session))
#define LOB_CURR_DATA_PAGE(session) (lob_data_page_t *)CURR_PAGE(session)
#define LOB_NEXT_DATA_PAGE(session) ((LOB_CURR_DATA_PAGE(session))->chunk.next)
#define LOB_GET_CHUNK(session) (&(LOB_CURR_DATA_PAGE(session))->chunk)
#define LOB_PCT_RATIO(lob_free_pages, lob_page_count) (((double)(lob_free_pages) / (double)(lob_page_count)) * 100)
#define LOB_MIN_SHRINK_EXTENTS 3
#define LOB_SEGMENT(session, pageid, segment) \
((buf_check_resident_page_version((session), (pageid))) ? \
((lob_segment_t *)(segment)) : ((lob_segment_t *)(segment)))
#define LOB_TEMP_MAX_CHUNK_SIZE (TEMP_PAGE_SIZE - sizeof(lob_data_page_t) - sizeof(page_tail_t))
#define LOB_TEMP_GET_CHUNK_COUNT(locator) (((locator)->head.size + LOB_TEMP_MAX_CHUNK_SIZE - 1) / LOB_TEMP_MAX_CHUNK_SIZE)
#define LOB_TEMP_GET_CHUNK(session) (&((lob_data_page_t *)(buf_curr_temp_page(session)->data))->chunk)
#define LOB_TEMP_NEXT_DATA_PAGE(session) (((lob_data_page_t *)(buf_curr_temp_page(session)->data))->chunk.next)
typedef struct st_lob_shrink_assist {
knl_scn_t min_scn;
page_id_t last_extent;
page_id_t last_free_pagid;
page_id_t new_extent;
uint32 free_count;
page_list_t extents;
} lob_shrink_assist_t;
typedef struct st_undo_lob_create {
uint32 space_id;
page_id_t entry;
} undo_lob_create_t;
typedef struct st_knl_lob_desc {
uint32 uid;
uint32 table_id;
uint32 column_id;
uint32 space_id;
page_id_t entry;
knl_scn_t org_scn;
knl_scn_t chg_scn;
knl_scn_t seg_scn;
uint32 chunk;
uint32 retention;
uint32 pctversion;
union {
uint32 flags;
struct {
uint32 is_stored : 1;
uint32 is_compressed : 1;
uint32 is_encrypted : 1;
uint32 is_inrow : 1;
uint32 unused : 28;
};
};
} knl_lob_desc_t;
typedef struct st_lob {
knl_lob_desc_t desc;
lob_entity_t lob_entity;
struct st_part_lob *part_lob;
} lob_t;
#define LOB_GET_PART(lob, part_no) PART_GET_ENTITY(((lob_t *)(lob))->part_lob, part_no)
typedef struct st_lob_pages_info {
uint32 uid;
uint32 table_id;
uint32 col_id;
knl_part_locate_t part_loc;
page_id_t entry;
page_list_t del_pages;
} lob_pages_info_t;
typedef struct st_lob_item {
spinlock_t lock;
uint32 item_id;
uint32 next;
lob_pages_info_t pages_info;
struct st_lob_item *next_item;
} lob_item_t;
typedef struct st_lob_area {
spinlock_t lock;
memory_pool_t pool;
uint32 page_count;
char *pages[MAX_LOB_ITEMS_PAGES];
id_list_t free_items;
uint32 hwm;
uint32 capacity;
} lob_area_t;
typedef struct st_lob_alloc_assist {
page_id_t *lob_page_id;
knl_scn_t org_scn;
bool32 generate_undo;
} lob_alloc_assist_t;
void lob_init_page(knl_session_t *session, page_id_t page_id, page_type_t type, bool32 init_head);
void lob_area_init(knl_session_t *session);
void lob_items_reset(knl_rm_t *rm);
void lob_items_free(knl_session_t *session);
void lob_reset_svpt(knl_session_t *session, knl_savepoint_t *savepoint);
status_t lob_create_segment(knl_session_t *session, lob_t *lob);
status_t lob_create_part_segment(knl_session_t *session, lob_part_t *lob_part);
void lob_drop_segment(knl_session_t *session, lob_t *lob);
void lob_drop_part_segment(knl_session_t *session, lob_part_t *lob_part);
void lob_truncate_segment(knl_session_t *session, knl_lob_desc_t *desc, bool32 reuse_storage);
void lob_truncate_part_segment(knl_session_t *session, knl_lob_part_desc_t *desc, bool32 reuse_storage);
status_t lob_purge_prepare(knl_session_t *session, knl_rb_desc_t *desc);
void lob_purge_segment(knl_session_t *session, knl_seg_desc_t *desc);
status_t lob_delete(knl_session_t *session, knl_cursor_t *cursor);
status_t lob_update(knl_session_t *session, knl_cursor_t *cursor, heap_update_assist_t *ua);
status_t lob_set_column_default(knl_session_t *session, knl_cursor_t *cursor, lob_locator_t *locator, void *data,
knl_column_t *column, void *stmt);
status_t knl_copy_lob(knl_session_t *session, knl_cursor_t *dst_cursor, lob_locator_t *dst_locator,
lob_locator_t *src_locator, knl_column_t *column);
void lob_free_delete_pages(knl_session_t *session);
void lob_undo_insert(knl_session_t *session, undo_row_t *ud_row, undo_page_t *ud_page, int32 ud_slot,
knl_dictionary_t *dc);
void lob_undo_delete_commit_recycle(knl_session_t *session, undo_row_t *ud_row, undo_page_t *ud_page, int32 ud_slot);
void lob_undo_delete(knl_session_t *session, undo_row_t *ud_row, undo_page_t *ud_page, int32 ud_slot);
void lob_undo_delete_commit(knl_session_t *session, undo_row_t *ud_row, undo_page_t *ud_page, int32 ud_slot);
void lob_undo_write_page(knl_session_t *session, undo_row_t *ud_row, undo_page_t *ud_page, int32 ud_slot);
status_t lob_write_2pc_buff(knl_session_t *session, binary_t *buf, uint32 max_size);
status_t lob_create_2pc_items(knl_session_t *session, uint8 *buf, uint32 buf_size, lob_item_list_t *item_list);
status_t lob_recycle_pages(knl_session_t *session, knl_cursor_t *cursor, lob_t *lob, lob_locator_t *locator);
void lob_drop_garbage_segment(knl_session_t *session, knl_seg_desc_t *seg);
void lob_drop_part_garbage_segment(knl_session_t *session, knl_seg_desc_t *seg);
void lob_truncate_garbage_segment(knl_session_t *session, knl_seg_desc_t *seg);
void lob_truncate_part_garbage_segment(knl_session_t *session, knl_seg_desc_t *seg);
status_t lob_reorganize_columns(knl_session_t *session, knl_cursor_t *cursor, heap_update_assist_t *ua,
knl_update_info_t *lob_info, bool32 *changed);
status_t lob_shrink_space(knl_session_t *session, knl_cursor_t *cursor, knl_column_t *column);
#ifdef LOG_DIAG
void lob_validate_page(knl_session_t *session, page_head_t *page);
#endif
static inline lob_item_t *lob_item_addr(lob_area_t *area, uint32 id)
{
uint32 page_id = id / LOB_ITEM_PAGE_CAPACITY;
uint32 item_id = id % LOB_ITEM_PAGE_CAPACITY;
return (lob_item_t *)(area->pages[page_id] + item_id * sizeof(lob_item_t));
}
static inline uint32 knl_lob_locator_size(knl_handle_t locator)
{
lob_locator_t *lob = (lob_locator_t *)locator;
if (lob->head.is_outline) {
return sizeof(lob_locator_t);
}
return (uint32)(lob->head.size + OFFSET_OF(lob_locator_t, data));
}
static inline uint32 knl_lob_inline_size(bool32 is_csf, uint32 lob_len, bool32 with_colsize)
{
uint32 row_len;
if (is_csf) {
row_len = sizeof(lob_head_t) + (lob_len);
return with_colsize ? ((row_len < CSF_VARLEN_EX) ?
(row_len + CSF_SHORT_COL_DESC_LEN) : (row_len + CSF_LONG_COL_DESC_LEN)) : (row_len);
} else {
return with_colsize ? KNL_LOB_INLINE_SIZE(lob_len) : (KNL_LOB_INLINE_SIZE(lob_len) - sizeof(uint16));
}
}
static inline uint32 knl_lob_outline_size(bool32 is_csf)
{
return is_csf ? (sizeof(lob_locator_t) + CSF_SHORT_COL_DESC_LEN) : KNL_LOB_OUTLINE_SIZE;
}
static inline lob_locator_t *knl_lob_col_new_start(bool32 is_csf, lob_locator_t *locator, uint32 lob_len)
{
char *new_addr = (char *)locator;
if (is_csf && !(locator->head.is_outline)) {
if ((sizeof(lob_head_t) + lob_len) >= CSF_VARLEN_EX) {
new_addr -= (CSF_LONG_COL_DESC_LEN - CSF_SHORT_COL_DESC_LEN);
}
return (lob_locator_t *)new_addr;
} else {
return locator;
}
}
static inline void lob_init_assist(lob_alloc_assist_t *lob_assist, page_id_t *page_id,
knl_scn_t org_scn, bool32 generate_undo)
{
lob_assist->lob_page_id = page_id;
lob_assist->org_scn = org_scn;
lob_assist->generate_undo = generate_undo;
}
status_t lob_dump_page(knl_session_t *session, page_head_t *page_head, cm_dump_t *dump);
status_t lob_segment_dump(knl_session_t *session, page_head_t *page_head, cm_dump_t *dump);
status_t lob_get_table_by_page(knl_session_t *session, page_head_t *page, uint32 *uid, uint32 *table_id);
status_t lob_corruption_scan(knl_session_t *session, lob_segment_t *segment, knl_corrupt_info_t *corrupt_info);
status_t lob_check_space(knl_session_t *session, table_t *table, uint32 space_id);
void lob_clean_all_default_segments(knl_session_t *session, knl_handle_t entity, uint32 old_col_count);
status_t lob_generate_create_undo(knl_session_t *session, page_id_t entry, uint32 space_id, bool32 need_redo);
void lob_undo_create_part(knl_session_t *session, undo_row_t *ud_row, undo_page_t *ud_page, int32 ud_slot);
void lob_temp_undo_write_page(knl_session_t *session, undo_row_t *ud_row, undo_page_t *ud_page, int32 ud_slot);
void lob_temp_undo_delete(knl_session_t *session, undo_row_t *ud_row, undo_page_t *ud_page, int32 ud_slot);
status_t lob_temp_create_segment(knl_session_t *session, knl_temp_cache_t *temp_table_ptr);
#ifdef __cplusplus
}
#endif
#endif