1864 lines
65 KiB
C++
1864 lines
65 KiB
C++
/**
|
|
* Copyright (c) 2021 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* 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 PubL v2 for more details.
|
|
*/
|
|
|
|
#define USING_LOG_PREFIX STORAGE
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <codecvt>
|
|
#include "mtlenv/mock_tenant_module_env.h"
|
|
#include "storage/test_lob_common.h"
|
|
#include "storage/lob/ob_lob_manager.h"
|
|
#include "share/ob_tablet_autoincrement_service.h"
|
|
#include "share/schema/ob_table_dml_param.h"
|
|
#include "share/schema/ob_multi_version_schema_service.h"
|
|
#include "lib/random/ob_random.h"
|
|
#include "storage/blocksstable/ob_data_file_prepare.h"
|
|
#include "share/ob_simple_mem_limit_getter.h"
|
|
#include "storage/blocksstable/ob_tmp_file.h"
|
|
#include "storage/lob/ob_lob_piece.h"
|
|
#include "sql/engine/ob_exec_context.h"
|
|
#include "observer/ob_safe_destroy_thread.h"
|
|
#include "lib/objectpool/ob_server_object_pool.h"
|
|
|
|
namespace oceanbase
|
|
{
|
|
using namespace storage;
|
|
using namespace common;
|
|
using namespace blocksstable;
|
|
using namespace share::schema;
|
|
|
|
namespace unittest
|
|
{
|
|
|
|
static ObSimpleMemLimitGetter getter;
|
|
|
|
class TestLobManager : public ::testing::Test
|
|
{
|
|
public:
|
|
TestLobManager();
|
|
virtual ~TestLobManager() = default;
|
|
public:
|
|
static void SetUpTestCase()
|
|
{
|
|
EXPECT_EQ(OB_SUCCESS, MockTenantModuleEnv::get_instance().init());
|
|
MTL(transaction::ObTransService*)->tx_desc_mgr_.tx_id_allocator_ =
|
|
[](transaction::ObTransID &tx_id) { tx_id = transaction::ObTransID(1001); return OB_SUCCESS; };
|
|
SAFE_DESTROY_INSTANCE.init();
|
|
SAFE_DESTROY_INSTANCE.start();
|
|
ObServerCheckpointSlogHandler::get_instance().is_started_ = true;
|
|
}
|
|
static void TearDownTestCase()
|
|
{
|
|
SAFE_DESTROY_INSTANCE.stop();
|
|
SAFE_DESTROY_INSTANCE.wait();
|
|
SAFE_DESTROY_INSTANCE.destroy();
|
|
MockTenantModuleEnv::get_instance().destroy();
|
|
}
|
|
virtual void SetUp()
|
|
{
|
|
|
|
}
|
|
|
|
virtual void TearDown()
|
|
{
|
|
|
|
}
|
|
public:
|
|
void build_lob_meta_row(ObIAllocator& allocator,
|
|
ObLobMetaInfo& info,
|
|
ObStoreRow *&row);
|
|
void insert_lob_meta(MockObAccessService *access_service,
|
|
ObIAllocator& allocator,
|
|
ObLobMetaInfo& info);
|
|
void scan_lob_meta(ObIAllocator& allocator,
|
|
uint64_t lob_id,
|
|
uint64_t byte_size,
|
|
uint64_t offset,
|
|
uint64_t len,
|
|
uint64_t expect_cnt,
|
|
bool is_reverse,
|
|
bool set_uft8,
|
|
ObString& out_data);
|
|
void prepare_random_data(
|
|
ObIAllocator& allocator,
|
|
uint64_t len,
|
|
char **data);
|
|
// void wirte_data_to_lob_oper(
|
|
// char *data,
|
|
// uint64_t offset,
|
|
// uint64_t len,
|
|
// MacroBlockId &id);
|
|
void scan_check_lob_data(
|
|
char *data,
|
|
ObIAllocator &allocator,
|
|
uint64_t lob_id,
|
|
uint64_t byte_size,
|
|
uint64_t offset,
|
|
uint64_t len,
|
|
uint64_t meta_cnt);
|
|
void flush_lob_piece(
|
|
ObIAllocator &allocator,
|
|
ObLobPieceInfo& info);
|
|
void build_lob_piece_row(
|
|
ObIAllocator& allocator,
|
|
ObLobPieceInfo& info,
|
|
ObStoreRow *&row);
|
|
void insert_lob_piece(
|
|
MockObAccessService *access_service,
|
|
ObIAllocator& allocator,
|
|
ObLobPieceInfo& info);
|
|
int random_range(const int low, const int high);
|
|
void gen_random_unicode_string(const int len, char *res, int &real_len);
|
|
void scan_check_lob_data_uft8(
|
|
char *data,
|
|
ObIAllocator &allocator,
|
|
uint64_t lob_id,
|
|
uint64_t byte_size,
|
|
uint64_t offset,
|
|
uint64_t char_len,
|
|
uint64_t byte_len,
|
|
uint64_t meta_cnt);
|
|
void lob_write(
|
|
ObIAllocator& allocator,
|
|
ObLobCommon *lob_common,
|
|
uint64_t handle_size,
|
|
uint64_t offset,
|
|
uint64_t len,
|
|
bool set_uft8,
|
|
ObString& data);
|
|
protected:
|
|
uint64_t tenant_id_;
|
|
share::ObLSID ls_id_;
|
|
common::ObTabletID tablet_id_;
|
|
common::ObTabletID lob_meta_tablet_id_;
|
|
common::ObTabletID lob_piece_tablet_id_;
|
|
};
|
|
|
|
TestLobManager::TestLobManager()
|
|
// : TestDataFilePrepare(&getter, "TestLobManager", 2 * 1024 * 1024, 2048),
|
|
: tenant_id_(OB_SYS_TENANT_ID),
|
|
ls_id_(TestLobCommon::TEST_LOB_LS_ID),
|
|
tablet_id_(TestLobCommon::TEST_LOB_TABLE_ID),
|
|
lob_meta_tablet_id_(TestLobCommon::TEST_LOB_META_TABLE_ID),
|
|
lob_piece_tablet_id_(TestLobCommon::TEST_LOB_PIECE_TABLE_ID)
|
|
{
|
|
// tenant_id_ = OB_SYS_TENANT_ID;
|
|
// ls_id_ = TestLobCommon::TEST_LOB_LS_ID;
|
|
// tablet_id_ = TestLobCommon::TEST_LOB_TABLE_ID;
|
|
// lob_meta_tablet_id_ = TestLobCommon::TEST_LOB_META_TABLE_ID;
|
|
}
|
|
|
|
int TestLobManager::random_range(const int low, const int high)
|
|
{
|
|
return std::rand() % (high - low) + low;
|
|
}
|
|
|
|
void TestLobManager::gen_random_unicode_string(const int len, char *res, int &real_len)
|
|
{
|
|
int i = 0;
|
|
int unicode_point = 0;
|
|
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
|
|
for (i = 0; i < len; ) {
|
|
const int bytes = random_range(1, 7);
|
|
if (bytes < 4) {
|
|
unicode_point = random_range(0, 127);
|
|
} else if (bytes < 6) {
|
|
unicode_point = random_range(0xFF, 0xFFFF);
|
|
} else if (bytes < 7) {
|
|
unicode_point = random_range(0XFFFF, 0X10FFFF);
|
|
}
|
|
std::string utf_str = converter.to_bytes(unicode_point);
|
|
//fprintf(stdout, "code_point=%d\n", unicode_point);
|
|
//fprintf(stdout, "utf8_str=%s\n", utf_str.c_str());
|
|
for (int j = 0; j < utf_str.size(); ++j) {
|
|
res[i] = utf_str[j];
|
|
i++;
|
|
}
|
|
}
|
|
real_len = i;
|
|
}
|
|
|
|
void TestLobManager::flush_lob_piece(
|
|
ObIAllocator &allocator,
|
|
ObLobPieceInfo& info)
|
|
{
|
|
ObLobManager *mgr = MTL(ObLobManager*);
|
|
ObStoreRow *row = NULL;
|
|
build_lob_piece_row(allocator, info, row);
|
|
// ASSERT_EQ(OB_SUCCESS, mgr->flush(tablet_id_, row->row_val_));
|
|
}
|
|
|
|
void TestLobManager::scan_check_lob_data(
|
|
char *data,
|
|
ObIAllocator &allocator,
|
|
uint64_t lob_id,
|
|
uint64_t byte_size,
|
|
uint64_t offset,
|
|
uint64_t len,
|
|
uint64_t meta_cnt)
|
|
{
|
|
char *ptr = reinterpret_cast<char*>(allocator.alloc(len));
|
|
ObString out_data;
|
|
out_data.assign_buffer(ptr, len);
|
|
printf("[SCAN] scan [%lu, %lu]:\n", offset, offset + len);
|
|
scan_lob_meta(allocator, lob_id, byte_size, offset, len, meta_cnt, false, false, out_data);
|
|
ASSERT_EQ(out_data.length(), len);
|
|
char *aptr = out_data.ptr();
|
|
for (uint64_t i = 0; i < len; i++) {
|
|
ASSERT_EQ(aptr[i], data[offset+i]);
|
|
}
|
|
ASSERT_EQ(MEMCMP(out_data.ptr(), data + offset, len), 0);
|
|
allocator.free(ptr);
|
|
}
|
|
|
|
void TestLobManager::scan_check_lob_data_uft8(
|
|
char *data,
|
|
ObIAllocator &allocator,
|
|
uint64_t lob_id,
|
|
uint64_t byte_size,
|
|
uint64_t offset,
|
|
uint64_t char_len,
|
|
uint64_t byte_len,
|
|
uint64_t meta_cnt)
|
|
{
|
|
char *ptr = reinterpret_cast<char*>(allocator.alloc(byte_len));
|
|
ObString out_data;
|
|
out_data.assign_buffer(ptr, byte_len);
|
|
printf("[SCAN] scan [%lu, %lu]:\n", offset, offset + char_len);
|
|
scan_lob_meta(allocator, lob_id, byte_size, offset, char_len, meta_cnt, false, true, out_data);
|
|
ASSERT_EQ(out_data.length(), byte_len);
|
|
char *aptr = out_data.ptr();
|
|
for (uint64_t i = 0; i < byte_len; i++) {
|
|
ASSERT_EQ(aptr[i], data[offset+i]);
|
|
}
|
|
ASSERT_EQ(MEMCMP(out_data.ptr(), data + offset, byte_len), 0);
|
|
int ret = ObCharset::strcmp(CS_TYPE_UTF8MB4_GENERAL_CI, out_data.ptr(), out_data.length(), data + offset, byte_len);
|
|
fprintf(stdout, "char set cmp ret:%d\n", ret);
|
|
ASSERT_EQ(0, ret);
|
|
|
|
allocator.free(ptr);
|
|
}
|
|
|
|
// void TestLobManager::wirte_data_to_lob_oper(
|
|
// char *data,
|
|
// uint64_t offset,
|
|
// uint64_t len,
|
|
// MacroBlockId &id)
|
|
// {
|
|
// ObLobManager *mgr = MTL(ObLobManager*);
|
|
// ObLobCtx lob_ctx;
|
|
// common::ObTabletID tablet_id(TestLobCommon::TEST_LOB_TABLE_ID);
|
|
// ASSERT_EQ(OB_SUCCESS, mgr->lob_ctxs_.get(tablet_id, lob_ctx));
|
|
// ASSERT_NE(lob_ctx.lob_oper_, nullptr);
|
|
|
|
// ASSERT_EQ(OB_SUCCESS, lob_ctx.lob_oper_->get_new_macro_id(id));
|
|
// LobPieceOperInfo in;
|
|
// in.macro_id_ = id;
|
|
// in.data_ = data + offset;
|
|
// in.offset_ = 0;
|
|
// in.len_ = len;
|
|
// in.bytes_len_ = 0;
|
|
|
|
// LobPieceOperInfo out;
|
|
// ASSERT_EQ(OB_SUCCESS, lob_ctx.lob_oper_->write(in, out));
|
|
// id = out.macro_id_;
|
|
// }
|
|
|
|
void TestLobManager::prepare_random_data(
|
|
ObIAllocator& allocator,
|
|
uint64_t len,
|
|
char **data)
|
|
{
|
|
char *ptr = reinterpret_cast<char*>(allocator.alloc(len));
|
|
ASSERT_NE(ptr, nullptr);
|
|
for (uint64_t i = 0; i < len; i++) {
|
|
ptr[i] = ObRandom::rand('a', 'z');
|
|
}
|
|
*data = ptr;
|
|
}
|
|
|
|
void TestLobManager::build_lob_piece_row(
|
|
ObIAllocator& allocator,
|
|
ObLobPieceInfo& info,
|
|
ObStoreRow *&row)
|
|
{
|
|
ASSERT_EQ(OB_SUCCESS, malloc_store_row(allocator, 3, row, FLAT_ROW_STORE));
|
|
row->flag_.set_flag(ObDmlFlag::DF_INSERT);
|
|
for (int64_t i = 0; i < 3; ++i) {
|
|
row->row_val_.cells_[i].set_nop_value();
|
|
}
|
|
|
|
{ // piece_id
|
|
row->row_val_.cells_[0].set_uint64(info.piece_id_);
|
|
}
|
|
{ // len
|
|
row->row_val_.cells_[1].set_uint32(info.len_);
|
|
}
|
|
{ // macro_id
|
|
int64_t pos = 0;
|
|
// do serialize
|
|
int64_t slen = info.macro_id_.get_serialize_size();
|
|
char *buf = reinterpret_cast<char*>(allocator.alloc(slen));
|
|
ASSERT_NE(nullptr, buf);
|
|
ASSERT_EQ(OB_SUCCESS, info.macro_id_.serialize(buf, slen, pos));
|
|
row->row_val_.cells_[2].set_varchar(buf, pos);
|
|
row->row_val_.cells_[2].set_collation_type(common::ObCollationType::CS_TYPE_BINARY);
|
|
}
|
|
}
|
|
|
|
void TestLobManager::insert_lob_piece(
|
|
MockObAccessService *access_service,
|
|
ObIAllocator& allocator,
|
|
ObLobPieceInfo& info)
|
|
{
|
|
ASSERT_NE(nullptr, access_service);
|
|
|
|
ObLSHandle ls_handle;
|
|
ObTabletHandle tablet_handle;
|
|
|
|
ObLSService *ls_svr = MTL(ObLSService*);
|
|
ASSERT_EQ(OB_SUCCESS, ls_svr->get_ls(ls_id_, ls_handle, ObLSGetMod::STORAGE_MOD));
|
|
ObLS *ls = ls_handle.get_ls();
|
|
ASSERT_NE(nullptr, ls);
|
|
ASSERT_EQ(OB_SUCCESS, ls->get_tablet(lob_piece_tablet_id_, tablet_handle));
|
|
ObTablet *tablet = tablet_handle.get_obj();
|
|
ASSERT_NE(nullptr, tablet);
|
|
|
|
// insert rows
|
|
ObMockNewRowIterator mock_iter;
|
|
ObSEArray<uint64_t, 512> column_ids;
|
|
column_ids.push_back(OB_APP_MIN_COLUMN_ID + 0); // pk
|
|
column_ids.push_back(OB_APP_MIN_COLUMN_ID + 1); // c1
|
|
column_ids.push_back(OB_APP_MIN_COLUMN_ID + 2); // c2
|
|
|
|
// build row
|
|
ObStoreRow *row = NULL;
|
|
build_lob_piece_row(allocator, info, row);
|
|
ASSERT_EQ(OB_SUCCESS, mock_iter.iter_.add_row(row));
|
|
//ASSERT_EQ(OB_SUCCESS, mock_iter.from(TestDmlCommon::data_row_str));
|
|
|
|
transaction::ObTransService *tx_service = MTL(transaction::ObTransService*);
|
|
|
|
// 1. get tx desc
|
|
transaction::ObTxDesc *tx_desc = nullptr;
|
|
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_tx_desc(tenant_id_, tx_desc));
|
|
|
|
// 2. create savepoint (can be rollbacked)
|
|
ObTxParam tx_param;
|
|
TestDmlCommon::build_tx_param(tx_param);
|
|
int64_t savepoint = 0;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->create_implicit_savepoint(*tx_desc, tx_param, savepoint, true));
|
|
// 3. acquire snapshot (write also need snapshot)
|
|
ObTxIsolationLevel isolation = ObTxIsolationLevel::RC;
|
|
int64_t expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
ObTxReadSnapshot read_snapshot;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->get_read_snapshot(*tx_desc, isolation, expire_ts, read_snapshot));
|
|
|
|
// 4. storage dml
|
|
ObDMLBaseParam dml_param;
|
|
dml_param.timeout_ = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
dml_param.is_total_quantity_log_ = false;
|
|
dml_param.tz_info_ = NULL;
|
|
dml_param.sql_mode_ = SMO_DEFAULT;
|
|
dml_param.schema_version_ = share::OB_CORE_SCHEMA_VERSION + 1;
|
|
dml_param.tenant_schema_version_ = share::OB_CORE_SCHEMA_VERSION + 1;
|
|
dml_param.encrypt_meta_ = &dml_param.encrypt_meta_legacy_;
|
|
dml_param.snapshot_ = read_snapshot;
|
|
|
|
share::schema::ObTableDMLParam table_dml_param(allocator);
|
|
|
|
share::schema::ObTableSchema table_schema;
|
|
TestLobCommon::build_lob_piece_table_schema(tenant_id_, table_schema);
|
|
|
|
ObSEArray<const ObTableSchema *, 4> index_schema_array;
|
|
|
|
ASSERT_EQ(OB_SUCCESS, table_dml_param.convert(&table_schema, 1, column_ids));
|
|
dml_param.table_param_ = &table_dml_param;
|
|
|
|
int64_t affected_rows = 0;
|
|
ASSERT_EQ(OB_SUCCESS, access_service->insert_rows(ls_id_, lob_piece_tablet_id_,
|
|
*tx_desc, dml_param, column_ids, &mock_iter, affected_rows));
|
|
|
|
ASSERT_EQ(1, affected_rows);
|
|
|
|
// 5. serialize trans result and ship
|
|
// 6. merge result if necessar
|
|
|
|
// 7. rollback if failed
|
|
// expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
// ASSERT_EQ(OB_SUCCESS, tx_service->rollback_to_implicit_savepoint(*tx_desc, savepoint, expire_ts, NULL));
|
|
|
|
// 8. submit transaction, or rollback
|
|
expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->commit_tx(*tx_desc, expire_ts));
|
|
|
|
// 9. release tx desc
|
|
tx_service->release_tx(*tx_desc);
|
|
}
|
|
|
|
void TestLobManager::build_lob_meta_row(
|
|
ObIAllocator& allocator,
|
|
ObLobMetaInfo& info,
|
|
ObStoreRow *&row)
|
|
{
|
|
ASSERT_EQ(OB_SUCCESS, malloc_store_row(allocator, ObLobMetaUtil::LOB_META_COLUMN_CNT, row, FLAT_ROW_STORE));
|
|
row->flag_.set_flag(ObDmlFlag::DF_INSERT);
|
|
for (int64_t i = 0; i < ObLobMetaUtil::LOB_META_COLUMN_CNT; ++i) {
|
|
row->row_val_.cells_[i].set_nop_value();
|
|
}
|
|
|
|
{ // lob_id
|
|
row->row_val_.cells_[0].set_varchar(reinterpret_cast<char*>(&info.lob_id_), sizeof(ObLobId));
|
|
row->row_val_.cells_[0].set_collation_type(common::ObCollationType::CS_TYPE_BINARY);
|
|
}
|
|
{ // seq_id
|
|
row->row_val_.cells_[1].set_varchar(info.seq_id_);
|
|
row->row_val_.cells_[1].set_collation_type(common::ObCollationType::CS_TYPE_BINARY);
|
|
}
|
|
{ // byte_len
|
|
row->row_val_.cells_[2].set_uint32(info.byte_len_);
|
|
}
|
|
{ // char_len
|
|
row->row_val_.cells_[3].set_uint32(info.char_len_);
|
|
}
|
|
{ // piece_id
|
|
row->row_val_.cells_[4].set_uint64(info.piece_id_);
|
|
}
|
|
{ // lob_data
|
|
row->row_val_.cells_[5].set_varchar(info.lob_data_);
|
|
row->row_val_.cells_[5].set_collation_type(common::ObCollationType::CS_TYPE_BINARY);
|
|
}
|
|
}
|
|
|
|
void TestLobManager::insert_lob_meta(
|
|
MockObAccessService *access_service,
|
|
ObIAllocator& allocator,
|
|
ObLobMetaInfo& info)
|
|
{
|
|
ASSERT_NE(nullptr, access_service);
|
|
|
|
ObLSHandle ls_handle;
|
|
ObTabletHandle tablet_handle;
|
|
|
|
ObLSService *ls_svr = MTL(ObLSService*);
|
|
ASSERT_EQ(OB_SUCCESS, ls_svr->get_ls(ls_id_, ls_handle, ObLSGetMod::STORAGE_MOD));
|
|
ObLS *ls = ls_handle.get_ls();
|
|
ASSERT_NE(nullptr, ls);
|
|
ASSERT_EQ(OB_SUCCESS, ls->get_tablet(lob_meta_tablet_id_, tablet_handle));
|
|
ObTablet *tablet = tablet_handle.get_obj();
|
|
ASSERT_NE(nullptr, tablet);
|
|
|
|
// insert rows
|
|
ObMockNewRowIterator mock_iter;
|
|
ObSEArray<uint64_t, 512> column_ids;
|
|
for (int i = 0; i < ObLobMetaUtil::LOB_META_COLUMN_CNT; i++) {
|
|
column_ids.push_back(OB_APP_MIN_COLUMN_ID + i);
|
|
}
|
|
|
|
// build row
|
|
ObStoreRow *row = NULL;
|
|
build_lob_meta_row(allocator, info, row);
|
|
ASSERT_EQ(OB_SUCCESS, mock_iter.iter_.add_row(row));
|
|
//ASSERT_EQ(OB_SUCCESS, mock_iter.from(TestDmlCommon::data_row_str));
|
|
|
|
transaction::ObTransService *tx_service = MTL(transaction::ObTransService*);
|
|
|
|
// 1. get tx desc
|
|
transaction::ObTxDesc *tx_desc = nullptr;
|
|
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_tx_desc(tenant_id_, tx_desc));
|
|
|
|
// 2. create savepoint (can be rollbacked)
|
|
ObTxParam tx_param;
|
|
TestDmlCommon::build_tx_param(tx_param);
|
|
int64_t savepoint = 0;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->create_implicit_savepoint(*tx_desc, tx_param, savepoint, true));
|
|
// 3. acquire snapshot (write also need snapshot)
|
|
ObTxIsolationLevel isolation = ObTxIsolationLevel::RC;
|
|
int64_t expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
ObTxReadSnapshot read_snapshot;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->get_read_snapshot(*tx_desc, isolation, expire_ts, read_snapshot));
|
|
|
|
// 4. storage dml
|
|
ObDMLBaseParam dml_param;
|
|
dml_param.timeout_ = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
dml_param.is_total_quantity_log_ = false;
|
|
dml_param.tz_info_ = NULL;
|
|
dml_param.sql_mode_ = SMO_DEFAULT;
|
|
dml_param.schema_version_ = share::OB_CORE_SCHEMA_VERSION + 1;
|
|
dml_param.tenant_schema_version_ = share::OB_CORE_SCHEMA_VERSION + 1;
|
|
dml_param.encrypt_meta_ = &dml_param.encrypt_meta_legacy_;
|
|
dml_param.snapshot_ = read_snapshot;
|
|
|
|
share::schema::ObTableDMLParam table_dml_param(allocator);
|
|
|
|
share::schema::ObTableSchema table_schema;
|
|
TestLobCommon::build_lob_meta_table_schema(tenant_id_, table_schema);
|
|
|
|
ObSEArray<const ObTableSchema *, 4> index_schema_array;
|
|
|
|
ASSERT_EQ(OB_SUCCESS, table_dml_param.convert(&table_schema, 1, column_ids));
|
|
dml_param.table_param_ = &table_dml_param;
|
|
|
|
int64_t affected_rows = 0;
|
|
ASSERT_EQ(OB_SUCCESS, access_service->insert_rows(ls_id_, lob_meta_tablet_id_,
|
|
*tx_desc, dml_param, column_ids, &mock_iter, affected_rows));
|
|
|
|
ASSERT_EQ(1, affected_rows);
|
|
|
|
// 5. serialize trans result and ship
|
|
// 6. merge result if necessary
|
|
|
|
// 7. end data access, if failed, rollback
|
|
// expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
// ASSERT_EQ(OB_SUCCESS, tx_service->rollback_to_implicit_savepoint(*tx_desc, savepoint, expire_ts, NULL));
|
|
|
|
// 8. submit transaction, or rollback
|
|
expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->commit_tx(*tx_desc, expire_ts));
|
|
|
|
// 9. release tx desc
|
|
tx_service->release_tx(*tx_desc);
|
|
}
|
|
|
|
// void TestLobManager::build_lob_piece_param(
|
|
// share::schema::ObTableParam& param,
|
|
// ObString& out_data)
|
|
// {
|
|
// // prepare table schema
|
|
// share::schema::ObTableSchema table_schema;
|
|
// TestLobCommon::build_lob_piece_table_schema(tenant_id_, table_schema);
|
|
|
|
// // build table param
|
|
// ObSArray<uint64_t> colunm_ids;
|
|
// colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 0);
|
|
// colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 1);
|
|
// colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 2);
|
|
// ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_table_param(table_schema, colunm_ids, table_param));
|
|
// }
|
|
|
|
void TestLobManager::lob_write(
|
|
ObIAllocator& allocator,
|
|
ObLobCommon *lob_common,
|
|
uint64_t handle_size,
|
|
uint64_t offset,
|
|
uint64_t len,
|
|
bool set_uft8,
|
|
ObString& data)
|
|
{
|
|
EXPECT_EQ(OB_SYS_TENANT_ID, MTL_ID());
|
|
ObLobManager *mgr = MTL(ObLobManager*);
|
|
uint64_t byte_size = lob_common->get_byte_size(handle_size);
|
|
ObLobData *lob_data = reinterpret_cast<ObLobData*>(lob_common->buffer_);
|
|
lob_data->id_.tablet_id_ = tablet_id_.id();
|
|
// prepare table schema
|
|
share::schema::ObTableSchema table_schema;
|
|
TestLobCommon::build_lob_meta_table_schema(tenant_id_, table_schema);
|
|
|
|
// build table param
|
|
share::schema::ObTableParam table_param(allocator);
|
|
ObSArray<uint64_t> colunm_ids;
|
|
for (int i = 0; i < ObLobMetaUtil::LOB_META_COLUMN_CNT; i++) {
|
|
colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + i);
|
|
}
|
|
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_table_param(table_schema, colunm_ids, table_param));
|
|
|
|
ObExecContext exec_ctx(allocator);
|
|
// 1. get tx desc
|
|
transaction::ObTxDesc *tx_desc = nullptr;
|
|
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_tx_desc(tenant_id_, tx_desc));
|
|
|
|
// 2. get read snapshot
|
|
ObTxIsolationLevel isolation = ObTxIsolationLevel::RC;
|
|
int64_t expire_ts = ObTimeUtility::current_time() + 1200 * 1000 * 1000;
|
|
ObTxReadSnapshot read_snapshot;
|
|
transaction::ObTransService *tx_service = MTL(transaction::ObTransService*);
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->get_read_snapshot(*tx_desc, isolation, expire_ts, read_snapshot));
|
|
|
|
|
|
// prepare param
|
|
ObLobAccessParam param;
|
|
param.tx_desc_ = tx_desc;
|
|
param.snapshot_ = read_snapshot;
|
|
param.tx_id_ = tx_desc->get_tx_id();
|
|
param.sql_mode_ = SMO_DEFAULT;
|
|
param.allocator_ = &allocator;
|
|
param.meta_table_schema_ = &table_schema;
|
|
param.meta_tablet_param_ = &table_param;
|
|
param.ls_id_ = ls_id_;
|
|
param.tablet_id_ = tablet_id_;
|
|
if (set_uft8) {
|
|
param.coll_type_ = CS_TYPE_UTF8MB4_GENERAL_CI;
|
|
} else {
|
|
param.coll_type_ = CS_TYPE_BINARY;
|
|
}
|
|
param.lob_common_ = lob_common;
|
|
param.byte_size_ = byte_size;
|
|
param.handle_size_ = handle_size;
|
|
param.timeout_ = expire_ts;
|
|
param.offset_ = offset;
|
|
param.len_ = len;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->write(param, data));
|
|
}
|
|
|
|
void TestLobManager::scan_lob_meta(
|
|
ObIAllocator& allocator,
|
|
uint64_t lob_id,
|
|
uint64_t byte_size,
|
|
uint64_t offset,
|
|
uint64_t len,
|
|
uint64_t expect_cnt,
|
|
bool is_reverse,
|
|
bool set_uft8,
|
|
ObString& out_data)
|
|
{
|
|
EXPECT_EQ(OB_SYS_TENANT_ID, MTL_ID());
|
|
ObLobManager *mgr = MTL(ObLobManager*);
|
|
char lob_data[1024];
|
|
ObString ld;
|
|
ld.assign_ptr(lob_data + sizeof(ObLobCommon) + sizeof(ObLobData), 1024 - sizeof(ObLobCommon) - sizeof(ObLobData));
|
|
ObLobCommon *lob_common = new(lob_data)ObLobCommon();
|
|
lob_common->is_init_ = 1;
|
|
lob_common->in_row_ = 0;
|
|
ObLobData *loc = new(lob_common->buffer_)ObLobData();
|
|
loc->id_.tablet_id_ = tablet_id_.id();
|
|
loc->id_.lob_id_ = lob_id;
|
|
loc->byte_size_ = byte_size;
|
|
|
|
// prepare table schema
|
|
share::schema::ObTableSchema table_schema;
|
|
TestLobCommon::build_lob_meta_table_schema(tenant_id_, table_schema);
|
|
|
|
// build table param
|
|
share::schema::ObTableParam table_param(allocator);
|
|
ObSArray<uint64_t> colunm_ids;
|
|
for (int i = 0; i < ObLobMetaUtil::LOB_META_COLUMN_CNT; i++) {
|
|
colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + i);
|
|
}
|
|
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_table_param(table_schema, colunm_ids, table_param));
|
|
|
|
// prepare piece table schema
|
|
share::schema::ObTableSchema ptable_schema;
|
|
TestLobCommon::build_lob_piece_table_schema(tenant_id_, ptable_schema);
|
|
|
|
// build table param
|
|
share::schema::ObTableParam ptable_param(allocator);
|
|
ObSArray<uint64_t> pcolunm_ids;
|
|
pcolunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 0);
|
|
pcolunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 1);
|
|
pcolunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 2);
|
|
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_table_param(ptable_schema, pcolunm_ids, ptable_param));
|
|
|
|
ObExecContext exec_ctx(allocator);
|
|
// 1. get tx desc
|
|
transaction::ObTxDesc *tx_desc = nullptr;
|
|
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_tx_desc(tenant_id_, tx_desc));
|
|
|
|
// 2. get read snapshot
|
|
ObTxIsolationLevel isolation = ObTxIsolationLevel::RC;
|
|
int64_t expire_ts = ObTimeUtility::current_time() + 12 * 1000 * 1000;
|
|
ObTxReadSnapshot read_snapshot;
|
|
transaction::ObTransService *tx_service = MTL(transaction::ObTransService*);
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->get_read_snapshot(*tx_desc, isolation, expire_ts, read_snapshot));
|
|
|
|
|
|
// prepare param
|
|
ObLobAccessParam param;
|
|
param.tx_desc_ = tx_desc;
|
|
param.snapshot_ = read_snapshot;
|
|
param.tx_id_ = tx_desc->get_tx_id();
|
|
param.sql_mode_ = SMO_DEFAULT;
|
|
param.allocator_ = &allocator;
|
|
param.meta_table_schema_ = &table_schema;
|
|
param.piece_table_schema_ = &ptable_schema;
|
|
param.meta_tablet_param_ = &table_param;
|
|
param.piece_tablet_param_ = &ptable_param;
|
|
param.ls_id_ = ls_id_;
|
|
param.asscess_ptable_ = true;
|
|
param.tablet_id_ = tablet_id_;
|
|
if (set_uft8) {
|
|
param.coll_type_ = CS_TYPE_UTF8MB4_GENERAL_CI;
|
|
} else {
|
|
param.coll_type_ = CS_TYPE_BINARY;
|
|
}
|
|
param.lob_common_ = lob_common;
|
|
param.byte_size_ = byte_size;
|
|
param.handle_size_ = 1024;
|
|
param.timeout_ = expire_ts;
|
|
param.scan_backward_ = is_reverse;
|
|
param.offset_ = offset;
|
|
param.len_ = len;
|
|
ObLobQueryIter *iter = NULL;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, iter));
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int cnt = 0;
|
|
while (OB_SUCC(ret)) {
|
|
ObLobQueryResult result;
|
|
ret = iter->get_next_row(result);
|
|
if (OB_FAIL(ret)) {
|
|
if (ret == OB_ITER_END) {
|
|
// ret = OB_SUCCESS;
|
|
} else {
|
|
LOG_WARN("failed to get next row.", K(ret));
|
|
}
|
|
} else {
|
|
cnt++;
|
|
int *tseq_id = (reinterpret_cast<int*>(result.meta_result_.info_.seq_id_.ptr()));
|
|
char seq_str[10] = {'\0'};
|
|
int seq_cnt = result.meta_result_.info_.seq_id_.length() / sizeof(int);
|
|
int seq_str_pos = 0;
|
|
for (int i = 0; i < seq_cnt; i++) {
|
|
if (i == 0) {
|
|
seq_str_pos = snprintf(seq_str, 10, "%d", tseq_id[i]);
|
|
} else {
|
|
int tpos = snprintf(seq_str + seq_str_pos, 10 - seq_str_pos, ".%d", tseq_id[i]);
|
|
seq_str_pos += tpos;
|
|
}
|
|
}
|
|
printf("[META] id : %lu, seq_id : %s, st : %u, len : %u, piece_id : %lu\n", result.meta_result_.info_.lob_id_.lob_id_, seq_str,
|
|
result.meta_result_.st_, result.meta_result_.len_, result.meta_result_.info_.piece_id_);
|
|
// get data
|
|
ASSERT_EQ(OB_SUCCESS, mgr->get_real_data(param, result, out_data));
|
|
}
|
|
}
|
|
if (expect_cnt != 0) { // do not need to check when 0
|
|
ASSERT_EQ(expect_cnt, cnt);
|
|
}
|
|
ASSERT_EQ(OB_ITER_END, ret);
|
|
}
|
|
if (iter != NULL) {
|
|
iter->reset();
|
|
// common::sop_return(ObLobMetaScanIter, iter);
|
|
}
|
|
// ASSERT_EQ(0, out_data.length());
|
|
|
|
// 9. release tx desc
|
|
tx_service->release_tx(*tx_desc);
|
|
}
|
|
|
|
// void TestLobManager::
|
|
TEST_F(TestLobManager, basic)
|
|
{
|
|
ObArenaAllocator allocator;
|
|
int ret = OB_SUCCESS;
|
|
ret = TestLobCommon::create_data_tablet(tenant_id_, ls_id_, tablet_id_, lob_meta_tablet_id_, lob_piece_tablet_id_);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
|
|
// mock ls tablet service and access service
|
|
ObLSTabletService *tablet_service = nullptr;
|
|
ret = TestDmlCommon::mock_ls_tablet_service(ls_id_, tablet_service);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_NE(nullptr, tablet_service);
|
|
|
|
MockObAccessService *access_service = nullptr;
|
|
ret = TestDmlCommon::mock_access_service(tablet_service, access_service);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_NE(nullptr, access_service);
|
|
|
|
// assume 1M * 10
|
|
printf("[test] 10M lob binary\n");
|
|
{
|
|
// uint64_t lob_id = 213;
|
|
// // prepare data
|
|
// char *data;
|
|
// uint64_t total_len = 10 * 1024 * 1024; // 10M
|
|
// prepare_random_data(allocator, total_len, &data);
|
|
// ObLobMetaInfo infos[10];
|
|
// ObLobPieceInfo pinfos[10];
|
|
// for (int i = 0; i < 10; i++) {
|
|
// ObLobMetaInfo *info = &infos[i];
|
|
// info->lob_id_ = lob_id;
|
|
// int seq_num[2];
|
|
// seq_num[0] = i/2;
|
|
// seq_num[1] = 5;
|
|
// if (i%2 != 0) {
|
|
// info->seq_id_.assign_ptr(reinterpret_cast<char*>(seq_num), sizeof(int) * 2);
|
|
// } else {
|
|
// info->seq_id_.assign_ptr(reinterpret_cast<char*>(seq_num), sizeof(int));
|
|
// }
|
|
// info->byte_len_ = 1 * 1024 * 1024;
|
|
// info->char_len_ = 1 * 1024 * 1024;
|
|
// info->piece_id_ = i;
|
|
// info->lob_data_.assign_ptr(nullptr, 0);
|
|
// // wirte_data_to_lob_oper(data, 1024*1024*i, info->byte_len_, pinfos[i].macro_id_);
|
|
// pinfos[i].piece_id_ = i;
|
|
// pinfos[i].len_ = info->byte_len_;
|
|
// insert_lob_piece(access_service, allocator, pinfos[i]);
|
|
// insert_lob_meta(access_service, allocator, *info);
|
|
// }
|
|
|
|
// // table scan
|
|
// // full scan
|
|
// scan_check_lob_data(data, allocator, lob_id, total_len, 0, 10*1024*1024, 10);
|
|
// // range covers multi meta
|
|
// scan_check_lob_data(data, allocator, lob_id, total_len, 1, 3*1024*1024, 4);
|
|
// // range covered by one meta
|
|
// scan_check_lob_data(data, allocator, lob_id, total_len, 1, 512*1024, 1);
|
|
// scan_check_lob_data(data, allocator, lob_id, total_len, 1024*1024, 1024*1024, 1);
|
|
|
|
// // do flush data
|
|
// for (int i = 0; i < 10; i++) {
|
|
// flush_lob_piece(allocator, pinfos[i]);
|
|
// }
|
|
// printf("do read after flush.\n");
|
|
// // table scan
|
|
// // full scan
|
|
// scan_check_lob_data(data, allocator, lob_id, total_len, 0, 10*1024*1024, 10);
|
|
// // range covers multi meta
|
|
// scan_check_lob_data(data, allocator, lob_id, total_len, 1, 3*1024*1024, 4);
|
|
// // range covered by one meta
|
|
// scan_check_lob_data(data, allocator, lob_id, total_len, 1, 512*1024, 1);
|
|
// scan_check_lob_data(data, allocator, lob_id, total_len, 1024*1024, 1024*1024, 1);
|
|
// allocator.free(data);
|
|
}
|
|
|
|
// insert lob2 with charset utf8
|
|
printf("[test] 10M lob utf8\n");
|
|
{
|
|
// uint64_t lobid2 = 111;
|
|
// uint64_t total_len2 = 10 * 1024 * 1024; // 10M
|
|
// // assume lob meta 10
|
|
// char *data2 = reinterpret_cast<char*>(allocator.alloc(sizeof(char) * total_len2));
|
|
// ASSERT_NE(nullptr, data2);
|
|
// ObLobMetaInfo infos2[10];
|
|
// ObLobPieceInfo pinfos2[10];
|
|
// uint64_t total_char_len = 0;
|
|
// int doffset = 0;
|
|
// int piece_id_base = 100;
|
|
// for (int i = 0; i < 10; i++) {
|
|
// int real_len = 0;
|
|
// gen_random_unicode_string(1048000, data2 + doffset, real_len);
|
|
// ObLobMetaInfo *info = &infos2[i];
|
|
// info->lob_id_ = lobid2;
|
|
// int seq_num[2];
|
|
// seq_num[0] = i/2;
|
|
// seq_num[1] = 5;
|
|
// if (i%2 != 0) {
|
|
// info->seq_id_.assign_ptr(reinterpret_cast<char*>(seq_num), sizeof(int) * 2);
|
|
// } else {
|
|
// info->seq_id_.assign_ptr(reinterpret_cast<char*>(seq_num), sizeof(int));
|
|
// }
|
|
// info->byte_len_ = real_len;
|
|
// info->char_len_ = ObCharset::strlen_char(CS_TYPE_UTF8MB4_GENERAL_CI, data2 + doffset, real_len);
|
|
// total_char_len += info->char_len_;
|
|
// info->piece_id_ = piece_id_base + i;
|
|
// info->lob_data_.assign_ptr(nullptr, 0);
|
|
// wirte_data_to_lob_oper(data2, doffset, info->byte_len_, pinfos2[i].macro_id_);
|
|
// pinfos2[i].piece_id_ = info->piece_id_;
|
|
// pinfos2[i].len_ = info->byte_len_;
|
|
// insert_lob_piece(access_service, allocator, pinfos2[i]);
|
|
// insert_lob_meta(access_service, allocator, *info);
|
|
// doffset += real_len;
|
|
// }
|
|
// // full scan
|
|
// scan_check_lob_data_uft8(data2, allocator, lobid2, doffset, 0, total_char_len, doffset, 10);
|
|
// allocator.free(data2);
|
|
}
|
|
|
|
// insert lob3 with inline lob meta data
|
|
printf("[test] 2.56M lob utf8 inline meta data\n");
|
|
{
|
|
uint64_t lobid3 = 222;
|
|
uint64_t total_len3 = 10 * 1024 * 1024; // 10M
|
|
// assume lob meta 10
|
|
char *data3 = reinterpret_cast<char*>(allocator.alloc(sizeof(char) * total_len3));
|
|
ASSERT_NE(nullptr, data3);
|
|
ObLobMetaInfo infos2[10];
|
|
// ObLobPieceInfo pinfos2[10];
|
|
uint64_t total_char_len = 0;
|
|
int doffset = 0;
|
|
for (int i = 0; i < 10; i++) {
|
|
int real_len = 0;
|
|
gen_random_unicode_string(256000, data3 + doffset, real_len);
|
|
ObLobMetaInfo *info = &infos2[i];
|
|
info->lob_id_.tablet_id_ = tablet_id_.id();
|
|
info->lob_id_.lob_id_ = lobid3;
|
|
int seq_num[2];
|
|
seq_num[0] = i/2;
|
|
seq_num[1] = 5;
|
|
if (i%2 != 0) {
|
|
info->seq_id_.assign_ptr(reinterpret_cast<char*>(seq_num), sizeof(int) * 2);
|
|
} else {
|
|
info->seq_id_.assign_ptr(reinterpret_cast<char*>(seq_num), sizeof(int));
|
|
}
|
|
info->byte_len_ = real_len;
|
|
info->char_len_ = ObCharset::strlen_char(CS_TYPE_UTF8MB4_GENERAL_CI, data3 + doffset, real_len);
|
|
total_char_len += info->char_len_;
|
|
info->piece_id_ = ObLobMetaUtil::LOB_META_INLINE_PIECE_ID;
|
|
info->lob_data_.assign_ptr(data3 + doffset, info->byte_len_);
|
|
// wirte_data_to_lob_oper(data3, doffset, info->byte_len_, pinfos2[i].macro_id_);
|
|
// pinfos2[i].piece_id_ = info->piece_id_;
|
|
// pinfos2[i].len_ = info->byte_len_;
|
|
// insert_lob_piece(access_service, allocator, pinfos2[i]);
|
|
insert_lob_meta(access_service, allocator, *info);
|
|
doffset += real_len;
|
|
}
|
|
// full scan
|
|
scan_check_lob_data_uft8(data3, allocator, lobid3, doffset, 0, total_char_len, doffset, 10);
|
|
allocator.free(data3);
|
|
}
|
|
|
|
printf("[test] write 10M lob utf8 inline meta data\n");
|
|
{
|
|
// uint64_t lobid3 = 233;
|
|
// uint64_t total_len3 = 10 * 1024 * 1024; // 10M
|
|
// char *data3 = reinterpret_cast<char*>(allocator.alloc(sizeof(char) * total_len3));
|
|
// ASSERT_NE(nullptr, data3);
|
|
// int real_len = 0;
|
|
// gen_random_unicode_string(total_len3, data3, real_len);
|
|
// uint64_t total_char_len = ObCharset::strlen_char(CS_TYPE_UTF8MB4_GENERAL_CI, data3, real_len);
|
|
// // build lob common
|
|
// char lob_header[100];
|
|
// ObLobCommon *lob_common = new(lob_header)ObLobCommon();
|
|
// lob_common->is_init_ = 1;
|
|
// ObLobData *lob_data = new(lob_common->buffer_)ObLobData();
|
|
// lob_data->id_.lob_id_ = lobid3;
|
|
// ObString in_data(real_len, data3);
|
|
// lob_write(allocator, lob_common, 100, 0, total_char_len, true, in_data);
|
|
// // full scan
|
|
// char *out_data = reinterpret_cast<char*>(allocator.alloc(sizeof(char) * total_len3));
|
|
// ObString out_str;
|
|
// out_str.assign_buffer(out_data, total_len3);
|
|
// scan_check_lob_data_uft8(data3, allocator, lobid3, real_len, 0, total_char_len, real_len, 0);
|
|
// allocator.free(data3);
|
|
}
|
|
|
|
// clean env
|
|
TestDmlCommon::delete_mocked_access_service(access_service);
|
|
TestDmlCommon::delete_mocked_ls_tablet_service(tablet_service);
|
|
// for exist
|
|
// the iter has store ctx and store ctx has one ls handle.
|
|
// iter->reset();
|
|
ASSERT_EQ(OB_SUCCESS, MTL(ObLSService*)->remove_ls(ls_id_, false));
|
|
}
|
|
|
|
// TEST_F(TestLobManager, basic2)
|
|
// {
|
|
// EXPECT_EQ(OB_SYS_TENANT_ID, MTL_ID());
|
|
// ObLobManager *mgr = MTL(ObLobManager*);
|
|
// ASSERT_NE(nullptr, mgr);
|
|
//
|
|
// MTL(ObLSSerivce*)
|
|
// do ...
|
|
//
|
|
// ObObj str1;
|
|
// str1.set_varchar("发生什么事了");
|
|
// str1.set_collation_type(CS_TYPE_UTF8MB4_GENERAL_CI);
|
|
// ObString data;
|
|
// str1.get_string(data);
|
|
// // test for charset lob
|
|
// // check "生什么事"
|
|
// size_t st = ObCharset::charpos(CS_TYPE_UTF8MB4_GENERAL_CI, data.ptr(), data.length(), 1);
|
|
// size_t len = ObCharset::charpos(CS_TYPE_UTF8MB4_GENERAL_CI, data.ptr() + st, data.length() - st, 4);
|
|
// char buf[100];
|
|
// memset(buf, 0, 100);
|
|
// ObString dest;
|
|
// dest.assign_buffer(buf, 99);
|
|
// dest.write(data.ptr() + st, len);
|
|
// printf("[%zu, %zu] : %s\n", st, len, dest.ptr());
|
|
// }
|
|
|
|
|
|
|
|
// append / erase
|
|
TEST_F(TestLobManager, DISABLED_basic3)
|
|
{
|
|
ObArenaAllocator allocator;
|
|
int ret = OB_SUCCESS;
|
|
|
|
ret = TestLobCommon::create_data_tablet(tenant_id_, ls_id_, tablet_id_, lob_meta_tablet_id_, lob_piece_tablet_id_);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
|
|
// mock ls tablet service and access service
|
|
ObLSTabletService *tablet_service = nullptr;
|
|
ret = TestDmlCommon::mock_ls_tablet_service(ls_id_, tablet_service);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_NE(nullptr, tablet_service);
|
|
|
|
MockObAccessService *access_service = nullptr;
|
|
ret = TestDmlCommon::mock_access_service(tablet_service, access_service);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_NE(nullptr, access_service);
|
|
|
|
ObLobManager *mgr = MTL(ObLobManager*);
|
|
char lob_data[1024];
|
|
uint64_t lob_id = 213;
|
|
ObString ld;
|
|
ld.assign_ptr(lob_data + sizeof(ObLobCommon) + sizeof(ObLobData), 1024 - sizeof(ObLobCommon) - sizeof(ObLobData));
|
|
// TODO mock lob_id
|
|
ObLobCommon *lob_common = new(lob_data)ObLobCommon();
|
|
lob_common->is_init_ = 1;
|
|
lob_common->in_row_ = 0;
|
|
ObLobData *loc = new(lob_common->buffer_)ObLobData();
|
|
loc->id_.tablet_id_ = tablet_id_.id();
|
|
loc->id_.lob_id_ = lob_id;
|
|
|
|
// prepare table schema
|
|
share::schema::ObTableSchema table_schema;
|
|
TestLobCommon::build_lob_meta_table_schema(tenant_id_, table_schema);
|
|
|
|
// build table param
|
|
share::schema::ObTableParam table_param(allocator);
|
|
ObSArray<uint64_t> colunm_ids;
|
|
colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 0);
|
|
colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 1);
|
|
colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 2);
|
|
colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 3);
|
|
colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 4);
|
|
colunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 5);
|
|
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_table_param(table_schema, colunm_ids, table_param));
|
|
|
|
// prepare piece table schema
|
|
share::schema::ObTableSchema ptable_schema;
|
|
TestLobCommon::build_lob_piece_table_schema(tenant_id_, ptable_schema);
|
|
|
|
// build table param
|
|
share::schema::ObTableParam ptable_param(allocator);
|
|
ObSArray<uint64_t> pcolunm_ids;
|
|
pcolunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 0);
|
|
pcolunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 1);
|
|
pcolunm_ids.push_back(OB_APP_MIN_COLUMN_ID + 2);
|
|
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_table_param(ptable_schema, pcolunm_ids, ptable_param));
|
|
|
|
|
|
uint64_t total_len = 10 * 1024 * 1024; // 10M
|
|
// assume lob meta 10
|
|
char *data;
|
|
bool is_unicode = true;
|
|
|
|
uint32_t data_len = total_len;
|
|
if (is_unicode) {
|
|
data = reinterpret_cast<char*>(allocator.alloc(total_len));
|
|
ASSERT_NE(nullptr, data);
|
|
int real_len = 0;
|
|
gen_random_unicode_string(256 * 1024 * 16, data, real_len);
|
|
data_len = real_len;
|
|
} else {
|
|
prepare_random_data(allocator, total_len, &data);
|
|
}
|
|
loc->byte_size_ = data_len;
|
|
|
|
auto tx_service = MTL(transaction::ObTransService*);
|
|
|
|
{
|
|
ObString write_data;
|
|
write_data.assign_ptr(data, data_len);
|
|
|
|
// 1. get tx desc
|
|
transaction::ObTxDesc *tx_desc = nullptr;
|
|
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_tx_desc(tenant_id_, tx_desc));
|
|
// 2. create savepoint (can be rollbacked)
|
|
ObTxParam tx_param;
|
|
TestDmlCommon::build_tx_param(tx_param);
|
|
int64_t savepoint = 0;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->create_implicit_savepoint(*tx_desc, tx_param, savepoint, true));
|
|
// 3. acquire snapshot (write also need snapshot)
|
|
ObTxIsolationLevel isolation = ObTxIsolationLevel::RC;
|
|
int64_t expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
ObTxReadSnapshot read_snapshot;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->get_read_snapshot(*tx_desc, isolation, expire_ts, read_snapshot));
|
|
|
|
ObLobAccessParam param;
|
|
param.tx_desc_ = tx_desc;
|
|
param.sql_mode_ = SMO_DEFAULT;
|
|
param.allocator_ = &allocator;
|
|
param.meta_table_schema_ = &table_schema;
|
|
param.piece_table_schema_ = &ptable_schema;
|
|
param.meta_tablet_param_ = &table_param;
|
|
param.piece_tablet_param_ = &ptable_param;
|
|
param.ls_id_ = ls_id_;
|
|
param.scan_backward_ = true;
|
|
param.tablet_id_ = tablet_id_;
|
|
param.lob_common_ = lob_common;
|
|
param.handle_size_ = 1024;
|
|
// TODO param.byte_size_ = ?
|
|
param.timeout_ = ObTimeUtility::current_time() + 12 * 1000 * 1000;
|
|
param.asscess_ptable_ = false;
|
|
param.snapshot_ = read_snapshot;
|
|
|
|
if (is_unicode) {
|
|
param.coll_type_ = CS_TYPE_UTF8MB4_GENERAL_CI;
|
|
} else {
|
|
param.coll_type_ = CS_TYPE_BINARY; // TODO
|
|
}
|
|
param.offset_ = 0;
|
|
param.len_ = 250 * 1024;
|
|
|
|
//
|
|
// ObString wr_data;
|
|
// wr_data.assign_ptr(data, total_len);
|
|
ret = mgr->append(param, write_data);
|
|
ASSERT_EQ(ret, OB_SUCCESS);
|
|
|
|
// 5. serialize trans result and ship
|
|
// 6. merge result if necessary
|
|
|
|
// 7. end data access, if failed, rollback
|
|
expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->rollback_to_implicit_savepoint(*tx_desc, savepoint, expire_ts, NULL));
|
|
|
|
// 8. submit transaction, or rollback
|
|
expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->commit_tx(*tx_desc, expire_ts));
|
|
|
|
// 9. release tx desc
|
|
tx_service->release_tx(*tx_desc);
|
|
}
|
|
|
|
|
|
// ObLobMetaInfo infos[10];
|
|
// ObLobPieceInfo pinfos[10];
|
|
// for (int i = 0; i < 8; ++i) {
|
|
// ObLobMetaInfo* info = &infos[i];
|
|
// info->byte_len_ = 250 * 1024;
|
|
// info->char_len_ = 250 * 1024;
|
|
// info->lob_id_ = lob_id;
|
|
// uint32_t seq_id[2] = {0};
|
|
// seq_id[0] = 256 * (i + 1);
|
|
// ObString seq_str;
|
|
// seq_str.assign_ptr(reinterpret_cast<char*>(seq_id), sizeof(uint32_t));
|
|
// info->seq_id_ = seq_str;
|
|
// info->lob_data_.assign_ptr(data + i * 250 * 1024, 250 * 1024);
|
|
// info->piece_id_ = ObLobMetaUtil::LOB_META_INLINE_PIECE_ID;
|
|
// insert_lob_meta(access_service, allocator, *info);
|
|
// }
|
|
|
|
{
|
|
// 1. get tx desc
|
|
transaction::ObTxDesc *tx_desc = nullptr;
|
|
ASSERT_EQ(OB_SUCCESS, TestDmlCommon::build_tx_desc(tenant_id_, tx_desc));
|
|
|
|
// 2. create savepoint (can be rollbacked)
|
|
ObTxParam tx_param;
|
|
TestDmlCommon::build_tx_param(tx_param);
|
|
int64_t savepoint = 0;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->create_implicit_savepoint(*tx_desc, tx_param, savepoint, true));
|
|
// 3. acquire snapshot (write also need snapshot)
|
|
ObTxIsolationLevel isolation = ObTxIsolationLevel::RC;
|
|
int64_t expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
ObTxReadSnapshot read_snapshot;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->get_read_snapshot(*tx_desc, isolation, expire_ts, read_snapshot));
|
|
|
|
ObLobAccessParam param;
|
|
param.tx_desc_ = tx_desc;
|
|
param.sql_mode_ = SMO_DEFAULT;
|
|
param.allocator_ = &allocator;
|
|
param.meta_table_schema_ = &table_schema;
|
|
param.piece_table_schema_ = &ptable_schema;
|
|
param.meta_tablet_param_ = &table_param;
|
|
param.piece_tablet_param_ = &ptable_param;
|
|
param.ls_id_ = ls_id_;
|
|
param.tablet_id_ = tablet_id_;
|
|
param.scan_backward_ = false;
|
|
param.lob_common_ = lob_common;
|
|
param.handle_size_ = 1024;
|
|
// TODO param.byte_size_ = ?
|
|
param.asscess_ptable_ = false;
|
|
param.snapshot_ = read_snapshot;
|
|
param.timeout_ = ObTimeUtility::current_time() + 12 * 1000 * 1000;
|
|
if (is_unicode) {
|
|
param.coll_type_ = CS_TYPE_UTF8MB4_GENERAL_CI;
|
|
} else {
|
|
param.coll_type_ = CS_TYPE_BINARY; // TODO
|
|
}
|
|
param.offset_ = 0;
|
|
param.len_ = 250 * 1024;
|
|
|
|
//
|
|
// ObString wr_data;
|
|
// wr_data.assign_ptr(data, total_len);
|
|
ret = mgr->erase(param);
|
|
ASSERT_EQ(ret, OB_SUCCESS);
|
|
|
|
|
|
// 5. serialize trans result and ship
|
|
// 6. merge result if necessary
|
|
|
|
// 7. end data access, if failed, rollback
|
|
expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->rollback_to_implicit_savepoint(*tx_desc, savepoint, expire_ts, NULL));
|
|
|
|
// 8. submit transaction, or rollback
|
|
expire_ts = ObTimeUtility::current_time() + TestDmlCommon::TX_EXPIRE_TIME_US;
|
|
ASSERT_EQ(OB_SUCCESS, tx_service->commit_tx(*tx_desc, expire_ts));
|
|
|
|
// 9. release tx desc
|
|
tx_service->release_tx(*tx_desc);
|
|
|
|
}
|
|
|
|
|
|
// clean env
|
|
TestDmlCommon::delete_mocked_access_service(access_service);
|
|
TestDmlCommon::delete_mocked_ls_tablet_service(tablet_service);
|
|
}
|
|
|
|
TEST_F(TestLobManager, inrow_bin_test)
|
|
{
|
|
ObArenaAllocator allocator;
|
|
int ret = OB_SUCCESS;
|
|
|
|
ObLobManager *mgr = MTL(ObLobManager*);
|
|
char *lob_data = reinterpret_cast<char*>(allocator.alloc(4096));
|
|
ObLobCommon *loc = new(lob_data)ObLobCommon();
|
|
|
|
char *tmp_buf;
|
|
uint32_t data_len = 900;
|
|
prepare_random_data(allocator, data_len, &tmp_buf);
|
|
|
|
ObLobAccessParam param;
|
|
param.tx_desc_ = nullptr;
|
|
param.sql_mode_ = SMO_DEFAULT;
|
|
param.allocator_ = &allocator;
|
|
param.ls_id_ = ls_id_;
|
|
param.tablet_id_ = tablet_id_;
|
|
param.scan_backward_ = false;
|
|
param.lob_common_ = loc;
|
|
param.handle_size_ = 4096;
|
|
param.asscess_ptable_ = false;
|
|
param.coll_type_ = CS_TYPE_BINARY;
|
|
param.timeout_ = ObTimeUtility::current_time() + 12 * 1000 * 1000;
|
|
// append [0,400]
|
|
ObString appeng_buf;
|
|
appeng_buf.assign_ptr(tmp_buf, 400);
|
|
ASSERT_EQ(OB_SUCCESS, mgr->append(param, appeng_buf));
|
|
|
|
// query check [0,400]
|
|
char *query_buf = reinterpret_cast<char*>(allocator.alloc(4096));
|
|
ObString query_str;
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
param.offset_ = 0;
|
|
param.len_ = 400;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf + param.offset_, param.len_), 0);
|
|
|
|
// erase [100, 250]
|
|
param.offset_ = 100;
|
|
param.len_ = 150;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->erase(param));
|
|
// query check [0,100],[250,400]
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
param.offset_ = 0;
|
|
param.len_ = 400;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
ASSERT_EQ(250, query_str.length());
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf, 100), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 100, tmp_buf + 250, 150), 0);
|
|
|
|
// replaced-write [50,100]
|
|
appeng_buf.assign_ptr(tmp_buf + 400, 50);
|
|
param.offset_ = 50;
|
|
param.len_ = 50;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->write(param, appeng_buf));
|
|
// query check [0,100],[250,900],
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
param.offset_ = 0;
|
|
param.len_ = 900;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
// 对应关系
|
|
// query [0,50] [50,100] [100,250]
|
|
// tmpbuf [0,50] [400,450] [250,400]
|
|
ASSERT_EQ(250, query_str.length());
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 50, tmp_buf + 400, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 100, tmp_buf + 250, 150), 0);
|
|
|
|
// overwrite-no padding [200,300] = tmpbuf[800,900]
|
|
appeng_buf.assign_ptr(tmp_buf + 800, 100);
|
|
param.offset_ = 200;
|
|
param.len_ = 100;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->write(param, appeng_buf));
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
param.offset_ = 0;
|
|
param.len_ = 900;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
// 对应关系
|
|
// query [0,50] [50,100] [100,200] [200,300]
|
|
// tmpbuf [0,50] [400,450] [250,350] [800,900]
|
|
ASSERT_EQ(300, query_str.length());
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 50, tmp_buf + 400, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 100, tmp_buf + 250, 100), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 200, tmp_buf + 800, 100), 0);
|
|
|
|
// overwrite with padding [1000, 1100] = tmpbuf[600,700]
|
|
appeng_buf.assign_ptr(tmp_buf + 600, 200); // set data 200, but only write 100
|
|
param.offset_ = 1000;
|
|
param.len_ = 100;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->write(param, appeng_buf));
|
|
query_str.assign_buffer(query_buf, 4096);
|
|
param.offset_ = 0;
|
|
param.len_ = 2000;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
// 对应关系
|
|
// query [0,50] [50,100] [100,200] [200,300] [300,1000] [1000,1100]
|
|
// tmpbuf [0,50] [400,450] [250,350] [800,900] [0x00] [600,700]
|
|
ASSERT_EQ(1100, query_str.length());
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 50, tmp_buf + 400, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 100, tmp_buf + 250, 100), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 200, tmp_buf + 800, 100), 0);
|
|
char empty_buf[1024];
|
|
MEMSET(empty_buf, 0x00, 1024);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 300, empty_buf, 700), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 1000, tmp_buf + 600, 100), 0);
|
|
allocator.free(query_buf);
|
|
allocator.free(lob_data);
|
|
}
|
|
|
|
TEST_F(TestLobManager, inrow_utf8_test)
|
|
{
|
|
ObArenaAllocator allocator;
|
|
int ret = OB_SUCCESS;
|
|
|
|
ObLobManager *mgr = MTL(ObLobManager*);
|
|
char *lob_data = reinterpret_cast<char*>(allocator.alloc(4096));
|
|
ObLobCommon *loc = new(lob_data)ObLobCommon();
|
|
|
|
char tmp_buf[1024];
|
|
uint32_t data_len = 1024;
|
|
int real_len = 0;
|
|
gen_random_unicode_string(1000, tmp_buf, real_len);
|
|
size_t char_len = ObCharset::strlen_char(CS_TYPE_UTF8MB4_GENERAL_CI, tmp_buf, real_len);
|
|
|
|
ObLobAccessParam param;
|
|
param.tx_desc_ = nullptr;
|
|
param.sql_mode_ = SMO_DEFAULT;
|
|
param.allocator_ = &allocator;
|
|
param.ls_id_ = ls_id_;
|
|
param.tablet_id_ = tablet_id_;
|
|
param.scan_backward_ = false;
|
|
param.lob_common_ = loc;
|
|
param.handle_size_ = 4096;
|
|
param.asscess_ptable_ = false;
|
|
param.coll_type_ = CS_TYPE_UTF8MB4_GENERAL_CI;
|
|
param.timeout_ = ObTimeUtility::current_time() + 12 * 1000 * 1000;
|
|
// append char len [0, char_len/2]
|
|
size_t fp_len = char_len / 2;
|
|
size_t byte_st = ObCharset::charpos(param.coll_type_, tmp_buf, real_len, 0);
|
|
size_t byte_len = ObCharset::charpos(param.coll_type_, tmp_buf + byte_st, real_len - byte_st, fp_len);
|
|
ObString appeng_buf;
|
|
appeng_buf.assign_ptr(tmp_buf + byte_st, byte_len);
|
|
param.offset_ = 0;
|
|
param.len_ = fp_len;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->write(param, appeng_buf));
|
|
|
|
// query check [0,400]
|
|
char *query_buf = reinterpret_cast<char*>(allocator.alloc(4096));
|
|
ObString query_str;
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
param.offset_ = 0;
|
|
param.len_ = fp_len;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
ASSERT_EQ(byte_len, query_str.length());
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf + byte_st, byte_len), 0);
|
|
ret = ObCharset::strcmp(CS_TYPE_UTF8MB4_GENERAL_CI, query_str.ptr(), query_str.length(), tmp_buf + byte_st, byte_len);
|
|
ASSERT_EQ(0, ret);
|
|
|
|
// erase [fp/2, 2fp/3]
|
|
param.offset_ = fp_len/2;
|
|
param.len_ = fp_len/6;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->erase(param));
|
|
// query check [0,fp/2],[2fp/3,fp]
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
param.offset_ = 0;
|
|
param.len_ = fp_len;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
// compare [0,fp/2]
|
|
byte_st = ObCharset::charpos(param.coll_type_, tmp_buf, real_len, 0);
|
|
byte_len = ObCharset::charpos(param.coll_type_, tmp_buf + byte_st, real_len - byte_st, fp_len/2);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf + byte_st, byte_len), 0);
|
|
ret = ObCharset::strcmp(CS_TYPE_UTF8MB4_GENERAL_CI, query_str.ptr(), byte_len, tmp_buf + byte_st, byte_len);
|
|
ASSERT_EQ(0, ret);
|
|
// compare [2fp/3,fp]
|
|
size_t q_byte_st = byte_len;
|
|
byte_st = ObCharset::charpos(param.coll_type_, tmp_buf, real_len, fp_len/2 + fp_len/6);
|
|
byte_len = ObCharset::charpos(param.coll_type_, tmp_buf + byte_st, real_len - byte_st, fp_len - fp_len/2 - fp_len/6);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + q_byte_st, tmp_buf + byte_st, byte_len), 0);
|
|
ret = ObCharset::strcmp(CS_TYPE_UTF8MB4_GENERAL_CI, query_str.ptr() + q_byte_st, query_str.length() - q_byte_st, tmp_buf + byte_st, byte_len);
|
|
ASSERT_EQ(0, ret);
|
|
|
|
allocator.free(query_buf);
|
|
allocator.free(lob_data);
|
|
}
|
|
|
|
TEST_F(TestLobManager, inrow_tmp_full_locator)
|
|
{
|
|
ObArenaAllocator allocator;
|
|
int ret = OB_SUCCESS;
|
|
|
|
ObLobManager *mgr = MTL(ObLobManager*);
|
|
// char *lob_data = reinterpret_cast<char*>(allocator.alloc(4096));
|
|
// ObLobCommon *loc = new(lob_data)ObLobCommon();
|
|
|
|
char *tmp_buf;
|
|
uint32_t data_len = 900;
|
|
prepare_random_data(allocator, data_len, &tmp_buf);
|
|
|
|
ObString data;
|
|
ObLobLocatorV2 lob_locator;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->build_tmp_full_lob_locator(allocator, data, CS_TYPE_BINARY, lob_locator));
|
|
|
|
ObLobAccessParam param;
|
|
param.tx_desc_ = nullptr;
|
|
param.sql_mode_ = SMO_DEFAULT;
|
|
param.allocator_ = &allocator;
|
|
param.ls_id_ = ls_id_;
|
|
param.tablet_id_ = tablet_id_;
|
|
param.scan_backward_ = false;
|
|
param.lob_locator_ = &lob_locator;
|
|
param.handle_size_ = param.lob_locator_->size_;
|
|
param.asscess_ptable_ = false;
|
|
param.coll_type_ = CS_TYPE_BINARY;
|
|
param.timeout_ = ObTimeUtility::current_time() + 12 * 1000 * 1000;
|
|
// append [0,400]
|
|
ObString appeng_buf;
|
|
appeng_buf.assign_ptr(tmp_buf, 400);
|
|
ASSERT_EQ(OB_SUCCESS, mgr->append(param, appeng_buf));
|
|
|
|
// query check [0,400]
|
|
char *query_buf = reinterpret_cast<char*>(allocator.alloc(4096));
|
|
ObString query_str;
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
param.handle_size_ = param.lob_locator_->size_;
|
|
param.offset_ = 0;
|
|
param.len_ = 400;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf + param.offset_, param.len_), 0);
|
|
|
|
// erase [100, 250]
|
|
// param.handle_size_ = param.lob_locator_->size_;
|
|
param.offset_ = 100;
|
|
param.len_ = 150;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->erase(param));
|
|
// query check [0,100],[250,400]
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
// param.handle_size_ = param.lob_locator_->size_;
|
|
param.offset_ = 0;
|
|
param.len_ = 400;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
ASSERT_EQ(250, query_str.length());
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf, 100), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 100, tmp_buf + 250, 150), 0);
|
|
|
|
// replaced-write [50,100]
|
|
appeng_buf.assign_ptr(tmp_buf + 400, 50);
|
|
param.offset_ = 50;
|
|
param.len_ = 50;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->write(param, appeng_buf));
|
|
// query check [0,100],[250,900],
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
param.offset_ = 0;
|
|
param.len_ = 900;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
// 对应关系
|
|
// query [0,50] [50,100] [100,250]
|
|
// tmpbuf [0,50] [400,450] [250,400]
|
|
ASSERT_EQ(250, query_str.length());
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 50, tmp_buf + 400, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 100, tmp_buf + 250, 150), 0);
|
|
|
|
// overwrite-no padding [200,300] = tmpbuf[800,900]
|
|
appeng_buf.assign_ptr(tmp_buf + 800, 100);
|
|
param.offset_ = 200;
|
|
param.len_ = 100;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->write(param, appeng_buf));
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
param.offset_ = 0;
|
|
param.len_ = 900;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
// 对应关系
|
|
// query [0,50] [50,100] [100,200] [200,300]
|
|
// tmpbuf [0,50] [400,450] [250,350] [800,900]
|
|
ASSERT_EQ(300, query_str.length());
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 50, tmp_buf + 400, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 100, tmp_buf + 250, 100), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 200, tmp_buf + 800, 100), 0);
|
|
|
|
// overwrite with padding [1000, 1100] = tmpbuf[600,700]
|
|
appeng_buf.assign_ptr(tmp_buf + 600, 200); // set data 200, but only write 100
|
|
param.offset_ = 1000;
|
|
param.len_ = 100;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->write(param, appeng_buf));
|
|
query_str.assign_buffer(query_buf, 4096);
|
|
param.offset_ = 0;
|
|
param.len_ = 2000;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
// 对应关系
|
|
// query [0,50] [50,100] [100,200] [200,300] [300,1000] [1000,1100]
|
|
// tmpbuf [0,50] [400,450] [250,350] [800,900] [0x00] [600,700]
|
|
ASSERT_EQ(1100, query_str.length());
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 50, tmp_buf + 400, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 100, tmp_buf + 250, 100), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 200, tmp_buf + 800, 100), 0);
|
|
char empty_buf[1024];
|
|
MEMSET(empty_buf, 0x00, 1024);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 300, empty_buf, 700), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 1000, tmp_buf + 600, 100), 0);
|
|
// allocator.free(query_buf);
|
|
// allocator.free(lob_locator.ptr_);
|
|
allocator.clear();
|
|
}
|
|
|
|
TEST_F(TestLobManager, inrow_tmp_delta_locator)
|
|
{
|
|
ObArenaAllocator allocator;
|
|
int ret = OB_SUCCESS;
|
|
|
|
ObLobManager *mgr = MTL(ObLobManager*);
|
|
char *persist_data = reinterpret_cast<char*>(allocator.alloc(4096));
|
|
// mock lob persis
|
|
{
|
|
ObMemLobCommon *lob_common = new(persist_data)ObMemLobCommon(ObMemLobType::PERSISTENT_LOB, false);
|
|
lob_common->set_read_only(false);
|
|
ObLobCommon *loc = new(lob_common->data_)ObLobCommon();
|
|
}
|
|
uint32_t handle_size = sizeof(ObMemLobCommon) + sizeof(ObLobCommon);
|
|
ObLobLocatorV2 persis_locator(persist_data, handle_size);
|
|
|
|
char *tmp_buf;
|
|
uint32_t data_len = 900;
|
|
prepare_random_data(allocator, data_len, &tmp_buf);
|
|
|
|
ObString data;
|
|
ObLobLocatorV2 lob_locator;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->build_tmp_full_lob_locator(allocator, data, CS_TYPE_BINARY, lob_locator));
|
|
|
|
ObLobAccessParam param;
|
|
// param.tx_desc_ = nullptr;
|
|
// param.sql_mode_ = SMO_DEFAULT;
|
|
param.allocator_ = &allocator;
|
|
// param.ls_id_ = ls_id_;
|
|
// param.tablet_id_ = tablet_id_;
|
|
// param.scan_backward_ = false;
|
|
// param.lob_locator_ = &lob_locator;
|
|
// param.handle_size_ = param.lob_locator_->size_;
|
|
// param.asscess_ptable_ = false;
|
|
param.coll_type_ = CS_TYPE_BINARY;
|
|
// param.timeout_ = ObTimeUtility::current_time() + 12 * 1000 * 1000;
|
|
// append [0,400]
|
|
ObString appeng_buf;
|
|
appeng_buf.assign_ptr(tmp_buf, 400);
|
|
ObLobLocatorV2 delta_locator;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->build_tmp_delta_lob_locator(allocator, &persis_locator, appeng_buf, false, ObLobDiffFlags(),
|
|
ObLobDiff::DiffType::APPEND, 0, 0, 0, delta_locator));
|
|
ASSERT_EQ(OB_SUCCESS, mgr->process_delta(param, delta_locator));
|
|
|
|
// query check [0,400]
|
|
char *query_buf = reinterpret_cast<char*>(allocator.alloc(4096));
|
|
ObString query_str;
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
// param.handle_size_ = param.lob_locator_->size_;
|
|
param.offset_ = 0;
|
|
param.len_ = 400;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf + param.offset_, param.len_), 0);
|
|
|
|
// erase [100, 250]
|
|
// mock lob persis
|
|
{
|
|
ObMemLobCommon *lob_common = new(persist_data)ObMemLobCommon(ObMemLobType::PERSISTENT_LOB, false);
|
|
lob_common->set_read_only(false);
|
|
MEMCPY(lob_common->data_, reinterpret_cast<char*>(param.lob_common_), param.handle_size_);
|
|
}
|
|
persis_locator.ptr_ = persist_data;
|
|
persis_locator.size_ = sizeof(ObMemLobCommon) + param.handle_size_;
|
|
// build delta
|
|
ASSERT_EQ(OB_SUCCESS, mgr->build_tmp_delta_lob_locator(allocator, &persis_locator, ObString(), false, ObLobDiffFlags(),
|
|
ObLobDiff::DiffType::ERASE, 100, 150, 0, delta_locator));
|
|
ASSERT_EQ(OB_SUCCESS, mgr->process_delta(param, delta_locator));
|
|
// query check [0,100],[250,400]
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
param.offset_ = 0;
|
|
param.len_ = 400;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
ASSERT_EQ(250, query_str.length());
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf, 100), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 100, tmp_buf + 250, 150), 0);
|
|
|
|
// replaced-write [50,100]
|
|
// mock lob persis
|
|
{
|
|
ObMemLobCommon *lob_common = new(persist_data)ObMemLobCommon(ObMemLobType::PERSISTENT_LOB, false);
|
|
lob_common->set_read_only(false);
|
|
MEMCPY(lob_common->data_, reinterpret_cast<char*>(param.lob_common_), param.handle_size_);
|
|
}
|
|
persis_locator.ptr_ = persist_data;
|
|
persis_locator.size_ = sizeof(ObMemLobCommon) + sizeof(ObLobCommon) + param.byte_size_;
|
|
// build delta
|
|
appeng_buf.assign_ptr(tmp_buf + 400, 50);
|
|
ASSERT_EQ(OB_SUCCESS, mgr->build_tmp_delta_lob_locator(allocator, &persis_locator, appeng_buf, false, ObLobDiffFlags(),
|
|
ObLobDiff::DiffType::WRITE, 50, 50, 0, delta_locator));
|
|
ASSERT_EQ(OB_SUCCESS, mgr->process_delta(param, delta_locator));
|
|
// query check [0,100],[250,900],
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
param.offset_ = 0;
|
|
param.len_ = 900;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
// 对应关系
|
|
// query [0,50] [50,100] [100,250]
|
|
// tmpbuf [0,50] [400,450] [250,400]
|
|
ASSERT_EQ(250, query_str.length());
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 50, tmp_buf + 400, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 100, tmp_buf + 250, 150), 0);
|
|
|
|
// overwrite-no padding [200,300] = tmpbuf[800,900]
|
|
// mock lob persis
|
|
{
|
|
ObMemLobCommon *lob_common = new(persist_data)ObMemLobCommon(ObMemLobType::PERSISTENT_LOB, false);
|
|
lob_common->set_read_only(false);
|
|
MEMCPY(lob_common->data_, reinterpret_cast<char*>(param.lob_common_), param.handle_size_);
|
|
}
|
|
persis_locator.ptr_ = persist_data;
|
|
persis_locator.size_ = sizeof(ObMemLobCommon) + param.handle_size_;
|
|
// biuld delta
|
|
appeng_buf.assign_ptr(tmp_buf + 800, 100);
|
|
ASSERT_EQ(OB_SUCCESS, mgr->build_tmp_delta_lob_locator(allocator, &persis_locator, appeng_buf, false, ObLobDiffFlags(),
|
|
ObLobDiff::DiffType::WRITE, 200, 100, 0, delta_locator));
|
|
ASSERT_EQ(OB_SUCCESS, mgr->process_delta(param, delta_locator));
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
param.offset_ = 0;
|
|
param.len_ = 900;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
// 对应关系
|
|
// query [0,50] [50,100] [100,200] [200,300]
|
|
// tmpbuf [0,50] [400,450] [250,350] [800,900]
|
|
ASSERT_EQ(300, query_str.length());
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 50, tmp_buf + 400, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 100, tmp_buf + 250, 100), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 200, tmp_buf + 800, 100), 0);
|
|
|
|
// overwrite with padding [1000, 1100] = tmpbuf[600,700]
|
|
// mock lob persis
|
|
{
|
|
ObMemLobCommon *lob_common = new(persist_data)ObMemLobCommon(ObMemLobType::PERSISTENT_LOB, false);
|
|
lob_common->set_read_only(false);
|
|
MEMCPY(lob_common->data_, reinterpret_cast<char*>(param.lob_common_), param.handle_size_);
|
|
}
|
|
persis_locator.ptr_ = persist_data;
|
|
persis_locator.size_ = sizeof(ObMemLobCommon) + param.handle_size_;
|
|
// build delta
|
|
appeng_buf.assign_ptr(tmp_buf + 600, 200); // set data 200, but only write 100
|
|
// param.offset_ = 1000;
|
|
// param.len_ = 100;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->build_tmp_delta_lob_locator(allocator, &persis_locator, appeng_buf, false, ObLobDiffFlags(),
|
|
ObLobDiff::DiffType::WRITE, 1000, 100, 0, delta_locator));
|
|
ASSERT_EQ(OB_SUCCESS, mgr->process_delta(param, delta_locator));
|
|
query_str.assign_buffer(query_buf, 4096);
|
|
param.offset_ = 0;
|
|
param.len_ = 2000;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
// 对应关系
|
|
// query [0,50] [50,100] [100,200] [200,300] [300,1000] [1000,1100]
|
|
// tmpbuf [0,50] [400,450] [250,350] [800,900] [0x00] [600,700]
|
|
ASSERT_EQ(1100, query_str.length());
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 50, tmp_buf + 400, 50), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 100, tmp_buf + 250, 100), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 200, tmp_buf + 800, 100), 0);
|
|
char empty_buf[1024];
|
|
MEMSET(empty_buf, 0x00, 1024);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 300, empty_buf, 700), 0);
|
|
ASSERT_EQ(MEMCMP(query_str.ptr() + 1000, tmp_buf + 600, 100), 0);
|
|
// allocator.free(query_buf);
|
|
// allocator.free(lob_locator.ptr_);
|
|
allocator.clear();
|
|
}
|
|
|
|
TEST_F(TestLobManager, inrow_bin_reverse_query)
|
|
{
|
|
ObArenaAllocator allocator;
|
|
int ret = OB_SUCCESS;
|
|
|
|
ObLobManager *mgr = MTL(ObLobManager*);
|
|
char *lob_data = reinterpret_cast<char*>(allocator.alloc(4096));
|
|
ObLobCommon *loc = new(lob_data)ObLobCommon();
|
|
|
|
char *tmp_buf;
|
|
uint32_t data_len = 900;
|
|
prepare_random_data(allocator, data_len, &tmp_buf);
|
|
|
|
ObLobAccessParam param;
|
|
param.tx_desc_ = nullptr;
|
|
param.sql_mode_ = SMO_DEFAULT;
|
|
param.allocator_ = &allocator;
|
|
param.ls_id_ = ls_id_;
|
|
param.tablet_id_ = tablet_id_;
|
|
param.scan_backward_ = false;
|
|
param.lob_common_ = loc;
|
|
param.handle_size_ = 4096;
|
|
param.asscess_ptable_ = false;
|
|
param.coll_type_ = CS_TYPE_BINARY;
|
|
param.timeout_ = ObTimeUtility::current_time() + 12 * 1000 * 1000;
|
|
// append [0,400]
|
|
ObString appeng_buf;
|
|
appeng_buf.assign_ptr(tmp_buf, 900);
|
|
ASSERT_EQ(OB_SUCCESS, mgr->append(param, appeng_buf));
|
|
|
|
// query check [0,900]
|
|
char *query_buf = reinterpret_cast<char*>(allocator.alloc(4096));
|
|
ObString query_str;
|
|
query_str.assign_buffer(query_buf, 1024);
|
|
param.offset_ = 0;
|
|
param.len_ = 900;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, query_str));
|
|
ASSERT_EQ(MEMCMP(query_str.ptr(), tmp_buf + param.offset_, param.len_), 0);
|
|
|
|
// query by iter in reverse
|
|
// [0, 900]
|
|
{
|
|
param.scan_backward_ = true;
|
|
ObLobQueryIter *iter = NULL;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, iter));
|
|
// perpare read buffer
|
|
int32_t read_buff_len = 200;
|
|
char *read_buf = reinterpret_cast<char*>(allocator.alloc(read_buff_len));
|
|
ObString read_str;
|
|
int32_t offset = 0;
|
|
while (OB_SUCC(ret)) {
|
|
read_str.assign_buffer(read_buf, read_buff_len);
|
|
ret = iter->get_next_row(read_str);
|
|
if (OB_FAIL(ret)) {
|
|
if (ret == OB_ITER_END) {
|
|
} else {
|
|
ASSERT_EQ(ret, OB_SUCCESS);
|
|
}
|
|
} else {
|
|
int32_t read_len = read_str.length();
|
|
MEMCMP(read_str.ptr(), tmp_buf + 900 - offset - read_len, read_len);
|
|
offset += read_len;
|
|
}
|
|
}
|
|
iter->reset();
|
|
common::sop_return(ObLobQueryIter, iter);
|
|
allocator.free(read_buf);
|
|
}
|
|
|
|
// query [450, 700]
|
|
{
|
|
param.scan_backward_ = true;
|
|
param.offset_ = 200; // offset from end
|
|
param.len_ = 250;
|
|
ObLobQueryIter *iter = NULL;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, iter));
|
|
// perpare read buffer
|
|
int32_t read_buff_len = 200;
|
|
char *read_buf = reinterpret_cast<char*>(allocator.alloc(read_buff_len));
|
|
ObString read_str;
|
|
int32_t offset = 0;
|
|
while (OB_SUCC(ret)) {
|
|
read_str.assign_buffer(read_buf, read_buff_len);
|
|
ret = iter->get_next_row(read_str);
|
|
if (OB_FAIL(ret)) {
|
|
if (ret == OB_ITER_END) {
|
|
} else {
|
|
ASSERT_EQ(ret, OB_SUCCESS);
|
|
}
|
|
} else {
|
|
int32_t read_len = read_str.length();
|
|
MEMCMP(read_str.ptr(), tmp_buf + 700 - offset - read_len, read_len);
|
|
offset += read_len;
|
|
}
|
|
}
|
|
iter->reset();
|
|
common::sop_return(ObLobQueryIter, iter);
|
|
allocator.free(read_buf);
|
|
}
|
|
|
|
allocator.free(query_buf);
|
|
allocator.free(lob_data);
|
|
}
|
|
|
|
TEST_F(TestLobManager, inrow_utf8_reverse_query)
|
|
{
|
|
ObArenaAllocator allocator;
|
|
int ret = OB_SUCCESS;
|
|
|
|
ObLobManager *mgr = MTL(ObLobManager*);
|
|
char *lob_data = reinterpret_cast<char*>(allocator.alloc(4096));
|
|
ObLobCommon *loc = new(lob_data)ObLobCommon();
|
|
|
|
char tmp_buf[1024];
|
|
uint32_t data_len = 1024;
|
|
int real_len = 0;
|
|
gen_random_unicode_string(1000, tmp_buf, real_len);
|
|
size_t char_len = ObCharset::strlen_char(CS_TYPE_UTF8MB4_GENERAL_CI, tmp_buf, real_len);
|
|
|
|
ObLobAccessParam param;
|
|
param.tx_desc_ = nullptr;
|
|
param.sql_mode_ = SMO_DEFAULT;
|
|
param.allocator_ = &allocator;
|
|
param.ls_id_ = ls_id_;
|
|
param.tablet_id_ = tablet_id_;
|
|
param.scan_backward_ = false;
|
|
param.lob_common_ = loc;
|
|
param.handle_size_ = 4096;
|
|
param.asscess_ptable_ = false;
|
|
param.coll_type_ = CS_TYPE_UTF8MB4_GENERAL_CI;
|
|
param.timeout_ = ObTimeUtility::current_time() + 12 * 1000 * 1000;
|
|
// append char len [0, char_len]
|
|
ObString appeng_buf;
|
|
appeng_buf.assign_ptr(tmp_buf, real_len);
|
|
param.offset_ = 0;
|
|
param.len_ = char_len;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->write(param, appeng_buf));
|
|
|
|
// query by iter in reverse
|
|
// [0, 900]
|
|
{
|
|
param.scan_backward_ = true;
|
|
ObLobQueryIter *iter = NULL;
|
|
ASSERT_EQ(OB_SUCCESS, mgr->query(param, iter));
|
|
// perpare read buffer
|
|
int32_t read_buff_len = 200;
|
|
char *read_buf = reinterpret_cast<char*>(allocator.alloc(read_buff_len));
|
|
ObString read_str;
|
|
int32_t offset = 0;
|
|
while (OB_SUCC(ret)) {
|
|
read_str.assign_buffer(read_buf, read_buff_len);
|
|
ret = iter->get_next_row(read_str);
|
|
if (OB_FAIL(ret)) {
|
|
if (ret == OB_ITER_END) {
|
|
} else {
|
|
ASSERT_EQ(ret, OB_SUCCESS);
|
|
}
|
|
} else {
|
|
int32_t read_len = read_str.length();
|
|
MEMCMP(read_str.ptr(), tmp_buf + real_len - offset - read_len, read_len);
|
|
offset += read_len;
|
|
}
|
|
}
|
|
iter->reset();
|
|
common::sop_return(ObLobQueryIter, iter);
|
|
allocator.free(read_buf);
|
|
}
|
|
|
|
}
|
|
|
|
} // end unittest
|
|
} // end oceanbase
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
system("rm -rf test_lob_manager.log");
|
|
OB_LOGGER.set_file_name("test_lob_manager.log", true);
|
|
OB_LOGGER.set_log_level("INFO");
|
|
GCONF._enable_defensive_check = false;
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|