add index storage cache
This commit is contained in:
parent
b65424de02
commit
1c3429f4bb
36
src/search_local/index_storage/cache/Makefile
vendored
Normal file
36
src/search_local/index_storage/cache/Makefile
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
LIB_PATH = ../../..
|
||||
include ../Make.conf
|
||||
VPATH :=../stat
|
||||
|
||||
####################compile#################
|
||||
CFLAGS += -D_GLIBCXX_USE_CXX11_ABI=0
|
||||
CFLAGS += -I./ -I../common -I../api/c_api -I../stat -I../watchdog -I../helper
|
||||
LIBPATH := -L. -L../common -L../watchdog -L../stat -L../../../3rdlib/attr_api -L../api
|
||||
DB%.o tmp.DB%.o:CFLAGS += $(MYSQLINC)
|
||||
ifneq ($(findstring x86_64,$(PLATFORM)),)
|
||||
BITS=64
|
||||
else
|
||||
BITS=32
|
||||
endif
|
||||
|
||||
LIBDTCAPI := -L../api -lpthread -Wl,-rpath,\$$ORIGIN/../lib/ -Wl,-rpath,\$$ORIGIN -Wl,-rpath,\$$ORIGIN/../api/ -Wl,-rpath,\$$ORIGIN/../ -z origin
|
||||
|
||||
target = libdtcd.a dtcd
|
||||
target_external = ../api/libdtc.a ../stat/libstat.a ../common/libcommon.a
|
||||
|
||||
$(filterout libdtcd.a,$(target)): libdtcd.a;
|
||||
|
||||
filelist := feature hash ng_info node_set node_index fence_unit buffer_bypass buffer_pool pt_malloc sys_malloc raw_data raw_data_process buffer_process buffer_flush buffer_unit empty_filter black_hole logger task_pendlist lru_bit hb_log admin_process hb_feature container_dtcd col_expand t_tree tree_data tree_data_process expire_time main hb_process task_control
|
||||
libdtcd_objs:= $(sort $(filelist:%=%.o))
|
||||
|
||||
#dtcd
|
||||
dtcd: CFLAGS += -export-dynamic
|
||||
dtcd: LDFLAGS += -Wl,--version-script,dtcd.export.lst
|
||||
dtcd_objs:= main.o task_control.o stat_client.o expire_time.o hb_process.o
|
||||
dtcd_libs:= -lstat -lwatchdog -ldtcd -lcommon -lattr_api_$(BITS) -lpthread -ldl $(Z_LIB) -rdynamic
|
||||
|
||||
#####################install############
|
||||
target_install = dtcd
|
||||
install_dir = ../../bin
|
||||
|
||||
include ../Make.rules
|
1243
src/search_local/index_storage/cache/admin_process.cc
vendored
Normal file
1243
src/search_local/index_storage/cache/admin_process.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
50
src/search_local/index_storage/cache/black_hole.cc
vendored
Normal file
50
src/search_local/index_storage/cache/black_hole.cc
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: black_hole.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <black_hole.h>
|
||||
|
||||
BlackHole::~BlackHole(void)
|
||||
{
|
||||
}
|
||||
|
||||
void BlackHole::task_notify(TaskRequest *cur)
|
||||
{
|
||||
#if 0
|
||||
switch(cur->request_code()){
|
||||
case DRequest::Get:
|
||||
break;
|
||||
|
||||
case DRequest::Insert: // TableDef->has_auto_increment() must be false
|
||||
cur->resultInfo.set_affected_rows(1);
|
||||
break;
|
||||
|
||||
case DRequest::Update:
|
||||
case DRequest::Delete:
|
||||
case DRequest::Purge:
|
||||
case DRequest::Replace:
|
||||
default:
|
||||
cur->resultInfo.set_affected_rows(1);
|
||||
break;
|
||||
}
|
||||
|
||||
#else
|
||||
// preset affected_rows==0 is obsoleted
|
||||
// use BlackHole flag instead
|
||||
cur->mark_as_black_hole();
|
||||
#endif
|
||||
cur->reply_notify();
|
||||
}
|
30
src/search_local/index_storage/cache/black_hole.h
vendored
Normal file
30
src/search_local/index_storage/cache/black_hole.h
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: black_hole.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <task_request.h>
|
||||
|
||||
class BlackHole : public TaskDispatcher<TaskRequest>
|
||||
{
|
||||
public:
|
||||
BlackHole(PollThread *o) : TaskDispatcher<TaskRequest>(o), output(o){};
|
||||
virtual ~BlackHole(void);
|
||||
void bind_dispatcher(TaskDispatcher<TaskRequest> *p) { output.bind_dispatcher(p); }
|
||||
|
||||
private:
|
||||
RequestOutput<TaskRequest> output;
|
||||
virtual void task_notify(TaskRequest *);
|
||||
};
|
61
src/search_local/index_storage/cache/buffer_bypass.cc
vendored
Normal file
61
src/search_local/index_storage/cache/buffer_bypass.cc
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: buffer_bypass.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <buffer_bypass.h>
|
||||
|
||||
class ReplyBypass : public ReplyDispatcher<TaskRequest>
|
||||
{
|
||||
public:
|
||||
ReplyBypass(void) {}
|
||||
virtual ~ReplyBypass(void);
|
||||
virtual void reply_notify(TaskRequest *task);
|
||||
};
|
||||
|
||||
ReplyBypass::~ReplyBypass(void) {}
|
||||
|
||||
void ReplyBypass::reply_notify(TaskRequest *task)
|
||||
{
|
||||
if (task->result)
|
||||
task->pass_all_result(task->result);
|
||||
task->reply_notify();
|
||||
}
|
||||
|
||||
static ReplyBypass replyBypass;
|
||||
|
||||
BufferBypass::~BufferBypass(void)
|
||||
{
|
||||
}
|
||||
|
||||
void BufferBypass::task_notify(TaskRequest *cur)
|
||||
{
|
||||
if (cur->is_batch_request())
|
||||
{
|
||||
cur->reply_notify();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cur->count_only() && (cur->requestInfo.limit_start() || cur->requestInfo.limit_count()))
|
||||
{
|
||||
cur->set_error(-EC_BAD_COMMAND, "BufferBypass", "There's nothing to limit because no fields required");
|
||||
cur->reply_notify();
|
||||
return;
|
||||
}
|
||||
|
||||
cur->mark_as_pass_thru();
|
||||
cur->push_reply_dispatcher(&replyBypass);
|
||||
output.task_notify(cur);
|
||||
}
|
30
src/search_local/index_storage/cache/buffer_bypass.h
vendored
Normal file
30
src/search_local/index_storage/cache/buffer_bypass.h
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: buffer_bypass.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <task_request.h>
|
||||
|
||||
class BufferBypass : public TaskDispatcher<TaskRequest>
|
||||
{
|
||||
public:
|
||||
BufferBypass(PollThread *o) : TaskDispatcher<TaskRequest>(o), output(o){};
|
||||
virtual ~BufferBypass(void);
|
||||
void bind_dispatcher(TaskDispatcher<TaskRequest> *p) { output.bind_dispatcher(p); }
|
||||
|
||||
private:
|
||||
RequestOutput<TaskRequest> output;
|
||||
virtual void task_notify(TaskRequest *);
|
||||
};
|
46
src/search_local/index_storage/cache/buffer_def.h
vendored
Normal file
46
src/search_local/index_storage/cache/buffer_def.h
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: buffer_def.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __CACHE_DEF_H
|
||||
#define __CACHE_DEF_H
|
||||
|
||||
#define E_OK 0 //success
|
||||
#define E_FAIL -1 //fail
|
||||
#define KEY_LEN_LEN sizeof(char) //"key长"字段长度
|
||||
#define MAX_KEY_LEN 256 //key最大长度,由"key长"字段长度所能表示的最大数字决定
|
||||
#define ERR_MSG_LEN 1024
|
||||
#define MAX_PURGE_NUM 1000 //每次purge的节点数上限
|
||||
#define CACHE_SVC "dtc" //cache服务名
|
||||
//#define VERSION "1.0.3" //版本信息
|
||||
|
||||
#define STRNCPY(dest, src, len) \
|
||||
{ \
|
||||
memset(dest, 0x00, len); \
|
||||
strncpy(dest, src, len - 1); \
|
||||
}
|
||||
#define SNPRINTF(dest, len, fmt, args...) \
|
||||
{ \
|
||||
memset(dest, 0x00, len); \
|
||||
snprintf(dest, len - 1, fmt, ##args); \
|
||||
}
|
||||
#define MSGNCPY(dest, len, fmt, args...) \
|
||||
{ \
|
||||
memset(dest, 0x00, len); \
|
||||
snprintf(dest, len - 1, "[%s][%d]%s: " fmt "\n", __FILE__, __LINE__, __FUNCTION__, ##args); \
|
||||
}
|
||||
|
||||
#endif
|
442
src/search_local/index_storage/cache/buffer_flush.cc
vendored
Normal file
442
src/search_local/index_storage/cache/buffer_flush.cc
vendored
Normal file
@ -0,0 +1,442 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: buffer_flush.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include "buffer_flush.h"
|
||||
#include "buffer_process.h"
|
||||
#include "global.h"
|
||||
|
||||
DTCFlushRequest::DTCFlushRequest(BufferProcess *o, const char *key) : owner(o),
|
||||
numReq(0),
|
||||
badReq(0),
|
||||
wait(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
DTCFlushRequest::~DTCFlushRequest()
|
||||
{
|
||||
if (wait)
|
||||
{
|
||||
wait->reply_notify();
|
||||
wait = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
class DropDataReply : public ReplyDispatcher<TaskRequest>
|
||||
{
|
||||
public:
|
||||
DropDataReply() {}
|
||||
virtual void reply_notify(TaskRequest *cur);
|
||||
};
|
||||
|
||||
void DropDataReply::reply_notify(TaskRequest *cur)
|
||||
{
|
||||
DTCFlushRequest *req = cur->OwnerInfo<DTCFlushRequest>();
|
||||
if (req == NULL)
|
||||
delete cur;
|
||||
else
|
||||
req->complete_row(cur, cur->owner_index());
|
||||
}
|
||||
|
||||
static DropDataReply dropReply;
|
||||
|
||||
int DTCFlushRequest::flush_row(const RowValue &row)
|
||||
{
|
||||
TaskRequest *pTask = new TaskRequest;
|
||||
if (pTask == NULL)
|
||||
{
|
||||
log_error("cannot flush row, new task error, possible memory exhausted\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pTask->Copy(row) < 0)
|
||||
{
|
||||
log_error("cannot flush row, from: %s error: %s \n",
|
||||
pTask->resultInfo.error_from(),
|
||||
pTask->resultInfo.error_message());
|
||||
return -1;
|
||||
}
|
||||
pTask->set_request_type(TaskTypeCommit);
|
||||
pTask->push_reply_dispatcher(&dropReply);
|
||||
pTask->set_owner_info(this, numReq, NULL);
|
||||
owner->inc_async_flush_stat();
|
||||
//TaskTypeCommit never expired
|
||||
//pTask->set_expire_time(3600*1000/*ms*/);
|
||||
numReq++;
|
||||
owner->push_flush_queue(pTask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DTCFlushRequest::complete_row(TaskRequest *req, int index)
|
||||
{
|
||||
delete req;
|
||||
numReq--;
|
||||
if (numReq == 0)
|
||||
{
|
||||
if (wait)
|
||||
{
|
||||
wait->reply_notify();
|
||||
wait = NULL;
|
||||
}
|
||||
owner->complete_flush_request(this);
|
||||
}
|
||||
}
|
||||
|
||||
MARKER_STAMP BufferProcess::calculate_current_marker()
|
||||
{
|
||||
time_t now;
|
||||
|
||||
time(&now);
|
||||
return now - (now % markerInterval);
|
||||
}
|
||||
|
||||
void BufferProcess::set_drop_count(int c)
|
||||
{
|
||||
// Cache.set_drop_count(c);
|
||||
}
|
||||
|
||||
void BufferProcess::get_dirty_stat()
|
||||
{
|
||||
uint64_t ullMaxNode;
|
||||
uint64_t ullMaxRow;
|
||||
const double rate = 0.9;
|
||||
|
||||
if (DTCBinMalloc::Instance()->user_alloc_size() >= DTCBinMalloc::Instance()->total_size() * rate)
|
||||
{
|
||||
ullMaxNode = Cache.total_used_node();
|
||||
ullMaxRow = Cache.total_used_row();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DTCBinMalloc::Instance()->user_alloc_size() > 0)
|
||||
{
|
||||
double enlarge = DTCBinMalloc::Instance()->total_size() * rate / DTCBinMalloc::Instance()->user_alloc_size();
|
||||
ullMaxNode = (uint64_t)(Cache.total_used_node() * enlarge);
|
||||
ullMaxRow = (uint64_t)(Cache.total_used_row() * enlarge);
|
||||
}
|
||||
else
|
||||
{
|
||||
ullMaxNode = 0;
|
||||
ullMaxRow = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BufferProcess::set_flush_parameter(
|
||||
int intvl,
|
||||
int mreq,
|
||||
int mintime,
|
||||
int maxtime)
|
||||
{
|
||||
// require v4 cache
|
||||
if (Cache.get_cache_info()->version < 4)
|
||||
return;
|
||||
|
||||
/*
|
||||
if(intvl < 60)
|
||||
intvl = 60;
|
||||
else if(intvl > 43200)
|
||||
intvl = 43200;
|
||||
*/
|
||||
|
||||
/* marker time interval changed to 1sec */
|
||||
intvl = 1;
|
||||
markerInterval = intvl;
|
||||
|
||||
/* 1. make sure at least one time marker exist
|
||||
* 2. init first marker time and last marker time
|
||||
* */
|
||||
Node stTimeNode = Cache.first_time_marker();
|
||||
if (!stTimeNode)
|
||||
Cache.insert_time_marker(calculate_current_marker());
|
||||
Cache.first_time_marker_time();
|
||||
Cache.last_time_marker_time();
|
||||
|
||||
if (mreq <= 0)
|
||||
mreq = 1;
|
||||
if (mreq > 10000)
|
||||
mreq = 10000;
|
||||
|
||||
if (mintime < 10)
|
||||
mintime = 10;
|
||||
if (maxtime <= mintime)
|
||||
maxtime = mintime * 2;
|
||||
|
||||
maxFlushReq = mreq;
|
||||
minDirtyTime = mintime;
|
||||
maxDirtyTime = maxtime;
|
||||
|
||||
//get_dirty_stat();
|
||||
|
||||
/*attach timer only if async mode or sync mode but mem dirty*/
|
||||
if (updateMode == MODE_ASYNC ||
|
||||
(updateMode == MODE_SYNC && mem_dirty == true))
|
||||
{
|
||||
/* check for expired dirty node every second */
|
||||
flushTimer = owner->get_timer_list(1);
|
||||
attach_timer(flushTimer);
|
||||
}
|
||||
}
|
||||
|
||||
int BufferProcess::commit_flush_request(DTCFlushRequest *req, TaskRequest *callbackTask)
|
||||
{
|
||||
req->wait = callbackTask;
|
||||
|
||||
if (req->numReq == 0)
|
||||
delete req;
|
||||
else
|
||||
nFlushReq++;
|
||||
|
||||
statCurrFlushReq = nFlushReq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BufferProcess::complete_flush_request(DTCFlushRequest *req)
|
||||
{
|
||||
delete req;
|
||||
nFlushReq--;
|
||||
statCurrFlushReq = nFlushReq;
|
||||
|
||||
calculate_flush_speed(0);
|
||||
|
||||
if (nFlushReq < mFlushReq)
|
||||
flush_next_node();
|
||||
}
|
||||
|
||||
void BufferProcess::timer_notify(void)
|
||||
{
|
||||
log_debug("flush timer event...");
|
||||
int ret = 0;
|
||||
|
||||
MARKER_STAMP cur = calculate_current_marker();
|
||||
if (Cache.first_time_marker_time() != cur)
|
||||
Cache.insert_time_marker(cur);
|
||||
|
||||
calculate_flush_speed(1);
|
||||
|
||||
/* flush next node return
|
||||
* 1: no dirty node exist, sync dtc, should not attach timer again
|
||||
* 0: one flush request created, nFlushReq inc in flush_next_node, notinue
|
||||
* others: on flush request created due to some reason, should break for another flush timer event, otherwise may be
|
||||
* block here, eg. no dirty node exist, and in async mode
|
||||
* */
|
||||
while (nFlushReq < mFlushReq)
|
||||
{
|
||||
ret = flush_next_node();
|
||||
if (ret == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*SYNC + mem_dirty/ASYNC need to reattach flush timer*/
|
||||
if ((updateMode == MODE_SYNC && mem_dirty == true) || updateMode == MODE_ASYNC)
|
||||
attach_timer(flushTimer);
|
||||
}
|
||||
|
||||
int BufferProcess::oldest_dirty_node_alarm()
|
||||
{
|
||||
Node stHead = Cache.dirty_lru_head();
|
||||
Node stNode = stHead.Prev();
|
||||
|
||||
if (Cache.is_time_marker(stNode))
|
||||
{
|
||||
stNode = stNode.Prev();
|
||||
if (Cache.is_time_marker(stNode) || stNode == stHead)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (stNode == stHead)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*flush speed(nFlushReq) only depend on oldest dirty node existing time*/
|
||||
void BufferProcess::calculate_flush_speed(int is_flush_timer)
|
||||
{
|
||||
delete_tail_time_markers();
|
||||
|
||||
// time base
|
||||
int m, v;
|
||||
unsigned int t1 = Cache.first_time_marker_time();
|
||||
unsigned int t2 = Cache.last_time_marker_time();
|
||||
//initialized t1 and t2, so no need of test for this
|
||||
v = t1 - t2;
|
||||
|
||||
//if start with sync and mem dirty, flush as fast as we can
|
||||
if (updateMode == MODE_SYNC)
|
||||
{
|
||||
if (mem_dirty == false)
|
||||
{
|
||||
mFlushReq = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mFlushReq = maxFlushReq;
|
||||
}
|
||||
goto __stat;
|
||||
}
|
||||
|
||||
//alarm if oldest dirty node exist too much time, flush at fastest speed
|
||||
if (v >= maxDirtyTime)
|
||||
{
|
||||
mFlushReq = maxFlushReq;
|
||||
if (oldest_dirty_node_alarm() && is_flush_timer)
|
||||
{
|
||||
log_notice("oldest dirty node exist time > max dirty time");
|
||||
}
|
||||
}
|
||||
else if (v >= minDirtyTime)
|
||||
{
|
||||
m = 1 + (v - minDirtyTime) * (maxFlushReq - 1) / (maxDirtyTime - minDirtyTime);
|
||||
if (m > mFlushReq)
|
||||
mFlushReq = m;
|
||||
}
|
||||
else
|
||||
{
|
||||
mFlushReq = 0;
|
||||
}
|
||||
|
||||
__stat:
|
||||
if (mFlushReq > maxFlushReq)
|
||||
mFlushReq = maxFlushReq;
|
||||
|
||||
statMaxFlushReq = mFlushReq;
|
||||
statOldestDirtyTime = v;
|
||||
}
|
||||
|
||||
/* return -1: encount the only time marker
|
||||
* return 1: no dirty node exist, clear mem dirty
|
||||
* return 2: no dirty node exist, in async mode
|
||||
* return -2: no flush request created
|
||||
* return 0: one flush request created
|
||||
* */
|
||||
int BufferProcess::flush_next_node(void)
|
||||
{
|
||||
unsigned int uiFlushRowsCnt = 0;
|
||||
MARKER_STAMP stamp;
|
||||
static MARKER_STAMP last_rm_stamp;
|
||||
|
||||
Node stHead = Cache.dirty_lru_head();
|
||||
Node stNode = stHead;
|
||||
Node stPreNode = stNode.Prev();
|
||||
|
||||
/*case 1: delete continues time marker, until
|
||||
* encount a normal node/head node, go next
|
||||
* encount the only time marker*/
|
||||
while (1)
|
||||
{
|
||||
stNode = stPreNode;
|
||||
stPreNode = stNode.Prev();
|
||||
|
||||
if (!Cache.is_time_marker(stNode))
|
||||
break;
|
||||
|
||||
if (Cache.first_time_marker_time() == stNode.Time())
|
||||
{
|
||||
if (updateMode == MODE_SYNC && mem_dirty == true)
|
||||
{
|
||||
/* delete this time marker, flush all dirty node */
|
||||
Cache.remove_time_marker(stNode);
|
||||
stNode = stPreNode;
|
||||
stPreNode = stNode.Prev();
|
||||
while (stNode != stHead)
|
||||
{
|
||||
buffer_flush_data_timer(stNode, uiFlushRowsCnt);
|
||||
stNode = stPreNode;
|
||||
stPreNode = stNode.Prev();
|
||||
}
|
||||
|
||||
disable_timer();
|
||||
mem_dirty = false;
|
||||
log_notice("mem clean now for sync cache");
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
stamp = stNode.Time();
|
||||
if (stamp > last_rm_stamp)
|
||||
{
|
||||
last_rm_stamp = stamp;
|
||||
}
|
||||
|
||||
log_debug("remove time marker in dirty lru, time %u", stNode.Time());
|
||||
Cache.remove_time_marker(stNode);
|
||||
}
|
||||
|
||||
/*case 2: this the head node, clear mem dirty if nessary, return, should not happen*/
|
||||
if (stNode == stHead)
|
||||
{
|
||||
if (updateMode == MODE_SYNC && mem_dirty == true)
|
||||
{
|
||||
disable_timer();
|
||||
mem_dirty = false;
|
||||
log_notice("mem clean now for sync cache");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*case 3: this a normal node, flush it.
|
||||
* return -2 if no flush request added to cache process
|
||||
* */
|
||||
int iRet = buffer_flush_data_timer(stNode, uiFlushRowsCnt);
|
||||
if (iRet == -1 || iRet == -2 || iRet == -3 || iRet == 1)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BufferProcess::delete_tail_time_markers()
|
||||
{
|
||||
Node stHead = Cache.dirty_lru_head();
|
||||
Node stNode = stHead;
|
||||
Node stPreNode = stNode.Prev();
|
||||
|
||||
while (1)
|
||||
{
|
||||
stNode = stPreNode;
|
||||
stPreNode = stNode.Prev();
|
||||
|
||||
if (stNode == stHead || Cache.first_time_marker_time() == stNode.Time())
|
||||
break;
|
||||
|
||||
if (Cache.is_time_marker(stNode) && Cache.is_time_marker(stPreNode))
|
||||
Cache.remove_time_marker(stNode);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
49
src/search_local/index_storage/cache/buffer_flush.h
vendored
Normal file
49
src/search_local/index_storage/cache/buffer_flush.h
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: buffer_flush.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __H_CACHE_FLUSH_H__
|
||||
#define __H_CACHE_FLUSH_H__
|
||||
|
||||
#include "timer_list.h"
|
||||
#include "lqueue.h"
|
||||
#include "task_request.h"
|
||||
#include "buffer_process.h"
|
||||
#include "log.h"
|
||||
|
||||
class BufferProcess;
|
||||
|
||||
class DTCFlushRequest
|
||||
{
|
||||
private:
|
||||
BufferProcess *owner;
|
||||
int numReq;
|
||||
int badReq;
|
||||
TaskRequest *wait;
|
||||
|
||||
public:
|
||||
friend class BufferProcess;
|
||||
DTCFlushRequest(BufferProcess *, const char *key);
|
||||
~DTCFlushRequest(void);
|
||||
|
||||
const DTCTableDefinition *table_definition(void) const { return owner->table_definition(); }
|
||||
|
||||
int flush_row(const RowValue &);
|
||||
void complete_row(TaskRequest *req, int index);
|
||||
int Count(void) const { return numReq; }
|
||||
};
|
||||
|
||||
#endif
|
1561
src/search_local/index_storage/cache/buffer_pool.cc
vendored
Normal file
1561
src/search_local/index_storage/cache/buffer_pool.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
272
src/search_local/index_storage/cache/buffer_pool.h
vendored
Normal file
272
src/search_local/index_storage/cache/buffer_pool.h
vendored
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: buffer_pool.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __DTC_CACHE_POOL_H
|
||||
#define __DTC_CACHE_POOL_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "stat_dtc.h"
|
||||
#include "namespace.h"
|
||||
#include "pt_malloc.h"
|
||||
#include "shmem.h"
|
||||
#include "global.h"
|
||||
#include "node_list.h"
|
||||
#include "node_index.h"
|
||||
#include "node_set.h"
|
||||
#include "feature.h"
|
||||
#include "ng_info.h"
|
||||
#include "hash.h"
|
||||
#include "col_expand.h"
|
||||
#include "node.h"
|
||||
#include "timer_list.h"
|
||||
#include "data_chunk.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
/* time-marker node in dirty lru list */
|
||||
//#define TIME_MARKER_NEXT_NODE_ID INVALID_NODE_ID
|
||||
#define TIME_MARKER_NEXT_NODE_ID (INVALID_NODE_ID-1)
|
||||
|
||||
/* cache基本信息 */
|
||||
typedef struct _CacheInfo{
|
||||
int ipcMemKey; // 共享内存key
|
||||
uint64_t ipcMemSize; // 共享内存大小
|
||||
unsigned short keySize; // key大小
|
||||
unsigned char version; // 内存版本号
|
||||
unsigned char syncUpdate:1; // 同异步模式
|
||||
unsigned char readOnly:1; // 只读模式打开
|
||||
unsigned char createOnly:1; // 供mem_tool使用
|
||||
unsigned char emptyFilter:1; // 是否启用空节点过滤功能
|
||||
unsigned char autoDeleteDirtyShm:1; // 是否需要在检出到内存不完整时自动删除并重建共享内存
|
||||
unsigned char forceUpdateTableConf:1; // 是否需要强制使用table.conf更新共享内存中的配置
|
||||
|
||||
inline void Init(int keyFormat, unsigned long cacheSize, unsigned int createVersion)
|
||||
{
|
||||
// calculate buckettotal
|
||||
keySize = keyFormat;
|
||||
ipcMemSize = cacheSize;
|
||||
version = createVersion;
|
||||
}
|
||||
|
||||
} CacheInfo;
|
||||
|
||||
class PurgeNodeNotifier {
|
||||
public:
|
||||
PurgeNodeNotifier(){};
|
||||
virtual ~PurgeNodeNotifier(){};
|
||||
virtual void purge_node_notify(const char *key, Node node) = 0;
|
||||
};
|
||||
|
||||
class BufferProcess;
|
||||
class RawDataProcess;
|
||||
class TreeDataProcess;
|
||||
class DTCBufferPool : private TimerObject
|
||||
{
|
||||
protected:
|
||||
PurgeNodeNotifier *_purge_notifier;
|
||||
SharedMemory _shm; //共享内存管理器
|
||||
CacheInfo _cacheInfo; //cache基本信息
|
||||
|
||||
DTCHash *_hash; // hash桶
|
||||
NGInfo *_ngInfo; // node管理
|
||||
Feature *_feature; // 特性抽象
|
||||
NodeIndex *_nodeIndex; // NodeID转换
|
||||
//CTableInfo *_tableInfo; // Table信息
|
||||
DTCColExpand *_colExpand;
|
||||
|
||||
char _errmsg[256];
|
||||
int _need_set_integrity;
|
||||
|
||||
/* 待淘汰节点数目 */
|
||||
unsigned _need_purge_node_count;
|
||||
|
||||
TimerList * _delay_purge_timerlist;
|
||||
unsigned firstMarkerTime;
|
||||
unsigned lastMarkerTime;
|
||||
int emptyLimit;
|
||||
/**********for purge alert*******/
|
||||
int disableTryPurge;
|
||||
//如果自动淘汰的数据最后更新时间比当前时间减DataExpireAlertTime小则报警
|
||||
int dateExpireAlertTime;
|
||||
|
||||
|
||||
protected:
|
||||
/* for statistic*/
|
||||
StatItemU32 statCacheSize;
|
||||
StatItemU32 statCacheKey;
|
||||
StatItemU32 statCacheVersion;
|
||||
StatItemU32 statUpdateMode;
|
||||
StatItemU32 statEmptyFilter;
|
||||
StatItemU32 statHashSize;
|
||||
StatItemU32 statFreeBucket;
|
||||
StatItemU32 statDirtyEldest;
|
||||
StatItemU32 statDirtyAge;
|
||||
StatSample statTryPurgeCount;
|
||||
StatItemU32 statTryPurgeNodes;
|
||||
StatItemU32 statLastPurgeNodeModTime;//最后被淘汰的节点的lastcmod的最大值(如果多行)
|
||||
StatItemU32 statDataExistTime;//当前时间减去statLastPurgeNodeModTime
|
||||
StatSample survival_hour;
|
||||
StatSample statPurgeForCreateUpdateCount;
|
||||
private:
|
||||
int app_storage_open();
|
||||
int dtc_mem_open(APP_STORAGE_T *);
|
||||
int dtc_mem_attach(APP_STORAGE_T *);
|
||||
int dtc_mem_init(APP_STORAGE_T *);
|
||||
int verify_cache_info(CacheInfo *);
|
||||
unsigned int hash_bucket_num(uint64_t);
|
||||
|
||||
int remove_from_hash_base(const char *key, Node node, int newhash);
|
||||
int remove_from_hash(const char *key, Node node);
|
||||
int move_to_new_hash(const char *key, Node node);
|
||||
int Insert2Hash(const char *key, Node node);
|
||||
|
||||
int purge_node(const char *key, Node purge_node);
|
||||
int purge_node_everything(const char* key, Node purge_node);
|
||||
|
||||
/* purge alert*/
|
||||
int check_and_purge_node_everything(Node purge_node);
|
||||
uint32_t get_cmodtime(Node* purge_node);
|
||||
|
||||
uint32_t get_expire_time(Node *node, uint32_t &expire);
|
||||
|
||||
/* lru list op */
|
||||
int insert2_dirty_lru(Node node) {return _ngInfo->insert2_dirty_lru(node);}
|
||||
int insert2_clean_lru(Node node) {return _ngInfo->insert2_clean_lru(node);}
|
||||
int insert2_empty_lru(Node node) {
|
||||
return emptyLimit ?
|
||||
_ngInfo->insert2_empty_lru(node) :
|
||||
_ngInfo->insert2_clean_lru(node) ;
|
||||
|
||||
}
|
||||
int remove_from_lru(Node node) {return _ngInfo->remove_from_lru(node);}
|
||||
int key_cmp(const char *key, const char *other);
|
||||
|
||||
/* node|row count statistic for async flush.*/
|
||||
void inc_dirty_node(int v){ _ngInfo->inc_dirty_node(v);}
|
||||
void inc_dirty_row(int v) { _ngInfo->inc_dirty_row(v); }
|
||||
void dec_empty_node(void) { if(emptyLimit) _ngInfo->inc_empty_node(-1); }
|
||||
void inc_empty_node(void) {
|
||||
if(emptyLimit) {
|
||||
_ngInfo->inc_empty_node(1);
|
||||
if(_ngInfo->empty_count() > emptyLimit) {
|
||||
purge_single_empty_node();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned int total_dirty_node() const {return _ngInfo->total_dirty_node();}
|
||||
|
||||
const uint64_t total_dirty_row() const {return _ngInfo->total_dirty_row();}
|
||||
const uint64_t total_used_row() const {return _ngInfo->total_used_row();}
|
||||
|
||||
/*定期调度delay purge任务*/
|
||||
virtual void timer_notify(void);
|
||||
|
||||
public:
|
||||
DTCBufferPool(PurgeNodeNotifier *o = NULL);
|
||||
~DTCBufferPool();
|
||||
|
||||
int check_expand_status();
|
||||
unsigned char shm_table_idx();
|
||||
bool col_expand(const char *table, int len);
|
||||
int try_col_expand(const char *table, int len);
|
||||
bool reload_table();
|
||||
|
||||
int cache_open(CacheInfo *);
|
||||
void set_empty_node_limit(int v) { emptyLimit = v<0?0:v; }
|
||||
int init_empty_node_list(void);
|
||||
int upgrade_empty_node_list(void);
|
||||
int merge_empty_node_list(void);
|
||||
int prune_empty_node_list(void);
|
||||
int shrink_empty_node_list(void);
|
||||
int purge_single_empty_node(void);
|
||||
|
||||
Node cache_find(const char *key, int newhash);
|
||||
Node cache_find_auto_chose_hash(const char *key);
|
||||
int cache_purge(const char *key);
|
||||
int purge_node_everything(Node purge_node);
|
||||
Node cache_allocate(const char *key);
|
||||
int try_purge_size(size_t size, Node purge_node, unsigned count=2500);
|
||||
void disable_try_purge(void) { disableTryPurge = 1; }
|
||||
void set_date_expire_alert_time(int time){dateExpireAlertTime = time<0?0:time;};
|
||||
|
||||
/* 淘汰固定个节点 */
|
||||
void delay_purge_notify(const unsigned count=50);
|
||||
int pre_purge_nodes(int purge_cnt, Node reserve);
|
||||
int purge_by_time(unsigned int oldesttime);
|
||||
void start_delay_purge_task(TimerList *);
|
||||
|
||||
int insert_time_marker(unsigned int);
|
||||
int remove_time_marker(Node node);
|
||||
int is_time_marker(Node node) const;
|
||||
Node first_time_marker() const;
|
||||
Node last_time_marker() const;
|
||||
unsigned int first_time_marker_time();
|
||||
unsigned int last_time_marker_time();
|
||||
|
||||
Node dirty_lru_head() const;
|
||||
Node clean_lru_head() const;
|
||||
Node empty_lru_head() const;
|
||||
int dirty_lru_empty()const{return NODE_LIST_EMPTY(dirty_lru_head());}
|
||||
|
||||
const CacheInfo* get_cache_info() const { return &_cacheInfo;}
|
||||
const char *Error(void) const { return _errmsg; }
|
||||
|
||||
FEATURE_INFO_T* query_feature_by_id(const uint32_t id)
|
||||
{
|
||||
return _feature ? _feature->get_feature_by_id(id):(FEATURE_INFO_T *)(0);
|
||||
}
|
||||
|
||||
int add_feature(const uint32_t id, const MEM_HANDLE_T v)
|
||||
{
|
||||
if(_feature == NULL)
|
||||
return -1;
|
||||
return _feature->add_feature(id, v);
|
||||
}
|
||||
|
||||
int clear_create();
|
||||
|
||||
uint32_t max_node_id(void) const{
|
||||
return _ngInfo->max_node_id();
|
||||
}
|
||||
|
||||
NODE_ID_T min_valid_node_id(void) const {
|
||||
return _ngInfo->min_valid_node_id();
|
||||
}
|
||||
|
||||
const unsigned int total_used_node() const {return _ngInfo->total_used_node();}
|
||||
void inc_total_row(int v) { _ngInfo->inc_total_row(v); }
|
||||
|
||||
static int32_t node_rows_count(Node node) {
|
||||
if(!node || node.vd_handle() == INVALID_HANDLE)
|
||||
return 0;
|
||||
|
||||
DataChunk *chunk = ((DataChunk*)(DTCBinMalloc::Instance()->handle_to_ptr(node.vd_handle())));
|
||||
if(!chunk) return 0;
|
||||
|
||||
return chunk->total_rows();
|
||||
}
|
||||
|
||||
friend class BufferProcess;
|
||||
friend class RawDataProcess;
|
||||
friend class TreeDataProcess;
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
2433
src/search_local/index_storage/cache/buffer_process.cc
vendored
Normal file
2433
src/search_local/index_storage/cache/buffer_process.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
520
src/search_local/index_storage/cache/buffer_process.h
vendored
Normal file
520
src/search_local/index_storage/cache/buffer_process.h
vendored
Normal file
@ -0,0 +1,520 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: buffer_process.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __CACHE_RPOCESS
|
||||
#define __CACHE_RPOCESS
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "protocol.h"
|
||||
#include "value.h"
|
||||
#include "field.h"
|
||||
#include "section.h"
|
||||
#include "table_def.h"
|
||||
#include "task_request.h"
|
||||
#include "list.h"
|
||||
#include "fence.h"
|
||||
#include "buffer_pool.h"
|
||||
#include "poll_thread.h"
|
||||
#include "dbconfig.h"
|
||||
#include "lqueue.h"
|
||||
#include "stat_dtc.h"
|
||||
#include "data_process.h"
|
||||
#include "empty_filter.h"
|
||||
#include "namespace.h"
|
||||
#include "task_pendlist.h"
|
||||
#include "data_chunk.h"
|
||||
#include "hb_log.h"
|
||||
#include "lru_bit.h"
|
||||
#include "hb_feature.h"
|
||||
#include "blacklist_unit.h"
|
||||
#include "expire_time.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
class DTCFlushRequest;
|
||||
class BufferProcess;
|
||||
class DTCTableDefinition;
|
||||
class TaskPendingList;
|
||||
enum BufferResult {
|
||||
BUFFER_PROCESS_ERROR =-1,
|
||||
BUFFER_PROCESS_OK =0,
|
||||
BUFFER_PROCESS_NEXT =1,
|
||||
BUFFER_PROCESS_PENDING =2,
|
||||
BUFFER_PROCESS_REMOTE =3 ,
|
||||
BUFFER_PROCESS_PUSH_HB = 4
|
||||
};
|
||||
typedef unsigned int MARKER_STAMP;
|
||||
|
||||
class BufferReplyNotify: public ReplyDispatcher<TaskRequest> {
|
||||
private:
|
||||
BufferProcess *owner;
|
||||
public:
|
||||
BufferReplyNotify(BufferProcess *o) :
|
||||
owner(o)
|
||||
{}
|
||||
virtual ~BufferReplyNotify(){}
|
||||
virtual void reply_notify(TaskRequest *);
|
||||
};
|
||||
|
||||
class FlushReplyNotify: public ReplyDispatcher<TaskRequest> {
|
||||
private:
|
||||
BufferProcess *owner;
|
||||
public:
|
||||
FlushReplyNotify(BufferProcess *o) :
|
||||
owner(o)
|
||||
{}
|
||||
virtual ~FlushReplyNotify(){}
|
||||
virtual void reply_notify(TaskRequest *);
|
||||
};
|
||||
|
||||
class HotBackReplay : public ReplyDispatcher<TaskRequest>
|
||||
{
|
||||
public:
|
||||
HotBackReplay() {}
|
||||
virtual ~HotBackReplay() {}
|
||||
virtual void reply_notify(TaskRequest *task);
|
||||
};
|
||||
|
||||
enum {
|
||||
LRU_NONE=0,
|
||||
LRU_BATCH,
|
||||
LRU_READ,
|
||||
LRU_WRITE,
|
||||
LRU_ALWAYS=999,
|
||||
};
|
||||
|
||||
enum {
|
||||
NODESTAT_MISSING,
|
||||
NODESTAT_EMPTY,
|
||||
NODESTAT_PRESENT
|
||||
};
|
||||
|
||||
struct CacheTransation {
|
||||
TaskRequest *curTask;
|
||||
const char *ptrKey;
|
||||
Node m_stNode;
|
||||
int oldRows;
|
||||
uint8_t nodeStat;
|
||||
uint8_t keyDirty;
|
||||
uint8_t nodeEmpty;
|
||||
uint8_t lruUpdate;
|
||||
int logtype; // OLD ASYNC TRANSATION LOG
|
||||
RawData *fstLogRows; // OLD ASYNC TRANSATION LOG
|
||||
RawData *pstLogRows; // OLD ASYNC TRANSATION LOG
|
||||
|
||||
void Init(TaskRequest *task) {
|
||||
memset(this, 0, sizeof(CacheTransation));
|
||||
curTask = task;
|
||||
}
|
||||
|
||||
void Free(void) {
|
||||
if(fstLogRows) delete fstLogRows;
|
||||
fstLogRows = NULL;
|
||||
pstLogRows = NULL;
|
||||
logtype = 0;
|
||||
|
||||
ptrKey = NULL;
|
||||
m_stNode = Node::Empty();
|
||||
nodeStat = 0;
|
||||
keyDirty = 0;
|
||||
oldRows = 0;
|
||||
nodeEmpty = 0;
|
||||
lruUpdate = 0;
|
||||
//curTask = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
class BufferProcess :
|
||||
public TaskDispatcher<TaskRequest>,
|
||||
private TimerObject,
|
||||
public PurgeNodeNotifier,
|
||||
public CacheTransation
|
||||
{
|
||||
protected: // base members
|
||||
// cache chain control
|
||||
RequestOutput<TaskRequest> output;
|
||||
RequestOutput<TaskRequest> remoteoutput;//将请求传给远端dtc,用于migrate命令
|
||||
RequestOutput<TaskRequest> hblogoutput; // hblog task output
|
||||
BufferReplyNotify cacheReply;
|
||||
|
||||
// table info
|
||||
DTCTableDefinition *tableDef;
|
||||
// cache memory management
|
||||
DTCBufferPool Cache;
|
||||
DataProcess* pstDataProcess;
|
||||
CacheInfo cacheInfo;
|
||||
|
||||
// no backup db
|
||||
bool nodbMode;
|
||||
// full cache
|
||||
bool fullMode;
|
||||
bool lossyMode;
|
||||
// treat empty key as default value, flat bitmap emulation
|
||||
bool m_bReplaceEmpty;
|
||||
// lru update level
|
||||
int noLRU;
|
||||
// working mode
|
||||
EUpdateMode asyncServer;
|
||||
EUpdateMode updateMode;
|
||||
EUpdateMode insertMode;
|
||||
/*indicate mem dirty when start with sync dtc*/
|
||||
bool mem_dirty;
|
||||
// server side sorting
|
||||
unsigned char insertOrder;
|
||||
|
||||
// cache protection
|
||||
int nodeSizeLimit; //node size limit
|
||||
int nodeRowsLimit; //node rows limit
|
||||
int nodeEmptyLimit; //empty nodes limit
|
||||
|
||||
// generated error message
|
||||
char szErrMsg[256];
|
||||
|
||||
int maxExpireCount;
|
||||
int maxExpireTime;
|
||||
|
||||
|
||||
protected: // stat subsystem
|
||||
StatItemU32 statGetCount;
|
||||
StatItemU32 statGetHits;
|
||||
StatItemU32 statInsertCount;
|
||||
StatItemU32 statInsertHits;
|
||||
StatItemU32 statUpdateCount;
|
||||
StatItemU32 statUpdateHits;
|
||||
StatItemU32 statDeleteCount;
|
||||
StatItemU32 statDeleteHits;
|
||||
StatItemU32 statPurgeCount;
|
||||
|
||||
StatItemU32 statDropCount;
|
||||
StatItemU32 statDropRows;
|
||||
StatItemU32 statFlushCount;
|
||||
StatItemU32 statFlushRows;
|
||||
StatSample statIncSyncStep;
|
||||
|
||||
StatItemU32 statMaxFlushReq;
|
||||
StatItemU32 statCurrFlushReq;
|
||||
StatItemU32 statOldestDirtyTime;
|
||||
StatItemU32 statAsyncFlushCount;
|
||||
|
||||
StatItemU32 statExpireCount;
|
||||
StatItemU32 statBufferProcessExpireCount;
|
||||
protected: // async flush members
|
||||
FlushReplyNotify flushReply;
|
||||
TimerList *flushTimer;
|
||||
volatile int nFlushReq; // current pending node
|
||||
volatile int mFlushReq; // pending node limit
|
||||
volatile unsigned short maxFlushReq; // max speed
|
||||
volatile unsigned short markerInterval;
|
||||
volatile int minDirtyTime;
|
||||
volatile int maxDirtyTime;
|
||||
// async log writer
|
||||
int noAsyncLog;
|
||||
|
||||
|
||||
protected:
|
||||
//空节点过滤
|
||||
EmptyNodeFilter *m_pstEmptyNodeFilter;
|
||||
|
||||
protected:
|
||||
// Hot Backup
|
||||
//记录更新key
|
||||
bool hbLogSwitch;
|
||||
//记录lru变更
|
||||
|
||||
HBFeature* hbFeature;
|
||||
// Hot Backup
|
||||
|
||||
protected:
|
||||
// BlackList
|
||||
BlackListUnit *blacklist;
|
||||
TimerList *blacklist_timer;
|
||||
// BlackList
|
||||
|
||||
ExpireTime *key_expire;
|
||||
TimerList *key_expire_timer;
|
||||
HotBackReplay hotbackReply;
|
||||
private:
|
||||
// level 1 processing
|
||||
// GET entrance
|
||||
BufferResult buffer_get_data (TaskRequest &Task);
|
||||
// GET batch entrance
|
||||
BufferResult buffer_batch_get_data (TaskRequest &Task);
|
||||
// GET response, DB --> cache
|
||||
BufferResult buffer_replace_result (TaskRequest &Task);
|
||||
// GET response, DB --> client
|
||||
BufferResult buffer_get_rb (TaskRequest &Task);
|
||||
|
||||
// implementation some admin/purge/flush function
|
||||
BufferResult buffer_process_admin(TaskRequest &Task);
|
||||
BufferResult buffer_purge_data (TaskRequest &Task);
|
||||
BufferResult buffer_flush_data(TaskRequest &Task);
|
||||
BufferResult buffer_flush_data_before_delete(TaskRequest &Task);
|
||||
int buffer_flush_data_timer(Node& stNode, unsigned int& uiFlushRowsCnt);
|
||||
BufferResult buffer_flush_data(Node& stNode, TaskRequest* pstTask, unsigned int& uiFlushRowsCnt);
|
||||
|
||||
// sync mode operation, called by reply
|
||||
BufferResult buffer_sync_insert_precheck (TaskRequest& task);
|
||||
BufferResult buffer_sync_insert (TaskRequest& task);
|
||||
BufferResult buffer_sync_update (TaskRequest& task);
|
||||
BufferResult buffer_sync_replace (TaskRequest& task);
|
||||
BufferResult buffer_sync_delete (TaskRequest& task);
|
||||
|
||||
// async mode operation, called by entrance
|
||||
BufferResult buffer_async_insert (TaskRequest& task);
|
||||
BufferResult buffer_async_update (TaskRequest& task);
|
||||
BufferResult buffer_async_replace (TaskRequest& task);
|
||||
|
||||
// fullcache mode operation, called by entrance
|
||||
BufferResult buffer_nodb_insert (TaskRequest& task);
|
||||
BufferResult buffer_nodb_update (TaskRequest& task);
|
||||
BufferResult buffer_nodb_replace (TaskRequest& task);
|
||||
BufferResult buffer_nodb_delete (TaskRequest& task);
|
||||
|
||||
// level 2 operation
|
||||
// level 2: INSERT with async compatible, create node & clear empty filter
|
||||
BufferResult buffer_insert_row (TaskRequest &Task, bool async, bool setrows);
|
||||
// level 2: UPDATE with async compatible, accept empty node only if EmptyAsDefault
|
||||
BufferResult buffer_update_rows (TaskRequest &Task, bool async, bool setrows);
|
||||
// level 2: REPLACE with async compatible, don't allow empty node
|
||||
BufferResult buffer_replace_rows (TaskRequest &Task, bool async, bool setrows);
|
||||
// level 2: DELETE has no async mode, don't allow empty node
|
||||
BufferResult buffer_delete_rows (TaskRequest &Task);
|
||||
|
||||
// very low level
|
||||
// 空结点inset default值进cache内存
|
||||
// auto clear empty filter
|
||||
BufferResult InsertDefaultRow(TaskRequest &Task);
|
||||
bool InsertEmptyNode(void);
|
||||
|
||||
// 热备操作
|
||||
BufferResult buffer_register_hb(TaskRequest &Task);
|
||||
BufferResult buffer_logout_hb(TaskRequest &Task);
|
||||
BufferResult buffer_get_key_list(TaskRequest &Task);
|
||||
BufferResult buffer_get_update_key(TaskRequest &Task);
|
||||
BufferResult buffer_get_raw_data(TaskRequest &Task);
|
||||
BufferResult buffer_replace_raw_data(TaskRequest &Task);
|
||||
BufferResult buffer_adjust_lru(TaskRequest &Task);
|
||||
BufferResult buffer_verify_hbt(TaskRequest &Task);
|
||||
BufferResult buffer_get_hbt(TaskRequest &Task);
|
||||
|
||||
//内存整理操作
|
||||
BufferResult buffer_nodehandlechange(TaskRequest &Task);
|
||||
|
||||
// column expand related
|
||||
BufferResult buffer_check_expand_status(TaskRequest &Task);
|
||||
BufferResult buffer_column_expand(TaskRequest &Task);
|
||||
BufferResult buffer_column_expand_done(TaskRequest &Task);
|
||||
BufferResult buffer_column_expand_key(TaskRequest &Task);
|
||||
|
||||
//迁移操作
|
||||
BufferResult buffer_migrate(TaskRequest &Task);
|
||||
|
||||
// clear cache(only support nodb mode)
|
||||
BufferResult buffer_clear_cache(TaskRequest &Task);
|
||||
|
||||
/* we can still purge clean node if hit ratio is ok */
|
||||
BufferResult cache_purgeforhit(TaskRequest &Task);
|
||||
|
||||
//rows限制
|
||||
BufferResult check_allowed_insert(TaskRequest &Task);
|
||||
|
||||
BufferResult buffer_query_serverinfo(TaskRequest &Task);
|
||||
|
||||
// 主从复制操作
|
||||
BufferResult buffer_process_replicate(TaskRequest &Task);
|
||||
|
||||
// 热备日志
|
||||
int write_hb_log(const char* key, char *pstChunk, unsigned int uiNodeSize, int iType);
|
||||
int write_hb_log(const char* key, Node& stNode, int iType);
|
||||
int write_hb_log(TaskRequest &Task, Node& stNode, int iType);
|
||||
int write_lru_hb_log(const char* key);
|
||||
public:
|
||||
virtual void purge_node_notify(const char *key, Node node);
|
||||
/* inc flush task stat(created by flush dirty node function) */
|
||||
void inc_async_flush_stat() { statAsyncFlushCount++; }
|
||||
|
||||
private:
|
||||
virtual void task_notify(TaskRequest *);
|
||||
void reply_notify(TaskRequest *);
|
||||
|
||||
// flush internal
|
||||
virtual void timer_notify(void);
|
||||
int flush_next_node(void);
|
||||
void delete_tail_time_markers();
|
||||
void get_dirty_stat();
|
||||
void calculate_flush_speed(int is_flush_timer);
|
||||
MARKER_STAMP calculate_current_marker();
|
||||
|
||||
BufferProcess (const BufferProcess& robj);
|
||||
BufferProcess& operator= (const BufferProcess& robj);
|
||||
|
||||
public:
|
||||
BufferProcess (PollThread *, DTCTableDefinition *, EUpdateMode async);
|
||||
~BufferProcess (void);
|
||||
|
||||
const DTCTableDefinition *table_definition(void) const { return tableDef; }
|
||||
const char *last_error_message(void) const { return szErrMsg[0] ? szErrMsg : "unknown error"; }
|
||||
|
||||
void set_limit_node_size(int node_size) {
|
||||
nodeSizeLimit = node_size;
|
||||
}
|
||||
|
||||
/* 0 = no limit */
|
||||
void set_limit_node_rows(int rows) {
|
||||
nodeRowsLimit = rows < 0 ? 0 : rows;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 0 = no limit,
|
||||
* 1-999: invalid, use 1000 instead
|
||||
* 1000-1G: max empty node count
|
||||
* >1G: invalid, no limit
|
||||
*/
|
||||
void set_limit_empty_nodes(int nodes) {
|
||||
nodeEmptyLimit = nodes <= 0 ? 0 :
|
||||
nodes < 1000 ? 1000 :
|
||||
nodes > (1<<30) ? 0 :
|
||||
nodes;
|
||||
return;
|
||||
}
|
||||
|
||||
void disable_auto_purge(void) {
|
||||
Cache.disable_try_purge();
|
||||
}
|
||||
|
||||
void set_date_expire_alert_time(int time) {
|
||||
Cache.set_date_expire_alert_time(time);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 设置cache内存大小以及版本
|
||||
Input: cacheSize 共享内存的大小
|
||||
createVersion cache内存版本号
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int buffer_set_size(unsigned long cacheSize, unsigned int createVersion);
|
||||
|
||||
/*************************************************
|
||||
Description: 打开共享内存并初始化
|
||||
Input: iIpcKey 共享内存的key
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int cache_open(int iIpcKey, int iEnableEmptyFilter, int iEnableAutoDeleteDirtyShm);
|
||||
|
||||
int update_mode(void) const { return updateMode; }
|
||||
int enable_no_db_mode(void);
|
||||
void enable_lossy_data_source(int v) { lossyMode = v == 0 ? false : true; }
|
||||
int disable_lru_update(int);
|
||||
int disable_async_log(int);
|
||||
|
||||
/*************************************************
|
||||
Description: 处理task请求
|
||||
Input: Task task请求
|
||||
Output:
|
||||
Return: BUFFER_PROCESS_OK为成功,CACHE_PROCESS_NEXT为转交helper处理,CACHE_PROCESS_PENDING为flush请求需要等待
|
||||
BUFFER_PROCESS_ERROR为错误
|
||||
*************************************************/
|
||||
BufferResult buffer_process_request(TaskRequest &Task);
|
||||
|
||||
/*************************************************
|
||||
Description: 处理helper的回应
|
||||
Input: Task task请求
|
||||
Output:
|
||||
Return: BUFFER_PROCESS_OK为成功,BUFFER_PROCESS_ERROR为错误
|
||||
*************************************************/
|
||||
BufferResult buffer_process_reply(TaskRequest &Task);
|
||||
|
||||
/*************************************************
|
||||
Description: 处理helper的回应
|
||||
Input: Task task请求
|
||||
Output:
|
||||
Return: BUFFER_PROCESS_OK为成功,BUFFER_PROCESS_ERROR为错误
|
||||
*************************************************/
|
||||
BufferResult buffer_process_batch(TaskRequest &Task);
|
||||
|
||||
/*************************************************
|
||||
Description: 处理helper的回应
|
||||
Input: Task task请求
|
||||
Output:
|
||||
Return: BUFFER_PROCESS_OK为成功,BUFFER_PROCESS_ERROR为错误
|
||||
*************************************************/
|
||||
BufferResult buffer_process_nodb(TaskRequest &Task);
|
||||
|
||||
/*************************************************
|
||||
Description: 处理flush请求的helper回应
|
||||
Input: Task task请求
|
||||
Output:
|
||||
Return: BUFFER_PROCESS_OK为成功,BUFFER_PROCESS_ERROR为错误
|
||||
*************************************************/
|
||||
BufferResult buffer_flush_reply(TaskRequest &Task);
|
||||
|
||||
/*************************************************
|
||||
Description: task出错的处理
|
||||
Input: Task task请求
|
||||
Output:
|
||||
Return: BUFFER_PROCESS_OK为成功,BUFFER_PROCESS_ERROR为错误
|
||||
*************************************************/
|
||||
BufferResult buffer_process_error(TaskRequest &Task);
|
||||
|
||||
void print_row(const RowValue *r);
|
||||
int set_insert_order(int o);
|
||||
void set_replace_empty(bool v) { m_bReplaceEmpty = v; }
|
||||
|
||||
// stage relate
|
||||
void bind_dispatcher(TaskDispatcher<TaskRequest> *p) { output.bind_dispatcher(p); }
|
||||
void bind_dispatcher_remote(TaskDispatcher<TaskRequest> *p) { remoteoutput.bind_dispatcher(p); }
|
||||
void bind_hb_log_dispatcher(TaskDispatcher<TaskRequest> *p) { hblogoutput.bind_dispatcher(p); }
|
||||
|
||||
// flush api
|
||||
void set_flush_parameter(int, int, int, int);
|
||||
void set_drop_count(int); // to be remove
|
||||
int commit_flush_request(DTCFlushRequest *, TaskRequest*);
|
||||
void complete_flush_request(DTCFlushRequest *);
|
||||
void push_flush_queue(TaskRequest *p) { p->push_reply_dispatcher(&flushReply); output.indirect_notify(p); }
|
||||
inline bool is_mem_dirty() {return mem_dirty;}
|
||||
int oldest_dirty_node_alarm();
|
||||
|
||||
// expire
|
||||
BufferResult check_and_expire(TaskRequest &Task);
|
||||
|
||||
|
||||
friend class TaskPendingList;
|
||||
friend class BufferReplyNotify;
|
||||
|
||||
public:
|
||||
// transation implementation
|
||||
inline void transation_begin(TaskRequest *task) { CacheTransation::Init(task); }
|
||||
void transation_end(void);
|
||||
inline int transation_find_node(TaskRequest &task);
|
||||
inline void transation_update_lru(bool async, int type);
|
||||
void dispatch_hot_back_task(TaskRequest *task)
|
||||
{
|
||||
|
||||
task->push_reply_dispatcher(&hotbackReply);
|
||||
hblogoutput.task_notify(task);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
183
src/search_local/index_storage/cache/buffer_reader.cc
vendored
Normal file
183
src/search_local/index_storage/cache/buffer_reader.cc
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: buffer_reader.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "task_pkey.h"
|
||||
#include "buffer_reader.h"
|
||||
#include "log.h"
|
||||
#include "sys_malloc.h"
|
||||
|
||||
BufferReader::BufferReader(void) : DTCBufferPool(NULL)
|
||||
{
|
||||
pstItem = NULL;
|
||||
pstDataProcess = NULL;
|
||||
iInDirtyLRU = 1;
|
||||
notFetch = 1;
|
||||
}
|
||||
|
||||
BufferReader::~BufferReader(void)
|
||||
{
|
||||
if (pstItem != NULL)
|
||||
delete pstItem;
|
||||
pstItem = NULL;
|
||||
}
|
||||
|
||||
int BufferReader::cache_open(int shmKey, int keySize, DTCTableDefinition *pstTab)
|
||||
{
|
||||
int iRet;
|
||||
|
||||
CacheInfo stInfo;
|
||||
memset(&stInfo, 0, sizeof(stInfo));
|
||||
stInfo.ipcMemKey = shmKey;
|
||||
stInfo.keySize = keySize;
|
||||
stInfo.readOnly = 1;
|
||||
|
||||
iRet = DTCBufferPool::cache_open(&stInfo);
|
||||
if (iRet != E_OK)
|
||||
return -1;
|
||||
|
||||
pstItem = new RawData(&g_stSysMalloc, 1);
|
||||
if (pstItem == NULL)
|
||||
{
|
||||
snprintf(error_message, sizeof(error_message), "new RawData error: %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
UpdateMode stUpdateMod;
|
||||
stUpdateMod.m_iAsyncServer = MODE_SYNC;
|
||||
stUpdateMod.m_iUpdateMode = MODE_SYNC;
|
||||
stUpdateMod.m_iInsertMode = MODE_SYNC;
|
||||
stUpdateMod.m_uchInsertOrder = 0;
|
||||
|
||||
if (pstTab->index_fields() > 0)
|
||||
{
|
||||
#if HAS_TREE_DATA
|
||||
pstDataProcess = new TreeDataProcess(DTCBinMalloc::Instance(), pstTab, this, &stUpdateMod);
|
||||
#else
|
||||
log_error("tree index not supported, index field num[%d]", pstTab->index_fields());
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
pstDataProcess = new RawDataProcess(DTCBinMalloc::Instance(), pstTab, this, &stUpdateMod);
|
||||
if (pstDataProcess == NULL)
|
||||
{
|
||||
log_error("create %s error: %m", pstTab->index_fields() > 0 ? "TreeDataProcess" : "RawDataProcess");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BufferReader::begin_read()
|
||||
{
|
||||
stDirtyHead = dirty_lru_head();
|
||||
stClrHead = clean_lru_head();
|
||||
if (!dirty_lru_empty())
|
||||
{
|
||||
iInDirtyLRU = 1;
|
||||
stCurNode = stDirtyHead;
|
||||
}
|
||||
else
|
||||
{
|
||||
iInDirtyLRU = 0;
|
||||
stCurNode = stClrHead;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BufferReader::fetch_node()
|
||||
{
|
||||
|
||||
pstItem->Destroy();
|
||||
if (!stCurNode)
|
||||
{
|
||||
snprintf(error_message, sizeof(error_message), "begin read first!");
|
||||
return -1;
|
||||
}
|
||||
if (end())
|
||||
{
|
||||
snprintf(error_message, sizeof(error_message), "reach end of cache");
|
||||
return -2;
|
||||
}
|
||||
notFetch = 0;
|
||||
|
||||
curRowIdx = 0;
|
||||
if (iInDirtyLRU)
|
||||
{
|
||||
while (stCurNode != stDirtyHead && is_time_marker(stCurNode))
|
||||
stCurNode = stCurNode.Next();
|
||||
if (stCurNode != stDirtyHead && !is_time_marker(stCurNode))
|
||||
{
|
||||
if (pstDataProcess->get_all_rows(&stCurNode, pstItem) != 0)
|
||||
{
|
||||
snprintf(error_message, sizeof(error_message), "get node's data error");
|
||||
return -3;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
iInDirtyLRU = 0;
|
||||
stCurNode = stClrHead.Next();
|
||||
}
|
||||
|
||||
stCurNode = stCurNode.Next();
|
||||
if (stCurNode != stClrHead)
|
||||
{
|
||||
if (pstDataProcess->get_all_rows(&stCurNode, pstItem) != 0)
|
||||
{
|
||||
snprintf(error_message, sizeof(error_message), "get node's data error");
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(error_message, sizeof(error_message), "reach end of cache");
|
||||
return -2;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int BufferReader::num_rows()
|
||||
{
|
||||
if (pstItem == NULL)
|
||||
return (-1);
|
||||
|
||||
return pstItem->total_rows();
|
||||
}
|
||||
|
||||
int BufferReader::read_row(RowValue &row)
|
||||
{
|
||||
while (notFetch || curRowIdx >= (int)pstItem->total_rows())
|
||||
{
|
||||
if (fetch_node() != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
TaskPackedKey::unpack_key(row.table_definition(), pstItem->Key(), row.field_value(0));
|
||||
|
||||
if (pstItem->decode_row(row, uchRowFlags, 0) != 0)
|
||||
return -2;
|
||||
|
||||
curRowIdx++;
|
||||
|
||||
return 0;
|
||||
}
|
63
src/search_local/index_storage/cache/buffer_reader.h
vendored
Normal file
63
src/search_local/index_storage/cache/buffer_reader.h
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: buffer_reader.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __CACHE_READER_H
|
||||
#define __CACHE_READER_H
|
||||
|
||||
#include "reader_interface.h"
|
||||
#include "buffer_pool.h"
|
||||
#include "table_def.h"
|
||||
#include "raw_data_process.h"
|
||||
|
||||
class BufferReader : public ReaderInterface, public DTCBufferPool
|
||||
{
|
||||
private:
|
||||
Node stClrHead;
|
||||
Node stDirtyHead;
|
||||
int iInDirtyLRU;
|
||||
Node stCurNode;
|
||||
unsigned char uchRowFlags;
|
||||
RawData *pstItem;
|
||||
DataProcess *pstDataProcess;
|
||||
int notFetch;
|
||||
int curRowIdx;
|
||||
char error_message[200];
|
||||
|
||||
public:
|
||||
BufferReader(void);
|
||||
~BufferReader(void);
|
||||
|
||||
int cache_open(int shmKey, int keySize, DTCTableDefinition *pstTab);
|
||||
|
||||
const char *err_msg() { return error_message; }
|
||||
int begin_read();
|
||||
int read_row(RowValue &row);
|
||||
int end();
|
||||
int key_flags(void) const { return stCurNode.is_dirty(); }
|
||||
int key_flag_dirty(void) const { return stCurNode.is_dirty(); }
|
||||
int row_flags(void) const { return uchRowFlags; }
|
||||
int row_flag_dirty(void) const { return uchRowFlags & OPER_DIRTY; }
|
||||
int fetch_node();
|
||||
int num_rows();
|
||||
};
|
||||
|
||||
inline int BufferReader::end()
|
||||
{
|
||||
return (iInDirtyLRU == 0) && (notFetch == 0) && (stCurNode == stClrHead);
|
||||
}
|
||||
|
||||
#endif
|
421
src/search_local/index_storage/cache/buffer_remoteLog.h
vendored
Normal file
421
src/search_local/index_storage/cache/buffer_remoteLog.h
vendored
Normal file
@ -0,0 +1,421 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: buffer_remoteLog.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef _CACHE_REMOTE_LOG_
|
||||
#define _CACHE_REMOTE_LOG_
|
||||
|
||||
#include "value.h"
|
||||
#include <task_request.h>
|
||||
#include "singleton.h"
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include "table_def.h"
|
||||
#include "protocol.h"
|
||||
#include "log.h"
|
||||
#include <stdio.h>
|
||||
#define REMOTELOG_OP_FLOW_TYPE 1
|
||||
extern void remote_log(int type, const char *key, int op_type, int op_result, char *content, long op_time, int cmd, int magic, int contentlen);
|
||||
enum E_TASK_PROCESS_STAGE
|
||||
{
|
||||
TASK_NOTIFY_STAGE = 0,
|
||||
TASK_REPLY_STAGE = 1
|
||||
};
|
||||
|
||||
class CacheRemoteLog
|
||||
{
|
||||
public:
|
||||
CacheRemoteLog() : m_curtask(NULL), m_IsNoDbMode(false), m_TableDef(0), m_UpdateMode(MODE_SYNC), m_InsertMode(MODE_SYNC), m_RemotePort(0), m_OpLog(false)
|
||||
{
|
||||
}
|
||||
~CacheRemoteLog()
|
||||
{
|
||||
}
|
||||
void set_remote_port(int iPort)
|
||||
{
|
||||
m_RemotePort = iPort;
|
||||
}
|
||||
void set_op_log_on()
|
||||
{
|
||||
m_OpLog = true;
|
||||
}
|
||||
void set_remote_log_mode(DTCTableDefinition *tableDef, bool isNoDbMode, EUpdateMode insertMode, EUpdateMode updateMode)
|
||||
{
|
||||
this->m_TableDef = tableDef;
|
||||
this->m_IsNoDbMode = isNoDbMode;
|
||||
this->m_UpdateMode = updateMode;
|
||||
this->m_InsertMode = insertMode;
|
||||
}
|
||||
|
||||
void write_remote_log(uint64_t ddwOptime, TaskRequest *curtask, E_TASK_PROCESS_STAGE stage)
|
||||
{
|
||||
if (0 == m_RemotePort)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!m_OpLog)
|
||||
return;
|
||||
this->m_curtask = curtask;
|
||||
if (NULL == m_curtask)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((DRequest::Get == m_curtask->request_code()) || (DRequest::SvrAdmin == m_curtask->request_code()))
|
||||
{
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((DRequest::Replace == m_curtask->request_code()) && (m_UpdateMode == MODE_ASYNC || m_InsertMode == MODE_ASYNC))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL == m_TableDef)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (DRequest::Purge == m_curtask->request_code())
|
||||
{
|
||||
std::string strPurgeContent = "purge Node";
|
||||
remote_log(REMOTELOG_OP_FLOW_TYPE, extract_key().c_str(), DRequest::Purge,
|
||||
0, const_cast<char *>(strPurgeContent.c_str()), ddwOptime, 0, 0, strPurgeContent.length());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_IsNoDbMode)
|
||||
{
|
||||
|
||||
if (TASK_NOTIFY_STAGE == stage)
|
||||
{
|
||||
|
||||
if ((m_UpdateMode == MODE_SYNC) && ((m_InsertMode == MODE_SYNC)))
|
||||
{
|
||||
|
||||
return;
|
||||
}
|
||||
write_task_notify_stage_log(ddwOptime);
|
||||
return;
|
||||
}
|
||||
if (TASK_REPLY_STAGE == stage)
|
||||
{
|
||||
|
||||
write_task_reply_stage_log(ddwOptime);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
write_no_db_op_log(ddwOptime);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void write_task_notify_stage_log(uint64_t ddwOptime)
|
||||
{
|
||||
std::stringstream oss;
|
||||
oss << "task notify stage, Async mode , ";
|
||||
if ((DRequest::Update == m_curtask->request_code()) && (m_UpdateMode == MODE_ASYNC))
|
||||
{
|
||||
oss << extract_update_content();
|
||||
remote_log(REMOTELOG_OP_FLOW_TYPE, extract_key().c_str(), m_curtask->request_code(),
|
||||
m_curtask->result_code(), const_cast<char *>(oss.str().c_str()), ddwOptime, 0, 0, oss.str().length());
|
||||
}
|
||||
if ((DRequest::Insert == m_curtask->request_code()) && (m_InsertMode == MODE_ASYNC))
|
||||
{
|
||||
oss << extract_insert_content();
|
||||
remote_log(REMOTELOG_OP_FLOW_TYPE, extract_key().c_str(), m_curtask->request_code(),
|
||||
m_curtask->result_code(), const_cast<char *>(oss.str().c_str()), ddwOptime, 0, 0, oss.str().length());
|
||||
}
|
||||
if ((DRequest::Replace == m_curtask->request_code()) && (m_UpdateMode == MODE_ASYNC))
|
||||
{
|
||||
oss << extract_replace_content();
|
||||
remote_log(REMOTELOG_OP_FLOW_TYPE, extract_key().c_str(), m_curtask->request_code(),
|
||||
m_curtask->result_code(), const_cast<char *>(oss.str().c_str()), ddwOptime, 0, 0, oss.str().length());
|
||||
}
|
||||
}
|
||||
|
||||
void write_task_reply_stage_log(uint64_t ddwOptime)
|
||||
{
|
||||
std::stringstream oss;
|
||||
oss << "task reply stage, ";
|
||||
oss << get_op_content();
|
||||
remote_log(REMOTELOG_OP_FLOW_TYPE, extract_key().c_str(), m_curtask->request_code(),
|
||||
m_curtask->result_code(), const_cast<char *>(oss.str().c_str()), ddwOptime, 0, 0, oss.str().length());
|
||||
}
|
||||
|
||||
void write_no_db_op_log(uint64_t ddwOptime)
|
||||
{
|
||||
std::string strContent = get_no_db_op_content();
|
||||
remote_log(REMOTELOG_OP_FLOW_TYPE, extract_key().c_str(), m_curtask->request_code(),
|
||||
m_curtask->result_code(), const_cast<char *>(strContent.c_str()), ddwOptime, 0, 0, strContent.length());
|
||||
}
|
||||
std::string get_no_db_op_content()
|
||||
{
|
||||
|
||||
std::stringstream oss;
|
||||
oss << "NoDb Op,content: " << get_op_content();
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string get_op_content()
|
||||
{
|
||||
if (DRequest::Update == m_curtask->request_code())
|
||||
{
|
||||
return extract_update_content();
|
||||
}
|
||||
else if (DRequest::Insert == m_curtask->request_code())
|
||||
{
|
||||
return extract_insert_content();
|
||||
}
|
||||
else if (DRequest::Delete == m_curtask->request_code())
|
||||
{
|
||||
return extract_delete_content();
|
||||
}
|
||||
else if (DRequest::Replace == m_curtask->request_code())
|
||||
{
|
||||
return extract_replace_content();
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void filter_quotation(char *ptr, int len)
|
||||
{
|
||||
if ((NULL == ptr) || (len <= 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int iCharLoop = 0; iCharLoop < len; iCharLoop++)
|
||||
{
|
||||
if ('\"' == ptr[iCharLoop])
|
||||
{
|
||||
ptr[iCharLoop] = '|';
|
||||
}
|
||||
}
|
||||
}
|
||||
std::string hex_to_string(char *ptr, int len)
|
||||
{
|
||||
if ((NULL == ptr) || (len <= 0))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
std::string str;
|
||||
while (len--)
|
||||
{
|
||||
char szTemp[16] = {0};
|
||||
memset(szTemp, 0, 16);
|
||||
snprintf(szTemp, sizeof(szTemp), "%02x", *ptr++);
|
||||
str += szTemp;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string value_to_str(const DTCValue *value, int fieldType)
|
||||
{
|
||||
if (NULL == value)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
std::stringstream oss;
|
||||
switch (fieldType)
|
||||
{
|
||||
case DField::Signed:
|
||||
{
|
||||
oss << value->s64;
|
||||
break;
|
||||
}
|
||||
|
||||
case DField::Unsigned:
|
||||
{
|
||||
oss << value->u64;
|
||||
break;
|
||||
}
|
||||
|
||||
case DField::String:
|
||||
{
|
||||
filter_quotation(value->str.ptr, value->str.len);
|
||||
oss << value->str.ptr;
|
||||
break;
|
||||
}
|
||||
case DField::Binary:
|
||||
{
|
||||
return hex_to_string(value->str.ptr, value->str.len);
|
||||
}
|
||||
case DField::Float:
|
||||
{
|
||||
oss << value->flt;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string extract_key()
|
||||
{
|
||||
if (NULL == m_curtask)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return value_to_str(m_curtask->request_key(), m_TableDef->field_type(0));
|
||||
}
|
||||
|
||||
std::string extract_condition_content(const DTCFieldValue *condition)
|
||||
{
|
||||
if (NULL == condition)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
std::stringstream oss;
|
||||
oss << "where conditon:[";
|
||||
for (int j = 0; j < condition->num_fields(); j++)
|
||||
{
|
||||
if (m_TableDef->is_volatile(j))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
uint8_t op = condition->field_operation(j);
|
||||
if (op >= DField::TotalComparison)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
static const char *const compStr[] = {"EQ", "NE", "LT", "LE", "GT", "GE"};
|
||||
oss << m_TableDef->field_name(condition->field_id(j)) << " ";
|
||||
oss << compStr[op] << " ";
|
||||
oss << value_to_str(condition->field_value(j), condition->field_type(j));
|
||||
oss << ";";
|
||||
}
|
||||
oss << "]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string extract_update_content(const DTCFieldValue *updateInfo)
|
||||
{
|
||||
if (NULL == updateInfo)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
std::stringstream oss;
|
||||
oss << "update content:[";
|
||||
for (int i = 0; i < updateInfo->num_fields(); i++)
|
||||
{
|
||||
const int fid = updateInfo->field_id(i);
|
||||
|
||||
if (m_TableDef->is_volatile(fid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (updateInfo->field_operation(i))
|
||||
{
|
||||
case DField::Set:
|
||||
{
|
||||
oss << m_TableDef->field_name(fid) << ":" << value_to_str(updateInfo->field_value(i), updateInfo->field_type(i)) << ";";
|
||||
break;
|
||||
}
|
||||
case DField::Add:
|
||||
{
|
||||
oss << m_TableDef->field_name(fid) << ":" << m_TableDef->field_name(fid) << "+" << value_to_str(updateInfo->field_value(i), updateInfo->field_type(i)) << ";";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
oss << "]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string extract_insert_content()
|
||||
{
|
||||
if (NULL == m_curtask)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
std::stringstream oss;
|
||||
|
||||
if (m_curtask->request_operation())
|
||||
{
|
||||
oss << "insert content: [";
|
||||
const DTCFieldValue *updateInfo = m_curtask->request_operation();
|
||||
for (int i = 0; i < updateInfo->num_fields(); ++i)
|
||||
{
|
||||
int fid = updateInfo->field_id(i);
|
||||
if (m_TableDef->is_volatile(fid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
oss << m_TableDef->field_name(fid) << ":" << value_to_str(updateInfo->field_value(i), updateInfo->field_type(i)) << ";";
|
||||
}
|
||||
oss << "]";
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string extract_update_content()
|
||||
{
|
||||
if (NULL == m_curtask)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
std::stringstream oss;
|
||||
oss << extract_update_content(m_curtask->request_operation());
|
||||
oss << extract_condition_content(m_curtask->request_condition());
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string extract_delete_content()
|
||||
{
|
||||
if (NULL == m_curtask)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return extract_condition_content(m_curtask->request_condition());
|
||||
}
|
||||
|
||||
std::string extract_replace_content()
|
||||
{
|
||||
if (NULL == m_curtask)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return extract_update_content(m_curtask->request_operation());
|
||||
}
|
||||
|
||||
private:
|
||||
TaskRequest *m_curtask;
|
||||
bool m_IsNoDbMode;
|
||||
DTCTableDefinition *m_TableDef;
|
||||
EUpdateMode m_UpdateMode;
|
||||
EUpdateMode m_InsertMode;
|
||||
int m_RemotePort; /*如果端口没有设置正确,写日志函数就啥都不用做了*/
|
||||
bool m_OpLog;
|
||||
};
|
||||
|
||||
#define REMOTE_LOG Singleton<CacheRemoteLog>::Instance()
|
||||
#endif
|
241
src/search_local/index_storage/cache/buffer_unit.cc
vendored
Normal file
241
src/search_local/index_storage/cache/buffer_unit.cc
vendored
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: buffer_unit.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include "log.h"
|
||||
#include "buffer_process.h"
|
||||
#include <daemon.h>
|
||||
#include "buffer_remoteLog.h"
|
||||
|
||||
void BufferReplyNotify::reply_notify(TaskRequest *cur)
|
||||
{
|
||||
owner->reply_notify(cur);
|
||||
}
|
||||
|
||||
void BufferProcess::reply_notify(TaskRequest *cur)
|
||||
{
|
||||
if (DRequest::ReloadConfig == cur->request_code() && TaskTypeHelperReloadConfig == cur->request_type())
|
||||
{
|
||||
/*only delete task */
|
||||
log_debug("reload config task reply ,just delete task");
|
||||
delete cur;
|
||||
return;
|
||||
}
|
||||
|
||||
transation_begin(cur);
|
||||
|
||||
if (cur->result_code() < 0)
|
||||
{
|
||||
buffer_process_error(*cur);
|
||||
}
|
||||
else if (cur->result_code() > 0)
|
||||
{
|
||||
log_notice("result_code() > 0: from %s msg %s", cur->resultInfo.error_from(), cur->resultInfo.error_message());
|
||||
}
|
||||
if (cur->result_code() >= 0 && buffer_process_reply(*cur) != BUFFER_PROCESS_OK)
|
||||
{
|
||||
if (cur->result_code() >= 0)
|
||||
cur->set_error(-EC_SERVER_ERROR, "buffer_process_reply", last_error_message());
|
||||
}
|
||||
|
||||
if (!cur->flag_black_hole())
|
||||
{
|
||||
/* 如果cache操作有失败,则加入黑名单*/
|
||||
unsigned blacksize = cur->pop_black_list_size();
|
||||
if (blacksize > 0)
|
||||
{
|
||||
log_debug("add to blacklist, key=%d size=%u", cur->int_key(), blacksize);
|
||||
blacklist->add_blacklist(cur->packed_key(), blacksize);
|
||||
}
|
||||
}
|
||||
|
||||
REMOTE_LOG->write_remote_log(owner->get_now_time() / 1000000, cur, TASK_REPLY_STAGE);
|
||||
cur->reply_notify();
|
||||
|
||||
transation_end();
|
||||
|
||||
/* 启动匀速淘汰(deplay purge) */
|
||||
Cache.delay_purge_notify();
|
||||
}
|
||||
|
||||
void HotBackReplay::reply_notify(TaskRequest *cur)
|
||||
{
|
||||
log_debug("reply_notify, request type %d", cur->request_type());
|
||||
int iRet = cur->result_code();
|
||||
if (0 != iRet)
|
||||
{
|
||||
if ((-ETIMEDOUT == iRet) || (-EC_INC_SYNC_STAGE == iRet) || (-EC_FULL_SYNC_STAGE == iRet))
|
||||
{
|
||||
log_debug("hotback task , normal fail: from %s msg %s, request type %d", cur->resultInfo.error_from(), cur->resultInfo.error_message(), cur->request_type());
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("hotback task fail: from %s msg %s, request type %d", cur->resultInfo.error_from(), cur->resultInfo.error_message(), cur->request_type());
|
||||
}
|
||||
}
|
||||
|
||||
if ((TaskTypeWriteHbLog == cur->request_type()) || (TaskTypeWriteLruHbLog == cur->request_type()))
|
||||
{
|
||||
/*only delete task */
|
||||
log_debug("write hotback task reply ,just delete task");
|
||||
delete cur;
|
||||
return;
|
||||
}
|
||||
log_debug("read hotback task ,reply to client");
|
||||
cur->reply_notify();
|
||||
}
|
||||
|
||||
void FlushReplyNotify::reply_notify(TaskRequest *cur)
|
||||
{
|
||||
owner->transation_begin(cur);
|
||||
if (cur->result_code() < 0)
|
||||
{
|
||||
owner->buffer_process_error(*cur);
|
||||
}
|
||||
else if (cur->result_code() > 0)
|
||||
{
|
||||
log_notice("result_code() > 0: from %s msg %s", cur->resultInfo.error_from(), cur->resultInfo.error_message());
|
||||
}
|
||||
if (cur->result_code() >= 0 && owner->buffer_flush_reply(*cur) != BUFFER_PROCESS_OK)
|
||||
{
|
||||
if (cur->result_code() >= 0)
|
||||
cur->set_error(-EC_SERVER_ERROR, "buffer_flush_reply", owner->last_error_message());
|
||||
}
|
||||
REMOTE_LOG->write_remote_log(owner->owner->get_now_time() / 1000000, cur, TASK_REPLY_STAGE);
|
||||
cur->reply_notify();
|
||||
owner->transation_end();
|
||||
}
|
||||
|
||||
void BufferProcess::task_notify(TaskRequest *cur)
|
||||
{
|
||||
tableDef = TableDefinitionManager::Instance()->get_cur_table_def();
|
||||
uint64_t now_unix_time = GET_TIMESTAMP() / 1000;
|
||||
if (cur->is_expired(now_unix_time))
|
||||
{
|
||||
log_debug("task time out, throw it for availability, now is [%lld] expire is [%lld]", (long long)now_unix_time, (long long)cur->get_expire_time());
|
||||
statBufferProcessExpireCount++;
|
||||
cur->set_error(-EC_TASK_TIMEOUT, "buffer_process", "task time out");
|
||||
cur->reply_notify();
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned blacksize = 0;
|
||||
transation_begin(cur);
|
||||
|
||||
if (cur->result_code() < 0)
|
||||
{
|
||||
cur->mark_as_hit(); /* mark as hit if result done */
|
||||
cur->reply_notify();
|
||||
}
|
||||
else if (cur->is_batch_request())
|
||||
{
|
||||
switch (buffer_process_batch(*cur))
|
||||
{
|
||||
default:
|
||||
cur->set_error(-EC_SERVER_ERROR, "buffer_process", last_error_message());
|
||||
cur->mark_as_hit(); /* mark as hit if result done */
|
||||
cur->reply_notify();
|
||||
break;
|
||||
|
||||
case BUFFER_PROCESS_OK:
|
||||
cur->mark_as_hit(); /* mark as hit if result done */
|
||||
cur->reply_notify();
|
||||
break;
|
||||
|
||||
case BUFFER_PROCESS_ERROR:
|
||||
if (cur->result_code() >= 0)
|
||||
cur->set_error(-EC_SERVER_ERROR, "buffer_process", last_error_message());
|
||||
cur->mark_as_hit(); /* mark as hit if result done */
|
||||
cur->reply_notify();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (nodbMode == false)
|
||||
{
|
||||
BufferResult result = buffer_process_request(*cur);
|
||||
REMOTE_LOG->write_remote_log(owner->get_now_time() / 1000000, cur, TASK_NOTIFY_STAGE);
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
if (!cur->flag_black_hole())
|
||||
{
|
||||
/* 如果cache操作有失败,则加入黑名单*/
|
||||
blacksize = cur->pop_black_list_size();
|
||||
if (blacksize > 0)
|
||||
{
|
||||
log_debug("add to blacklist, key=%d size=%u", cur->int_key(), blacksize);
|
||||
blacklist->add_blacklist(cur->packed_key(), blacksize);
|
||||
}
|
||||
}
|
||||
case BUFFER_PROCESS_ERROR:
|
||||
if (cur->result_code() >= 0)
|
||||
cur->set_error(-EC_SERVER_ERROR, "buffer_process", last_error_message());
|
||||
|
||||
case BUFFER_PROCESS_OK:
|
||||
cur->mark_as_hit(); /* mark as hit if result done */
|
||||
cur->reply_notify();
|
||||
break;
|
||||
case BUFFER_PROCESS_NEXT:
|
||||
log_debug("push task to next-unit");
|
||||
cur->push_reply_dispatcher(&cacheReply);
|
||||
output.task_notify(cur);
|
||||
break;
|
||||
case BUFFER_PROCESS_PENDING:
|
||||
break;
|
||||
case BUFFER_PROCESS_REMOTE: //migrate 命令,给远端dtc
|
||||
cur->push_reply_dispatcher(&cacheReply);
|
||||
remoteoutput.task_notify(cur);
|
||||
break;
|
||||
case BUFFER_PROCESS_PUSH_HB:
|
||||
{
|
||||
log_debug("push task to hotback thread");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferResult result = buffer_process_nodb(*cur);
|
||||
REMOTE_LOG->write_remote_log(owner->get_now_time() / 1000000, cur, TASK_NOTIFY_STAGE);
|
||||
switch (result)
|
||||
{
|
||||
default:
|
||||
case BUFFER_PROCESS_ERROR:
|
||||
if (cur->result_code() >= 0)
|
||||
cur->set_error(-EC_SERVER_ERROR, "buffer_process", last_error_message());
|
||||
|
||||
case BUFFER_PROCESS_NEXT:
|
||||
case BUFFER_PROCESS_OK:
|
||||
cur->mark_as_hit(); /* mark as hit if result done */
|
||||
cur->reply_notify();
|
||||
break;
|
||||
case BUFFER_PROCESS_PENDING:
|
||||
break;
|
||||
case BUFFER_PROCESS_REMOTE: //migrate 命令,给远端dtc
|
||||
cur->push_reply_dispatcher(&cacheReply);
|
||||
remoteoutput.task_notify(cur);
|
||||
break;
|
||||
case BUFFER_PROCESS_PUSH_HB:
|
||||
{
|
||||
log_debug("push task to hotback thread");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
transation_end();
|
||||
/* 启动匀速淘汰(deplay purge) */
|
||||
Cache.delay_purge_notify();
|
||||
}
|
187
src/search_local/index_storage/cache/buffer_writer.cc
vendored
Normal file
187
src/search_local/index_storage/cache/buffer_writer.cc
vendored
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: buffer_writer.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "task_pkey.h"
|
||||
#include "buffer_writer.h"
|
||||
#include "pt_malloc.h"
|
||||
#include "sys_malloc.h"
|
||||
#include "log.h"
|
||||
|
||||
BufferWriter::BufferWriter(void) : DTCBufferPool(NULL)
|
||||
{
|
||||
pstItem = NULL;
|
||||
iRowIdx = 0;
|
||||
iIsFull = 0;
|
||||
memset(achPackKey, 0, sizeof(achPackKey));
|
||||
}
|
||||
|
||||
BufferWriter::~BufferWriter(void)
|
||||
{
|
||||
if (pstItem != NULL)
|
||||
delete pstItem;
|
||||
pstItem = NULL;
|
||||
}
|
||||
|
||||
int BufferWriter::cache_open(CacheInfo *pstInfo, DTCTableDefinition *pstTab)
|
||||
{
|
||||
int iRet;
|
||||
|
||||
iRet = DTCBufferPool::cache_open(pstInfo);
|
||||
if (iRet != E_OK)
|
||||
{
|
||||
log_error("cache open error: %d, %s", iRet, Error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
pstItem = new RawData(&g_stSysMalloc, 1);
|
||||
if (pstItem == NULL)
|
||||
{
|
||||
snprintf(szErrMsg, sizeof(szErrMsg), "new RawData error: %m");
|
||||
return -2;
|
||||
}
|
||||
|
||||
UpdateMode stUpdateMod;
|
||||
stUpdateMod.m_iAsyncServer = pstInfo->syncUpdate ? MODE_SYNC : MODE_ASYNC;
|
||||
stUpdateMod.m_iUpdateMode = pstInfo->syncUpdate ? MODE_SYNC : MODE_ASYNC;
|
||||
stUpdateMod.m_iInsertMode = pstInfo->syncUpdate ? MODE_SYNC : MODE_ASYNC;
|
||||
stUpdateMod.m_uchInsertOrder = 0;
|
||||
|
||||
if (pstTab->index_fields() > 0)
|
||||
{
|
||||
#if HAS_TREE_DATA
|
||||
pstDataProcess = new TreeDataProcess(DTCBinMalloc::Instance(), pstTab, this, &stUpdateMod);
|
||||
#else
|
||||
log_error("tree index not supported, index field num[%d]", pstTab->index_fields());
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
pstDataProcess = new RawDataProcess(DTCBinMalloc::Instance(), pstTab, this, &stUpdateMod);
|
||||
if (pstDataProcess == NULL)
|
||||
{
|
||||
log_error("create %s error: %m", pstTab->index_fields() > 0 ? "TreeDataProcess" : "RawDataProcess");
|
||||
return -3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BufferWriter::begin_write()
|
||||
{
|
||||
iRowIdx = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BufferWriter::full()
|
||||
{
|
||||
return (iIsFull);
|
||||
}
|
||||
|
||||
int BufferWriter::AllocNode(const RowValue &row)
|
||||
{
|
||||
int iRet;
|
||||
|
||||
iRet = TaskPackedKey::build_packed_key(row.table_definition(), row.field_value(0), sizeof(achPackKey), achPackKey);
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(szErrMsg, sizeof(szErrMsg), "build packed key error: %d", iRet);
|
||||
return -1;
|
||||
}
|
||||
|
||||
stCurNode = cache_allocate(achPackKey);
|
||||
if (!stCurNode)
|
||||
{
|
||||
snprintf(szErrMsg, sizeof(szErrMsg), "cache alloc node error");
|
||||
iIsFull = 1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
iRet = pstItem->Init(row.table_definition()->key_fields() - 1, row.table_definition()->key_format(), achPackKey, 0);
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(szErrMsg, sizeof(szErrMsg), "raw data init error: %s", pstItem->get_err_msg());
|
||||
cache_purge(achPackKey);
|
||||
return -3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BufferWriter::write_row(const RowValue &row)
|
||||
{
|
||||
int iRet;
|
||||
|
||||
if (iRowIdx == 0)
|
||||
{
|
||||
if (AllocNode(row) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
iRet = pstItem->insert_row(row, false, false);
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(szErrMsg, sizeof(szErrMsg), "insert row error: %s", pstItem->get_err_msg());
|
||||
cache_purge(achPackKey);
|
||||
return -2;
|
||||
}
|
||||
|
||||
iRowIdx++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BufferWriter::commit_node()
|
||||
{
|
||||
int iRet;
|
||||
|
||||
if (iRowIdx < 1)
|
||||
return 0;
|
||||
|
||||
const MemHead *pstHead = DTCBinMalloc::Instance()->get_head_info();
|
||||
if (pstHead->m_hTop + pstItem->data_size() + MINSIZE >= pstHead->m_tSize)
|
||||
{
|
||||
iIsFull = 1;
|
||||
cache_purge(achPackKey);
|
||||
return -1;
|
||||
}
|
||||
|
||||
iRet = pstDataProcess->replace_data(&stCurNode, pstItem);
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(szErrMsg, sizeof(szErrMsg), "write data into cache error");
|
||||
cache_purge(achPackKey);
|
||||
return -2;
|
||||
}
|
||||
|
||||
iRowIdx = 0;
|
||||
memset(achPackKey, 0, sizeof(achPackKey));
|
||||
pstItem->Destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BufferWriter::rollback_node()
|
||||
{
|
||||
pstItem->Destroy();
|
||||
cache_purge(achPackKey);
|
||||
memset(achPackKey, 0, sizeof(achPackKey));
|
||||
|
||||
return 0;
|
||||
}
|
54
src/search_local/index_storage/cache/buffer_writer.h
vendored
Normal file
54
src/search_local/index_storage/cache/buffer_writer.h
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: buffer_writer.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __CACHE_WRITER_H
|
||||
#define __CACHE_WRITER_H
|
||||
|
||||
#include "buffer_pool.h"
|
||||
#include "table_def.h"
|
||||
#include "writer_interface.h"
|
||||
#include "raw_data_process.h"
|
||||
|
||||
class BufferWriter : public WriterInterface, public DTCBufferPool
|
||||
{
|
||||
private:
|
||||
RawData *pstItem;
|
||||
DataProcess *pstDataProcess;
|
||||
int iIsFull;
|
||||
int iRowIdx;
|
||||
Node stCurNode;
|
||||
char achPackKey[MAX_KEY_LEN + 1];
|
||||
char szErrMsg[200];
|
||||
|
||||
protected:
|
||||
int AllocNode(const RowValue &row);
|
||||
|
||||
public:
|
||||
BufferWriter(void);
|
||||
~BufferWriter(void);
|
||||
|
||||
int cache_open(CacheInfo *pstInfo, DTCTableDefinition *pstTab);
|
||||
|
||||
const char *err_msg() { return szErrMsg; }
|
||||
int begin_write();
|
||||
int full();
|
||||
int write_row(const RowValue &row);
|
||||
int commit_node();
|
||||
int rollback_node();
|
||||
};
|
||||
|
||||
#endif
|
176
src/search_local/index_storage/cache/col_expand.cc
vendored
Normal file
176
src/search_local/index_storage/cache/col_expand.cc
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: col_expand.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "col_expand.h"
|
||||
#include "table_def_manager.h"
|
||||
|
||||
DTC_USING_NAMESPACE
|
||||
|
||||
extern DTCConfig *gConfig;
|
||||
|
||||
DTCColExpand::DTCColExpand() : _colExpand(NULL)
|
||||
{
|
||||
memset(_errmsg, 0, sizeof(_errmsg));
|
||||
}
|
||||
|
||||
DTCColExpand::~DTCColExpand()
|
||||
{
|
||||
}
|
||||
|
||||
int DTCColExpand::Init()
|
||||
{
|
||||
// alloc mem
|
||||
size_t size = sizeof(COL_EXPAND_T);
|
||||
MEM_HANDLE_T v = M_CALLOC(size);
|
||||
if (INVALID_HANDLE == v)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "init column expand failed, %s", M_ERROR());
|
||||
return -1;
|
||||
}
|
||||
_colExpand = M_POINTER(COL_EXPAND_T, v);
|
||||
_colExpand->expanding = false;
|
||||
_colExpand->curTable = 0;
|
||||
memset(_colExpand->tableBuff, 0, sizeof(_colExpand->tableBuff));
|
||||
// copy file's table.conf to shm
|
||||
if (strlen(TableDefinitionManager::Instance()->table_file_buffer()) > COL_EXPAND_BUFF_SIZE)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "table buf size bigger than %d", COL_EXPAND_BUFF_SIZE);
|
||||
return -1;
|
||||
}
|
||||
strcpy(_colExpand->tableBuff[_colExpand->curTable % COL_EXPAND_BUFF_NUM],
|
||||
TableDefinitionManager::Instance()->table_file_buffer());
|
||||
// use file's tabledef
|
||||
DTCTableDefinition *t = TableDefinitionManager::Instance()->table_file_table_def();
|
||||
TableDefinitionManager::Instance()->set_cur_table_def(t, _colExpand->curTable % COL_EXPAND_BUFF_NUM);
|
||||
log_debug("init col expand with curTable: %d, tableBuff: %s", _colExpand->curTable, _colExpand->tableBuff[_colExpand->curTable % COL_EXPAND_BUFF_NUM]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DTCColExpand::reload_table()
|
||||
{
|
||||
if (TableDefinitionManager::Instance()->get_cur_table_idx() == _colExpand->curTable)
|
||||
return 0;
|
||||
|
||||
DTCTableDefinition *t = TableDefinitionManager::Instance()->load_buffered_table(_colExpand->tableBuff[_colExpand->curTable % COL_EXPAND_BUFF_NUM]);
|
||||
if (!t)
|
||||
{
|
||||
log_error("load shm table.conf error, buf: %s", _colExpand->tableBuff[_colExpand->curTable % COL_EXPAND_BUFF_NUM]);
|
||||
return -1;
|
||||
}
|
||||
TableDefinitionManager::Instance()->set_cur_table_def(t, _colExpand->curTable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DTCColExpand::Attach(MEM_HANDLE_T handle, int forceFlag)
|
||||
{
|
||||
if (INVALID_HANDLE == handle)
|
||||
{
|
||||
log_crit("attch col expand error, handle = 0");
|
||||
return -1;
|
||||
}
|
||||
_colExpand = M_POINTER(COL_EXPAND_T, handle);
|
||||
// 1) force update shm mem, 2)replace shm mem by dumped mem
|
||||
if (forceFlag)
|
||||
{
|
||||
log_debug("force use table.conf, not use shm conf");
|
||||
if (strlen(TableDefinitionManager::Instance()->table_file_buffer()) > COL_EXPAND_BUFF_SIZE)
|
||||
{
|
||||
log_error("table.conf to long while force update shm");
|
||||
return -1;
|
||||
}
|
||||
if (_colExpand->expanding)
|
||||
{
|
||||
log_error("col expanding, can't force update table.conf, delete shm and try again");
|
||||
return -1;
|
||||
}
|
||||
strcpy(_colExpand->tableBuff[_colExpand->curTable % COL_EXPAND_BUFF_NUM],
|
||||
TableDefinitionManager::Instance()->table_file_buffer());
|
||||
DTCTableDefinition *t = TableDefinitionManager::Instance()->table_file_table_def();
|
||||
TableDefinitionManager::Instance()->set_cur_table_def(t, _colExpand->curTable);
|
||||
return 0;
|
||||
}
|
||||
// parse shm table.conf
|
||||
DTCTableDefinition *t, *tt = NULL;
|
||||
t = TableDefinitionManager::Instance()->load_buffered_table(_colExpand->tableBuff[_colExpand->curTable % COL_EXPAND_BUFF_NUM]);
|
||||
if (!t)
|
||||
{
|
||||
log_error("load shm table.conf error, buf: %s", _colExpand->tableBuff[_colExpand->curTable % COL_EXPAND_BUFF_NUM]);
|
||||
return -1;
|
||||
}
|
||||
if (_colExpand->expanding)
|
||||
{
|
||||
tt = TableDefinitionManager::Instance()->load_buffered_table(_colExpand->tableBuff[(_colExpand->curTable + 1) % COL_EXPAND_BUFF_NUM]);
|
||||
if (!tt)
|
||||
{
|
||||
log_error("load shm col expand new table.conf error, buf: %s", _colExpand->tableBuff[(_colExpand->curTable + 1) % COL_EXPAND_BUFF_NUM]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// compare
|
||||
// if not same
|
||||
// log_error
|
||||
if (!t->is_same_table(TableDefinitionManager::Instance()->table_file_table_def()))
|
||||
{ // same with hash_equal
|
||||
DTCTableDefinition *tt = TableDefinitionManager::Instance()->table_file_table_def();
|
||||
log_error("table.conf is not same to shm's");
|
||||
log_error("shm table, name: %s, hash: %s", t->table_name(), t->table_hash());
|
||||
log_error("file table, name: %s, hash: %s", tt->table_name(), tt->table_hash());
|
||||
}
|
||||
else
|
||||
{
|
||||
log_debug("table.conf is same to shm's");
|
||||
}
|
||||
// use shm's
|
||||
TableDefinitionManager::Instance()->set_cur_table_def(t, _colExpand->curTable);
|
||||
if (_colExpand->expanding)
|
||||
TableDefinitionManager::Instance()->set_new_table_def(tt, _colExpand->curTable + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DTCColExpand::is_expanding()
|
||||
{
|
||||
return _colExpand->expanding;
|
||||
}
|
||||
|
||||
bool DTCColExpand::expand(const char *table, int len)
|
||||
{
|
||||
_colExpand->expanding = true;
|
||||
memcpy(_colExpand->tableBuff[(_colExpand->curTable + 1) % COL_EXPAND_BUFF_NUM], table, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
int DTCColExpand::try_expand(const char *table, int len)
|
||||
{
|
||||
if (_colExpand->expanding || len > COL_EXPAND_BUFF_SIZE || _colExpand->curTable > 255)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DTCColExpand::expand_done()
|
||||
{
|
||||
++_colExpand->curTable;
|
||||
_colExpand->expanding = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int DTCColExpand::cur_table_idx()
|
||||
{
|
||||
return _colExpand->curTable;
|
||||
}
|
67
src/search_local/index_storage/cache/col_expand.h
vendored
Normal file
67
src/search_local/index_storage/cache/col_expand.h
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: col_expand.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __DTC_COL_EXPAND_H_
|
||||
#define __DTC_COL_EXPAND_H_
|
||||
|
||||
#include "namespace.h"
|
||||
#include "global.h"
|
||||
#include "singleton.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
#define COL_EXPAND_BUFF_SIZE (1024 * 1024)
|
||||
#define COL_EXPAND_BUFF_NUM 2
|
||||
|
||||
struct _col_expand
|
||||
{
|
||||
bool expanding;
|
||||
unsigned char curTable;
|
||||
char tableBuff[COL_EXPAND_BUFF_NUM][COL_EXPAND_BUFF_SIZE];
|
||||
};
|
||||
typedef struct _col_expand COL_EXPAND_T;
|
||||
|
||||
class DTCColExpand
|
||||
{
|
||||
public:
|
||||
DTCColExpand();
|
||||
~DTCColExpand();
|
||||
|
||||
static DTCColExpand *Instance() { return Singleton<DTCColExpand>::Instance(); }
|
||||
static void Destroy() { Singleton<DTCColExpand>::Destroy(); }
|
||||
|
||||
int Init();
|
||||
int Attach(MEM_HANDLE_T handle, int forceFlag);
|
||||
|
||||
bool is_expanding();
|
||||
bool expand(const char *table, int len);
|
||||
int try_expand(const char *table, int len);
|
||||
bool expand_done();
|
||||
int cur_table_idx();
|
||||
int reload_table();
|
||||
|
||||
const MEM_HANDLE_T Handle() const { return M_HANDLE(_colExpand); }
|
||||
const char *Error() const { return _errmsg; }
|
||||
|
||||
private:
|
||||
COL_EXPAND_T *_colExpand;
|
||||
char _errmsg[256];
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
202
src/search_local/index_storage/cache/container_dtcd.cc
vendored
Normal file
202
src/search_local/index_storage/cache/container_dtcd.cc
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: container_dtcd.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <map>
|
||||
|
||||
#include "compiler.h"
|
||||
#include "container.h"
|
||||
#include "version.h"
|
||||
#include "table_def.h"
|
||||
#include "buffer_error.h"
|
||||
#include "listener_pool.h"
|
||||
#include "request_threading.h"
|
||||
#include "task_multiplexer.h"
|
||||
#include "../api/c_api/dtc_int.h"
|
||||
#include "proxy_listen_pool.h"
|
||||
#include "table_def_manager.h"
|
||||
|
||||
class DTCTaskExecutor : public IDTCTaskExecutor, public ThreadingOutputDispatcher<TaskRequest>
|
||||
{
|
||||
public:
|
||||
virtual NCResultInternal *task_execute(NCRequest &rq, const DTCValue *kptr);
|
||||
};
|
||||
|
||||
NCResultInternal *DTCTaskExecutor::task_execute(NCRequest &rq, const DTCValue *kptr)
|
||||
{
|
||||
NCResultInternal *res = new NCResultInternal(rq.tdef);
|
||||
if (res->Copy(rq, kptr) < 0)
|
||||
return res;
|
||||
res->set_owner_info(this, 0, NULL);
|
||||
switch (ThreadingOutputDispatcher<TaskRequest>::execute((TaskRequest *)res))
|
||||
{
|
||||
case 0: // OK
|
||||
res->process_internal_result(res->Timestamp());
|
||||
break;
|
||||
case -1: // no side effect
|
||||
res->set_error(-EC_REQUEST_ABORTED, "API::sending", "Server Shutdown");
|
||||
break;
|
||||
case -2:
|
||||
default: // result unknown, leak res by purpose
|
||||
//new NCResult(-EC_REQUEST_ABORTED, "API::recving", "Server Shutdown");
|
||||
log_error("(-EC_REQUEST_ABORTED, API::sending, Server Shutdown");
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
class DTCInstance : public IDTCService
|
||||
{
|
||||
public:
|
||||
AgentListenPool *ports;
|
||||
DTCTaskExecutor *executor;
|
||||
int mypid;
|
||||
|
||||
public:
|
||||
DTCInstance();
|
||||
virtual ~DTCInstance();
|
||||
|
||||
virtual const char *query_version_string(void);
|
||||
virtual const char *query_service_type(void);
|
||||
virtual const char *query_instance_name(void);
|
||||
|
||||
virtual DTCTableDefinition *query_table_definition(void);
|
||||
virtual DTCTableDefinition *query_admin_table_definition(void);
|
||||
virtual IDTCTaskExecutor *query_task_executor(void);
|
||||
virtual int match_listening_ports(const char *, const char * = NULL);
|
||||
|
||||
int IsOK(void) const
|
||||
{
|
||||
return this != NULL &&
|
||||
ports != NULL &&
|
||||
executor != NULL &&
|
||||
getpid() == mypid;
|
||||
}
|
||||
};
|
||||
|
||||
extern ListenerPool *listener;
|
||||
DTCInstance::DTCInstance(void)
|
||||
{
|
||||
ports = NULL;
|
||||
executor = NULL;
|
||||
mypid = getpid();
|
||||
}
|
||||
|
||||
DTCInstance::~DTCInstance(void)
|
||||
{
|
||||
}
|
||||
|
||||
const char *DTCInstance::query_version_string(void)
|
||||
{
|
||||
return version_detail;
|
||||
}
|
||||
|
||||
const char *DTCInstance::query_service_type(void)
|
||||
{
|
||||
return "dtcd";
|
||||
}
|
||||
|
||||
const char *DTCInstance::query_instance_name(void)
|
||||
{
|
||||
return TableDefinitionManager::Instance()->get_cur_table_def()->table_name();
|
||||
}
|
||||
|
||||
DTCTableDefinition *DTCInstance::query_table_definition(void)
|
||||
{
|
||||
return TableDefinitionManager::Instance()->get_cur_table_def();
|
||||
}
|
||||
|
||||
DTCTableDefinition *DTCInstance::query_admin_table_definition(void)
|
||||
{
|
||||
return TableDefinitionManager::Instance()->get_hot_backup_table_def();
|
||||
}
|
||||
|
||||
IDTCTaskExecutor *DTCInstance::query_task_executor(void)
|
||||
{
|
||||
return executor;
|
||||
}
|
||||
|
||||
int DTCInstance::match_listening_ports(const char *host, const char *port)
|
||||
{
|
||||
return ports->Match(host, port);
|
||||
}
|
||||
|
||||
struct nocase
|
||||
{
|
||||
bool operator()(const char *const &a, const char *const &b) const
|
||||
{
|
||||
return strcasecmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
typedef std::map<const char *, DTCInstance, nocase> instmap_t;
|
||||
static instmap_t instMap;
|
||||
|
||||
extern "C" __EXPORT
|
||||
IInternalService *
|
||||
_QueryInternalService(const char *name, const char *instance)
|
||||
{
|
||||
instmap_t::iterator i;
|
||||
|
||||
if (!name || !instance)
|
||||
return NULL;
|
||||
|
||||
if (strcasecmp(name, "dtcd") != 0)
|
||||
return NULL;
|
||||
|
||||
/* not found */
|
||||
i = instMap.find(instance);
|
||||
if (i == instMap.end())
|
||||
return NULL;
|
||||
|
||||
DTCInstance &inst = i->second;
|
||||
if (inst.IsOK() == 0)
|
||||
return NULL;
|
||||
|
||||
return &inst;
|
||||
}
|
||||
|
||||
void InitTaskExecutor(const char *name, AgentListenPool *listener, TaskDispatcher<TaskRequest> *output)
|
||||
{
|
||||
if (NCResultInternal::verify_class() == 0)
|
||||
{
|
||||
log_error("Inconsistent class NCResultInternal detected, internal API disabled");
|
||||
return;
|
||||
}
|
||||
// this may cause memory leak, but this is small
|
||||
char *tablename = (char *)malloc(strlen(name) + 1);
|
||||
memset(tablename, 0, strlen(name) + 1);
|
||||
strncpy(tablename, name, strlen(name));
|
||||
|
||||
DTCInstance &inst = instMap[tablename];
|
||||
inst.ports = listener;
|
||||
DTCTaskExecutor *executor = new DTCTaskExecutor();
|
||||
TaskMultiplexer *batcher = new TaskMultiplexer(output->owner_thread());
|
||||
batcher->bind_dispatcher(output);
|
||||
executor->bind_dispatcher(batcher);
|
||||
inst.executor = executor;
|
||||
log_info("Internal Task Executor initialized");
|
||||
}
|
||||
|
||||
void StopTaskExecutor(void)
|
||||
{
|
||||
instmap_t::iterator i;
|
||||
for (i = instMap.begin(); i != instMap.end(); i++)
|
||||
{
|
||||
if (i->second.executor)
|
||||
i->second.executor->Stop();
|
||||
}
|
||||
}
|
331
src/search_local/index_storage/cache/data_chunk.h
vendored
Normal file
331
src/search_local/index_storage/cache/data_chunk.h
vendored
Normal file
@ -0,0 +1,331 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: data_chunk.h
|
||||
*
|
||||
* Description: packaging data chunk method.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef DATA_CHUNK_H
|
||||
#define DATA_CHUNK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "raw_data.h"
|
||||
#include "tree_data.h"
|
||||
|
||||
class DataChunk
|
||||
{
|
||||
protected:
|
||||
unsigned char m_uchDataType; // 数据chunk的类型
|
||||
|
||||
public:
|
||||
/*************************************************
|
||||
Description: 计算基本结构大小
|
||||
Input:
|
||||
Output:
|
||||
Return: 内存大小
|
||||
*************************************************/
|
||||
ALLOC_SIZE_T base_size()
|
||||
{
|
||||
if (m_uchDataType == DATA_TYPE_RAW)
|
||||
return (sizeof(RawFormat));
|
||||
else
|
||||
return (sizeof(RootData));
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: index key
|
||||
Input:
|
||||
Output:
|
||||
Return: key
|
||||
*************************************************/
|
||||
char *index_key()
|
||||
{
|
||||
char *indexKey = (char *)this;
|
||||
return indexKey + sizeof(unsigned char) * 2 + sizeof(uint32_t) * 2;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 获取格式化后的key
|
||||
Input:
|
||||
Output:
|
||||
Return: key指针
|
||||
*************************************************/
|
||||
const char *Key() const
|
||||
{
|
||||
if ((m_uchDataType & 0x7f) == DATA_TYPE_RAW)
|
||||
{
|
||||
RawFormat *pstRaw = (RawFormat *)this;
|
||||
return pstRaw->m_achKey;
|
||||
}
|
||||
else if ((m_uchDataType & 0x7f) == DATA_TYPE_TREE_ROOT)
|
||||
{
|
||||
RootData *pstRoot = (RootData *)this;
|
||||
return pstRoot->m_achKey;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 获取格式化后的key
|
||||
Input:
|
||||
Output:
|
||||
Return: key指针
|
||||
*************************************************/
|
||||
char *Key()
|
||||
{
|
||||
if ((m_uchDataType & 0x7f) == DATA_TYPE_RAW)
|
||||
{
|
||||
RawFormat *pstRaw = (RawFormat *)this;
|
||||
return pstRaw->m_achKey;
|
||||
}
|
||||
else if ((m_uchDataType & 0x7f) == DATA_TYPE_TREE_ROOT)
|
||||
{
|
||||
RootData *pstRoot = (RootData *)this;
|
||||
return pstRoot->m_achKey;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 保存key
|
||||
Input: key key的实际值
|
||||
Output:
|
||||
Return:
|
||||
*************************************************/
|
||||
|
||||
#define SET_KEY_FUNC(type, key) \
|
||||
void set_key(type key) \
|
||||
{ \
|
||||
if (m_uchDataType == DATA_TYPE_RAW) \
|
||||
{ \
|
||||
RawFormat *pstRaw = (RawFormat *)this; \
|
||||
*(type *)(void *)pstRaw->m_achKey = key; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
RootData *pstRoot = (RootData *)this; \
|
||||
*(type *)(void *)pstRoot->m_achKey = key; \
|
||||
} \
|
||||
}
|
||||
|
||||
SET_KEY_FUNC(int32_t, iKey)
|
||||
SET_KEY_FUNC(uint32_t, uiKey)
|
||||
SET_KEY_FUNC(int64_t, llKey)
|
||||
SET_KEY_FUNC(uint64_t, ullKey)
|
||||
|
||||
/*************************************************
|
||||
Description: 保存字符串key
|
||||
Input: key key的实际值
|
||||
iLen key的长度
|
||||
Output:
|
||||
Return:
|
||||
*************************************************/
|
||||
void set_key(const char *pchKey, int iLen)
|
||||
{
|
||||
if (m_uchDataType == DATA_TYPE_RAW)
|
||||
{
|
||||
RawFormat *pstRaw = (RawFormat *)this;
|
||||
*(unsigned char *)pstRaw->m_achKey = iLen;
|
||||
memcpy(pstRaw->m_achKey + 1, pchKey, iLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
RootData *pstRoot = (RootData *)this;
|
||||
*(unsigned char *)pstRoot->m_achKey = iLen;
|
||||
memcpy(pstRoot->m_achKey + 1, pchKey, iLen);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 保存格式化好的字符串key
|
||||
Input: key key的实际值, 要求key[0]是长度
|
||||
Output:
|
||||
Return:
|
||||
*************************************************/
|
||||
void set_key(const char *pchKey)
|
||||
{
|
||||
if (m_uchDataType == DATA_TYPE_RAW)
|
||||
{
|
||||
RawFormat *pstRaw = (RawFormat *)this;
|
||||
memcpy(pstRaw->m_achKey, pchKey, *(unsigned char *)pchKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
RootData *pstRoot = (RootData *)this;
|
||||
memcpy(pstRoot->m_achKey, pchKey, *(unsigned char *)pchKey);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 查询字符串key大小
|
||||
Input:
|
||||
Output:
|
||||
Return: key大小
|
||||
*************************************************/
|
||||
int str_key_size()
|
||||
{
|
||||
if (m_uchDataType == DATA_TYPE_RAW)
|
||||
{
|
||||
RawFormat *pstRaw = (RawFormat *)this;
|
||||
return *(unsigned char *)pstRaw->m_achKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
RootData *pstRoot = (RootData *)this;
|
||||
return *(unsigned char *)pstRoot->m_achKey;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 查询二进制key大小
|
||||
Input:
|
||||
Output:
|
||||
Return: key大小
|
||||
*************************************************/
|
||||
int bin_key_size() { return str_key_size(); }
|
||||
|
||||
unsigned int head_size()
|
||||
{
|
||||
if (m_uchDataType == DATA_TYPE_RAW)
|
||||
return sizeof(RawFormat);
|
||||
else
|
||||
return sizeof(RootData);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 查询数据头大小,如果是CRawData的chunk,data_size()是不包括Row的长度,仅包括头部信息以及key
|
||||
Input:
|
||||
Output:
|
||||
Return: 内存大小
|
||||
*************************************************/
|
||||
unsigned int data_size(int iKeySize)
|
||||
{
|
||||
int iKeyLen = iKeySize ? iKeySize : 1 + str_key_size();
|
||||
return head_size() + iKeyLen;
|
||||
}
|
||||
|
||||
unsigned int node_size()
|
||||
{
|
||||
if (m_uchDataType == DATA_TYPE_RAW)
|
||||
{
|
||||
RawFormat *pstRaw = (RawFormat *)this;
|
||||
return pstRaw->m_uiDataSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; // unknow
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int create_time()
|
||||
{
|
||||
if (m_uchDataType == DATA_TYPE_RAW)
|
||||
{
|
||||
RawFormat *pstRaw = (RawFormat *)this;
|
||||
return pstRaw->m_CreateHour;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; // unknow
|
||||
}
|
||||
}
|
||||
unsigned last_access_time()
|
||||
{
|
||||
if (m_uchDataType == DATA_TYPE_RAW)
|
||||
{
|
||||
RawFormat *pstRaw = (RawFormat *)this;
|
||||
return pstRaw->m_LastAccessHour;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; // unknow
|
||||
}
|
||||
}
|
||||
unsigned int last_update_time()
|
||||
{
|
||||
if (m_uchDataType == DATA_TYPE_RAW)
|
||||
{
|
||||
RawFormat *pstRaw = (RawFormat *)this;
|
||||
return pstRaw->m_LastUpdateHour;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; // unknow
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t total_rows()
|
||||
{
|
||||
if (m_uchDataType == DATA_TYPE_RAW)
|
||||
{
|
||||
RawFormat *pstRaw = (RawFormat *)this;
|
||||
return pstRaw->m_uiRowCnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
RootData *pstRoot = (RootData *)this;
|
||||
return pstRoot->m_uiRowCnt;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 销毁内存并释放内存
|
||||
Input:
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int Destroy(Mallocator *pstMalloc)
|
||||
{
|
||||
MEM_HANDLE_T hHandle = pstMalloc->ptr_to_handle(this);
|
||||
if (m_uchDataType == DATA_TYPE_RAW)
|
||||
{
|
||||
return pstMalloc->Free(hHandle);
|
||||
}
|
||||
else if (m_uchDataType == DATA_TYPE_TREE_ROOT)
|
||||
{
|
||||
TreeData stTree(pstMalloc);
|
||||
int iRet = stTree.Attach(hHandle);
|
||||
if (iRet != 0)
|
||||
{
|
||||
return (iRet);
|
||||
}
|
||||
return stTree.Destroy();
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* 查询如果destroy这块内存,能释放多少空间出来 (包括合并)*/
|
||||
unsigned ask_for_destroy_size(Mallocator *pstMalloc)
|
||||
{
|
||||
MEM_HANDLE_T hHandle = pstMalloc->ptr_to_handle(this);
|
||||
|
||||
if (m_uchDataType == DATA_TYPE_RAW)
|
||||
{
|
||||
return pstMalloc->ask_for_destroy_size(hHandle);
|
||||
}
|
||||
else if (m_uchDataType == DATA_TYPE_TREE_ROOT)
|
||||
{
|
||||
TreeData stTree(pstMalloc);
|
||||
if (stTree.Attach(hHandle))
|
||||
return 0;
|
||||
|
||||
return stTree.ask_for_destroy_size();
|
||||
}
|
||||
|
||||
log_debug("ask_for_destroy_size failed");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
205
src/search_local/index_storage/cache/data_process.h
vendored
Normal file
205
src/search_local/index_storage/cache/data_process.h
vendored
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: data_process.h
|
||||
*
|
||||
* Description: data processing interface(abstract class) definition.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef DATA_PROCESS_H
|
||||
#define DATA_PROCESS_H
|
||||
|
||||
#include "buffer_def.h"
|
||||
#include "protocol.h"
|
||||
#include "value.h"
|
||||
#include "field.h"
|
||||
#include "section.h"
|
||||
#include "table_def.h"
|
||||
#include "task_request.h"
|
||||
#include "stat_dtc.h"
|
||||
#include "raw_data.h"
|
||||
#include "node.h"
|
||||
|
||||
#include "namespace.h"
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
enum EUpdateMode
|
||||
{
|
||||
MODE_SYNC = 0,
|
||||
MODE_ASYNC,
|
||||
MODE_FLUSH
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
EUpdateMode m_iAsyncServer;
|
||||
EUpdateMode m_iUpdateMode;
|
||||
EUpdateMode m_iInsertMode;
|
||||
unsigned char m_uchInsertOrder;
|
||||
} UpdateMode;
|
||||
|
||||
class DTCFlushRequest;
|
||||
class DataProcess
|
||||
{
|
||||
public:
|
||||
DataProcess() {}
|
||||
virtual ~DataProcess() {}
|
||||
|
||||
virtual const char *get_err_msg() = 0;
|
||||
virtual void set_insert_mode(EUpdateMode iMode) = 0;
|
||||
virtual void set_insert_order(int iOrder) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 查询本次操作增加的行数(可以为负数)
|
||||
Input:
|
||||
Output:
|
||||
Return: 行数
|
||||
*************************************************/
|
||||
virtual int64_t rows_inc() = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 查询本次操作增加的脏行数(可以为负数)
|
||||
Input:
|
||||
Output:
|
||||
Return: 行数
|
||||
*************************************************/
|
||||
virtual int64_t dirty_rows_inc() = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 查询node里的所有数据
|
||||
Input: pstNode node节点
|
||||
Output: pstRows 保存数据的结构
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
virtual int get_all_rows(Node *pstNode, RawData *pstRows) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 用pstRows的数据替换cache里的数据
|
||||
Input: pstRows 新数据
|
||||
pstNode node节点
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
virtual int replace_data(Node *pstNode, RawData *pstRawData) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 根据task请求删除数据
|
||||
Input: stTask task请求
|
||||
pstNode node节点
|
||||
Output: pstAffectedRows 保存被删除的数据(为NULL时不保存)
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
virtual int delete_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 根据task请求查询数据
|
||||
Input: stTask task请求
|
||||
pstNode node节点
|
||||
Output: stTask 保存查找到的数据
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
virtual int get_data(TaskRequest &stTask, Node *pstNode) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 根据task请求添加一行数据
|
||||
Input: stTask task请求
|
||||
pstNode node节点
|
||||
isDirty 是否脏数据
|
||||
Output: pstAffectedRows 保存被删除的数据(为NULL时不保存)
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
virtual int append_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool isDirty, bool uniq) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 用task的数据替换cache里的数据
|
||||
Input: stTask task请求
|
||||
pstNode node节点
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
virtual int replace_data(TaskRequest &stTask, Node *pstNode) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 用task的数据替换cache里的数据
|
||||
Input: stTask task请求
|
||||
pstNode node节点
|
||||
async 是否异步操作
|
||||
Output: pstAffectedRows 保存被更新后的数据(为NULL时不保存)
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
virtual int replace_rows(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool async, bool setrows = false) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 根据task请求更新cache数据
|
||||
Input: stTask task请求
|
||||
pstNode node节点
|
||||
async 是否异步操作
|
||||
Output: pstAffectedRows 保存被更新后的数据(为NULL时不保存)
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
virtual int update_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool async, bool setrows = false) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 将node节点的脏数据组成若干个flush请求
|
||||
Input: pstNode node节点
|
||||
Output: pstFlushReq 保存flush请求
|
||||
uiFlushRowsCnt 被flush的行数
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
virtual int flush_data(DTCFlushRequest *pstFlushReq, Node *pstNode, unsigned int &uiFlushRowsCnt) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 删除cache里的数据,如果有脏数据会生成flush请求
|
||||
Input: pstNode node节点
|
||||
Output: pstFlushReq 保存flush请求
|
||||
uiFlushRowsCnt 被flush的行数
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
virtual int purge_data(DTCFlushRequest *pstFlushReq, Node *pstNode, unsigned int &uiFlushRowsCnt) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: get cache expire time
|
||||
Input: pstNode node
|
||||
Output:
|
||||
Return:
|
||||
*************************************************/
|
||||
virtual int get_expire_time(DTCTableDefinition *t, Node *pstNode, uint32_t &expire) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Input:
|
||||
Output:
|
||||
Return:
|
||||
*************************************************/
|
||||
virtual int expand_node(TaskRequest &stTask, Node *pstNode) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Input:
|
||||
Output:
|
||||
Return:
|
||||
*************************************************/
|
||||
virtual void change_mallocator(Mallocator *pstMalloc) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Input:
|
||||
Output:
|
||||
Return:
|
||||
*************************************************/
|
||||
virtual int dirty_rows_in_node(TaskRequest &stTask, Node *node) = 0;
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
77
src/search_local/index_storage/cache/defragment.h
vendored
Normal file
77
src/search_local/index_storage/cache/defragment.h
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: defragment.h
|
||||
*
|
||||
* Description: memory clear up.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include "pt_malloc.h"
|
||||
#include "dtc_api.h"
|
||||
|
||||
class Defragment
|
||||
{
|
||||
public:
|
||||
Defragment()
|
||||
{
|
||||
_mem = NULL;
|
||||
_pstChunk = NULL;
|
||||
_keysize = -1;
|
||||
_s = NULL;
|
||||
_error_count = 0;
|
||||
_skip_count = 0;
|
||||
_ok_count = 0;
|
||||
_bulk_per_ten_microscoends = 1;
|
||||
}
|
||||
|
||||
~Defragment()
|
||||
{
|
||||
}
|
||||
int Attach(const char *key, int keysize, int step);
|
||||
char *get_key_by_handle(INTER_HANDLE_T handle, int *len);
|
||||
int proccess(INTER_HANDLE_T handle);
|
||||
int dump_mem(bool verbose = false);
|
||||
int dump_mem_new(const char *filename, uint64_t &memsize);
|
||||
int defrag_mem(int level, DTC::Server *s);
|
||||
int defrag_mem_new(int level, DTC::Server *s, const char *filename, uint64_t memsize);
|
||||
int proccess_handle(const char *filename, DTC::Server *s);
|
||||
void frequency_limit(void);
|
||||
|
||||
private:
|
||||
DTCBinMalloc *_mem;
|
||||
MallocChunk *_pstChunk;
|
||||
int _keysize;
|
||||
DTC::Server *_s;
|
||||
|
||||
//stat
|
||||
uint64_t _error_count;
|
||||
uint64_t _skip_count;
|
||||
uint64_t _ok_count;
|
||||
int _bulk_per_ten_microscoends;
|
||||
};
|
||||
|
||||
#define SEARCH 0
|
||||
#define MATCH 1
|
||||
class DefragMemAlgo
|
||||
{
|
||||
public:
|
||||
DefragMemAlgo(int level, Defragment *master);
|
||||
~DefragMemAlgo();
|
||||
int Push(INTER_HANDLE_T handle, int used);
|
||||
|
||||
private:
|
||||
int _status;
|
||||
INTER_HANDLE_T *_queue;
|
||||
Defragment *_master;
|
||||
int _count;
|
||||
int _level;
|
||||
};
|
3
src/search_local/index_storage/cache/dtcd.export.lst
vendored
Normal file
3
src/search_local/index_storage/cache/dtcd.export.lst
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
global: _QueryInternalService;
|
||||
};
|
128
src/search_local/index_storage/cache/empty_filter.cc
vendored
Normal file
128
src/search_local/index_storage/cache/empty_filter.cc
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: empty_filter.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "pt_malloc.h"
|
||||
#include "empty_filter.h"
|
||||
#include "bitsop.h"
|
||||
|
||||
EmptyNodeFilter::EmptyNodeFilter() : _enf(0)
|
||||
{
|
||||
memset(_errmsg, 0x0, sizeof(_errmsg));
|
||||
}
|
||||
|
||||
EmptyNodeFilter::~EmptyNodeFilter()
|
||||
{
|
||||
}
|
||||
|
||||
int EmptyNodeFilter::ISSET(uint32_t key)
|
||||
{
|
||||
uint32_t bitoff = Offset(key);
|
||||
uint32_t tableid = Index(key);
|
||||
|
||||
if (_enf->enf_tables[tableid].t_size < bitoff / CHAR_BIT + 1)
|
||||
return 0;
|
||||
|
||||
return ISSET_B(bitoff, M_POINTER(void, _enf->enf_tables[tableid].t_handle));
|
||||
}
|
||||
|
||||
void EmptyNodeFilter::SET(uint32_t key)
|
||||
{
|
||||
uint32_t bitoff = Offset(key);
|
||||
uint32_t tableid = Index(key);
|
||||
|
||||
if (_enf->enf_tables[tableid].t_size < bitoff / CHAR_BIT + 1)
|
||||
{
|
||||
/* 按step的整数倍来increase table*/
|
||||
int incbyte = bitoff / CHAR_BIT + 1 - _enf->enf_tables[tableid].t_size;
|
||||
int how = (incbyte + _enf->enf_step - 1) / _enf->enf_step;
|
||||
size_t size = _enf->enf_tables[tableid].t_size + how * _enf->enf_step;
|
||||
|
||||
_enf->enf_tables[tableid].t_handle = M_REALLOC(_enf->enf_tables[tableid].t_handle, size);
|
||||
if (_enf->enf_tables[tableid].t_handle == INVALID_HANDLE)
|
||||
{
|
||||
/* realloc 失败后,不会重试*/
|
||||
return;
|
||||
}
|
||||
|
||||
_enf->enf_tables[tableid].t_size = size;
|
||||
}
|
||||
|
||||
return SET_B(bitoff, M_POINTER(void, _enf->enf_tables[tableid].t_handle));
|
||||
}
|
||||
|
||||
void EmptyNodeFilter::CLR(uint32_t key)
|
||||
{
|
||||
uint32_t bitoff = Offset(key);
|
||||
uint32_t tableid = Index(key);
|
||||
|
||||
if (_enf->enf_tables[tableid].t_size < bitoff / CHAR_BIT + 1)
|
||||
/* 超出表范围,return*/
|
||||
return;
|
||||
|
||||
return CLR_B(bitoff, M_POINTER(void, _enf->enf_tables[tableid].t_handle));
|
||||
}
|
||||
|
||||
int EmptyNodeFilter::Init(uint32_t total, uint32_t step, uint32_t mod)
|
||||
{
|
||||
mod = mod ? mod : DF_ENF_MOD;
|
||||
step = step ? step : DF_ENF_STEP;
|
||||
total = total ? total : DF_ENF_TOTAL;
|
||||
|
||||
/* allocate header */
|
||||
uint32_t size = sizeof(ENF_T);
|
||||
size += sizeof(ENF_TABLE_T) * mod;
|
||||
|
||||
MEM_HANDLE_T v = M_CALLOC(size);
|
||||
if (INVALID_HANDLE == v)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg),
|
||||
"calloc %u bytes mem failed, %s", size, M_ERROR());
|
||||
return -1;
|
||||
}
|
||||
|
||||
_enf = M_POINTER(ENF_T, v);
|
||||
|
||||
_enf->enf_total = total;
|
||||
_enf->enf_step = step;
|
||||
_enf->enf_mod = mod;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EmptyNodeFilter::Attach(MEM_HANDLE_T v)
|
||||
{
|
||||
if (INVALID_HANDLE == v)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg),
|
||||
"attach Empty-Node Filter failed, memory handle = 0");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_enf = M_POINTER(ENF_T, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EmptyNodeFilter::Detach(void)
|
||||
{
|
||||
_enf = 0;
|
||||
_errmsg[0] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
82
src/search_local/index_storage/cache/empty_filter.h
vendored
Normal file
82
src/search_local/index_storage/cache/empty_filter.h
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: empty_filter.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __DTC_EMPTY_FILTER_H
|
||||
#define __DTC_EMPTY_FILTER_H
|
||||
|
||||
#include "namespace.h"
|
||||
#include "singleton.h"
|
||||
#include "global.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
#define DF_ENF_TOTAL 0 /* 0 = unlimited */
|
||||
#define DF_ENF_STEP 512 /* byte */
|
||||
#define DF_ENF_MOD 30000
|
||||
|
||||
struct _enf_table
|
||||
{
|
||||
MEM_HANDLE_T t_handle;
|
||||
uint32_t t_size;
|
||||
};
|
||||
typedef struct _enf_table ENF_TABLE_T;
|
||||
|
||||
struct _empty_node_filter
|
||||
{
|
||||
uint32_t enf_total; // 占用的总内存
|
||||
uint32_t enf_step; // 表增长步长
|
||||
uint32_t enf_mod; // 分表算子
|
||||
|
||||
ENF_TABLE_T enf_tables[0]; // 位图表
|
||||
};
|
||||
typedef struct _empty_node_filter ENF_T;
|
||||
|
||||
class EmptyNodeFilter
|
||||
{
|
||||
public:
|
||||
void SET(uint32_t key);
|
||||
void CLR(uint32_t key);
|
||||
int ISSET(uint32_t key);
|
||||
|
||||
public:
|
||||
/* 0 = use default value */
|
||||
int Init(uint32_t total = 0, uint32_t step = 0, uint32_t mod = 0);
|
||||
int Attach(MEM_HANDLE_T);
|
||||
int Detach(void);
|
||||
|
||||
public:
|
||||
EmptyNodeFilter();
|
||||
~EmptyNodeFilter();
|
||||
static EmptyNodeFilter *Instance() { return Singleton<EmptyNodeFilter>::Instance(); }
|
||||
static void Destroy() { Singleton<EmptyNodeFilter>::Destroy(); }
|
||||
const char *Error() const { return _errmsg; }
|
||||
const MEM_HANDLE_T Handle() const { return M_HANDLE(_enf); }
|
||||
|
||||
private:
|
||||
/* 计算表id */
|
||||
uint32_t Index(uint32_t key) { return key % _enf->enf_mod; }
|
||||
/* 计算表中的位图偏移 */
|
||||
uint32_t Offset(uint32_t key) { return key / _enf->enf_mod; }
|
||||
|
||||
private:
|
||||
ENF_T *_enf;
|
||||
char _errmsg[256];
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
106
src/search_local/index_storage/cache/expire_time.cc
vendored
Normal file
106
src/search_local/index_storage/cache/expire_time.cc
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: expire_time.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include "expire_time.h"
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
DTC_USING_NAMESPACE
|
||||
|
||||
ExpireTime::ExpireTime(TimerList *t, DTCBufferPool *c, DataProcess *p, DTCTableDefinition *td, int e) : timer(t),
|
||||
cache(c),
|
||||
process(p),
|
||||
tableDef(td),
|
||||
maxExpire(e)
|
||||
{
|
||||
statExpireCount = statmgr.get_item_u32(DTC_KEY_EXPIRE_DTC_COUNT);
|
||||
statGetCount = statmgr.get_item_u32(DTC_GET_COUNT);
|
||||
statInsertCount = statmgr.get_item_u32(DTC_INSERT_COUNT);
|
||||
statUpdateCount = statmgr.get_item_u32(DTC_UPDATE_COUNT);
|
||||
statDeleteCount = statmgr.get_item_u32(DTC_DELETE_COUNT);
|
||||
statPurgeCount = statmgr.get_item_u32(DTC_PURGE_COUNT);
|
||||
}
|
||||
|
||||
ExpireTime::~ExpireTime()
|
||||
{
|
||||
}
|
||||
|
||||
void ExpireTime::start_key_expired_task(void)
|
||||
{
|
||||
log_info("start key expired task");
|
||||
attach_timer(timer);
|
||||
return;
|
||||
}
|
||||
|
||||
int ExpireTime::try_expire_count()
|
||||
{
|
||||
int num1 = maxExpire - (statGetCount.get() + statInsertCount.get() +
|
||||
statUpdateCount.get() + statDeleteCount.get() +
|
||||
statPurgeCount.get()) /
|
||||
10;
|
||||
int num2 = cache->total_used_node();
|
||||
return num1 < num2 ? num1 : num2;
|
||||
}
|
||||
|
||||
void ExpireTime::timer_notify(void)
|
||||
{
|
||||
log_debug("sched key expire task");
|
||||
int start = cache->min_valid_node_id(), end = cache->max_node_id();
|
||||
int count, interval = end - start, node_id;
|
||||
int i, j, k = 0;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
log_debug("tv.tv_usec: %ld", tv.tv_usec);
|
||||
srandom(tv.tv_usec);
|
||||
count = try_expire_count();
|
||||
log_debug("try_expire_count: %d", count);
|
||||
for (i = 0, j = 0; i < count && j < count * 3; ++j)
|
||||
{
|
||||
Node node;
|
||||
node_id = random() % interval + start;
|
||||
node = I_SEARCH(node_id);
|
||||
uint32_t expire = 0;
|
||||
if (!!node && !node.not_in_lru_list() && !cache->is_time_marker(node))
|
||||
{
|
||||
// read expire time
|
||||
// if expired
|
||||
// purge
|
||||
++i;
|
||||
if (process->get_expire_time(tableDef, &node, expire) != 0)
|
||||
{
|
||||
log_error("get expire time error for node: %d", node.node_id());
|
||||
continue;
|
||||
}
|
||||
log_debug("node id: %d, expire: %d, current: %ld", node.node_id(), expire, tv.tv_sec);
|
||||
if (expire != 0 && expire < tv.tv_sec)
|
||||
{
|
||||
log_debug("expire time timer purge node: %d, %d", node.node_id(), ++k);
|
||||
cache->inc_total_row(0LL - cache->node_rows_count(node));
|
||||
if (cache->purge_node_everything(node) != 0)
|
||||
{
|
||||
log_error("purge node error, node: %d", node.node_id());
|
||||
}
|
||||
++statExpireCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
log_debug("expire time found %d real node, %d", i, k);
|
||||
|
||||
attach_timer(timer);
|
||||
return;
|
||||
}
|
59
src/search_local/index_storage/cache/expire_time.h
vendored
Normal file
59
src/search_local/index_storage/cache/expire_time.h
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: expire_time.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __DTC_EXPIRE_TIME_H
|
||||
#define __DTC_EXPIRE_TIME_H
|
||||
|
||||
#include "namespace.h"
|
||||
#include "timer_list.h"
|
||||
#include "log.h"
|
||||
#include "stat_dtc.h"
|
||||
#include "buffer_pool.h"
|
||||
#include "data_process.h"
|
||||
#include "raw_data_process.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
class TimerObject;
|
||||
class ExpireTime : private TimerObject
|
||||
{
|
||||
public:
|
||||
ExpireTime(TimerList *t, DTCBufferPool *c, DataProcess *p, DTCTableDefinition *td, int e);
|
||||
virtual ~ExpireTime(void);
|
||||
virtual void timer_notify(void);
|
||||
void start_key_expired_task(void);
|
||||
int try_expire_count();
|
||||
|
||||
private:
|
||||
TimerList *timer;
|
||||
DTCBufferPool *cache;
|
||||
DataProcess *process;
|
||||
DTCTableDefinition *tableDef;
|
||||
|
||||
StatItemU32 statExpireCount;
|
||||
StatItemU32 statGetCount;
|
||||
StatItemU32 statInsertCount;
|
||||
StatItemU32 statUpdateCount;
|
||||
StatItemU32 statDeleteCount;
|
||||
StatItemU32 statPurgeCount;
|
||||
|
||||
int maxExpire;
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
169
src/search_local/index_storage/cache/feature.cc
vendored
Normal file
169
src/search_local/index_storage/cache/feature.cc
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: feature.cc
|
||||
*
|
||||
* Description: feature description character definition.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "singleton.h"
|
||||
#include "feature.h"
|
||||
#include "global.h"
|
||||
|
||||
DTC_USING_NAMESPACE
|
||||
|
||||
Feature *Feature::Instance()
|
||||
{
|
||||
return Singleton<Feature>::Instance();
|
||||
}
|
||||
|
||||
void Feature::Destroy()
|
||||
{
|
||||
return Singleton<Feature>::Destroy();
|
||||
}
|
||||
|
||||
Feature::Feature() : _baseInfo(NULL)
|
||||
{
|
||||
memset(_errmsg, 0, sizeof(_errmsg));
|
||||
}
|
||||
|
||||
Feature::~Feature()
|
||||
{
|
||||
}
|
||||
/* feature id -> feature. 拷贝输入feature 到 找到feature
|
||||
*/
|
||||
int Feature::modify_feature(FEATURE_INFO_T *fi)
|
||||
{
|
||||
if (!fi)
|
||||
return -1;
|
||||
|
||||
FEATURE_INFO_T *p = get_feature_by_id(fi->fi_id);
|
||||
if (!p)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "not found feature[%d]", fi->fi_id);
|
||||
return -2;
|
||||
}
|
||||
|
||||
*p = *fi;
|
||||
return 0;
|
||||
}
|
||||
/* feature id -> feature. 清空这个feature
|
||||
*/
|
||||
int Feature::delete_feature(FEATURE_INFO_T *fi)
|
||||
{
|
||||
if (!fi)
|
||||
return -1;
|
||||
|
||||
FEATURE_INFO_T *p = get_feature_by_id(fi->fi_id);
|
||||
if (!p)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "not found feature[%d]", fi->fi_id);
|
||||
return -2;
|
||||
}
|
||||
|
||||
//delete feature
|
||||
p->fi_id = 0;
|
||||
p->fi_attr = 0;
|
||||
p->fi_handle = INVALID_HANDLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* 找一个空闲feature, 赋值
|
||||
*/
|
||||
int Feature::add_feature(const uint32_t id, const MEM_HANDLE_T v, const uint32_t attr)
|
||||
{
|
||||
if (INVALID_HANDLE == v)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "handle is invalid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//find freespace
|
||||
FEATURE_INFO_T *p = get_feature_by_id(0);
|
||||
if (!p)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "have no free space to add a new feature");
|
||||
return -2;
|
||||
}
|
||||
|
||||
p->fi_id = id;
|
||||
p->fi_attr = attr;
|
||||
p->fi_handle = v;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* feature id -> feature.
|
||||
* 1. feature id == 0: 则表示找一个空闲feature.
|
||||
* 2. 否则根据feature id 找对应的feature
|
||||
*/
|
||||
FEATURE_INFO_T *Feature::get_feature_by_id(const uint32_t fd)
|
||||
{
|
||||
if (!_baseInfo || _baseInfo->bi_total == 0)
|
||||
{
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < _baseInfo->bi_total; i++)
|
||||
{
|
||||
if (_baseInfo->bi_features[i].fi_id == fd)
|
||||
{
|
||||
return (&(_baseInfo->bi_features[i]));
|
||||
}
|
||||
}
|
||||
|
||||
EXIT:
|
||||
return (FEATURE_INFO_T *)(0);
|
||||
}
|
||||
/* 1. 创建num个空feature
|
||||
* 2. 初始化头信息(baseInfo)
|
||||
*/
|
||||
int Feature::Init(const uint32_t num)
|
||||
{
|
||||
size_t size = sizeof(FEATURE_INFO_T);
|
||||
size *= num;
|
||||
size += sizeof(BASE_INFO_T);
|
||||
|
||||
MEM_HANDLE_T v = M_CALLOC(size);
|
||||
if (INVALID_HANDLE == v)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "init features failed, %s", M_ERROR());
|
||||
return -1;
|
||||
}
|
||||
|
||||
_baseInfo = M_POINTER(BASE_INFO_T, v);
|
||||
_baseInfo->bi_total = num;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* feature已经存在,第一个feature的内存句柄。直接初始化头信息指向
|
||||
*/
|
||||
int Feature::Attach(MEM_HANDLE_T handle)
|
||||
{
|
||||
if (INVALID_HANDLE == handle)
|
||||
{
|
||||
|
||||
snprintf(_errmsg, sizeof(_errmsg), "attach features failed, memory handle=0");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_baseInfo = M_POINTER(BASE_INFO_T, handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Feature::Detach(void)
|
||||
{
|
||||
_baseInfo = NULL;
|
||||
return 0;
|
||||
}
|
87
src/search_local/index_storage/cache/feature.h
vendored
Normal file
87
src/search_local/index_storage/cache/feature.h
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: feature.h
|
||||
*
|
||||
* Description: feature description character definition.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __DTC_FEATURE_H
|
||||
#define __DTC_FEATURE_H
|
||||
|
||||
#include "namespace.h"
|
||||
#include "global.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
// feature type
|
||||
enum feature_id
|
||||
{
|
||||
NODE_GROUP = 10, //DTC begin feature id
|
||||
NODE_INDEX,
|
||||
HASH_BUCKET,
|
||||
TABLE_INFO,
|
||||
EMPTY_FILTER,
|
||||
HOT_BACKUP,
|
||||
COL_EXPAND,
|
||||
};
|
||||
typedef enum feature_id FEATURE_ID_T;
|
||||
|
||||
struct feature_info
|
||||
{
|
||||
uint32_t fi_id; // feature id
|
||||
uint32_t fi_attr; // feature attribute
|
||||
MEM_HANDLE_T fi_handle; // feature handler
|
||||
};
|
||||
typedef struct feature_info FEATURE_INFO_T;
|
||||
|
||||
struct base_info
|
||||
{
|
||||
uint32_t bi_total; // total features
|
||||
FEATURE_INFO_T bi_features[0];
|
||||
};
|
||||
typedef struct base_info BASE_INFO_T;
|
||||
|
||||
class Feature
|
||||
{
|
||||
public:
|
||||
static Feature *Instance();
|
||||
static void Destroy();
|
||||
|
||||
MEM_HANDLE_T Handle() const { return M_HANDLE(_baseInfo); }
|
||||
const char *Error() const { return _errmsg; }
|
||||
|
||||
int modify_feature(FEATURE_INFO_T *fi);
|
||||
int delete_feature(FEATURE_INFO_T *fi);
|
||||
int add_feature(const uint32_t id, const MEM_HANDLE_T v, const uint32_t attr = 0);
|
||||
FEATURE_INFO_T *get_feature_by_id(const uint32_t id);
|
||||
|
||||
//创建物理内存并格式化
|
||||
int Init(const uint32_t num = MIN_FEATURES);
|
||||
//绑定到物理内存
|
||||
int Attach(MEM_HANDLE_T handle);
|
||||
//脱离物理内存
|
||||
int Detach(void);
|
||||
|
||||
public:
|
||||
Feature();
|
||||
~Feature();
|
||||
|
||||
private:
|
||||
BASE_INFO_T *_baseInfo;
|
||||
char _errmsg[256];
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
45
src/search_local/index_storage/cache/fence.h
vendored
Normal file
45
src/search_local/index_storage/cache/fence.h
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: fence.h
|
||||
*
|
||||
* Description: fence class definition.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __BARRIER_H__
|
||||
#define __BARRIER_H__
|
||||
|
||||
#include <list.h>
|
||||
#include <lqueue.h>
|
||||
|
||||
class TaskRequest;
|
||||
class BarrierUnit;
|
||||
class Barrier;
|
||||
|
||||
class Barrier : public ListObject<Barrier>,
|
||||
public LinkQueue<TaskRequest *>
|
||||
{
|
||||
public:
|
||||
friend class BarrierUnit;
|
||||
|
||||
inline Barrier(LinkQueue<TaskRequest *>::allocator *a = NULL) : LinkQueue<TaskRequest *>(a), key(0)
|
||||
{
|
||||
}
|
||||
inline ~Barrier(){};
|
||||
|
||||
inline unsigned long Key() const { return key; }
|
||||
inline void set_key(unsigned long k) { key = k; }
|
||||
|
||||
private:
|
||||
unsigned long key;
|
||||
};
|
||||
|
||||
#endif
|
207
src/search_local/index_storage/cache/fence_unit.cc
vendored
Normal file
207
src/search_local/index_storage/cache/fence_unit.cc
vendored
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: barrier_unit.cc
|
||||
*
|
||||
* Description: barrier uint class definition.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include <fence.h>
|
||||
#include <fence_unit.h>
|
||||
#include <poll_thread.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
BarrierUnit::BarrierUnit(PollThread *o, int max, int maxkeycount, E_BARRIER_UNIT_PLACE place) : TaskDispatcher<TaskRequest>(o),
|
||||
count(0),
|
||||
maxBarrier(max),
|
||||
maxKeyCount(maxkeycount),
|
||||
output(o)
|
||||
{
|
||||
freeList.InitList();
|
||||
for (int i = 0; i < BARRIER_HASH_MAX; i++)
|
||||
hashSlot[i].InitList();
|
||||
//stat
|
||||
if (IN_FRONT == place)
|
||||
{
|
||||
statBarrierCount = statmgr.get_item_u32(DTC_FRONT_BARRIER_COUNT);
|
||||
statBarrierMaxTask = statmgr.get_item_u32(DTC_FRONT_BARRIER_MAX_TASK);
|
||||
}
|
||||
else if (IN_BACK == place)
|
||||
{
|
||||
statBarrierCount = statmgr.get_item_u32(DTC_BACK_BARRIER_COUNT);
|
||||
statBarrierMaxTask = statmgr.get_item_u32(DTC_BACK_BARRIER_MAX_TASK);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("bad place value %d", place);
|
||||
}
|
||||
statBarrierCount = 0;
|
||||
statBarrierMaxTask = 0;
|
||||
}
|
||||
|
||||
BarrierUnit::~BarrierUnit()
|
||||
{
|
||||
while (!freeList.ListEmpty())
|
||||
{
|
||||
delete static_cast<Barrier *>(freeList.ListNext());
|
||||
}
|
||||
for (int i = 0; i < BARRIER_HASH_MAX; i++)
|
||||
{
|
||||
while (!hashSlot[i].ListEmpty())
|
||||
{
|
||||
delete static_cast<Barrier *>(hashSlot[i].ListNext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Barrier *BarrierUnit::get_barrier(unsigned long key)
|
||||
{
|
||||
ListObject<Barrier> *h = &hashSlot[key2idx(key)];
|
||||
ListObject<Barrier> *p;
|
||||
|
||||
for (p = h->ListNext(); p != h; p = p->ListNext())
|
||||
{
|
||||
if (p->ListOwner()->Key() == key)
|
||||
return p->ListOwner();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Barrier *BarrierUnit::get_barrier_by_idx(unsigned long idx)
|
||||
{
|
||||
if (idx >= BARRIER_HASH_MAX)
|
||||
return NULL;
|
||||
|
||||
ListObject<Barrier> *h = &hashSlot[idx];
|
||||
ListObject<Barrier> *p;
|
||||
|
||||
p = h->ListNext();
|
||||
return p->ListOwner();
|
||||
}
|
||||
|
||||
void BarrierUnit::attach_free_barrier(Barrier *bar)
|
||||
{
|
||||
bar->ListMove(freeList);
|
||||
count--;
|
||||
statBarrierCount = count;
|
||||
//Stat.set_barrier_count (count);
|
||||
}
|
||||
|
||||
void BarrierUnit::task_notify(TaskRequest *cur)
|
||||
{
|
||||
if (cur->request_code() == DRequest::SvrAdmin &&
|
||||
cur->requestInfo.admin_code() != DRequest::ServerAdminCmd::Migrate)
|
||||
{
|
||||
//Migrate命令在PrepareRequest的时候已经计算了PackedKey和hash,需要跟普通的task一起排队
|
||||
chain_request(cur);
|
||||
return;
|
||||
}
|
||||
if (cur->is_batch_request())
|
||||
{
|
||||
chain_request(cur);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long key = cur->barrier_key();
|
||||
Barrier *bar = get_barrier(key);
|
||||
|
||||
if (bar)
|
||||
{
|
||||
if (bar->Count() < maxKeyCount)
|
||||
{
|
||||
bar->Push(cur);
|
||||
if (bar->Count() > statBarrierMaxTask) //max key number
|
||||
statBarrierMaxTask = bar->Count();
|
||||
}
|
||||
else
|
||||
{
|
||||
log_warning("barrier[%s]: overload max key count %d bars %d", owner->Name(), maxKeyCount, count);
|
||||
cur->set_error(-EC_SERVER_BUSY, __FUNCTION__,
|
||||
"too many request blocked at key");
|
||||
cur->reply_notify();
|
||||
}
|
||||
}
|
||||
else if (count >= maxBarrier)
|
||||
{
|
||||
log_warning("too many barriers, count=%d", count);
|
||||
cur->set_error(-EC_SERVER_BUSY, __FUNCTION__,
|
||||
"too many barriers");
|
||||
cur->reply_notify();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (freeList.ListEmpty())
|
||||
{
|
||||
bar = new Barrier(&taskQueueAllocator);
|
||||
}
|
||||
else
|
||||
{
|
||||
bar = freeList.NextOwner();
|
||||
}
|
||||
bar->set_key(key);
|
||||
bar->list_move_tail(hashSlot[key2idx(key)]);
|
||||
bar->Push(cur);
|
||||
count++;
|
||||
statBarrierCount = count; //barrier number
|
||||
//Stat.set_barrier_count (count);
|
||||
chain_request(cur);
|
||||
}
|
||||
}
|
||||
|
||||
void BarrierUnit::reply_notify(TaskRequest *cur)
|
||||
{
|
||||
if (cur->request_code() == DRequest::SvrAdmin &&
|
||||
cur->requestInfo.admin_code() != DRequest::ServerAdminCmd::Migrate)
|
||||
{
|
||||
cur->reply_notify();
|
||||
return;
|
||||
}
|
||||
if (cur->is_batch_request())
|
||||
{
|
||||
cur->reply_notify();
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long key = cur->barrier_key();
|
||||
Barrier *bar = get_barrier(key);
|
||||
if (bar == NULL)
|
||||
{
|
||||
log_error("return task not in barrier, key=%lu", key);
|
||||
}
|
||||
else if (bar->Front() == cur)
|
||||
{
|
||||
if (bar->Count() == statBarrierMaxTask) //max key number
|
||||
statBarrierMaxTask--;
|
||||
bar->Pop();
|
||||
TaskRequest *next = bar->Front();
|
||||
if (next == NULL)
|
||||
{
|
||||
attach_free_barrier(bar);
|
||||
}
|
||||
else
|
||||
{
|
||||
queue_request(next);
|
||||
}
|
||||
//printf("pop bar %lu: count %d\n", key, bar->Count());
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("return task not barrier header, key=%lu", key);
|
||||
}
|
||||
|
||||
cur->reply_notify();
|
||||
}
|
84
src/search_local/index_storage/cache/fence_unit.h
vendored
Normal file
84
src/search_local/index_storage/cache/fence_unit.h
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: fence_unit.h
|
||||
*
|
||||
* Description: barrier uint class definition.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __BARRIER_UNIT_H__
|
||||
#define __BARRIER_UNIT_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <list.h>
|
||||
#include "task_request.h"
|
||||
#include "timer_list.h"
|
||||
#include "fence.h"
|
||||
#include "stat_dtc.h"
|
||||
|
||||
#define BARRIER_HASH_MAX 1024 * 8
|
||||
|
||||
class TaskRequest;
|
||||
class PollThread;
|
||||
class BarrierUnit;
|
||||
|
||||
class BarrierUnit : public TaskDispatcher<TaskRequest>, public ReplyDispatcher<TaskRequest>
|
||||
{
|
||||
public:
|
||||
enum E_BARRIER_UNIT_PLACE
|
||||
{
|
||||
IN_FRONT,
|
||||
IN_BACK
|
||||
};
|
||||
BarrierUnit(PollThread *, int max, int maxkeycount, E_BARRIER_UNIT_PLACE place);
|
||||
~BarrierUnit();
|
||||
virtual void task_notify(TaskRequest *);
|
||||
virtual void reply_notify(TaskRequest *);
|
||||
|
||||
void chain_request(TaskRequest *p)
|
||||
{
|
||||
p->push_reply_dispatcher(this);
|
||||
output.task_notify(p);
|
||||
}
|
||||
void queue_request(TaskRequest *p)
|
||||
{
|
||||
p->push_reply_dispatcher(this);
|
||||
output.indirect_notify(p);
|
||||
}
|
||||
PollThread *owner_thread(void) const { return owner; }
|
||||
void attach_free_barrier(Barrier *);
|
||||
int max_count_by_key(void) const { return maxKeyCount; }
|
||||
void bind_dispatcher(TaskDispatcher<TaskRequest> *p) { output.bind_dispatcher(p); }
|
||||
int barrier_count() const { return count; }
|
||||
|
||||
protected:
|
||||
int count;
|
||||
LinkQueue<TaskRequest *>::allocator taskQueueAllocator;
|
||||
ListObject<Barrier> freeList;
|
||||
ListObject<Barrier> hashSlot[BARRIER_HASH_MAX];
|
||||
int maxBarrier;
|
||||
|
||||
Barrier *get_barrier(unsigned long key);
|
||||
Barrier *get_barrier_by_idx(unsigned long idx);
|
||||
int key2idx(unsigned long key) { return key % BARRIER_HASH_MAX; }
|
||||
|
||||
private:
|
||||
int maxKeyCount;
|
||||
|
||||
RequestOutput<TaskRequest> output;
|
||||
|
||||
//stat
|
||||
StatItemU32 statBarrierCount;
|
||||
StatItemU32 statBarrierMaxTask;
|
||||
};
|
||||
|
||||
#endif
|
85
src/search_local/index_storage/cache/global.h
vendored
Normal file
85
src/search_local/index_storage/cache/global.h
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: global.h
|
||||
*
|
||||
* Description: macro definition and common function.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __DTC_GLOBAL_H
|
||||
#define __DTC_GLOBAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include "namespace.h"
|
||||
#include "pt_malloc.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
/* 共享内存操作定义 */
|
||||
#define M_HANDLE(ptr) DTCBinMalloc::Instance()->Handle(ptr)
|
||||
#define M_POINTER(type, v) DTCBinMalloc::Instance()->Pointer<type>(v)
|
||||
#define M_MALLOC(size) DTCBinMalloc::Instance()->Malloc(size)
|
||||
#define M_CALLOC(size) DTCBinMalloc::Instance()->Calloc(size)
|
||||
#define M_REALLOC(v, size) DTCBinMalloc::Instance()->ReAlloc(v, size)
|
||||
#define M_FREE(v) DTCBinMalloc::Instance()->Free(v)
|
||||
#define M_ERROR() DTCBinMalloc::Instance()->get_err_msg()
|
||||
|
||||
/* Node查找函数 */
|
||||
#define I_SEARCH(id) NodeIndex::Instance()->Search(id)
|
||||
#define I_INSERT(node) NodeIndex::Instance()->Insert(node)
|
||||
/*#define I_DELETE(node) NodeIndex::Instance()->Delete(node) */
|
||||
|
||||
/* memory handle*/
|
||||
#define MEM_HANDLE_T ALLOC_HANDLE_T
|
||||
|
||||
/*Node ID*/
|
||||
#define NODE_ID_T uint32_t
|
||||
#define INVALID_NODE_ID ((NODE_ID_T)(-1))
|
||||
#define SYS_MIN_NODE_ID ((NODE_ID_T)(0))
|
||||
#define SYS_DIRTY_NODE_INDEX 0
|
||||
#define SYS_CLEAN_NODE_INDEX 1
|
||||
#define SYS_EMPTY_NODE_INDEX 2
|
||||
#define SYS_DIRTY_HEAD_ID (SYS_MIN_NODE_ID + SYS_DIRTY_NODE_INDEX)
|
||||
#define SYS_CLEAN_HEAD_ID (SYS_MIN_NODE_ID + SYS_CLEAN_NODE_INDEX)
|
||||
#define SYS_EMPTY_HEAD_ID (SYS_MIN_NODE_ID + SYS_EMPTY_NODE_INDEX)
|
||||
|
||||
/* Node time list */
|
||||
#define LRU_PREV (0)
|
||||
#define LRU_NEXT (1)
|
||||
|
||||
/* features */
|
||||
#define MIN_FEATURES 32
|
||||
|
||||
/*Hash ID*/
|
||||
#define HASH_ID_T uint32_t
|
||||
|
||||
/* Node Group */
|
||||
#define NODE_GROUP_INCLUDE_NODES 256
|
||||
|
||||
/* output u64 format */
|
||||
#if __WORDSIZE == 64
|
||||
#define UINT64FMT "%lu"
|
||||
#else
|
||||
#define UINT64FMT "%llu"
|
||||
#endif
|
||||
|
||||
#if __WORDSIZE == 64
|
||||
#define INT64FMT "%ld"
|
||||
#else
|
||||
#define INT64FMT "%lld"
|
||||
#endif
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
83
src/search_local/index_storage/cache/hash.cc
vendored
Normal file
83
src/search_local/index_storage/cache/hash.cc
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: hash.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "hash.h"
|
||||
#include "global.h"
|
||||
|
||||
DTC_USING_NAMESPACE
|
||||
|
||||
DTCHash::DTCHash() : _hash(NULL)
|
||||
{
|
||||
memset(_errmsg, 0, sizeof(_errmsg));
|
||||
}
|
||||
|
||||
DTCHash::~DTCHash()
|
||||
{
|
||||
}
|
||||
|
||||
NODE_ID_T &DTCHash::hash2_node(const HASH_ID_T v)
|
||||
{
|
||||
return _hash->hh_buckets[v];
|
||||
}
|
||||
|
||||
int DTCHash::Init(const uint32_t hsize, const uint32_t fixedsize)
|
||||
{
|
||||
size_t size = sizeof(NODE_ID_T);
|
||||
size *= hsize;
|
||||
size += sizeof(HASH_T);
|
||||
|
||||
MEM_HANDLE_T v = M_CALLOC(size);
|
||||
if (INVALID_HANDLE == v)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "init hash bucket failed, %s", M_ERROR());
|
||||
return -1;
|
||||
}
|
||||
|
||||
_hash = M_POINTER(HASH_T, v);
|
||||
_hash->hh_size = hsize;
|
||||
_hash->hh_free = hsize;
|
||||
_hash->hh_node = 0;
|
||||
_hash->hh_fixedsize = fixedsize;
|
||||
|
||||
/* init each nodeid to invalid */
|
||||
for (uint32_t i = 0; i < hsize; i++)
|
||||
{
|
||||
_hash->hh_buckets[i] = INVALID_NODE_ID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DTCHash::Attach(MEM_HANDLE_T handle)
|
||||
{
|
||||
if (INVALID_HANDLE == handle)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "attach hash bucket failed, memory handle = 0");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_hash = M_POINTER(HASH_T, handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DTCHash::Detach(void)
|
||||
{
|
||||
_hash = (HASH_T *)(0);
|
||||
return 0;
|
||||
}
|
124
src/search_local/index_storage/cache/hash.h
vendored
Normal file
124
src/search_local/index_storage/cache/hash.h
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: hash.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __DTC_HASH_H
|
||||
#define __DTC_HASH_H
|
||||
|
||||
#include "namespace.h"
|
||||
#include "singleton.h"
|
||||
#include "global.h"
|
||||
#include "node.h"
|
||||
#include "new_hash.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
struct _hash
|
||||
{
|
||||
uint32_t hh_size; // hash 大小
|
||||
uint32_t hh_free; // 空闲的hash数量
|
||||
uint32_t hh_node; // 挂接的node总数量
|
||||
uint32_t hh_fixedsize; // key大小:变长key时,hh_fixedsize = 0;其他就是其实际长度
|
||||
uint32_t hh_buckets[0]; // hash bucket start
|
||||
};
|
||||
typedef struct _hash HASH_T;
|
||||
|
||||
class DTCHash
|
||||
{
|
||||
public:
|
||||
DTCHash();
|
||||
~DTCHash();
|
||||
|
||||
static DTCHash *Instance() { return Singleton<DTCHash>::Instance(); }
|
||||
static void Destroy() { Singleton<DTCHash>::Destroy(); }
|
||||
|
||||
inline HASH_ID_T new_hash_slot(const char *key)
|
||||
{
|
||||
//变长key的前一个字节编码的是key的长度
|
||||
uint32_t size = _hash->hh_fixedsize ? _hash->hh_fixedsize : *(unsigned char *)key++;
|
||||
|
||||
//目前仅支持1、2、4字节的定长key
|
||||
switch (size)
|
||||
{
|
||||
case sizeof(unsigned char):
|
||||
return (*(unsigned char *)key) % _hash->hh_size;
|
||||
case sizeof(unsigned short):
|
||||
return (*(unsigned short *)key) % _hash->hh_size;
|
||||
case sizeof(unsigned int):
|
||||
return (*(unsigned int *)key) % _hash->hh_size;
|
||||
}
|
||||
|
||||
unsigned int h = new_hash(key, size);
|
||||
return h % _hash->hh_size;
|
||||
}
|
||||
|
||||
inline HASH_ID_T hash_slot(const char *key)
|
||||
{
|
||||
//变长key的前一个字节编码的是key的长度
|
||||
uint32_t size = _hash->hh_fixedsize ? _hash->hh_fixedsize : *(unsigned char *)key++;
|
||||
|
||||
//目前仅支持1、2、4字节的定长key
|
||||
switch (size)
|
||||
{
|
||||
case sizeof(unsigned char):
|
||||
return (*(unsigned char *)key) % _hash->hh_size;
|
||||
case sizeof(unsigned short):
|
||||
return (*(unsigned short *)key) % _hash->hh_size;
|
||||
case sizeof(unsigned int):
|
||||
return (*(unsigned int *)key) % _hash->hh_size;
|
||||
}
|
||||
|
||||
unsigned int h = 0, g = 0;
|
||||
const char *arEnd = key + size;
|
||||
|
||||
//变长key hash算法, 目前8字节的定长整型key也是作为变长hash的。
|
||||
while (key < arEnd)
|
||||
{
|
||||
h = (h << 4) + *key++;
|
||||
if ((g = (h & 0xF0000000)))
|
||||
{
|
||||
h = h ^ (g >> 24);
|
||||
h = h ^ g;
|
||||
}
|
||||
}
|
||||
return h % _hash->hh_size;
|
||||
}
|
||||
|
||||
NODE_ID_T &hash2_node(const HASH_ID_T);
|
||||
|
||||
const MEM_HANDLE_T Handle() const { return M_HANDLE(_hash); }
|
||||
const char *Error() const { return _errmsg; }
|
||||
|
||||
//创建物理内存并格式化
|
||||
int Init(const uint32_t hsize, const uint32_t fixedsize);
|
||||
//绑定到物理内存
|
||||
int Attach(MEM_HANDLE_T handle);
|
||||
//脱离物理内存
|
||||
int Detach(void);
|
||||
|
||||
uint32_t hash_size() const { return _hash->hh_size; }
|
||||
uint32_t free_bucket() const { return _hash->hh_free; }
|
||||
void inc_free_bucket(int v) { _hash->hh_free += v; }
|
||||
void inc_node_cnt(int v) { _hash->hh_node += v; }
|
||||
|
||||
private:
|
||||
HASH_T *_hash;
|
||||
char _errmsg[256];
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
69
src/search_local/index_storage/cache/hb_feature.cc
vendored
Normal file
69
src/search_local/index_storage/cache/hb_feature.cc
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: hb_feature.cc
|
||||
*
|
||||
* Description: hotbackup method release.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "hb_feature.h"
|
||||
#include "global.h"
|
||||
|
||||
DTC_USING_NAMESPACE
|
||||
|
||||
HBFeature::HBFeature() : _hb_info(NULL), _handle(INVALID_HANDLE)
|
||||
{
|
||||
memset(_errmsg, 0, sizeof(_errmsg));
|
||||
}
|
||||
|
||||
HBFeature::~HBFeature()
|
||||
{
|
||||
}
|
||||
|
||||
int HBFeature::Init(time_t tMasterUptime)
|
||||
{
|
||||
_handle = M_CALLOC(sizeof(HB_FEATURE_INFO_T));
|
||||
if (INVALID_HANDLE == _handle)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "init hb_feature fail, %s", M_ERROR());
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
_hb_info = M_POINTER(HB_FEATURE_INFO_T, _handle);
|
||||
_hb_info->master_up_time = tMasterUptime;
|
||||
_hb_info->slave_up_time = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HBFeature::Attach(MEM_HANDLE_T handle)
|
||||
{
|
||||
if (INVALID_HANDLE == handle)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "attach hb feature failed, memory handle = 0");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_handle = handle;
|
||||
_hb_info = M_POINTER(HB_FEATURE_INFO_T, _handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HBFeature::Detach(void)
|
||||
{
|
||||
_hb_info = NULL;
|
||||
_handle = INVALID_HANDLE;
|
||||
}
|
63
src/search_local/index_storage/cache/hb_feature.h
vendored
Normal file
63
src/search_local/index_storage/cache/hb_feature.h
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: hb_feature.h
|
||||
*
|
||||
* Description: hotbackup method release.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __DTC_HB_FEATURE_H
|
||||
#define __DTC_HB_FEATURE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "namespace.h"
|
||||
#include "singleton.h"
|
||||
#include "global.h"
|
||||
|
||||
struct hb_feature_info
|
||||
{
|
||||
int64_t master_up_time;
|
||||
int64_t slave_up_time;
|
||||
};
|
||||
typedef struct hb_feature_info HB_FEATURE_INFO_T;
|
||||
|
||||
class HBFeature
|
||||
{
|
||||
public:
|
||||
HBFeature();
|
||||
~HBFeature();
|
||||
|
||||
static HBFeature* Instance(){return Singleton<HBFeature>::Instance();}
|
||||
static void Destroy() { Singleton<HBFeature>::Destroy();}
|
||||
|
||||
int Init(time_t tMasterUptime);
|
||||
int Attach(MEM_HANDLE_T handle);
|
||||
void Detach(void);
|
||||
|
||||
const char *Error() const {return _errmsg;}
|
||||
|
||||
MEM_HANDLE_T Handle() const { return _handle; }
|
||||
|
||||
int64_t& master_uptime() { return _hb_info->master_up_time; }
|
||||
int64_t& slave_uptime() { return _hb_info->slave_up_time; }
|
||||
|
||||
private:
|
||||
HB_FEATURE_INFO_T* _hb_info;
|
||||
MEM_HANDLE_T _handle;
|
||||
char _errmsg[256];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
224
src/search_local/index_storage/cache/hb_log.cc
vendored
Normal file
224
src/search_local/index_storage/cache/hb_log.cc
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: hb_log.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include "hb_log.h"
|
||||
#include "global.h"
|
||||
#include "admin_tdef.h"
|
||||
|
||||
HBLog::HBLog(DTCTableDefinition *tbl) : _tabledef(tbl),
|
||||
_log_writer(0),
|
||||
_log_reader(0)
|
||||
{
|
||||
}
|
||||
|
||||
HBLog::~HBLog()
|
||||
{
|
||||
DELETE(_log_writer);
|
||||
DELETE(_log_reader);
|
||||
}
|
||||
|
||||
int HBLog::Init(const char *path, const char *prefix, uint64_t total, off_t max_size)
|
||||
{
|
||||
_log_writer = new BinlogWriter;
|
||||
_log_reader = new BinlogReader;
|
||||
|
||||
if (_log_writer->Init(path, prefix, total, max_size))
|
||||
{
|
||||
log_error("init log_writer failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_log_reader->Init(path, prefix))
|
||||
{
|
||||
log_error("init log_reader failed");
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HBLog::write_update_log(TaskRequest &task)
|
||||
{
|
||||
RawData *raw_data;
|
||||
NEW(RawData(&g_stSysMalloc, 1), raw_data);
|
||||
|
||||
if (!raw_data)
|
||||
{
|
||||
log_error("raw_data is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
HotBackTask &hotbacktask = task.get_hot_back_task();
|
||||
int type = hotbacktask.get_type();
|
||||
if (raw_data->Init(0, _tabledef->key_size(), (const char *)&type, 0, -1, -1, 0))
|
||||
{
|
||||
DELETE(raw_data);
|
||||
return -1;
|
||||
}
|
||||
DTCValue key;
|
||||
DTCValue value;
|
||||
if (0 == hotbacktask.get_packed_key_len())
|
||||
{
|
||||
log_error("packedkey len is zero");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
key.Set(hotbacktask.get_packed_key(), hotbacktask.get_packed_key_len());
|
||||
}
|
||||
|
||||
if (0 == hotbacktask.get_value_len())
|
||||
{
|
||||
value.Set(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
value.Set(hotbacktask.get_value(), hotbacktask.get_value_len());
|
||||
}
|
||||
|
||||
RowValue row(_tabledef);
|
||||
row[0].u64 = type;
|
||||
row[1].u64 = hotbacktask.get_flag();
|
||||
row[2] = key;
|
||||
row[3] = value;
|
||||
log_debug(" tye is %d, flag %d", type, hotbacktask.get_flag());
|
||||
raw_data->insert_row(row, false, false);
|
||||
_log_writer->insert_header(type, 0, 1);
|
||||
_log_writer->append_body(raw_data->get_addr(), raw_data->data_size());
|
||||
DELETE(raw_data);
|
||||
|
||||
log_debug(" packed key len:%d,key len:%d, key :%s", key.bin.len, *(unsigned char *)key.bin.ptr, key.bin.ptr + 1);
|
||||
return _log_writer->Commit();
|
||||
}
|
||||
|
||||
int HBLog::write_lru_hb_log(TaskRequest &task)
|
||||
{
|
||||
RawData *raw_data;
|
||||
NEW(RawData(&g_stSysMalloc, 1), raw_data);
|
||||
|
||||
if (!raw_data)
|
||||
{
|
||||
log_error("raw_data is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
HotBackTask &hotbacktask = task.get_hot_back_task();
|
||||
int type = hotbacktask.get_type();
|
||||
if (raw_data->Init(0, _tabledef->key_size(), (const char *)&type, 0, -1, -1, 0))
|
||||
{
|
||||
DELETE(raw_data);
|
||||
return -1;
|
||||
}
|
||||
DTCValue key;
|
||||
if (0 == hotbacktask.get_packed_key_len())
|
||||
{
|
||||
log_error("packedkey len is zero");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
key.Set(hotbacktask.get_packed_key(), hotbacktask.get_packed_key_len());
|
||||
}
|
||||
|
||||
RowValue row(_tabledef);
|
||||
row[0].u64 = type;
|
||||
row[1].u64 = hotbacktask.get_flag();
|
||||
row[2] = key;
|
||||
row[3].Set(0);
|
||||
log_debug(" type is %d, flag %d", type, hotbacktask.get_flag());
|
||||
raw_data->insert_row(row, false, false);
|
||||
_log_writer->insert_header(BINLOG_LRU, 0, 1);
|
||||
_log_writer->append_body(raw_data->get_addr(), raw_data->data_size());
|
||||
DELETE(raw_data);
|
||||
|
||||
log_debug(" write lru hotback log, packed key len:%d,key len:%d, key :%s", key.bin.len, *(unsigned char *)key.bin.ptr, key.bin.ptr + 1);
|
||||
return _log_writer->Commit();
|
||||
}
|
||||
|
||||
int HBLog::Seek(const JournalID &v)
|
||||
{
|
||||
return _log_reader->Seek(v);
|
||||
}
|
||||
|
||||
/* 批量拉取更新key,返回更新key的个数 */
|
||||
int HBLog::task_append_all_rows(TaskRequest &task, int limit)
|
||||
{
|
||||
int count;
|
||||
for (count = 0; count < limit; ++count)
|
||||
{
|
||||
/* 没有待处理日志 */
|
||||
if (_log_reader->Read())
|
||||
break;
|
||||
|
||||
RawData *raw_data;
|
||||
|
||||
NEW(RawData(&g_stSysMalloc, 0), raw_data);
|
||||
|
||||
if (!raw_data)
|
||||
{
|
||||
log_error("allocate rawdata mem failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (raw_data->check_size(g_stSysMalloc.Handle(_log_reader->record_pointer()),
|
||||
0,
|
||||
_tabledef->key_size(),
|
||||
_log_reader->record_length(0)) < 0)
|
||||
{
|
||||
log_error("raw data broken: wrong size");
|
||||
DELETE(raw_data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* attach raw data read from one binlog */
|
||||
if (raw_data->Attach(g_stSysMalloc.Handle(_log_reader->record_pointer()), 0, _tabledef->key_size()))
|
||||
{
|
||||
log_error("attach rawdata mem failed");
|
||||
|
||||
DELETE(raw_data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
RowValue r(_tabledef);
|
||||
r[0].u64 = *(unsigned *)raw_data->Key();
|
||||
|
||||
unsigned char flag = 0;
|
||||
while (raw_data->decode_row(r, flag) == 0)
|
||||
{
|
||||
|
||||
log_debug("type: " UINT64FMT ", flag: " UINT64FMT ", key:%s, value :%s",
|
||||
r[0].u64, r[1].u64, r[2].bin.ptr, r[3].bin.ptr);
|
||||
log_debug("binlog-type: %d", _log_reader->binlog_type());
|
||||
|
||||
task.append_row(&r);
|
||||
}
|
||||
|
||||
DELETE(raw_data);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
JournalID HBLog::get_reader_jid(void)
|
||||
{
|
||||
return _log_reader->query_id();
|
||||
}
|
||||
|
||||
JournalID HBLog::get_writer_jid(void)
|
||||
{
|
||||
return _log_writer->query_id();
|
||||
}
|
63
src/search_local/index_storage/cache/hb_log.h
vendored
Normal file
63
src/search_local/index_storage/cache/hb_log.h
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: hb_log.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __DTC_HB_LOG_H
|
||||
#define __DTC_HB_LOG_H
|
||||
|
||||
#include "logger.h"
|
||||
#include "journal_id.h"
|
||||
#include "task_request.h"
|
||||
#include "field.h"
|
||||
#include "raw_data.h"
|
||||
#include "admin_tdef.h"
|
||||
#include "sys_malloc.h"
|
||||
#include "table_def.h"
|
||||
|
||||
class BinlogWriter;
|
||||
class BinlogReader;
|
||||
|
||||
class HBLog
|
||||
{
|
||||
public:
|
||||
//传入编解码的表结构
|
||||
HBLog(DTCTableDefinition *tbl);
|
||||
~HBLog();
|
||||
|
||||
int Init(const char *path, const char *prefix, uint64_t total, off_t max_size);
|
||||
int Seek(const JournalID &);
|
||||
|
||||
JournalID get_reader_jid(void);
|
||||
JournalID get_writer_jid(void);
|
||||
|
||||
//不带value,只写更新key
|
||||
int write_update_key(DTCValue key, int type);
|
||||
|
||||
//将多条log记录编码进TaskReqeust
|
||||
int task_append_all_rows(TaskRequest &, int limit);
|
||||
|
||||
//提供给LRUBitUnit来记录lru变更
|
||||
int write_lru_hb_log(TaskRequest &task);
|
||||
int write_update_log(TaskRequest &task);
|
||||
int write_update_key(DTCValue key, DTCValue v, int type);
|
||||
|
||||
private:
|
||||
DTCTableDefinition *_tabledef;
|
||||
BinlogWriter *_log_writer;
|
||||
BinlogReader *_log_reader;
|
||||
};
|
||||
|
||||
#endif
|
201
src/search_local/index_storage/cache/hb_process.cc
vendored
Normal file
201
src/search_local/index_storage/cache/hb_process.cc
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: hb_process.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include "hb_process.h"
|
||||
#include "poll_thread.h"
|
||||
#include "task_request.h"
|
||||
#include "log.h"
|
||||
#include "hotback_task.h"
|
||||
|
||||
extern DTCTableDefinition *gTableDef[];
|
||||
|
||||
HBProcess::HBProcess(PollThread *o) : TaskDispatcher<TaskRequest>(o),
|
||||
ownerThread(o),
|
||||
output(o),
|
||||
taskPendList(this),
|
||||
hbLog(TableDefinitionManager::Instance()->get_hot_backup_table_def())
|
||||
{
|
||||
}
|
||||
|
||||
HBProcess::~HBProcess()
|
||||
{
|
||||
}
|
||||
void HBProcess::task_notify(TaskRequest *cur)
|
||||
{
|
||||
log_debug("request type is %d ", cur->request_type());
|
||||
THBResult result = HB_PROCESS_ERROR;
|
||||
switch (cur->request_type())
|
||||
{
|
||||
case TaskTypeWriteHbLog:
|
||||
{
|
||||
result = write_hb_log_process(*cur);
|
||||
break;
|
||||
}
|
||||
case TaskTypeReadHbLog:
|
||||
{
|
||||
result = read_hb_log_process(*cur);
|
||||
break;
|
||||
}
|
||||
case TaskTypeWriteLruHbLog:
|
||||
{
|
||||
result = write_lru_hb_log_process(*cur);
|
||||
break;
|
||||
}
|
||||
case TaskTypeRegisterHbLog:
|
||||
{
|
||||
result = register_hb_log_process(*cur);
|
||||
break;
|
||||
}
|
||||
case TaskTypeQueryHbLogInfo:
|
||||
{
|
||||
result = query_hb_log_info_process(*cur);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
cur->set_error(-EBADRQC, "hb process", "invalid hb cmd code");
|
||||
log_notice("invalid hb cmd code[%d]", cur->request_type());
|
||||
cur->reply_notify();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (HB_PROCESS_PENDING == result)
|
||||
{
|
||||
log_debug("hb task is pending ");
|
||||
return;
|
||||
}
|
||||
log_debug("hb task reply");
|
||||
cur->reply_notify();
|
||||
return;
|
||||
}
|
||||
|
||||
bool HBProcess::Init(uint64_t total, off_t max_size)
|
||||
{
|
||||
log_debug("total: %lu, max_size: %ld", total, max_size);
|
||||
if (hbLog.Init("../log/hblog", "hblog", total, max_size))
|
||||
{
|
||||
log_error("hotback process for hblog init failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
THBResult HBProcess::write_hb_log_process(TaskRequest &task)
|
||||
{
|
||||
if (0 != hbLog.write_update_log(task))
|
||||
{
|
||||
task.set_error(-EC_ERR_HOTBACK_WRITEUPDATE, "HBProcess", "write_hb_log_process fail");
|
||||
return HB_PROCESS_ERROR;
|
||||
}
|
||||
taskPendList.Wakeup();
|
||||
return HB_PROCESS_OK;
|
||||
}
|
||||
|
||||
THBResult HBProcess::write_lru_hb_log_process(TaskRequest &task)
|
||||
{
|
||||
if (0 != hbLog.write_lru_hb_log(task))
|
||||
{
|
||||
task.set_error(-EC_ERR_HOTBACK_WRITELRU, "HBProcess", "write_lru_hb_log_process fail");
|
||||
return HB_PROCESS_ERROR;
|
||||
}
|
||||
return HB_PROCESS_OK;
|
||||
}
|
||||
|
||||
THBResult HBProcess::read_hb_log_process(TaskRequest &task)
|
||||
{
|
||||
log_debug("read Hb log begin ");
|
||||
JournalID hb_jid = task.versionInfo.hot_backup_id();
|
||||
JournalID write_jid = hbLog.get_writer_jid();
|
||||
|
||||
if (hb_jid.GE(write_jid))
|
||||
{
|
||||
taskPendList.add2_list(&task);
|
||||
return HB_PROCESS_PENDING;
|
||||
}
|
||||
|
||||
if (hbLog.Seek(hb_jid))
|
||||
{
|
||||
task.set_error(-EC_BAD_HOTBACKUP_JID, "HBProcess", "read_hb_log_process jid overflow");
|
||||
return HB_PROCESS_ERROR;
|
||||
}
|
||||
|
||||
task.prepare_result_no_limit();
|
||||
|
||||
int count = hbLog.task_append_all_rows(task, task.requestInfo.limit_count());
|
||||
if (count >= 0)
|
||||
{
|
||||
statIncSyncStep.push(count);
|
||||
}
|
||||
else
|
||||
{
|
||||
task.set_error(-EC_ERROR_BASE, "HBProcess", "read_hb_log_process,decode binlog error");
|
||||
return HB_PROCESS_ERROR;
|
||||
}
|
||||
|
||||
task.versionInfo.set_hot_backup_id((uint64_t)hbLog.get_reader_jid());
|
||||
return HB_PROCESS_OK;
|
||||
}
|
||||
THBResult HBProcess::register_hb_log_process(TaskRequest &task)
|
||||
{
|
||||
|
||||
JournalID client_jid = task.versionInfo.hot_backup_id();
|
||||
JournalID master_jid = hbLog.get_writer_jid();
|
||||
log_notice("hb register, client[serial=%u, offset=%u], master[serial=%u, offset=%u]",
|
||||
client_jid.serial, client_jid.offset, master_jid.serial, master_jid.offset);
|
||||
|
||||
//full sync
|
||||
if (client_jid.Zero())
|
||||
{
|
||||
log_info("full-sync stage.");
|
||||
task.versionInfo.set_hot_backup_id((uint64_t)master_jid);
|
||||
task.set_error(-EC_FULL_SYNC_STAGE, "HBProcess", "Register,full-sync stage");
|
||||
return HB_PROCESS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
//inc sync
|
||||
if (hbLog.Seek(client_jid) == 0)
|
||||
{
|
||||
log_info("inc-sync stage.");
|
||||
task.versionInfo.set_hot_backup_id((uint64_t)client_jid);
|
||||
task.set_error(-EC_INC_SYNC_STAGE, "HBProcess", "register, inc-sync stage");
|
||||
return HB_PROCESS_ERROR;
|
||||
}
|
||||
//error
|
||||
else
|
||||
{
|
||||
log_info("err-sync stage.");
|
||||
task.versionInfo.set_hot_backup_id((uint64_t)0);
|
||||
task.set_error(-EC_ERR_SYNC_STAGE, "HBProcess", "register, err-sync stage");
|
||||
return HB_PROCESS_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
THBResult HBProcess::query_hb_log_info_process(TaskRequest &task)
|
||||
{
|
||||
struct DTCServerInfo s_info;
|
||||
memset(&s_info, 0x00, sizeof(s_info));
|
||||
s_info.version = 0x1;
|
||||
|
||||
JournalID jid = hbLog.get_writer_jid();
|
||||
s_info.binlog_id = jid.Serial();
|
||||
s_info.binlog_off = jid.Offset();
|
||||
task.resultInfo.set_server_info(&s_info);
|
||||
return HB_PROCESS_OK;
|
||||
}
|
61
src/search_local/index_storage/cache/hb_process.h
vendored
Normal file
61
src/search_local/index_storage/cache/hb_process.h
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: hb_process.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef _HB_PROCESS_H_
|
||||
#define _HB_PROCESS_H_
|
||||
|
||||
#include "request_base.h"
|
||||
#include "hb_log.h"
|
||||
#include "task_pendlist.h"
|
||||
#include "stat_manager.h"
|
||||
#include <map>
|
||||
|
||||
class PollThread;
|
||||
class TaskRequest;
|
||||
enum THBResult
|
||||
{
|
||||
HB_PROCESS_ERROR = -1,
|
||||
HB_PROCESS_OK = 0,
|
||||
HB_PROCESS_PENDING = 2,
|
||||
};
|
||||
|
||||
class HBProcess : public TaskDispatcher<TaskRequest>
|
||||
{
|
||||
public:
|
||||
HBProcess(PollThread *o);
|
||||
virtual ~HBProcess();
|
||||
|
||||
virtual void task_notify(TaskRequest *cur);
|
||||
bool Init(uint64_t total, off_t max_size);
|
||||
|
||||
private:
|
||||
/*concrete hb operation*/
|
||||
THBResult write_hb_log_process(TaskRequest &task);
|
||||
THBResult read_hb_log_process(TaskRequest &task);
|
||||
THBResult write_lru_hb_log_process(TaskRequest &task);
|
||||
THBResult register_hb_log_process(TaskRequest &task);
|
||||
THBResult query_hb_log_info_process(TaskRequest &task);
|
||||
|
||||
private:
|
||||
PollThread *ownerThread;
|
||||
RequestOutput<TaskRequest> output;
|
||||
TaskPendingList taskPendList;
|
||||
HBLog hbLog;
|
||||
StatSample statIncSyncStep;
|
||||
};
|
||||
|
||||
#endif
|
517
src/search_local/index_storage/cache/logger.cc
vendored
Normal file
517
src/search_local/index_storage/cache/logger.cc
vendored
Normal file
@ -0,0 +1,517 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: logger.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <strings.h>
|
||||
#include "logger.h"
|
||||
#include "log.h"
|
||||
#include "global.h"
|
||||
|
||||
LogBase::LogBase() : _fd(-1)
|
||||
{
|
||||
bzero(_path, sizeof(_path));
|
||||
bzero(_prefix, sizeof(_prefix));
|
||||
}
|
||||
|
||||
LogBase::~LogBase()
|
||||
{
|
||||
close_file();
|
||||
}
|
||||
|
||||
int LogBase::set_path(const char *path, const char *prefix)
|
||||
{
|
||||
snprintf(_path, sizeof(_path), "%s", path);
|
||||
snprintf(_prefix, sizeof(_prefix), "%s", prefix);
|
||||
|
||||
mkdir(_path, 0777);
|
||||
|
||||
if (access(_path, W_OK | X_OK) < 0)
|
||||
{
|
||||
log_error("dir(%s) Not writable", _path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LogBase::close_file()
|
||||
{
|
||||
if (_fd > 0)
|
||||
{
|
||||
::close(_fd);
|
||||
_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int LogBase::stat_size(off_t *s)
|
||||
{
|
||||
struct stat st;
|
||||
if (fstat(_fd, &st))
|
||||
return -1;
|
||||
|
||||
*s = st.st_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LogBase::delete_file(uint32_t serial)
|
||||
{
|
||||
char file[MAX_PATH_NAME_LEN] = {0};
|
||||
file_name(file, MAX_PATH_NAME_LEN, serial);
|
||||
|
||||
return unlink(file);
|
||||
}
|
||||
|
||||
int LogBase::open_file(uint32_t serial, int read)
|
||||
{
|
||||
char file[MAX_PATH_NAME_LEN] = {0};
|
||||
file_name(file, MAX_PATH_NAME_LEN, serial);
|
||||
|
||||
read ? _fd = ::open(file, O_RDONLY | O_LARGEFILE, 0644) : _fd = ::open(file, O_WRONLY | O_APPEND | O_CREAT | O_LARGEFILE | O_TRUNC, 0644);
|
||||
|
||||
if (_fd < 0)
|
||||
{
|
||||
log_debug("open file[%s] failed, %m", file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LogBase::scan_serial(uint32_t *min, uint32_t *max)
|
||||
{
|
||||
DIR *dir = opendir(_path);
|
||||
if (!dir)
|
||||
return -1;
|
||||
|
||||
struct dirent *drt = readdir(dir);
|
||||
if (!drt)
|
||||
{
|
||||
closedir(dir);
|
||||
return -2;
|
||||
}
|
||||
|
||||
*min = (uint32_t)((1ULL << 32) - 1);
|
||||
*max = 0;
|
||||
|
||||
char prefix[MAX_PATH_NAME_LEN] = {0};
|
||||
snprintf(prefix, MAX_PATH_NAME_LEN, "%s.binlog.", _prefix);
|
||||
|
||||
int l = strlen(prefix);
|
||||
uint32_t v = 0;
|
||||
int found = 0;
|
||||
|
||||
for (; drt; drt = readdir(dir))
|
||||
{
|
||||
int n = strncmp(drt->d_name, prefix, l);
|
||||
if (n == 0)
|
||||
{
|
||||
v = strtoul(drt->d_name + l, NULL, 10);
|
||||
v >= 1 ? (*max < v ? *max = v : v), (v < *min ? *min = v : v) : v;
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
found ? *max : (*max = 0, *min = 0);
|
||||
|
||||
log_debug("scan serial: min=%u, max=%u\n", *min, *max);
|
||||
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LogBase::file_name(char *s, int len, unsigned serial)
|
||||
{
|
||||
snprintf(s, len, "%s/%s.binlog.%u", _path, _prefix, serial);
|
||||
}
|
||||
|
||||
LogWriter::LogWriter() : LogBase(),
|
||||
_cur_size(0),
|
||||
_max_size(0),
|
||||
_total_size(0),
|
||||
_cur_max_serial(0), //serial start 0
|
||||
_cur_min_serial(0) //serial start 0
|
||||
{
|
||||
}
|
||||
|
||||
LogWriter::~LogWriter()
|
||||
{
|
||||
}
|
||||
|
||||
int LogWriter::open(const char *path, const char *prefix,
|
||||
off_t max_size, uint64_t total_size)
|
||||
{
|
||||
if (set_path(path, prefix))
|
||||
return -1;
|
||||
|
||||
_max_size = max_size;
|
||||
_total_size = total_size;
|
||||
|
||||
if (scan_serial(&_cur_min_serial, &_cur_max_serial))
|
||||
{
|
||||
log_debug("scan file serial failed, %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_cur_max_serial += 1; //skip current binlog file.
|
||||
return open_file(_cur_max_serial, 0);
|
||||
}
|
||||
|
||||
int LogWriter::write(const void *buf, size_t size)
|
||||
{
|
||||
int unused;
|
||||
|
||||
unused = ::write(_fd, buf, size);
|
||||
if (unused != size)
|
||||
{
|
||||
log_error("wirte hblog[input size %u, write success size %d] err, %m", size, unused);
|
||||
}
|
||||
_cur_size += size;
|
||||
return shift_file();
|
||||
}
|
||||
|
||||
JournalID LogWriter::query()
|
||||
{
|
||||
JournalID v(_cur_max_serial, _cur_size);
|
||||
return v;
|
||||
}
|
||||
|
||||
int LogWriter::shift_file()
|
||||
{
|
||||
int need_shift = 0;
|
||||
int need_delete = 0;
|
||||
|
||||
if (_cur_size >= _max_size)
|
||||
need_shift = 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
uint64_t total = _cur_max_serial - _cur_min_serial;
|
||||
total *= _max_size;
|
||||
|
||||
if (total >= _total_size)
|
||||
{
|
||||
need_delete = 1;
|
||||
}
|
||||
|
||||
log_debug("shift file: cur_size:" UINT64FMT ", total_size:" UINT64FMT ", \
|
||||
shift:%d, cur_min_serial=%u, cur_max_serial=%u\n",
|
||||
total, _total_size, need_shift, _cur_min_serial, _cur_max_serial);
|
||||
|
||||
if (need_shift)
|
||||
{
|
||||
if (need_delete)
|
||||
{
|
||||
delete_file(_cur_min_serial);
|
||||
_cur_min_serial += 1;
|
||||
}
|
||||
|
||||
close_file();
|
||||
|
||||
_cur_size = 0;
|
||||
_cur_max_serial += 1;
|
||||
}
|
||||
|
||||
return open_file(_cur_max_serial, 0);
|
||||
}
|
||||
|
||||
LogReader::LogReader() : LogBase(),
|
||||
_min_serial(0),
|
||||
_max_serial(0),
|
||||
_cur_serial(0),
|
||||
_cur_offset(0)
|
||||
{
|
||||
}
|
||||
|
||||
LogReader::~LogReader()
|
||||
{
|
||||
}
|
||||
|
||||
int LogReader::open(const char *path, const char *prefix)
|
||||
{
|
||||
if (set_path(path, prefix))
|
||||
return -1;
|
||||
|
||||
//refresh directory
|
||||
refresh();
|
||||
|
||||
_cur_serial = _min_serial;
|
||||
_cur_offset = 0;
|
||||
|
||||
return open_file(_cur_serial, 1);
|
||||
}
|
||||
|
||||
void LogReader::refresh()
|
||||
{
|
||||
scan_serial(&_min_serial, &_max_serial);
|
||||
}
|
||||
|
||||
int LogReader::read(void *buf, size_t size)
|
||||
{
|
||||
ssize_t rd = ::read(_fd, buf, size);
|
||||
if (rd == (ssize_t)size)
|
||||
{
|
||||
_cur_offset += rd;
|
||||
return 0;
|
||||
}
|
||||
else if (rd < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 如果还有更大的serial,则丢弃buf内容,切换文件。否则,回退文件指针
|
||||
refresh();
|
||||
|
||||
if (_cur_serial < _max_serial)
|
||||
{
|
||||
_cur_serial += 1;
|
||||
_cur_offset = 0;
|
||||
|
||||
close_file();
|
||||
//跳过序号不存在的文件
|
||||
while (open_file(_cur_serial, 1) == -1 && _cur_serial < _max_serial)
|
||||
_cur_serial += 1;
|
||||
|
||||
if (_fd > 0 && _cur_serial <= _max_serial)
|
||||
return read(buf, size);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 回退文件指针
|
||||
if (rd > 0)
|
||||
{
|
||||
seek(JournalID(_cur_serial, _cur_offset));
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
JournalID LogReader::query()
|
||||
{
|
||||
JournalID v(_cur_serial, _cur_offset);
|
||||
return v;
|
||||
}
|
||||
|
||||
int LogReader::seek(const JournalID &v)
|
||||
{
|
||||
char file[MAX_PATH_NAME_LEN] = {0};
|
||||
file_name(file, MAX_PATH_NAME_LEN, v.serial);
|
||||
|
||||
/* 确保文件存在 */
|
||||
if (access(file, F_OK))
|
||||
return -1;
|
||||
|
||||
if (v.serial != _cur_serial)
|
||||
{
|
||||
close_file();
|
||||
|
||||
if (open_file(v.serial, 1) == -1)
|
||||
{
|
||||
log_debug("hblog %u not exist, seek failed", v.serial);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("open serial=%u, %m", v.serial);
|
||||
|
||||
off_t file_size = 0;
|
||||
stat_size(&file_size);
|
||||
|
||||
if (v.offset > (uint32_t)file_size)
|
||||
return -1;
|
||||
|
||||
lseek(_fd, v.offset, SEEK_SET);
|
||||
|
||||
_cur_offset = v.offset;
|
||||
_cur_serial = v.serial;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BinlogWriter::BinlogWriter() : _log_writer()
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
BinlogWriter::~BinlogWriter()
|
||||
{
|
||||
}
|
||||
|
||||
int BinlogWriter::Init(const char *path, const char *prefix, uint64_t total, off_t max_size)
|
||||
{
|
||||
return _log_writer.open(path, prefix, max_size, total);
|
||||
}
|
||||
|
||||
#define struct_sizeof(t) sizeof(((binlog_header_t *)NULL)->t)
|
||||
#define struct_typeof(t) typeof(((binlog_header_t *)NULL)->t)
|
||||
|
||||
int BinlogWriter::insert_header(uint8_t type, uint8_t operater, uint32_t count)
|
||||
{
|
||||
_codec_buffer.clear();
|
||||
|
||||
_codec_buffer.expand(offsetof(binlog_header_t, endof));
|
||||
|
||||
_codec_buffer << (struct_typeof(length))0; //length
|
||||
_codec_buffer << (struct_typeof(version))BINLOG_DEFAULT_VERSION; //version
|
||||
_codec_buffer << (struct_typeof(type))type; //type
|
||||
_codec_buffer << (struct_typeof(operater))operater; //operator
|
||||
_codec_buffer.append("\0\0\0\0\0", 5); //reserve char[5]
|
||||
_codec_buffer << (struct_typeof(timestamp))(time(NULL)); //timestamp
|
||||
_codec_buffer << (struct_typeof(recordcount))count; //recordcount
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BinlogWriter::append_body(const void *buf, size_t size)
|
||||
{
|
||||
_codec_buffer.append((char *)&size, struct_sizeof(length));
|
||||
_codec_buffer.append((const char *)buf, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BinlogWriter::Commit()
|
||||
{
|
||||
//计算总长度
|
||||
uint32_t total = _codec_buffer.size();
|
||||
total -= struct_sizeof(length);
|
||||
|
||||
//写入总长度
|
||||
struct_typeof(length) *length = (struct_typeof(length) *)(_codec_buffer.c_str());
|
||||
*length = total;
|
||||
|
||||
return _log_writer.write(_codec_buffer.c_str(), _codec_buffer.size());
|
||||
}
|
||||
|
||||
int BinlogWriter::Abort()
|
||||
{
|
||||
_codec_buffer.clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
JournalID BinlogWriter::query_id()
|
||||
{
|
||||
return _log_writer.query();
|
||||
}
|
||||
|
||||
BinlogReader::BinlogReader() : _log_reader()
|
||||
{
|
||||
}
|
||||
BinlogReader::~BinlogReader()
|
||||
{
|
||||
}
|
||||
|
||||
int BinlogReader::Init(const char *path, const char *prefix)
|
||||
{
|
||||
return _log_reader.open(path, prefix);
|
||||
}
|
||||
|
||||
int BinlogReader::Read()
|
||||
{
|
||||
/* prepare buffer */
|
||||
if (_codec_buffer.resize(struct_sizeof(length)) < 0)
|
||||
{
|
||||
log_error("expand _codec_buffer failed");
|
||||
return -1;
|
||||
}
|
||||
/* read length part of one binlog */
|
||||
if (_log_reader.read(_codec_buffer.c_str(), struct_sizeof(length)))
|
||||
return -1;
|
||||
|
||||
struct_typeof(length) len = *(struct_typeof(length) *)_codec_buffer.c_str();
|
||||
if (len < 8 || len >= (1 << 20) /*1M*/)
|
||||
{
|
||||
// filter some out of range length,
|
||||
// prevent client sending invalid jid crash server
|
||||
return -1;
|
||||
}
|
||||
_codec_buffer.resize(len + struct_sizeof(length));
|
||||
if (_log_reader.read(_codec_buffer.c_str() + struct_sizeof(length), len))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
JournalID BinlogReader::query_id()
|
||||
{
|
||||
return _log_reader.query();
|
||||
}
|
||||
|
||||
int BinlogReader::Seek(const JournalID &v)
|
||||
{
|
||||
return _log_reader.seek(v);
|
||||
}
|
||||
|
||||
uint8_t BinlogReader::binlog_type()
|
||||
{
|
||||
return ((binlog_header_t *)(_codec_buffer.c_str()))->type;
|
||||
}
|
||||
|
||||
uint8_t BinlogReader::binlog_operator()
|
||||
{
|
||||
return ((binlog_header_t *)(_codec_buffer.c_str()))->operater;
|
||||
}
|
||||
|
||||
uint32_t BinlogReader::record_count()
|
||||
{
|
||||
return ((binlog_header_t *)(_codec_buffer.c_str()))->recordcount;
|
||||
}
|
||||
|
||||
/*
|
||||
* binlog format:
|
||||
*
|
||||
* =====================================================
|
||||
* binlog_header_t | len1 | record1 | len2 | record2 | ...
|
||||
* =====================================================
|
||||
*
|
||||
*/
|
||||
char *BinlogReader::record_pointer(int id)
|
||||
{
|
||||
//record start
|
||||
char *p = (char *)(_codec_buffer.c_str() + offsetof(binlog_header_t, endof));
|
||||
char *m = 0;
|
||||
uint32_t l = struct_sizeof(length);
|
||||
uint32_t ll = 0;
|
||||
|
||||
for (int i = 0; i <= id; i++)
|
||||
{
|
||||
m = p + l;
|
||||
ll = *(struct_typeof(length) *)(m - struct_sizeof(length));
|
||||
l += (ll + struct_sizeof(length));
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
size_t BinlogReader::record_length(int id)
|
||||
{
|
||||
char *p = (char *)(_codec_buffer.c_str() + offsetof(binlog_header_t, endof));
|
||||
uint32_t ll, l;
|
||||
l = ll = 0;
|
||||
|
||||
for (int i = 0; i <= id; i++)
|
||||
{
|
||||
l = *(struct_typeof(length) *)(p + ll);
|
||||
ll += (l + struct_sizeof(length));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
193
src/search_local/index_storage/cache/logger.h
vendored
Normal file
193
src/search_local/index_storage/cache/logger.h
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: logger.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __DTC_LOGGER_H
|
||||
#define __DTC_LOGGER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include "buffer.h"
|
||||
#include "log.h"
|
||||
#include "journal_id.h"
|
||||
|
||||
#define MAX_PATH_NAME_LEN 256
|
||||
|
||||
/*
|
||||
* DTC binlog base class(file)
|
||||
*/
|
||||
class LogBase
|
||||
{
|
||||
public:
|
||||
LogBase();
|
||||
virtual ~LogBase();
|
||||
|
||||
protected:
|
||||
int set_path(const char *path, const char *prefix);
|
||||
void file_name(char *s, int len, uint32_t serail);
|
||||
int open_file(uint32_t serial, int read);
|
||||
void close_file();
|
||||
int scan_serial(uint32_t *min, uint32_t *max);
|
||||
int stat_size(off_t *);
|
||||
int delete_file(uint32_t serial);
|
||||
|
||||
private:
|
||||
LogBase(const LogBase &);
|
||||
|
||||
protected:
|
||||
int _fd;
|
||||
|
||||
private:
|
||||
char _path[MAX_PATH_NAME_LEN]; //日志集所在目录
|
||||
char _prefix[MAX_PATH_NAME_LEN]; //日志集的文件前缀
|
||||
};
|
||||
|
||||
class LogWriter : public LogBase
|
||||
{
|
||||
public:
|
||||
int open(const char *path, const char *prefix,
|
||||
off_t max_size, uint64_t total_size);
|
||||
int write(const void *buf, size_t size);
|
||||
JournalID query();
|
||||
|
||||
public:
|
||||
LogWriter();
|
||||
virtual ~LogWriter();
|
||||
|
||||
private:
|
||||
int shift_file();
|
||||
|
||||
private:
|
||||
off_t _cur_size; //当前日志文件的大小
|
||||
off_t _max_size; //单个日志文件允许的最大大小
|
||||
uint64_t _total_size; //日志集允许的最大大小
|
||||
uint32_t _cur_max_serial; //当前日志文件最大编号
|
||||
uint32_t _cur_min_serial; //当前日志文件最大编号
|
||||
};
|
||||
|
||||
class LogReader : public LogBase
|
||||
{
|
||||
public:
|
||||
int open(const char *path, const char *prefix);
|
||||
int read(void *buf, size_t size);
|
||||
|
||||
int seek(const JournalID &);
|
||||
JournalID query();
|
||||
|
||||
public:
|
||||
LogReader();
|
||||
virtual ~LogReader();
|
||||
|
||||
private:
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
uint32_t _min_serial; //日志集的最小文件编号
|
||||
uint32_t _max_serial; //日志集的最大文件编号
|
||||
uint32_t _cur_serial; //当前日志文件编号
|
||||
off_t _cur_offset; //当前日志文件偏移量
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
* generic binlog header
|
||||
*/
|
||||
typedef struct binlog_header
|
||||
{
|
||||
uint32_t length; //长度
|
||||
uint8_t version; //版本
|
||||
uint8_t type; //类型: bitmap, dtc, other
|
||||
uint8_t operater; //操作: insert,select,upate ...
|
||||
uint8_t reserve[5]; //保留
|
||||
uint32_t timestamp; //时间戳
|
||||
uint32_t recordcount; //子记录个数
|
||||
uint8_t endof[0];
|
||||
} __attribute__((__aligned__(1))) binlog_header_t;
|
||||
|
||||
/*
|
||||
* binlog type
|
||||
* t
|
||||
*/
|
||||
typedef enum binlog_type
|
||||
{
|
||||
BINLOG_LRU = 1,
|
||||
BINLOG_INSERT = 2,
|
||||
BINLOG_UPDATE = 4,
|
||||
BINLOG_PRUGE = 8,
|
||||
|
||||
} BINLOG_TYPE;
|
||||
|
||||
/*
|
||||
* binlog class
|
||||
*/
|
||||
#define BINLOG_MAX_SIZE (100 * (1U << 20)) //100M, 默认单个日志文件大小
|
||||
#define BINLOG_MAX_TOTAL_SIZE (3ULL << 30) //3G, 默认最大日志文件编号
|
||||
#define BINLOG_DEFAULT_VERSION 0x02
|
||||
|
||||
class BinlogWriter
|
||||
{
|
||||
public:
|
||||
int Init(const char *path, const char *prefix,
|
||||
uint64_t total_size = BINLOG_MAX_TOTAL_SIZE, off_t max_size = BINLOG_MAX_SIZE);
|
||||
int insert_header(uint8_t type, uint8_t operater, uint32_t recordcount);
|
||||
int append_body(const void *buf, size_t size);
|
||||
|
||||
int Commit();
|
||||
int Abort();
|
||||
JournalID query_id();
|
||||
|
||||
public:
|
||||
BinlogWriter();
|
||||
virtual ~BinlogWriter();
|
||||
|
||||
private:
|
||||
BinlogWriter(const BinlogWriter &);
|
||||
|
||||
private:
|
||||
LogWriter _log_writer; //写者
|
||||
buffer _codec_buffer; //编码缓冲区
|
||||
};
|
||||
|
||||
class BinlogReader
|
||||
{
|
||||
public:
|
||||
int Init(const char *path, const char *prefix);
|
||||
|
||||
int Read(); //顺序读,每次读出一条binlog记录
|
||||
int Seek(const JournalID &);
|
||||
JournalID query_id();
|
||||
|
||||
uint8_t binlog_type();
|
||||
uint8_t binlog_operator();
|
||||
|
||||
uint32_t record_count();
|
||||
char *record_pointer(int id = 0);
|
||||
size_t record_length(int id = 0);
|
||||
|
||||
public:
|
||||
BinlogReader();
|
||||
virtual ~BinlogReader();
|
||||
|
||||
private:
|
||||
BinlogReader(const BinlogReader &);
|
||||
|
||||
private:
|
||||
LogReader _log_reader; //读者
|
||||
buffer _codec_buffer; //编码缓冲区
|
||||
};
|
||||
|
||||
#endif
|
292
src/search_local/index_storage/cache/lru_bit.cc
vendored
Normal file
292
src/search_local/index_storage/cache/lru_bit.cc
vendored
Normal file
@ -0,0 +1,292 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: lru_bit.h
|
||||
*
|
||||
* Description: lru bitmap restore function.
|
||||
* recording master lru change infomation in order to improve slave hit rate.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include "lru_bit.h"
|
||||
#include "mem_check.h"
|
||||
#include "admin_tdef.h"
|
||||
#include "field.h"
|
||||
#include "table_def.h"
|
||||
#include "node.h"
|
||||
#include "node_index.h"
|
||||
#include "log.h"
|
||||
#include "table_def_manager.h"
|
||||
|
||||
LruBitObj::LruBitObj(LruBitUnit *t) : _max_lru_bit(0),
|
||||
_scan_lru_bit(0),
|
||||
_scan_idx_off(0),
|
||||
_lru_writer(0),
|
||||
_owner(t),
|
||||
scan_tm(0)
|
||||
|
||||
{
|
||||
bzero(_lru_bits, LRU_BITS * sizeof(lru_bit_t *));
|
||||
|
||||
lru_scan_tm = statmgr.get_item_u32(HBP_LRU_SCAN_TM);
|
||||
total_bits = statmgr.get_item_u32(HBP_LRU_TOTAL_BITS);
|
||||
total_1_bits = statmgr.get_item_u32(HBP_LRU_TOTAL_1_BITS);
|
||||
lru_set_count = statmgr.get_item_u32(HBP_LRU_SET_COUNT);
|
||||
lru_clr_count = statmgr.get_item_u32(HBP_LRU_CLR_COUNT);
|
||||
lru_set_hit_count = statmgr.get_item_u32(HBP_LRU_SET_HIT_COUNT);
|
||||
}
|
||||
|
||||
LruBitObj::~LruBitObj()
|
||||
{
|
||||
for (int i = 0; i < LRU_BITS; i++)
|
||||
{
|
||||
DELETE(_lru_bits[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int LruBitObj::SetNodeID(unsigned int v, int b)
|
||||
{
|
||||
int off = BBLK_OFF(v);
|
||||
|
||||
if (!_lru_bits[off])
|
||||
{
|
||||
NEW(lru_bit_t, _lru_bits[off]);
|
||||
if (!_lru_bits[off])
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* stat set/clr count */
|
||||
if (b)
|
||||
lru_set_count++;
|
||||
else
|
||||
lru_clr_count++;
|
||||
|
||||
if (_lru_bits[off]->set(v, b))
|
||||
{
|
||||
/* stat set hit count */
|
||||
lru_set_hit_count++;
|
||||
}
|
||||
else if (b)
|
||||
{
|
||||
total_1_bits++;
|
||||
}
|
||||
|
||||
_max_lru_bit < off ? _max_lru_bit = off : off;
|
||||
|
||||
/* stat total bits */
|
||||
total_bits < v ? total_bits = v : total_bits;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LruBitObj::timer_notify(void)
|
||||
{
|
||||
|
||||
Scan();
|
||||
|
||||
attach_timer(_owner->_scan_timerlist);
|
||||
}
|
||||
|
||||
int LruBitObj::Init(BinlogWriter *w, int stop_until)
|
||||
{
|
||||
_scan_stop_until = stop_until;
|
||||
|
||||
NEW(LruWriter(w), _lru_writer);
|
||||
if (!_lru_writer)
|
||||
return -1;
|
||||
|
||||
if (_lru_writer->Init())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LruBitObj::Scan(void)
|
||||
{
|
||||
if (scan_tm == 0)
|
||||
{
|
||||
INIT_MSEC(scan_tm);
|
||||
}
|
||||
|
||||
lru_bit_t *p = _lru_bits[_scan_lru_bit];
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
unsigned found_id = 0;
|
||||
for (; _scan_idx_off < IDX_SIZE;)
|
||||
{
|
||||
unsigned found = 0;
|
||||
|
||||
//扫描idx中的1 byte, 最大会有512个node id
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
//读取idx中的第_scan_idx_off个字节的第j位对应的blk中的8 bytes
|
||||
uint64_t v = p->read(_scan_idx_off, j);
|
||||
if (0 == v)
|
||||
continue;
|
||||
|
||||
//扫描blk中的8 bytes
|
||||
for (int i = 0; i < 64; ++i)
|
||||
{
|
||||
if (v & 0x1)
|
||||
{
|
||||
found += 1;
|
||||
|
||||
uint32_t id = (_scan_lru_bit << 21) + (_scan_idx_off << 9) + (j << 6) + i;
|
||||
|
||||
log_debug("adjust lru: node-id=%u", id);
|
||||
|
||||
_lru_writer->Write(id);
|
||||
}
|
||||
|
||||
v >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (found > 0)
|
||||
{
|
||||
//批量写入lru变更
|
||||
_lru_writer->Commit();
|
||||
|
||||
//idx清零1byete, blk清零64bytes
|
||||
total_1_bits -= p->clear(_scan_idx_off);
|
||||
}
|
||||
|
||||
_scan_idx_off += 1;
|
||||
|
||||
found_id += found;
|
||||
// 如果超过此水位,终止扫描, 等待下一次被调度
|
||||
if (found_id >= _scan_stop_until)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//调整为下一个lru_bit(4k)
|
||||
_scan_idx_off = 0;
|
||||
_scan_lru_bit += 1;
|
||||
if (_scan_lru_bit > _max_lru_bit)
|
||||
{
|
||||
|
||||
_scan_lru_bit = 0;
|
||||
|
||||
CALC_MSEC(scan_tm);
|
||||
lru_scan_tm = scan_tm;
|
||||
scan_tm = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LruBitUnit::LruBitUnit(TimerUnit *p) : _scan_timerlist(0),
|
||||
_lru_bit_obj(0),
|
||||
_is_start(0),
|
||||
_owner(p)
|
||||
{
|
||||
}
|
||||
|
||||
LruBitUnit::~LruBitUnit()
|
||||
{
|
||||
DELETE(_lru_bit_obj);
|
||||
}
|
||||
|
||||
int LruBitUnit::Init(BinlogWriter *w)
|
||||
{
|
||||
_scan_timerlist = _owner->get_timer_list_by_m_seconds(LRU_SCAN_INTERVAL);
|
||||
|
||||
NEW(LruBitObj(this), _lru_bit_obj);
|
||||
if (!_lru_bit_obj)
|
||||
return -1;
|
||||
|
||||
if (_lru_bit_obj->Init(w))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LruBitUnit::enable_log(void)
|
||||
{
|
||||
_is_start = 1;
|
||||
_lru_bit_obj->attach_timer(_scan_timerlist);
|
||||
}
|
||||
|
||||
void LruBitUnit::disable_log(void)
|
||||
{
|
||||
_is_start = 0;
|
||||
_lru_bit_obj->disable_timer();
|
||||
}
|
||||
|
||||
int LruBitUnit::Set(unsigned int v)
|
||||
{
|
||||
return _is_start ? _lru_bit_obj->SetNodeID(v, 1) : 0;
|
||||
}
|
||||
|
||||
int LruBitUnit::Unset(unsigned int v)
|
||||
{
|
||||
return _is_start ? _lru_bit_obj->SetNodeID(v, 0) : 0;
|
||||
}
|
||||
|
||||
LruWriter::LruWriter(BinlogWriter *w) : _log_writer(w),
|
||||
_raw_data(0)
|
||||
{
|
||||
}
|
||||
|
||||
LruWriter::~LruWriter()
|
||||
{
|
||||
DELETE(_raw_data);
|
||||
}
|
||||
|
||||
int LruWriter::Init()
|
||||
{
|
||||
NEW(RawData(&g_stSysMalloc, 1), _raw_data);
|
||||
if (!_raw_data)
|
||||
return -1;
|
||||
|
||||
unsigned type = DTCHotBackup::SYNC_LRU;
|
||||
if (_raw_data->Init(0, TableDefinitionManager::Instance()->get_hot_backup_table_def()->key_size(), (const char *)&type, 0, -1, -1, 0))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LruWriter::Write(unsigned int v)
|
||||
{
|
||||
log_debug("enter LruWriter, lru changes, node id:%u", v);
|
||||
|
||||
Node node = I_SEARCH(v);
|
||||
if (!node) //NODE已经不存在,不处理
|
||||
return 0;
|
||||
|
||||
DataChunk *p = M_POINTER(DataChunk, node.vd_handle());
|
||||
RowValue r(TableDefinitionManager::Instance()->get_hot_backup_table_def());
|
||||
|
||||
r[0].u64 = DTCHotBackup::SYNC_LRU;
|
||||
r[1].u64 = DTCHotBackup::NON_VALUE;
|
||||
|
||||
//self table-definition encode packed key
|
||||
r[2] = TableDefinitionManager::Instance()->get_cur_table_def()->packed_key(p->Key());
|
||||
r[3].Set(0);
|
||||
|
||||
return _raw_data->insert_row(r, false, false);
|
||||
}
|
||||
|
||||
int LruWriter::Commit(void)
|
||||
{
|
||||
log_debug("lru write commit");
|
||||
|
||||
_log_writer->insert_header(BINLOG_LRU, 0, 1);
|
||||
_log_writer->append_body(_raw_data->get_addr(), _raw_data->data_size());
|
||||
|
||||
log_debug("body: len=%d, content:%x", _raw_data->data_size(), *(char *)_raw_data->get_addr());
|
||||
|
||||
_raw_data->delete_all_rows();
|
||||
return _log_writer->Commit();
|
||||
}
|
215
src/search_local/index_storage/cache/lru_bit.h
vendored
Normal file
215
src/search_local/index_storage/cache/lru_bit.h
vendored
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: lru_bit.h
|
||||
*
|
||||
* Description: lru bitmap restore function.
|
||||
* recording master lru change infomation in order to improve slave hit rate.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __LRU_BIT_H
|
||||
#define __LRU_BIT_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include "bitsop.h"
|
||||
#include "timer_list.h"
|
||||
#include "logger.h"
|
||||
#include "raw_data.h"
|
||||
#include "data_chunk.h"
|
||||
#include "admin_tdef.h"
|
||||
#include "sys_malloc.h"
|
||||
|
||||
#define IDX_SIZE (4 << 10) //4K
|
||||
#define BLK_SIZE (256 << 10) //256K
|
||||
#define LRU_BITS (2 << 10) //2k
|
||||
|
||||
#define BBLK_OFF(v) (v >> 21)
|
||||
#define IDX_BYTE_OFF(v) ((v >> 9) & 0xFFF)
|
||||
#define IDX_BYTE_SHIFT(v) ((v >> 6) & 0x7)
|
||||
#define BLK_8_BYTE_OFF(v) ((v >> 6) & 0x7FFF)
|
||||
#define BLK_BYTE_OFF(v) ((v >> 3) & 0x3FFFF)
|
||||
#define BLK_BYTE_SHIFT(v) (v & 0x7)
|
||||
|
||||
/*
|
||||
* Node ID 位图储存表
|
||||
*
|
||||
*====================================================================================
|
||||
*| 11 b | 12 b | 3 b | 3 b | 3 b |
|
||||
*| bblk off | idx byte off | idx byte shift|
|
||||
* | blk 8-bytes off |
|
||||
* | blk byte off | blk byte shift|
|
||||
*====================================================================================
|
||||
*/
|
||||
|
||||
typedef struct lru_bit
|
||||
{
|
||||
char _idx[IDX_SIZE];
|
||||
char _blk[BLK_SIZE];
|
||||
|
||||
lru_bit()
|
||||
{
|
||||
bzero(_idx, sizeof(_idx));
|
||||
bzero(_blk, sizeof(_blk));
|
||||
}
|
||||
|
||||
~lru_bit() {}
|
||||
|
||||
/* 如果set命中返回1,否则返回0 */
|
||||
int set(unsigned int v, int b)
|
||||
{
|
||||
int hit = 0;
|
||||
uint32_t byte_shift = BLK_BYTE_SHIFT(v);
|
||||
uint32_t byte_offset = BLK_BYTE_OFF(v);
|
||||
|
||||
if (b)
|
||||
{
|
||||
if (ISSET_B(byte_shift, _blk + byte_offset))
|
||||
{
|
||||
hit = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
SET_B(byte_shift, _blk + byte_offset);
|
||||
SET_B(IDX_BYTE_SHIFT(v), _idx + IDX_BYTE_OFF(v));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLR_B(byte_shift, _blk + byte_offset);
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
/* return total clear bits */
|
||||
int clear(int idx_off)
|
||||
{
|
||||
int clear_bits = COUNT_B(_blk + (idx_off << 6), 1 << 6);
|
||||
|
||||
/* 1 byte idx */
|
||||
memset(_idx + idx_off, 0x00, 1);
|
||||
|
||||
/* 64 bytes blk */
|
||||
memset(_blk + (idx_off << 6), 0x00, 1 << 6);
|
||||
|
||||
return clear_bits;
|
||||
}
|
||||
|
||||
uint64_t read(int idx_off, int idx_shift)
|
||||
{
|
||||
unsigned char *ix = (unsigned char *)_idx + idx_off;
|
||||
|
||||
if (ISSET_B(idx_shift, ix))
|
||||
{
|
||||
|
||||
uint64_t *p = (uint64_t *)_blk;
|
||||
return p[(idx_off << 3) + idx_shift];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} lru_bit_t;
|
||||
|
||||
/*
|
||||
*
|
||||
* 扫描频率、速度控制
|
||||
* 1. 不能影响正常的update同步
|
||||
* 2. 尽量在控制时间内完成一趟扫描
|
||||
*
|
||||
*/
|
||||
#define LRU_SCAN_STOP_UNTIL 20 //20
|
||||
#define LRU_SCAN_INTERVAL 10 //10ms
|
||||
|
||||
class RawData;
|
||||
class LruWriter
|
||||
{
|
||||
public:
|
||||
LruWriter(BinlogWriter *);
|
||||
virtual ~LruWriter();
|
||||
|
||||
int Init();
|
||||
int Write(unsigned int id);
|
||||
int Commit(void);
|
||||
|
||||
private:
|
||||
BinlogWriter *_log_writer;
|
||||
RawData *_raw_data;
|
||||
};
|
||||
|
||||
class LruBitUnit;
|
||||
class LruBitObj : private TimerObject
|
||||
{
|
||||
public:
|
||||
LruBitObj(LruBitUnit *);
|
||||
~LruBitObj();
|
||||
|
||||
int Init(BinlogWriter *, int stop_until = LRU_SCAN_STOP_UNTIL);
|
||||
int SetNodeID(unsigned int v, int b);
|
||||
|
||||
private:
|
||||
int Scan(void);
|
||||
virtual void timer_notify(void);
|
||||
|
||||
private:
|
||||
lru_bit_t *_lru_bits[LRU_BITS];
|
||||
uint16_t _max_lru_bit;
|
||||
uint16_t _scan_lru_bit;
|
||||
uint16_t _scan_idx_off;
|
||||
uint16_t _scan_stop_until;
|
||||
|
||||
LruWriter *_lru_writer;
|
||||
LruBitUnit *_owner;
|
||||
|
||||
friend class LruBitUnit;
|
||||
|
||||
private:
|
||||
/* statistic */
|
||||
uint32_t scan_tm;
|
||||
StatItemU32 lru_scan_tm;
|
||||
|
||||
StatItemU32 total_bits;
|
||||
StatItemU32 total_1_bits;
|
||||
|
||||
StatItemU32 lru_set_count;
|
||||
StatItemU32 lru_set_hit_count;
|
||||
StatItemU32 lru_clr_count;
|
||||
};
|
||||
|
||||
class LruBitUnit
|
||||
{
|
||||
public:
|
||||
LruBitUnit(TimerUnit *);
|
||||
~LruBitUnit();
|
||||
|
||||
int Init(BinlogWriter *);
|
||||
void enable_log(void);
|
||||
void disable_log(void);
|
||||
int check_status() { return _is_start; } // 0:不启动, 1:启动
|
||||
int Set(unsigned int v);
|
||||
int Unset(unsigned int v);
|
||||
|
||||
private:
|
||||
TimerList *_scan_timerlist;
|
||||
LruBitObj *_lru_bit_obj;
|
||||
int _is_start;
|
||||
TimerUnit *_owner;
|
||||
|
||||
friend class LruBitObj;
|
||||
};
|
||||
|
||||
#endif
|
1009
src/search_local/index_storage/cache/main.cc
vendored
Normal file
1009
src/search_local/index_storage/cache/main.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
123
src/search_local/index_storage/cache/mallocator.h
vendored
Normal file
123
src/search_local/index_storage/cache/mallocator.h
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: mallocator.h
|
||||
*
|
||||
* Description: memory operating interface.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef MALLOCATOR_H
|
||||
#define MALLOCATOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "namespace.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
#define ALLOC_SIZE_T uint32_t
|
||||
#define ALLOC_HANDLE_T uint64_t
|
||||
#define INTER_SIZE_T uint64_t
|
||||
#define INTER_HANDLE_T uint64_t
|
||||
|
||||
#define INVALID_HANDLE 0ULL
|
||||
|
||||
#define SIZE_SZ (sizeof(ALLOC_SIZE_T))
|
||||
#define MALLOC_ALIGNMENT (2 * SIZE_SZ)
|
||||
#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
|
||||
#define MAX_ALLOC_SIZE (((ALLOC_SIZE_T)-1) & ~MALLOC_ALIGN_MASK)
|
||||
|
||||
class Mallocator
|
||||
{
|
||||
public:
|
||||
Mallocator() {}
|
||||
virtual ~Mallocator() {}
|
||||
|
||||
template <class T>
|
||||
T *Pointer(ALLOC_HANDLE_T hHandle) { return reinterpret_cast<T *>(handle_to_ptr(hHandle)); }
|
||||
|
||||
virtual ALLOC_HANDLE_T Handle(void *p) = 0;
|
||||
|
||||
virtual const char *get_err_msg() = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 分配内存
|
||||
Input: tSize 分配的内存大小
|
||||
Output:
|
||||
Return: 内存块句柄,INVALID_HANDLE为失败
|
||||
*************************************************/
|
||||
virtual ALLOC_HANDLE_T Malloc(ALLOC_SIZE_T tSize) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 分配内存,并将内存初始化为0
|
||||
Input: tSize 分配的内存大小
|
||||
Output:
|
||||
Return: 内存块句柄,INVALID_HANDLE为失败
|
||||
*************************************************/
|
||||
virtual ALLOC_HANDLE_T Calloc(ALLOC_SIZE_T tSize) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 重新分配内存
|
||||
Input: hHandle 老内存句柄
|
||||
tSize 新分配的内存大小
|
||||
Output:
|
||||
Return: 内存块句柄,INVALID_HANDLE为失败(失败时不会释放老内存块)
|
||||
*************************************************/
|
||||
virtual ALLOC_HANDLE_T ReAlloc(ALLOC_HANDLE_T hHandle, ALLOC_SIZE_T tSize) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 释放内存
|
||||
Input: hHandle 内存句柄
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
virtual int Free(ALLOC_HANDLE_T hHandle) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 获取内存块大小
|
||||
Input: hHandle 内存句柄
|
||||
Output:
|
||||
Return: 内存大小
|
||||
*************************************************/
|
||||
virtual ALLOC_SIZE_T chunk_size(ALLOC_HANDLE_T hHandle) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 将句柄转换成内存地址
|
||||
Input: 内存句柄
|
||||
Output:
|
||||
Return: 内存地址,如果句柄无效返回NULL
|
||||
*************************************************/
|
||||
virtual void *handle_to_ptr(ALLOC_HANDLE_T hHandle) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 将内存地址转换为句柄
|
||||
Input: 内存地址
|
||||
Output:
|
||||
Return: 内存句柄,如果地址无效返回INVALID_HANDLE
|
||||
*************************************************/
|
||||
virtual ALLOC_HANDLE_T ptr_to_handle(void *p) = 0;
|
||||
|
||||
virtual ALLOC_SIZE_T ask_for_destroy_size(ALLOC_HANDLE_T hHandl) = 0;
|
||||
|
||||
/*************************************************
|
||||
Description: 检测handle是否有效
|
||||
Input: 内存句柄
|
||||
Output:
|
||||
Return: 0: 有效; -1:无效
|
||||
*************************************************/
|
||||
virtual int handle_is_valid(ALLOC_HANDLE_T mem_handle) = 0;
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
291
src/search_local/index_storage/cache/mysql_error.h
vendored
Normal file
291
src/search_local/index_storage/cache/mysql_error.h
vendored
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: mysql_error.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __H_DTC_MYSQL_ERROR_H__
|
||||
#define __H_DTC_MYSQL_ERROR_H__
|
||||
enum
|
||||
{
|
||||
ER_HASHCHK = 1000,
|
||||
ER_NISAMCHK = 1001,
|
||||
ER_NO = 1002,
|
||||
ER_YES = 1003,
|
||||
ER_CANT_CREATE_FILE = 1004,
|
||||
ER_CANT_CREATE_TABLE = 1005,
|
||||
ER_CANT_CREATE_DB = 1006,
|
||||
ER_DB_CREATE_EXISTS = 1007,
|
||||
ER_DB_DROP_EXISTS = 1008,
|
||||
ER_DB_DROP_DELETE = 1009,
|
||||
ER_DB_DROP_RMDIR = 1010,
|
||||
ER_CANT_DELETE_FILE = 1011,
|
||||
ER_CANT_FIND_SYSTEM_REC = 1012,
|
||||
ER_CANT_GET_STAT = 1013,
|
||||
ER_CANT_GET_WD = 1014,
|
||||
ER_CANT_LOCK = 1015,
|
||||
ER_CANT_OPEN_FILE = 1016,
|
||||
ER_FILE_NOT_FOUND = 1017,
|
||||
ER_CANT_READ_DIR = 1018,
|
||||
ER_CANT_SET_WD = 1019,
|
||||
ER_CHECKREAD = 1020,
|
||||
ER_DISK_FULL = 1021,
|
||||
ER_DUP_KEY = 1022,
|
||||
ER_ERROR_ON_CLOSE = 1023,
|
||||
ER_ERROR_ON_READ = 1024,
|
||||
ER_ERROR_ON_RENAME = 1025,
|
||||
ER_ERROR_ON_WRITE = 1026,
|
||||
ER_FILE_USED = 1027,
|
||||
ER_FILSORT_ABORT = 1028,
|
||||
ER_FORM_NOT_FOUND = 1029,
|
||||
ER_GET_ERRNO = 1030,
|
||||
ER_ILLEGAL_HA = 1031,
|
||||
ER_KEY_NOT_FOUND = 1032,
|
||||
ER_NOT_FORM_FILE = 1033,
|
||||
ER_NOT_KEYFILE = 1034,
|
||||
ER_OLD_KEYFILE = 1035,
|
||||
ER_OPEN_AS_READONLY = 1036,
|
||||
ER_OUTOFMEMORY = 1037,
|
||||
ER_OUT_OF_SORTMEMORY = 1038,
|
||||
ER_UNEXPECTED_EOF = 1039,
|
||||
ER_CON_COUNT_ERROR = 1040,
|
||||
ER_OUT_OF_RESOURCES = 1041,
|
||||
ER_BAD_HOST_ERROR = 1042,
|
||||
ER_HANDSHAKE_ERROR = 1043,
|
||||
ER_DBACCESS_DENIED_ERROR = 1044,
|
||||
ER_ACCESS_DENIED_ERROR = 1045,
|
||||
ER_NO_DB_ERROR = 1046,
|
||||
ER_UNKNOWN_COM_ERROR = 1047,
|
||||
ER_BAD_NULL_ERROR = 1048,
|
||||
ER_BAD_DB_ERROR = 1049,
|
||||
ER_TABLE_EXISTS_ERROR = 1050,
|
||||
ER_BAD_TABLE_ERROR = 1051,
|
||||
ER_NON_UNIQ_ERROR = 1052,
|
||||
ER_SERVER_SHUTDOWN = 1053,
|
||||
ER_BAD_FIELD_ERROR = 1054,
|
||||
ER_WRONG_FIELD_WITH_GROUP = 1055,
|
||||
ER_WRONG_GROUP_FIELD = 1056,
|
||||
ER_WRONG_SUM_SELECT = 1057,
|
||||
ER_WRONG_VALUE_COUNT = 1058,
|
||||
ER_TOO_LONG_IDENT = 1059,
|
||||
ER_DUP_FIELDNAME = 1060,
|
||||
ER_DUP_KEYNAME = 1061,
|
||||
ER_DUP_ENTRY = 1062,
|
||||
ER_WRONG_FIELD_SPEC = 1063,
|
||||
ER_PARSE_ERROR = 1064,
|
||||
ER_EMPTY_QUERY = 1065,
|
||||
ER_NONUNIQ_TABLE = 1066,
|
||||
ER_INVALID_DEFAULT = 1067,
|
||||
ER_MULTIPLE_PRI_KEY = 1068,
|
||||
ER_TOO_MANY_KEYS = 1069,
|
||||
ER_TOO_MANY_KEY_PARTS = 1070,
|
||||
ER_TOO_LONG_KEY = 1071,
|
||||
ER_KEY_COLUMN_DOES_NOT_EXITS = 1072,
|
||||
ER_BLOB_USED_AS_KEY = 1073,
|
||||
ER_TOO_BIG_FIELDLENGTH = 1074,
|
||||
ER_WRONG_AUTO_KEY = 1075,
|
||||
ER_READY = 1076,
|
||||
ER_NORMAL_SHUTDOWN = 1077,
|
||||
ER_GOT_SIGNAL = 1078,
|
||||
ER_SHUTDOWN_COMPLETE = 1079,
|
||||
ER_FORCING_CLOSE = 1080,
|
||||
ER_IPSOCK_ERROR = 1081,
|
||||
ER_NO_SUCH_INDEX = 1082,
|
||||
ER_WRONG_FIELD_TERMINATORS = 1083,
|
||||
ER_BLOBS_AND_NO_TERMINATED = 1084,
|
||||
ER_TEXTFILE_NOT_READABLE = 1085,
|
||||
ER_FILE_EXISTS_ERROR = 1086,
|
||||
ER_LOAD_INFO = 1087,
|
||||
ER_ALTER_INFO = 1088,
|
||||
ER_WRONG_SUB_KEY = 1089,
|
||||
ER_CANT_REMOVE_ALL_FIELDS = 1090,
|
||||
ER_CANT_DROP_FIELD_OR_KEY = 1091,
|
||||
ER_INSERT_INFO = 1092,
|
||||
ER_INSERT_TABLE_USED = 1093,
|
||||
ER_NO_SUCH_THREAD = 1094,
|
||||
ER_KILL_DENIED_ERROR = 1095,
|
||||
ER_NO_TABLES_USED = 1096,
|
||||
ER_TOO_BIG_SET = 1097,
|
||||
ER_NO_UNIQUE_LOGFILE = 1098,
|
||||
ER_TABLE_NOT_LOCKED_FOR_WRITE = 1099,
|
||||
ER_TABLE_NOT_LOCKED = 1100,
|
||||
ER_BLOB_CANT_HAVE_DEFAULT = 1101,
|
||||
ER_WRONG_DB_NAME = 1102,
|
||||
ER_WRONG_TABLE_NAME = 1103,
|
||||
ER_TOO_BIG_SELECT = 1104,
|
||||
ER_UNKNOWN_ERROR = 1105,
|
||||
ER_UNKNOWN_PROCEDURE = 1106,
|
||||
ER_WRONG_PARAMCOUNT_TO_PROCEDURE = 1107,
|
||||
ER_WRONG_PARAMETERS_TO_PROCEDURE = 1108,
|
||||
ER_UNKNOWN_TABLE = 1109,
|
||||
ER_FIELD_SPECIFIED_TWICE = 1110,
|
||||
ER_INVALID_GROUP_FUNC_USE = 1111,
|
||||
ER_UNSUPPORTED_EXTENSION = 1112,
|
||||
ER_TABLE_MUST_HAVE_COLUMNS = 1113,
|
||||
ER_RECORD_FILE_FULL = 1114,
|
||||
ER_UNKNOWN_CHARACTER_SET = 1115,
|
||||
ER_TOO_MANY_TABLES = 1116,
|
||||
ER_TOO_MANY_FIELDS = 1117,
|
||||
ER_TOO_BIG_ROWSIZE = 1118,
|
||||
ER_STACK_OVERRUN = 1119,
|
||||
ER_WRONG_OUTER_JOIN = 1120,
|
||||
ER_NULL_COLUMN_IN_INDEX = 1121,
|
||||
ER_CANT_FIND_UDF = 1122,
|
||||
ER_CANT_INITIALIZE_UDF = 1123,
|
||||
ER_UDF_NO_PATHS = 1124,
|
||||
ER_UDF_EXISTS = 1125,
|
||||
ER_CANT_OPEN_LIBRARY = 1126,
|
||||
ER_CANT_FIND_DL_ENTRY = 1127,
|
||||
ER_FUNCTION_NOT_DEFINED = 1128,
|
||||
ER_HOST_IS_BLOCKED = 1129,
|
||||
ER_HOST_NOT_PRIVILEGED = 1130,
|
||||
ER_PASSWORD_ANONYMOUS_USER = 1131,
|
||||
ER_PASSWORD_NOT_ALLOWED = 1132,
|
||||
ER_PASSWORD_NO_MATCH = 1133,
|
||||
ER_UPDATE_INFO = 1134,
|
||||
ER_CANT_CREATE_THREAD = 1135,
|
||||
ER_WRONG_VALUE_COUNT_ON_ROW = 1136,
|
||||
ER_CANT_REOPEN_TABLE = 1137,
|
||||
ER_INVALID_USE_OF_NULL = 1138,
|
||||
ER_REGEXP_ERROR = 1139,
|
||||
ER_MIX_OF_GROUP_FUNC_AND_FIELDS = 1140,
|
||||
ER_NONEXISTING_GRANT = 1141,
|
||||
ER_TABLEACCESS_DENIED_ERROR = 1142,
|
||||
ER_COLUMNACCESS_DENIED_ERROR = 1143,
|
||||
ER_ILLEGAL_GRANT_FOR_TABLE = 1144,
|
||||
ER_GRANT_WRONG_HOST_OR_USER = 1145,
|
||||
ER_NO_SUCH_TABLE = 1146,
|
||||
ER_NONEXISTING_TABLE_GRANT = 1147,
|
||||
ER_NOT_ALLOWED_COMMAND = 1148,
|
||||
ER_SYNTAX_ERROR = 1149,
|
||||
ER_DELAYED_CANT_CHANGE_LOCK = 1150,
|
||||
ER_TOO_MANY_DELAYED_THREADS = 1151,
|
||||
ER_ABORTING_CONNECTION = 1152,
|
||||
ER_NET_PACKET_TOO_LARGE = 1153,
|
||||
ER_NET_READ_ERROR_FROM_PIPE = 1154,
|
||||
ER_NET_FCNTL_ERROR = 1155,
|
||||
ER_NET_PACKETS_OUT_OF_ORDER = 1156,
|
||||
ER_NET_UNCOMPRESS_ERROR = 1157,
|
||||
ER_NET_READ_ERROR = 1158,
|
||||
ER_NET_READ_INTERRUPTED = 1159,
|
||||
ER_NET_ERROR_ON_WRITE = 1160,
|
||||
ER_NET_WRITE_INTERRUPTED = 1161,
|
||||
ER_TOO_LONG_STRING = 1162,
|
||||
ER_TABLE_CANT_HANDLE_BLOB = 1163,
|
||||
ER_TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164,
|
||||
ER_DELAYED_INSERT_TABLE_LOCKED = 1165,
|
||||
ER_WRONG_COLUMN_NAME = 1166,
|
||||
ER_WRONG_KEY_COLUMN = 1167,
|
||||
ER_WRONG_MRG_TABLE = 1168,
|
||||
ER_DUP_UNIQUE = 1169,
|
||||
ER_BLOB_KEY_WITHOUT_LENGTH = 1170,
|
||||
ER_PRIMARY_CANT_HAVE_NULL = 1171,
|
||||
ER_TOO_MANY_ROWS = 1172,
|
||||
ER_REQUIRES_PRIMARY_KEY = 1173,
|
||||
ER_NO_RAID_COMPILED = 1174,
|
||||
ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175,
|
||||
ER_KEY_DOES_NOT_EXITS = 1176,
|
||||
ER_CHECK_NO_SUCH_TABLE = 1177,
|
||||
ER_CHECK_NOT_IMPLEMENTED = 1178,
|
||||
ER_CANT_DO_THIS_DURING_AN_TRANSACTION = 1179,
|
||||
ER_ERROR_DURING_COMMIT = 1180,
|
||||
ER_ERROR_DURING_ROLLBACK = 1181,
|
||||
ER_ERROR_DURING_FLUSH_LOGS = 1182,
|
||||
ER_ERROR_DURING_CHECKPOINT = 1183,
|
||||
ER_NEW_ABORTING_CONNECTION = 1184,
|
||||
ER_DUMP_NOT_IMPLEMENTED = 1185,
|
||||
ER_FLUSH_MASTER_BINLOG_CLOSED = 1186,
|
||||
ER_INDEX_REBUILD = 1187,
|
||||
ER_MASTER = 1188,
|
||||
ER_MASTER_NET_READ = 1189,
|
||||
ER_MASTER_NET_WRITE = 1190,
|
||||
ER_FT_MATCHING_KEY_NOT_FOUND = 1191,
|
||||
ER_LOCK_OR_ACTIVE_TRANSACTION = 1192,
|
||||
ER_UNKNOWN_SYSTEM_VARIABLE = 1193,
|
||||
ER_CRASHED_ON_USAGE = 1194,
|
||||
ER_CRASHED_ON_REPAIR = 1195,
|
||||
ER_WARNING_NOT_COMPLETE_ROLLBACK = 1196,
|
||||
ER_TRANS_CACHE_FULL = 1197,
|
||||
ER_SLAVE_MUST_STOP = 1198,
|
||||
ER_SLAVE_NOT_RUNNING = 1199,
|
||||
ER_BAD_SLAVE = 1200,
|
||||
ER_MASTER_INFO = 1201,
|
||||
ER_SLAVE_THREAD = 1202,
|
||||
ER_TOO_MANY_USER_CONNECTIONS = 1203,
|
||||
ER_SET_CONSTANTS_ONLY = 1204,
|
||||
ER_LOCK_WAIT_TIMEOUT = 1205,
|
||||
ER_LOCK_TABLE_FULL = 1206,
|
||||
ER_READ_ONLY_TRANSACTION = 1207,
|
||||
ER_DROP_DB_WITH_READ_LOCK = 1208,
|
||||
ER_CREATE_DB_WITH_READ_LOCK = 1209,
|
||||
ER_WRONG_ARGUMENTS = 1210,
|
||||
ER_NO_PERMISSION_TO_CREATE_USER = 1211,
|
||||
ER_UNION_TABLES_IN_DIFFERENT_DIR = 1212,
|
||||
ER_LOCK_DEADLOCK = 1213,
|
||||
ER_TABLE_CANT_HANDLE_FULLTEXT = 1214,
|
||||
ER_CANNOT_ADD_FOREIGN = 1215,
|
||||
ER_NO_REFERENCED_ROW = 1216,
|
||||
ER_ROW_IS_REFERENCED = 1217,
|
||||
ER_CONNECT_TO_MASTER = 1218,
|
||||
ER_QUERY_ON_MASTER = 1219,
|
||||
ER_ERROR_WHEN_EXECUTING_COMMAND = 1220,
|
||||
ER_WRONG_USAGE = 1221,
|
||||
ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222,
|
||||
ER_CANT_UPDATE_WITH_READLOCK = 1223,
|
||||
ER_MIXING_NOT_ALLOWED = 1224,
|
||||
ER_DUP_ARGUMENT = 1225,
|
||||
ER_USER_LIMIT_REACHED = 1226,
|
||||
ER_SPECIFIC_ACCESS_DENIED_ERROR = 1227,
|
||||
ER_LOCAL_VARIABLE = 1228,
|
||||
ER_GLOBAL_VARIABLE = 1229,
|
||||
ER_NO_DEFAULT = 1230,
|
||||
ER_WRONG_VALUE_FOR_VAR = 1231,
|
||||
ER_WRONG_TYPE_FOR_VAR = 1232,
|
||||
ER_VAR_CANT_BE_READ = 1233,
|
||||
ER_CANT_USE_OPTION_HERE = 1234,
|
||||
ER_NOT_SUPPORTED_YET = 1235,
|
||||
ER_MASTER_FATAL_ERROR_READING_BINLOG = 1236,
|
||||
ER_SLAVE_IGNORED_TABLE = 1237,
|
||||
ER_INCORRECT_GLOBAL_LOCAL_VAR = 1238,
|
||||
CR_UNKNOWN_ERROR = 1900,
|
||||
CR_SOCKET_CREATE_ERROR = 1901,
|
||||
CR_CONNECTION_ERROR = 1902,
|
||||
CR_CONN_HOST_ERROR = 1903,
|
||||
CR_IPSOCK_ERROR = 1904,
|
||||
CR_UNKNOWN_HOST = 1905,
|
||||
CR_SERVER_GONE_ERROR = 1906,
|
||||
CR_VERSION_ERROR = 1907,
|
||||
CR_OUT_OF_MEMORY = 1908,
|
||||
CR_WRONG_HOST_INFO = 1909,
|
||||
CR_LOCALHOST_CONNECTION = 1910,
|
||||
CR_TCP_CONNECTION = 1911,
|
||||
CR_SERVER_HANDSHAKE_ERR = 1912,
|
||||
CR_SERVER_LOST = 1913,
|
||||
CR_COMMANDS_OUT_OF_SYNC = 1914,
|
||||
CR_NAMEDPIPE_CONNECTION = 1915,
|
||||
CR_NAMEDPIPEWAIT_ERROR = 1916,
|
||||
CR_NAMEDPIPEOPEN_ERROR = 1917,
|
||||
CR_NAMEDPIPESETSTATE_ERROR = 1918,
|
||||
CR_CANT_READ_CHARSET = 1919,
|
||||
CR_NET_PACKET_TOO_LARGE = 1920,
|
||||
CR_EMBEDDED_CONNECTION = 1921,
|
||||
CR_PROBE_SLAVE_STATUS = 1922,
|
||||
CR_PROBE_SLAVE_HOSTS = 1923,
|
||||
CR_PROBE_SLAVE_CONNECT = 1924,
|
||||
CR_PROBE_MASTER_CONNECT = 1925,
|
||||
CR_SSL_CONNECTION_ERROR = 1926,
|
||||
CR_MALFORMED_PACKET = 1927,
|
||||
CR_WRONG_LICENSE = 1928,
|
||||
};
|
||||
#endif
|
316
src/search_local/index_storage/cache/ng_info.cc
vendored
Normal file
316
src/search_local/index_storage/cache/ng_info.cc
vendored
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: ng_info.cc
|
||||
*
|
||||
* Description: NodeGroup operation.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "node_set.h"
|
||||
#include "node_list.h"
|
||||
#include "node_index.h"
|
||||
#include "ng_info.h"
|
||||
#include "node.h"
|
||||
#include "dtc_global.h"
|
||||
|
||||
DTC_USING_NAMESPACE
|
||||
|
||||
NGInfo::NGInfo() : _ngInfo(NULL)
|
||||
{
|
||||
memset(_errmsg, 0, sizeof(_errmsg));
|
||||
emptyCnt = 0;
|
||||
emptyStartupMode = CREATED;
|
||||
|
||||
statUsedNG = statmgr.get_item_u32(DTC_USED_NGS);
|
||||
statUsedNode = statmgr.get_item_u32(DTC_USED_NODES);
|
||||
statDirtyNode = statmgr.get_item_u32(DTC_DIRTY_NODES);
|
||||
statEmptyNode = statmgr.get_item_u32(DTC_EMPTY_NODES);
|
||||
statEmptyNode = 0;
|
||||
statUsedRow = statmgr.get_item_u32(DTC_USED_ROWS);
|
||||
statDirtyRow = statmgr.get_item_u32(DTC_DIRTY_ROWS);
|
||||
}
|
||||
|
||||
NGInfo::~NGInfo()
|
||||
{
|
||||
}
|
||||
|
||||
Node NGInfo::allocate_node(void)
|
||||
{
|
||||
//优先在空闲链表分配
|
||||
NODE_SET *NS = find_free_ng();
|
||||
if (!NS)
|
||||
{
|
||||
/* 防止NodeGroup把内存碎片化,采用预分配 */
|
||||
static int step = DTCGlobal::_pre_alloc_NG_num;
|
||||
static int fail = 0;
|
||||
for (int i = 0; i < step; i++)
|
||||
{
|
||||
NS = allocate_ng();
|
||||
if (!NS)
|
||||
{
|
||||
if (i == 0)
|
||||
return Node();
|
||||
else
|
||||
{
|
||||
fail = 1;
|
||||
step = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free_list_add(NS);
|
||||
}
|
||||
|
||||
/* find again */
|
||||
NS = find_free_ng();
|
||||
|
||||
if (step < 256 && !fail)
|
||||
step *= 2;
|
||||
}
|
||||
|
||||
Node node = NS->allocate_node();
|
||||
//NG中没有任何可分配的Node
|
||||
if (NS->is_full())
|
||||
{
|
||||
list_del(NS);
|
||||
full_list_add(NS);
|
||||
}
|
||||
|
||||
if (!node)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "PANIC: allocate node failed");
|
||||
return Node();
|
||||
}
|
||||
|
||||
//statistic
|
||||
_ngInfo->ni_used_node++;
|
||||
statUsedNode = _ngInfo->ni_used_node;
|
||||
|
||||
//insert to node_index
|
||||
I_INSERT(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
int NGInfo::release_node(Node &node)
|
||||
{
|
||||
NODE_SET *NS = node.Owner();
|
||||
if (NS->is_full())
|
||||
{
|
||||
//NG挂入空闲链表
|
||||
list_del(NS);
|
||||
free_list_add(NS);
|
||||
}
|
||||
|
||||
_ngInfo->ni_used_node--;
|
||||
statUsedNode = _ngInfo->ni_used_node;
|
||||
return node.Release();
|
||||
}
|
||||
|
||||
Node NGInfo::dirty_node_head()
|
||||
{
|
||||
NODE_SET *sysNG = M_POINTER(NODE_SET, _ngInfo->ni_sys_zone);
|
||||
if (!sysNG)
|
||||
return Node();
|
||||
return Node(sysNG, SYS_DIRTY_NODE_INDEX);
|
||||
}
|
||||
|
||||
Node NGInfo::clean_node_head()
|
||||
{
|
||||
NODE_SET *sysNG = M_POINTER(NODE_SET, _ngInfo->ni_sys_zone);
|
||||
if (!sysNG)
|
||||
return Node();
|
||||
return Node(sysNG, SYS_CLEAN_NODE_INDEX);
|
||||
}
|
||||
|
||||
Node NGInfo::empty_node_head()
|
||||
{
|
||||
NODE_SET *sysNG = M_POINTER(NODE_SET, _ngInfo->ni_sys_zone);
|
||||
if (!sysNG)
|
||||
return Node();
|
||||
return Node(sysNG, SYS_EMPTY_NODE_INDEX);
|
||||
}
|
||||
|
||||
int NGInfo::insert2_dirty_lru(Node node)
|
||||
{
|
||||
NODE_SET *sysNG = M_POINTER(NODE_SET, _ngInfo->ni_sys_zone);
|
||||
Node dirtyNode(sysNG, SYS_DIRTY_NODE_INDEX);
|
||||
|
||||
NODE_LIST_ADD(node, dirtyNode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NGInfo::insert2_clean_lru(Node node)
|
||||
{
|
||||
NODE_SET *sysNG = M_POINTER(NODE_SET, _ngInfo->ni_sys_zone);
|
||||
Node cleanNode(sysNG, SYS_CLEAN_NODE_INDEX);
|
||||
|
||||
NODE_LIST_ADD(node, cleanNode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NGInfo::insert2_empty_lru(Node node)
|
||||
{
|
||||
NODE_SET *sysNG = M_POINTER(NODE_SET, _ngInfo->ni_sys_zone);
|
||||
Node emptyNode(sysNG, SYS_EMPTY_NODE_INDEX);
|
||||
|
||||
NODE_LIST_ADD(node, emptyNode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NGInfo::remove_from_lru(Node node)
|
||||
{
|
||||
NODE_LIST_DEL(node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
NODE_SET *NGInfo::allocate_ng(void)
|
||||
{
|
||||
MEM_HANDLE_T v = M_CALLOC(NODE_SET::Size());
|
||||
if (INVALID_HANDLE == v)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "allocate nodegroup failed, %s", M_ERROR());
|
||||
return (NODE_SET *)0;
|
||||
}
|
||||
|
||||
NODE_SET *NS = M_POINTER(NODE_SET, v);
|
||||
NS->Init(_ngInfo->ni_min_id);
|
||||
_ngInfo->ni_min_id += NODE_GROUP_INCLUDE_NODES;
|
||||
_ngInfo->ni_used_ng++;
|
||||
statUsedNG = _ngInfo->ni_used_ng;
|
||||
|
||||
return NS;
|
||||
}
|
||||
|
||||
NODE_SET *NGInfo::find_free_ng(void)
|
||||
{
|
||||
//链表为空
|
||||
if (NG_LIST_EMPTY(&(_ngInfo->ni_free_head)))
|
||||
{
|
||||
return (NODE_SET *)0;
|
||||
}
|
||||
|
||||
return NG_LIST_ENTRY(_ngInfo->ni_free_head.Next(), NODE_SET, ng_list);
|
||||
}
|
||||
|
||||
void NGInfo::list_del(NODE_SET *NS)
|
||||
{
|
||||
NG_LIST_T *p = &(NS->ng_list);
|
||||
return NG_LIST_DEL(p);
|
||||
}
|
||||
|
||||
#define EXPORT_NG_LIST_FUNCTION(name, member, function) \
|
||||
void NGInfo::name(NODE_SET *NS) \
|
||||
{ \
|
||||
NG_LIST_T *p = &(NS->ng_list); \
|
||||
NG_LIST_T *head = &(_ngInfo->member); \
|
||||
return function(p, head); \
|
||||
}
|
||||
|
||||
EXPORT_NG_LIST_FUNCTION(free_list_add, ni_free_head, NG_LIST_ADD)
|
||||
EXPORT_NG_LIST_FUNCTION(full_list_add, ni_full_head, NG_LIST_ADD)
|
||||
EXPORT_NG_LIST_FUNCTION(free_list_add_tail, ni_free_head, NG_LIST_ADD_TAIL)
|
||||
EXPORT_NG_LIST_FUNCTION(full_list_add_tail, ni_full_head, NG_LIST_ADD_TAIL)
|
||||
|
||||
int NGInfo::InitHeader(NG_INFO_T *ni)
|
||||
{
|
||||
INIT_NG_LIST_HEAD(&(ni->ni_free_head));
|
||||
INIT_NG_LIST_HEAD(&(ni->ni_full_head));
|
||||
|
||||
ni->ni_min_id = SYS_MIN_NODE_ID;
|
||||
|
||||
/* init system reserved zone*/
|
||||
{
|
||||
NODE_SET *sysNG = allocate_ng();
|
||||
if (!sysNG)
|
||||
return -1;
|
||||
|
||||
sysNG->system_reserved_init();
|
||||
ni->ni_sys_zone = M_HANDLE(sysNG);
|
||||
}
|
||||
|
||||
ni->ni_used_ng = 1;
|
||||
ni->ni_used_node = 0;
|
||||
ni->ni_dirty_node = 0;
|
||||
ni->ni_used_row = 0;
|
||||
ni->ni_dirty_row = 0;
|
||||
|
||||
statUsedNG = ni->ni_used_ng;
|
||||
statUsedNode = ni->ni_used_node;
|
||||
statDirtyNode = ni->ni_dirty_node;
|
||||
statDirtyRow = ni->ni_dirty_row;
|
||||
statUsedRow = ni->ni_used_row;
|
||||
statEmptyNode = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NGInfo::Init(void)
|
||||
{
|
||||
//1. malloc ng_info mem.
|
||||
MEM_HANDLE_T v = M_CALLOC(sizeof(NG_INFO_T));
|
||||
if (INVALID_HANDLE == v)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "init nginfo failed, %s", M_ERROR());
|
||||
return -1;
|
||||
}
|
||||
|
||||
//2. mapping
|
||||
_ngInfo = M_POINTER(NG_INFO_T, v);
|
||||
|
||||
//3. init header
|
||||
return InitHeader(_ngInfo);
|
||||
}
|
||||
|
||||
int NGInfo::Attach(MEM_HANDLE_T v)
|
||||
{
|
||||
if (INVALID_HANDLE == v)
|
||||
{
|
||||
snprintf(_errmsg, sizeof(_errmsg), "attach nginfo failed, memory handle = 0");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_ngInfo = M_POINTER(NG_INFO_T, v);
|
||||
|
||||
/* check system reserved zone:
|
||||
* 1. the present of empty lru list
|
||||
*/
|
||||
{
|
||||
NODE_SET *sysNG = M_POINTER(NODE_SET, _ngInfo->ni_sys_zone);
|
||||
if (!sysNG)
|
||||
return -1;
|
||||
|
||||
int ret = sysNG->system_reserved_check();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
{
|
||||
emptyStartupMode = UPGRADED;
|
||||
}
|
||||
else
|
||||
{
|
||||
emptyStartupMode = ATTACHED;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NGInfo::Detach(void)
|
||||
{
|
||||
_ngInfo = NULL;
|
||||
return 0;
|
||||
}
|
196
src/search_local/index_storage/cache/ng_info.h
vendored
Normal file
196
src/search_local/index_storage/cache/ng_info.h
vendored
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: ng_info.h
|
||||
*
|
||||
* Description: NodeGroup operation.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __DTC_NG_INFO_H
|
||||
#define __DTC_NG_INFO_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "stat_dtc.h"
|
||||
#include "singleton.h"
|
||||
#include "namespace.h"
|
||||
#include "global.h"
|
||||
#include "ng_list.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
/* high-level 层支持的cache种类*/
|
||||
enum MEM_CACHE_TYPE_T
|
||||
{
|
||||
MEM_DTC_TYPE = 0x1UL,
|
||||
MEM_BMP_TYPE = 0x2UL,
|
||||
};
|
||||
|
||||
/* high-level 层cache的签名、版本、类型等*/
|
||||
#define MEM_CACHE_SIGN 0xFF00FF00FF00FF00ULL
|
||||
#define MEM_CACHE_VERSION 0x1ULL
|
||||
#define MEM_CACHE_TYPE MEM_DTC_TYPE
|
||||
|
||||
struct cache_info
|
||||
{
|
||||
uint64_t ci_sign;
|
||||
uint64_t ci_version;
|
||||
uint64_t ci_type;
|
||||
};
|
||||
typedef struct cache_info CACHE_INFO_T;
|
||||
|
||||
/* Low-Level预留了4k的空间,供后续扩展 */
|
||||
/* TODO: 增加更加细致的逻辑判断*/
|
||||
struct app_storage
|
||||
{
|
||||
CACHE_INFO_T as_cache_info;
|
||||
MEM_HANDLE_T as_extend_info;
|
||||
|
||||
int need_format()
|
||||
{
|
||||
return (as_cache_info.ci_sign != MEM_CACHE_SIGN) ||
|
||||
(INVALID_HANDLE == as_extend_info);
|
||||
}
|
||||
|
||||
int Format(MEM_HANDLE_T v)
|
||||
{
|
||||
as_cache_info.ci_sign = MEM_CACHE_SIGN;
|
||||
as_cache_info.ci_version = MEM_CACHE_VERSION;
|
||||
as_cache_info.ci_type = MEM_DTC_TYPE;
|
||||
|
||||
as_extend_info = v;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
typedef struct app_storage APP_STORAGE_T;
|
||||
|
||||
struct ng_info
|
||||
{
|
||||
NG_LIST_T ni_free_head; //有空闲Node的NG链表
|
||||
NG_LIST_T ni_full_head; //Node分配完的NG链表
|
||||
NODE_ID_T ni_min_id; //下一个被分配NG的起始NodeId
|
||||
MEM_HANDLE_T ni_sys_zone; //第一个NG为系统保留
|
||||
|
||||
/*以下为统计值,用来控制异步flush的起停,速度等*/
|
||||
uint32_t ni_used_ng;
|
||||
uint32_t ni_used_node;
|
||||
uint32_t ni_dirty_node;
|
||||
uint64_t ni_used_row;
|
||||
uint64_t ni_dirty_row;
|
||||
};
|
||||
typedef struct ng_info NG_INFO_T;
|
||||
|
||||
class NGInfo
|
||||
{
|
||||
public:
|
||||
NGInfo();
|
||||
~NGInfo();
|
||||
|
||||
static NGInfo *Instance() { return Singleton<NGInfo>::Instance(); }
|
||||
static void Destroy() { Singleton<NGInfo>::Destroy(); }
|
||||
|
||||
Node allocate_node(void); //分配一个新Node
|
||||
int release_node(Node &); //归还CNode到所属的NG并摧毁自己
|
||||
|
||||
/*statistic, for async flush */
|
||||
void inc_dirty_node(int v)
|
||||
{
|
||||
_ngInfo->ni_dirty_node += v;
|
||||
statDirtyNode = _ngInfo->ni_dirty_node;
|
||||
}
|
||||
void inc_dirty_row(int v)
|
||||
{
|
||||
_ngInfo->ni_dirty_row += v;
|
||||
statDirtyRow = _ngInfo->ni_dirty_row;
|
||||
}
|
||||
void inc_total_row(int v)
|
||||
{
|
||||
_ngInfo->ni_used_row += v;
|
||||
statUsedRow = _ngInfo->ni_used_row;
|
||||
}
|
||||
void inc_empty_node(int v)
|
||||
{
|
||||
emptyCnt += v;
|
||||
statEmptyNode = emptyCnt;
|
||||
}
|
||||
|
||||
const unsigned int total_dirty_node() const { return _ngInfo->ni_dirty_node; }
|
||||
const unsigned int total_used_node() const { return _ngInfo->ni_used_node; }
|
||||
|
||||
const uint64_t total_dirty_row() const { return _ngInfo->ni_dirty_row; }
|
||||
const uint64_t total_used_row() const { return _ngInfo->ni_used_row; }
|
||||
|
||||
Node dirty_node_head();
|
||||
Node clean_node_head();
|
||||
Node empty_node_head();
|
||||
|
||||
/* 获取最小可用的NodeID */
|
||||
NODE_ID_T min_valid_node_id() const { return (NODE_ID_T)256; }
|
||||
|
||||
/* 获取目前分配的最大NodeID */
|
||||
/* 由于目前node-group大小固定,而且分配后不会释放,因此可以直接通过已用的node-group算出来 */
|
||||
NODE_ID_T max_node_id() const { return _ngInfo->ni_used_ng * 256 - 1; }
|
||||
|
||||
//time-list op
|
||||
int insert2_dirty_lru(Node);
|
||||
int insert2_clean_lru(Node);
|
||||
int insert2_empty_lru(Node);
|
||||
int remove_from_lru(Node);
|
||||
int empty_count(void) const { return emptyCnt; }
|
||||
enum
|
||||
{
|
||||
CREATED, // this memory is fresh
|
||||
ATTACHED, // this is an old memory, and empty lru present
|
||||
UPGRADED // this is an old memory, and empty lru is missing
|
||||
};
|
||||
int empty_startup_mode(void) const { return emptyStartupMode; }
|
||||
|
||||
const MEM_HANDLE_T Handle() const { return M_HANDLE(_ngInfo); }
|
||||
const char *Error() const { return _errmsg; }
|
||||
|
||||
//创建物理内存并格式化
|
||||
int Init(void);
|
||||
//绑定到物理内存
|
||||
int Attach(MEM_HANDLE_T handle);
|
||||
//脱离物理内存
|
||||
int Detach(void);
|
||||
|
||||
protected:
|
||||
int InitHeader(NG_INFO_T *);
|
||||
|
||||
NODE_SET *allocate_ng(void);
|
||||
NODE_SET *find_free_ng(void);
|
||||
|
||||
void list_del(NODE_SET *);
|
||||
void free_list_add(NODE_SET *);
|
||||
void full_list_add(NODE_SET *);
|
||||
void full_list_add_tail(NODE_SET *);
|
||||
void free_list_add_tail(NODE_SET *);
|
||||
|
||||
private:
|
||||
NG_INFO_T *_ngInfo;
|
||||
char _errmsg[256];
|
||||
// the total empty node present
|
||||
int emptyCnt;
|
||||
int emptyStartupMode;
|
||||
|
||||
private:
|
||||
StatItemU32 statUsedNG;
|
||||
StatItemU32 statUsedNode;
|
||||
StatItemU32 statDirtyNode;
|
||||
StatItemU32 statEmptyNode;
|
||||
StatItemU32 statUsedRow;
|
||||
StatItemU32 statDirtyRow;
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
116
src/search_local/index_storage/cache/ng_list.h
vendored
Normal file
116
src/search_local/index_storage/cache/ng_list.h
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: ng_list.h
|
||||
*
|
||||
* Description: double linked list method in sharing memory.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __DTC_NG_LIST_H
|
||||
#define __DTC_NG_LIST_H
|
||||
|
||||
#include "namespace.h"
|
||||
#include "global.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
struct ng_list
|
||||
{
|
||||
MEM_HANDLE_T prev;
|
||||
MEM_HANDLE_T next;
|
||||
|
||||
struct ng_list *Next() { return M_POINTER(struct ng_list, next); }
|
||||
struct ng_list *Prev() { return M_POINTER(struct ng_list, prev); }
|
||||
};
|
||||
typedef struct ng_list NG_LIST_T;
|
||||
|
||||
#define INIT_NG_LIST_HEAD(ptr) \
|
||||
do \
|
||||
{ \
|
||||
MEM_HANDLE_T v = M_HANDLE(ptr); \
|
||||
(ptr)->prev = v; \
|
||||
(ptr)->next = v; \
|
||||
} while (0)
|
||||
|
||||
inline void __NG_LIST_ADD(NG_LIST_T *p,
|
||||
NG_LIST_T *prev,
|
||||
NG_LIST_T *next)
|
||||
{
|
||||
next->prev = M_HANDLE(p);
|
||||
p->next = M_HANDLE(next);
|
||||
p->prev = M_HANDLE(prev);
|
||||
prev->next = M_HANDLE(p);
|
||||
}
|
||||
|
||||
inline void NG_LIST_ADD(NG_LIST_T *p, NG_LIST_T *head)
|
||||
{
|
||||
__NG_LIST_ADD(p, head, head->Next());
|
||||
}
|
||||
|
||||
inline void NG_LIST_ADD_TAIL(NG_LIST_T *p, NG_LIST_T *head)
|
||||
{
|
||||
__NG_LIST_ADD(p, head->Prev(), head);
|
||||
}
|
||||
|
||||
inline void __NG_LIST_DEL(NG_LIST_T *prev, NG_LIST_T *next)
|
||||
{
|
||||
next->prev = M_HANDLE(prev);
|
||||
prev->next = M_HANDLE(next);
|
||||
}
|
||||
|
||||
inline void NG_LIST_DEL(NG_LIST_T *p)
|
||||
{
|
||||
__NG_LIST_DEL(p->Prev(), p->Next());
|
||||
p->next = INVALID_HANDLE;
|
||||
p->prev = INVALID_HANDLE;
|
||||
}
|
||||
|
||||
inline void NG_LIST_DEL_INIT(NG_LIST_T *p)
|
||||
{
|
||||
__NG_LIST_DEL(p->Prev(), p->Next());
|
||||
INIT_NG_LIST_HEAD(p);
|
||||
}
|
||||
|
||||
inline void NG_LIST_MOVE(NG_LIST_T *p, NG_LIST_T *head)
|
||||
{
|
||||
__NG_LIST_DEL(p->Prev(), p->Next());
|
||||
NG_LIST_ADD(p, head);
|
||||
}
|
||||
|
||||
inline void NG_LIST_MOVE_TAIL(NG_LIST_T *p, NG_LIST_T *head)
|
||||
{
|
||||
__NG_LIST_DEL(p->Prev(), p->Next());
|
||||
NG_LIST_ADD_TAIL(p, head);
|
||||
}
|
||||
|
||||
inline int NG_LIST_EMPTY(NG_LIST_T *head)
|
||||
{
|
||||
return head->next == M_HANDLE(head);
|
||||
}
|
||||
|
||||
#define OFFSETOF(type, member) (unsigned long)(&((type *)0)->member)
|
||||
|
||||
#define NG_LIST_ENTRY(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-OFFSETOF(type, member)))
|
||||
|
||||
#define NG_LIST_FOR_EACH(pos, head) \
|
||||
for (pos = (head)->Next(); pos != (head); pos = pos->Next())
|
||||
|
||||
#define NG_LIST_FOR_EACH_ENTRY(pos, head, member) \
|
||||
for (pos = NG_LIST_ENTRY((head)->Next(), typeof(*pos), member), \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry((pos->member).Next(), typeof(*pos), member))
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
136
src/search_local/index_storage/cache/node.h
vendored
Normal file
136
src/search_local/index_storage/cache/node.h
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: node.h
|
||||
*
|
||||
* Description: node operation.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __NODE_DTC_H
|
||||
#define __NODE_DTC_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "namespace.h"
|
||||
#include "global.h"
|
||||
#include "node_set.h"
|
||||
#include "node_index.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
class NGInfo;
|
||||
class NodeIndex;
|
||||
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
Node(NODE_SET *ns = NULL, int idx = 0) : _owner(ns), _index(idx) {}
|
||||
Node(const Node &n) : _owner(n._owner), _index(n._index) {}
|
||||
~Node() {}
|
||||
|
||||
public:
|
||||
int Index(void) { return _index; }
|
||||
NODE_SET *Owner() { return _owner; }
|
||||
|
||||
/* attribute op*/
|
||||
NODE_ID_T &lru_prev()
|
||||
{
|
||||
NODE_ID_T *p = node_lru();
|
||||
return p[LRU_PREV];
|
||||
}
|
||||
|
||||
NODE_ID_T &lru_next()
|
||||
{
|
||||
NODE_ID_T *p = node_lru();
|
||||
return p[LRU_NEXT];
|
||||
}
|
||||
|
||||
NODE_ID_T &next_node_id() { return _owner->next_node_id(_index); }
|
||||
NODE_ID_T node_id() { return _owner->node_id(_index); }
|
||||
|
||||
MEM_HANDLE_T &vd_handle() { return _owner->vd_handle(_index); }
|
||||
|
||||
/* return time-marker time */
|
||||
unsigned int Time() { return (unsigned int)vd_handle(); }
|
||||
|
||||
/* dirty flag*/
|
||||
bool is_dirty() const { return _owner->is_dirty(_index); }
|
||||
void set_dirty() { return _owner->set_dirty(_index); }
|
||||
void clr_dirty() { return _owner->clr_dirty(_index); }
|
||||
|
||||
public:
|
||||
/* used for timelist */
|
||||
Node Next() { return from_id(lru_next()); }
|
||||
Node Prev() { return from_id(lru_prev()); }
|
||||
|
||||
/* used for hash */
|
||||
Node next_node(void) { return from_id(next_node_id()); }
|
||||
|
||||
/* for copyable */
|
||||
Node &operator=(const Node &n)
|
||||
{
|
||||
_owner = n._owner;
|
||||
_index = n._index;
|
||||
return *this;
|
||||
}
|
||||
int operator!() const { return _owner == NULL || _index >= NODE_GROUP_INCLUDE_NODES; }
|
||||
int operator!=(Node &node) { return _owner != node.Owner() || _index != node.Index(); }
|
||||
int operator==(Node &node) { return _owner == node.Owner() && _index == node.Index(); }
|
||||
|
||||
int not_in_lru_list() { return lru_prev() == node_id() || lru_next() == node_id(); }
|
||||
static Node Empty(void)
|
||||
{
|
||||
Node node;
|
||||
return node;
|
||||
}
|
||||
|
||||
private:
|
||||
/* init or delete this */
|
||||
int Reset()
|
||||
{
|
||||
next_node_id() = INVALID_NODE_ID;
|
||||
lru_prev() = node_id();
|
||||
lru_next() = node_id();
|
||||
|
||||
clr_dirty();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Release()
|
||||
{
|
||||
_owner->release_node(*this);
|
||||
Reset();
|
||||
_owner = NULL;
|
||||
_index = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline Node from_id(NODE_ID_T id) { return I_SEARCH(id); }
|
||||
|
||||
private:
|
||||
// [0] = prev, [1] = next
|
||||
NODE_ID_T *node_lru() { return _owner->node_lru(_index); }
|
||||
|
||||
private:
|
||||
NODE_SET *_owner;
|
||||
int _index;
|
||||
|
||||
public:
|
||||
/* friend class */
|
||||
friend class NGInfo;
|
||||
friend class NodeIndex;
|
||||
friend struct node_set;
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
147
src/search_local/index_storage/cache/node_index.cc
vendored
Normal file
147
src/search_local/index_storage/cache/node_index.cc
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: node_index.cc
|
||||
*
|
||||
* Description: NodeId to Node
|
||||
*
|
||||
*
|
||||
* node_id ----- Node
|
||||
* 8bits 1-index
|
||||
* 16bits 2-index
|
||||
* 8bits NodeGroup internal index.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "node_index.h"
|
||||
#include "singleton.h"
|
||||
#include "node.h"
|
||||
|
||||
DTC_USING_NAMESPACE
|
||||
|
||||
NodeIndex::NodeIndex() : _firstIndex(NULL)
|
||||
{
|
||||
memset(_errmsg, 0, sizeof(_errmsg));
|
||||
}
|
||||
|
||||
NodeIndex::~NodeIndex()
|
||||
{
|
||||
}
|
||||
|
||||
NodeIndex *NodeIndex::Instance()
|
||||
{
|
||||
return Singleton<NodeIndex>::Instance();
|
||||
}
|
||||
|
||||
void NodeIndex::Destroy()
|
||||
{
|
||||
Singleton<NodeIndex>::Destroy();
|
||||
}
|
||||
|
||||
int NodeIndex::pre_allocate_index(size_t mem_size)
|
||||
{
|
||||
/*
|
||||
* 按所有节点全为空节点来分配2级NodeIndex
|
||||
* 一个空节点占用44 bytes
|
||||
*/
|
||||
uint32_t n = 65536 * 256 * 44;
|
||||
n = mem_size / n + 1;
|
||||
n = n > 256 ? 256 : n;
|
||||
|
||||
for (uint32_t i = 0; i < n; ++i)
|
||||
{
|
||||
_firstIndex->fi_h[i] = M_CALLOC(INDEX_2_SIZE);
|
||||
|
||||
if (INVALID_HANDLE == _firstIndex->fi_h[i])
|
||||
{
|
||||
log_crit("PANIC: PrepareNodeIndex[%u] failed", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NodeIndex::Insert(Node node)
|
||||
{
|
||||
NODE_ID_T id = node.node_id();
|
||||
|
||||
if (INVALID_HANDLE == _firstIndex->fi_h[OFFSET1(id)])
|
||||
{
|
||||
_firstIndex->fi_h[OFFSET1(id)] = M_CALLOC(INDEX_2_SIZE);
|
||||
if (INVALID_HANDLE == _firstIndex->fi_h[OFFSET1(id)])
|
||||
{
|
||||
log_crit("PANIC: Insert node=%u to NodeIndex failed", id);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
SECOND_INDEX_T *p = M_POINTER(SECOND_INDEX_T, _firstIndex->fi_h[OFFSET1(id)]);
|
||||
p->si_used++;
|
||||
p->si_h[OFFSET2(id)] = M_HANDLE(node.Owner());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Node NodeIndex::Search(NODE_ID_T id)
|
||||
{
|
||||
if (INVALID_NODE_ID == id)
|
||||
return Node(NULL, 0);
|
||||
|
||||
if (INVALID_HANDLE == _firstIndex->fi_h[OFFSET1(id)])
|
||||
return Node(NULL, 0);
|
||||
|
||||
SECOND_INDEX_T *p = M_POINTER(SECOND_INDEX_T, _firstIndex->fi_h[OFFSET1(id)]);
|
||||
if (INVALID_HANDLE == p->si_h[OFFSET2(id)])
|
||||
return Node(NULL, 0);
|
||||
|
||||
NODE_SET *NS = M_POINTER(NODE_SET, p->si_h[OFFSET2(id)]);
|
||||
|
||||
int index = (id - NS->ng_nid);
|
||||
if (index < 0 || index > 255)
|
||||
return Node(NULL, 0);
|
||||
|
||||
return Node(NS, index);
|
||||
}
|
||||
|
||||
int NodeIndex::Init(size_t mem_size)
|
||||
{
|
||||
MEM_HANDLE_T v = M_CALLOC(INDEX_1_SIZE);
|
||||
if (INVALID_HANDLE == v)
|
||||
{
|
||||
log_crit("Create Index-1 failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_firstIndex = M_POINTER(FIRST_INDEX_T, v);
|
||||
|
||||
return pre_allocate_index(mem_size);
|
||||
}
|
||||
|
||||
int NodeIndex::Attach(MEM_HANDLE_T handle)
|
||||
{
|
||||
if (INVALID_HANDLE == handle)
|
||||
{
|
||||
log_crit("attach index-1 failed, memory handle=0");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_firstIndex = M_POINTER(FIRST_INDEX_T, handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NodeIndex::Detach(void)
|
||||
{
|
||||
_firstIndex = 0;
|
||||
return 0;
|
||||
}
|
83
src/search_local/index_storage/cache/node_index.h
vendored
Normal file
83
src/search_local/index_storage/cache/node_index.h
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: node_index.h
|
||||
*
|
||||
* Description: NodeId to Node
|
||||
*
|
||||
*
|
||||
* node_id ----- Node
|
||||
* 8bits 1-index
|
||||
* 16bits 2-index
|
||||
* 8bits NodeGroup internal index.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __DTC_NODE_INDEX_H
|
||||
#define __DTC_NODE_INDEX_H
|
||||
|
||||
#include "namespace.h"
|
||||
#include "global.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
#define INDEX_1_SIZE (((1UL << 8) * sizeof(MEM_HANDLE_T)) + sizeof(FIRST_INDEX_T)) // first-index size
|
||||
#define INDEX_2_SIZE (((1UL << 16) * sizeof(MEM_HANDLE_T)) + sizeof(SECOND_INDEX_T)) // second-index size
|
||||
|
||||
#define OFFSET1(id) ((id) >> 24) //高8位,一级index
|
||||
#define OFFSET2(id) (((id)&0xFFFF00) >> 8) //中间16位,二级index
|
||||
#define OFFSET3(id) ((id)&0xFF) //低8位
|
||||
|
||||
struct first_index
|
||||
{
|
||||
uint32_t fi_used; //一级index使用个数
|
||||
MEM_HANDLE_T fi_h[0]; //存放二级index的handle
|
||||
};
|
||||
typedef struct first_index FIRST_INDEX_T;
|
||||
|
||||
struct second_index
|
||||
{
|
||||
uint32_t si_used;
|
||||
MEM_HANDLE_T si_h[0];
|
||||
};
|
||||
typedef struct second_index SECOND_INDEX_T;
|
||||
|
||||
class Node;
|
||||
class NodeIndex
|
||||
{
|
||||
public:
|
||||
NodeIndex();
|
||||
~NodeIndex();
|
||||
|
||||
static NodeIndex *Instance();
|
||||
static void Destroy();
|
||||
|
||||
int Insert(Node);
|
||||
Node Search(NODE_ID_T id);
|
||||
|
||||
int pre_allocate_index(size_t size);
|
||||
|
||||
const MEM_HANDLE_T Handle() const { return M_HANDLE(_firstIndex); }
|
||||
const char *Error() const { return _errmsg; }
|
||||
///* 内存区块操作函数 */
|
||||
int Init(size_t mem_size);
|
||||
int Attach(MEM_HANDLE_T handle);
|
||||
int Detach(void);
|
||||
|
||||
private:
|
||||
FIRST_INDEX_T *_firstIndex;
|
||||
char _errmsg[256];
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
94
src/search_local/index_storage/cache/node_list.h
vendored
Normal file
94
src/search_local/index_storage/cache/node_list.h
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: node_list.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __DTC_NODE_LIST_H
|
||||
#define __DTC_NODE_LIST_H
|
||||
|
||||
#include "namespace.h"
|
||||
#include "global.h"
|
||||
#include "node.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
#define INIT_NODE_LIST_HEAD(node, id) \
|
||||
do \
|
||||
{ \
|
||||
node.lru_prev() = id; \
|
||||
node.lru_next() = id; \
|
||||
} while (0)
|
||||
|
||||
inline void __NODE_LIST_ADD(Node p,
|
||||
Node prev,
|
||||
Node next)
|
||||
{
|
||||
next.lru_prev() = p.node_id();
|
||||
p.lru_next() = next.node_id();
|
||||
p.lru_prev() = prev.node_id();
|
||||
prev.lru_next() = p.node_id();
|
||||
}
|
||||
|
||||
inline void NODE_LIST_ADD(Node p, Node head)
|
||||
{
|
||||
__NODE_LIST_ADD(p, head, head.Next());
|
||||
}
|
||||
|
||||
inline void NODE_LIST_ADD_TAIL(Node p, Node head)
|
||||
{
|
||||
__NODE_LIST_ADD(p, head.Prev(), head);
|
||||
}
|
||||
|
||||
inline void __NODE_LIST_DEL(Node prev, Node next)
|
||||
{
|
||||
next.lru_prev() = prev.node_id();
|
||||
prev.lru_next() = next.node_id();
|
||||
}
|
||||
|
||||
inline void NODE_LIST_DEL(Node p)
|
||||
{
|
||||
__NODE_LIST_DEL(p.Prev(), p.Next());
|
||||
p.lru_prev() = p.node_id();
|
||||
p.lru_next() = p.node_id();
|
||||
}
|
||||
|
||||
inline void NODE_LIST_MOVE(Node p, Node head)
|
||||
{
|
||||
__NODE_LIST_DEL(p.Prev(), p.Next());
|
||||
NODE_LIST_ADD(p, head);
|
||||
}
|
||||
|
||||
inline void NODE_LIST_MOVE_TAIL(Node p, Node head)
|
||||
{
|
||||
__NODE_LIST_DEL(p.Prev(), p.Next());
|
||||
NODE_LIST_ADD_TAIL(p, head);
|
||||
}
|
||||
|
||||
inline int NODE_LIST_EMPTY(Node head)
|
||||
{
|
||||
return head.lru_next() == head.node_id();
|
||||
}
|
||||
|
||||
/*正向遍历*/
|
||||
#define NODE_LIST_FOR_EACH(pos, head) \
|
||||
for (pos = head.Next(); pos != head; pos = pos.Next())
|
||||
|
||||
/*反向遍历*/
|
||||
#define NODE_LIST_FOR_EACH_RVS(pos, head) \
|
||||
for (pos = head.Prev(); pos != head; pos = pos.Prev())
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
237
src/search_local/index_storage/cache/node_set.cc
vendored
Normal file
237
src/search_local/index_storage/cache/node_set.cc
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: node_set.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include "node_set.h"
|
||||
#include "node_index.h"
|
||||
#include "node_list.h"
|
||||
#include "global.h"
|
||||
#include "node.h"
|
||||
|
||||
DTC_USING_NAMESPACE
|
||||
|
||||
//定义每种属性的内存大小, 至少有以下四种,可以再增加
|
||||
const uint32_t NODE_SET::NG_ATTR_SIZE[] =
|
||||
{
|
||||
NODE_GROUP_INCLUDE_NODES * sizeof(NODE_ID_T), //NEXT_NODE
|
||||
NODE_GROUP_INCLUDE_NODES * sizeof(NODE_ID_T) * 2, //TIME_LIST
|
||||
NODE_GROUP_INCLUDE_NODES * sizeof(MEM_HANDLE_T), //VD_HANDLE
|
||||
NODE_GROUP_INCLUDE_NODES / 8, //DIRTY_BMP
|
||||
};
|
||||
|
||||
int NODE_SET::Init(NODE_ID_T id)
|
||||
{
|
||||
ng_list.prev = ng_list.next = INVALID_HANDLE;
|
||||
ng_dele.top = 0;
|
||||
ng_dele.count = 0;
|
||||
ng_free = 0;
|
||||
ng_nid = id;
|
||||
|
||||
//属性
|
||||
ng_attr.count = attr_count();
|
||||
ng_attr.offset[0] = base_header_size();
|
||||
for (unsigned int i = 1; i < ng_attr.count; i++)
|
||||
{
|
||||
ng_attr.offset[i] = ng_attr.offset[i - 1] + NG_ATTR_SIZE[i - 1];
|
||||
}
|
||||
|
||||
/* 初始化每个Node */
|
||||
for (unsigned i = 0; i < NODE_GROUP_INCLUDE_NODES; ++i)
|
||||
{
|
||||
next_node_id(i) = INVALID_NODE_ID;
|
||||
NODE_ID_T *lru = node_lru(i);
|
||||
lru[LRU_PREV] = node_id(i);
|
||||
lru[LRU_NEXT] = node_id(i);
|
||||
vd_handle(i) = INVALID_HANDLE;
|
||||
clr_dirty(i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* init system reserved zone */
|
||||
int NODE_SET::system_reserved_init()
|
||||
{
|
||||
Node dirtyNode = allocate_node();
|
||||
if (!dirtyNode)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
Node cleanNode = allocate_node();
|
||||
if (!cleanNode)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
Node emptyNode = allocate_node();
|
||||
if (!emptyNode)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* init node list head */
|
||||
INIT_NODE_LIST_HEAD(dirtyNode, dirtyNode.node_id());
|
||||
INIT_NODE_LIST_HEAD(cleanNode, cleanNode.node_id());
|
||||
INIT_NODE_LIST_HEAD(emptyNode, emptyNode.node_id());
|
||||
|
||||
/* insert node head's node-id to node-index*/
|
||||
I_INSERT(dirtyNode);
|
||||
I_INSERT(cleanNode);
|
||||
I_INSERT(emptyNode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check system reserved zone integrity
|
||||
* the main purpose is upgrade/add the missing empty lru list
|
||||
*/
|
||||
int NODE_SET::system_reserved_check()
|
||||
{
|
||||
if (ng_free < 2)
|
||||
return -10;
|
||||
// ng_free==2 old format, index 2 is free & reserved
|
||||
// ng_free==3 new format, index 2 allocated to emptyNodeLru
|
||||
int hasEmptyLru1 = ng_free >= 3;
|
||||
|
||||
// if new format, index 2 is allocated, lru pointer should be non-zero
|
||||
|
||||
// sanity check passed
|
||||
if (hasEmptyLru1 == 0)
|
||||
{
|
||||
// no empty lru, allocate one
|
||||
Node emptyNode = allocate_node();
|
||||
if (!emptyNode)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* init node list head */
|
||||
INIT_NODE_LIST_HEAD(emptyNode, emptyNode.node_id());
|
||||
|
||||
/* insert node head's node-id to node-index*/
|
||||
I_INSERT(emptyNode);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Node NODE_SET::allocate_node(void)
|
||||
{
|
||||
if (is_full())
|
||||
{
|
||||
return Node(NULL, 0);
|
||||
}
|
||||
|
||||
//优先分配release掉的Node空间
|
||||
if (ng_dele.count > 0)
|
||||
{
|
||||
Node N(this, ng_dele.top);
|
||||
N.Reset();
|
||||
|
||||
ng_dele.count--;
|
||||
ng_dele.top = (uint8_t)N.vd_handle();
|
||||
|
||||
return N;
|
||||
}
|
||||
//在空闲Node中分配
|
||||
else
|
||||
{
|
||||
Node N(this, ng_free);
|
||||
N.Reset();
|
||||
|
||||
ng_free++;
|
||||
return N;
|
||||
}
|
||||
}
|
||||
|
||||
int NODE_SET::release_node(Node N)
|
||||
{
|
||||
//复用node的handle attribute空间来把释放掉的node组织为单链表
|
||||
N.vd_handle() = ng_dele.top;
|
||||
ng_dele.top = N.Index();
|
||||
ng_dele.count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool NODE_SET::is_full(void)
|
||||
{
|
||||
return (ng_dele.count == 0 && ng_free >= NODE_GROUP_INCLUDE_NODES);
|
||||
}
|
||||
|
||||
uint32_t NODE_SET::attr_count(void)
|
||||
{
|
||||
return sizeof(NG_ATTR_SIZE) / sizeof(uint32_t);
|
||||
}
|
||||
|
||||
uint32_t NODE_SET::base_header_size(void)
|
||||
{
|
||||
return OFFSETOF(NODE_SET, ng_attr) + OFFSETOF(NG_ATTR_T, offset) + sizeof(uint32_t) * attr_count();
|
||||
}
|
||||
|
||||
uint32_t NODE_SET::attr_size(void)
|
||||
{
|
||||
uint32_t size = 0;
|
||||
|
||||
for (uint32_t i = 0; i < attr_count(); i++)
|
||||
{
|
||||
size += NG_ATTR_SIZE[i];
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t NODE_SET::Size(void)
|
||||
{
|
||||
return base_header_size() + attr_size();
|
||||
}
|
||||
|
||||
NODE_ID_T NODE_SET::node_id(int idx) const
|
||||
{
|
||||
return (ng_nid + idx);
|
||||
}
|
||||
|
||||
NODE_ID_T &NODE_SET::next_node_id(int idx)
|
||||
{
|
||||
return __CAST__<NODE_ID_T>(NEXT_NODE)[idx];
|
||||
}
|
||||
|
||||
NODE_ID_T *NODE_SET::node_lru(int idx)
|
||||
{
|
||||
return &(__CAST__<NODE_ID_T>(TIME_LIST)[idx * 2]);
|
||||
}
|
||||
|
||||
MEM_HANDLE_T &NODE_SET::vd_handle(int idx)
|
||||
{
|
||||
return __CAST__<MEM_HANDLE_T>(VD_HANDLE)[idx];
|
||||
}
|
||||
|
||||
bool NODE_SET::is_dirty(int idx)
|
||||
{
|
||||
return FD_ISSET(idx, __CAST__<fd_set>(DIRTY_BMP));
|
||||
}
|
||||
|
||||
void NODE_SET::set_dirty(int idx)
|
||||
{
|
||||
FD_SET(idx, __CAST__<fd_set>(DIRTY_BMP));
|
||||
}
|
||||
|
||||
void NODE_SET::clr_dirty(int idx)
|
||||
{
|
||||
FD_CLR(idx, __CAST__<fd_set>(DIRTY_BMP));
|
||||
}
|
104
src/search_local/index_storage/cache/node_set.h
vendored
Normal file
104
src/search_local/index_storage/cache/node_set.h
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: node_set.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __DTC_NODE_SET_H
|
||||
#define __DTC_NODE_SET_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "namespace.h"
|
||||
#include "global.h"
|
||||
#include "ng_list.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
enum attr_type
|
||||
{
|
||||
NEXT_NODE = 0,
|
||||
TIME_LIST = 1,
|
||||
VD_HANDLE = 2,
|
||||
DIRTY_BMP = 3,
|
||||
};
|
||||
typedef enum attr_type ATTR_TYPE_T;
|
||||
|
||||
//nodeset释放掉的node链表
|
||||
struct ng_delete
|
||||
{
|
||||
uint16_t top;
|
||||
uint16_t count;
|
||||
};
|
||||
typedef struct ng_delete NG_DELE_T;
|
||||
|
||||
//nodeset属性
|
||||
struct ng_attr
|
||||
{
|
||||
uint32_t count;
|
||||
uint32_t offset[0];
|
||||
};
|
||||
typedef struct ng_attr NG_ATTR_T;
|
||||
|
||||
class Node;
|
||||
struct node_set
|
||||
{
|
||||
public:
|
||||
NG_LIST_T ng_list;
|
||||
NG_DELE_T ng_dele;
|
||||
uint16_t ng_free;
|
||||
uint8_t ng_rsv[2]; //保留空间
|
||||
NODE_ID_T ng_nid;
|
||||
NG_ATTR_T ng_attr;
|
||||
|
||||
private:
|
||||
Node allocate_node(void); // 分配一个Node
|
||||
int release_node(Node); // 释放一个Node
|
||||
bool is_full(void); // NodeGroup是否已经分配完
|
||||
int Init(NODE_ID_T id); // NodeGroup初始化
|
||||
int system_reserved_init(); // 系统保留的NG初始化
|
||||
// this routine return:
|
||||
// 0, passed, empty lru present
|
||||
// 1, passed, empty lru created
|
||||
// <0, integrity error
|
||||
int system_reserved_check(); // 系统保留的NG一致性检查
|
||||
static uint32_t Size(void); // 返回nodegroup的总大小
|
||||
|
||||
private:
|
||||
//属性操作接口,供CNode访问
|
||||
NODE_ID_T node_id(int idx) const;
|
||||
NODE_ID_T &next_node_id(int idx); // attr1] -> 下一个Node的NodeID
|
||||
NODE_ID_T *node_lru(int idx); // attr[2] -> LRU链表
|
||||
MEM_HANDLE_T &vd_handle(int idx); // attr[3] -> 数据handle
|
||||
bool is_dirty(int idx); // attr[4] -> 脏位图
|
||||
void set_dirty(int idx);
|
||||
void clr_dirty(int idx);
|
||||
|
||||
//返回每种属性块的起始地址
|
||||
template <class T>
|
||||
T *__CAST__(ATTR_TYPE_T t) { return (T *)((char *)this + ng_attr.offset[t]); }
|
||||
|
||||
private:
|
||||
static uint32_t attr_count(void); // 支持的属性个数
|
||||
static uint32_t attr_size(void); // 所有属性的内存大小
|
||||
static uint32_t base_header_size(void); // 除开属性外,Nodegroup的大小
|
||||
static const uint32_t NG_ATTR_SIZE[];
|
||||
|
||||
friend class Node;
|
||||
friend class NGInfo;
|
||||
};
|
||||
typedef struct node_set NODE_SET;
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
1504
src/search_local/index_storage/cache/pt_malloc.cc
vendored
Normal file
1504
src/search_local/index_storage/cache/pt_malloc.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
374
src/search_local/index_storage/cache/pt_malloc.h
vendored
Normal file
374
src/search_local/index_storage/cache/pt_malloc.h
vendored
Normal file
@ -0,0 +1,374 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: pt_malloc.h
|
||||
*
|
||||
* Description: packaging ptmalloc memory dispatch algorithm and interface.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef BIN_MALLOC_H
|
||||
#define BIN_MALLOC_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "namespace.h"
|
||||
#include "mallocator.h"
|
||||
#include "log.h"
|
||||
#include "stat_dtc.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
#define MALLOC_FLAG_FAST 0x1
|
||||
|
||||
/*
|
||||
This struct declaration is misleading (but accurate and necessary).
|
||||
It declares a "view" into memory allowing access to necessary
|
||||
fields at known offsets from a given base. See explanation below.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ALLOC_SIZE_T m_tPreSize; /* Size of previous chunk (if free). */
|
||||
ALLOC_SIZE_T m_tSize; /* Size in bytes, including overhead. */
|
||||
|
||||
INTER_HANDLE_T m_hPreChunk; /* double links -- used only if free. */
|
||||
INTER_HANDLE_T m_hNextChunk;
|
||||
} MallocChunk;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
INTER_HANDLE_T m_hPreChunk;
|
||||
INTER_HANDLE_T m_hNextChunk;
|
||||
} CBin;
|
||||
|
||||
/* The smallest possible chunk */
|
||||
#define MIN_CHUNK_SIZE (sizeof(MallocChunk))
|
||||
|
||||
/* The smallest size we can malloc is an aligned minimal chunk */
|
||||
#define MINSIZE (unsigned long)(((MIN_CHUNK_SIZE + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
|
||||
|
||||
#define NBINS 128
|
||||
#define NSMALLBINS 64
|
||||
#define SMALLBIN_WIDTH 8
|
||||
#define MIN_LARGE_SIZE 512
|
||||
|
||||
#define DTC_SIGN_0 0
|
||||
#define DTC_SIGN_1 0x4D635474U
|
||||
#define DTC_SIGN_2 1
|
||||
#define DTC_SIGN_3 0xFFFFFFFFU
|
||||
#define DTC_SIGN_4 0xFFFFFFFFU
|
||||
#define DTC_SIGN_5 0xFFFFFFFFU
|
||||
#define DTC_SIGN_6 4
|
||||
#define DTC_SIGN_7 0
|
||||
#define DTC_SIGN_8 16
|
||||
#define DTC_SIGN_9 0xFFFFFFFFU
|
||||
#define DTC_SIGN_A 0
|
||||
#define DTC_SIGN_B 0
|
||||
#define DTC_SIGN_C 0xFFFFFFFFU
|
||||
#define DTC_SIGN_D 0xFFFFFFFFU
|
||||
|
||||
#define DTC_VER_MIN 4 // 本代码认识的dtc内存最小版本
|
||||
|
||||
#define DTC_RESERVE_SIZE (4 * 1024UL)
|
||||
|
||||
#define EC_NO_MEM 2041 // 内存不足错误码
|
||||
#define EC_KEY_EXIST 2042
|
||||
#define EC_KEY_NOT_EXIST 2043
|
||||
#define MAXSTATCOUNT 10000 * 3600 * 12
|
||||
|
||||
struct _MemHead
|
||||
{
|
||||
uint32_t m_auiSign[14]; // 内存格式标记
|
||||
unsigned short m_ushVer; // 内存格式版本号
|
||||
unsigned short m_ushHeadSize; // 头大小
|
||||
INTER_SIZE_T m_tSize; // 内存总大小
|
||||
INTER_SIZE_T m_tUserAllocSize; // 上层应用分配到可用的内存大小
|
||||
INTER_SIZE_T m_tUserAllocChunkCnt; // 上层应用分配的内存块数量
|
||||
uint32_t m_uiFlags; // 特性标记
|
||||
INTER_HANDLE_T m_hBottom; // 上层应用可用内存底地址
|
||||
INTER_HANDLE_T m_hReserveZone; // 为上层应用保留的地址
|
||||
INTER_HANDLE_T m_hTop; // 目前分配到的最高地址
|
||||
INTER_SIZE_T m_tLastFreeChunkSize; // 最近一次free后,合并得到的chunk大小
|
||||
uint16_t m_ushBinCnt; // bin的数量
|
||||
uint16_t m_ushFastBinCnt; // fastbin数量
|
||||
uint32_t m_auiBinBitMap[(NBINS - 1) / 32 + 1]; // bin的bitmap
|
||||
uint32_t m_shmIntegrity; //共享内存完整性标记
|
||||
char m_achReserv[872]; // 保留字段 (使CMemHead的大小为1008Bytes,加上后面的bins后达到4K)
|
||||
} __attribute__((__aligned__(4)));
|
||||
typedef struct _MemHead MemHead;
|
||||
|
||||
#define GET_OBJ(mallocter, handle, obj_ptr) \
|
||||
do \
|
||||
{ \
|
||||
obj_ptr = (typeof(obj_ptr))mallocter.handle_to_ptr(handle); \
|
||||
} while (0)
|
||||
|
||||
class DTCBinMalloc : public Mallocator
|
||||
{
|
||||
private:
|
||||
void *m_pBaseAddr;
|
||||
MemHead *m_pstHead;
|
||||
CBin *m_ptBin;
|
||||
CBin *m_ptFastBin;
|
||||
CBin *m_ptUnsortedBin;
|
||||
char m_szErr[200];
|
||||
|
||||
// stat
|
||||
StatItemU32 statChunkTotal;
|
||||
StatItem statDataSize;
|
||||
StatItem statMemoryTop;
|
||||
|
||||
uint64_t statTmpDataSizeRecently; //最近分配的内存大小
|
||||
uint64_t statTmpDataAllocCountRecently; //最近分配的内存次数
|
||||
StatItem statAverageDataSizeRecently;
|
||||
inline void add_alloc_size_to_stat(uint64_t size)
|
||||
{
|
||||
if (statTmpDataAllocCountRecently > MAXSTATCOUNT)
|
||||
{
|
||||
statTmpDataSizeRecently = 0;
|
||||
statTmpDataAllocCountRecently = 0;
|
||||
statAverageDataSizeRecently = MINSIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
statTmpDataSizeRecently += size;
|
||||
statTmpDataAllocCountRecently++;
|
||||
statAverageDataSizeRecently = statTmpDataSizeRecently / statTmpDataAllocCountRecently;
|
||||
}
|
||||
}
|
||||
|
||||
//最小的chrunk size,
|
||||
unsigned int minChunkSize;
|
||||
inline unsigned int get_min_chunk_size(void)
|
||||
{
|
||||
return minChunkSize == 1 ? (
|
||||
(statChunkTotal <= 0) ? MINSIZE : statDataSize / statChunkTotal)
|
||||
: minChunkSize;
|
||||
}
|
||||
|
||||
public:
|
||||
void set_min_chunk_size(unsigned int size)
|
||||
{
|
||||
minChunkSize = size == 1 ? 1 : (size < MINSIZE ? MINSIZE : size);
|
||||
}
|
||||
|
||||
protected:
|
||||
void init_sign();
|
||||
|
||||
void *bin_malloc(CBin &ptBin);
|
||||
void *small_bin_malloc(ALLOC_SIZE_T tSize);
|
||||
void *fast_malloc(ALLOC_SIZE_T tSize);
|
||||
void *top_alloc(ALLOC_SIZE_T tSize);
|
||||
int unlink_bin(CBin &stBin, INTER_HANDLE_T hHandle);
|
||||
int link_bin(CBin &stBin, INTER_HANDLE_T hHandle);
|
||||
int link_sorted_bin(CBin &stBin, INTER_HANDLE_T hHandle, ALLOC_SIZE_T tSize);
|
||||
int check_inuse_chunk(MallocChunk *pstChunk);
|
||||
int free_fast();
|
||||
|
||||
inline void set_bin_bit_map(unsigned int uiBinIdx)
|
||||
{
|
||||
m_pstHead->m_auiBinBitMap[uiBinIdx / 32] |= (1UL << (uiBinIdx % 32));
|
||||
}
|
||||
inline void clear_bin_bit_map(unsigned int uiBinIdx)
|
||||
{
|
||||
m_pstHead->m_auiBinBitMap[uiBinIdx / 32] &= (~(1UL << (uiBinIdx % 32)));
|
||||
}
|
||||
inline int empty_bin(unsigned int uiBinIdx)
|
||||
{
|
||||
return (m_ptBin[uiBinIdx].m_hNextChunk == INVALID_HANDLE);
|
||||
}
|
||||
|
||||
// 内部做一下统计
|
||||
ALLOC_HANDLE_T inter_malloc(ALLOC_SIZE_T tSize);
|
||||
ALLOC_HANDLE_T inter_re_alloc(ALLOC_HANDLE_T hHandle, ALLOC_SIZE_T tSize, ALLOC_SIZE_T &tOldMemSize);
|
||||
int inter_free(ALLOC_HANDLE_T hHandle, ALLOC_SIZE_T &tMemSize);
|
||||
|
||||
public:
|
||||
DTCBinMalloc();
|
||||
~DTCBinMalloc();
|
||||
|
||||
static DTCBinMalloc *Instance();
|
||||
static void Destroy();
|
||||
|
||||
template <class T>
|
||||
T *Pointer(ALLOC_HANDLE_T hHandle) { return reinterpret_cast<T *>(handle_to_ptr(hHandle)); }
|
||||
|
||||
ALLOC_HANDLE_T Handle(void *p) { return ptr_to_handle(p); }
|
||||
|
||||
const char *get_err_msg() { return m_szErr; }
|
||||
const MemHead *get_head_info() const { return m_pstHead; }
|
||||
|
||||
/*************************************************
|
||||
Description: 格式化内存
|
||||
Input: pAddr 内存块地址
|
||||
tSize 内存块大小
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int Init(void *pAddr, INTER_SIZE_T tSize);
|
||||
|
||||
/*************************************************
|
||||
Description: attach已经格式化好的内存块
|
||||
Input: pAddr 内存块地址
|
||||
tSize 内存块大小
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int Attach(void *pAddr, INTER_SIZE_T tSize);
|
||||
|
||||
/*************************************************
|
||||
Description: 检测内存块的dtc版本
|
||||
Input: pAddr 内存块地址
|
||||
tSize 内存块大小
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int detect_version();
|
||||
|
||||
/* 共享内存完整性检测接口 */
|
||||
int share_memory_integrity();
|
||||
void set_share_memory_integrity(const int flag);
|
||||
|
||||
/*************************************************
|
||||
Description: 检测内部数据结构bin是否正确
|
||||
Input:
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int check_bin();
|
||||
#if BIN_MEM_CHECK
|
||||
int check_mem();
|
||||
#endif
|
||||
int dump_bins();
|
||||
int dump_mem();
|
||||
|
||||
/*************************************************
|
||||
Description: 分配内存
|
||||
Input: tSize 分配的内存大小
|
||||
Output:
|
||||
Return: 内存块句柄,INVALID_HANDLE为失败
|
||||
*************************************************/
|
||||
ALLOC_HANDLE_T Malloc(ALLOC_SIZE_T tSize);
|
||||
|
||||
/*************************************************
|
||||
Description: 分配内存,并将内存初始化为0
|
||||
Input: tSize 分配的内存大小
|
||||
Output:
|
||||
Return: 内存块句柄,INVALID_HANDLE为失败
|
||||
*************************************************/
|
||||
ALLOC_HANDLE_T Calloc(ALLOC_SIZE_T tSize);
|
||||
|
||||
/*************************************************
|
||||
Description: 重新分配内存
|
||||
Input: hHandle 老内存句柄
|
||||
tSize 新分配的内存大小
|
||||
Output:
|
||||
Return: 内存块句柄,INVALID_HANDLE为失败(失败时不会释放老内存块)
|
||||
*************************************************/
|
||||
ALLOC_HANDLE_T ReAlloc(ALLOC_HANDLE_T hHandle, ALLOC_SIZE_T tSize);
|
||||
|
||||
/*************************************************
|
||||
Description: 释放内存
|
||||
Input: hHandle 内存句柄
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int Free(ALLOC_HANDLE_T hHandle);
|
||||
|
||||
/*************************************************
|
||||
Description: 获取释放这块内存后可以得到多少free空间
|
||||
Input: hHandle 内存句柄
|
||||
Output:
|
||||
Return: >0为成功,0失败
|
||||
*************************************************/
|
||||
unsigned ask_for_destroy_size(ALLOC_HANDLE_T hHandle);
|
||||
|
||||
/*************************************************
|
||||
Description: 获取内存块大小
|
||||
Input: hHandle 内存句柄
|
||||
Output:
|
||||
Return: 内存大小
|
||||
*************************************************/
|
||||
ALLOC_SIZE_T chunk_size(ALLOC_HANDLE_T hHandle);
|
||||
|
||||
/*************************************************
|
||||
Description: 获取用户已经分配的内存总大小
|
||||
Input:
|
||||
Output:
|
||||
Return: 内存大小
|
||||
*************************************************/
|
||||
INTER_SIZE_T user_alloc_size() { return m_pstHead->m_tUserAllocSize; }
|
||||
|
||||
/*************************************************
|
||||
Description: 获取内存总大小
|
||||
Input:
|
||||
Output:
|
||||
Return: 内存大小
|
||||
*************************************************/
|
||||
INTER_SIZE_T total_size() { return m_pstHead->m_tSize; }
|
||||
|
||||
/*************************************************
|
||||
Description: 最近一次释放内存,合并后的chunk大小
|
||||
Input:
|
||||
Output:
|
||||
Return: 内存大小
|
||||
*************************************************/
|
||||
ALLOC_SIZE_T last_free_size();
|
||||
|
||||
/*************************************************
|
||||
Description: 获取为上层应用保留的内存块(大小为DTC_RESERVE_SIZE=4K)
|
||||
Input:
|
||||
Output:
|
||||
Return: 内存句柄
|
||||
*************************************************/
|
||||
ALLOC_HANDLE_T get_reserve_zone();
|
||||
|
||||
/*************************************************
|
||||
Description: 将句柄转换成内存地址
|
||||
Input: 内存句柄
|
||||
Output:
|
||||
Return: 内存地址,如果句柄无效返回NULL
|
||||
*************************************************/
|
||||
inline void *handle_to_ptr(ALLOC_HANDLE_T hHandle)
|
||||
{
|
||||
if (hHandle == INVALID_HANDLE)
|
||||
return (NULL);
|
||||
return (void *)(((char *)m_pBaseAddr) + hHandle);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 将内存地址转换为句柄
|
||||
Input: 内存地址
|
||||
Output:
|
||||
Return: 内存句柄,如果地址无效返回INVALID_HANDLE
|
||||
*************************************************/
|
||||
inline ALLOC_HANDLE_T ptr_to_handle(void *p)
|
||||
{
|
||||
if ((char *)p < (char *)m_pBaseAddr || (char *)p >= ((char *)m_pBaseAddr) + m_pstHead->m_tSize)
|
||||
return INVALID_HANDLE;
|
||||
return (ALLOC_HANDLE_T)(((char *)p) - ((char *)m_pBaseAddr));
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 检测handle是否有效
|
||||
Input: 内存句柄
|
||||
Output:
|
||||
Return: 0: 有效; -1:无效
|
||||
*************************************************/
|
||||
virtual int handle_is_valid(ALLOC_HANDLE_T mem_handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
1181
src/search_local/index_storage/cache/raw_data.cc
vendored
Normal file
1181
src/search_local/index_storage/cache/raw_data.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
430
src/search_local/index_storage/cache/raw_data.h
vendored
Normal file
430
src/search_local/index_storage/cache/raw_data.h
vendored
Normal file
@ -0,0 +1,430 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: raw_data.h
|
||||
*
|
||||
* Description: raw data fundamental operation
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef RAW_DATA_H
|
||||
#define RAW_DATA_H
|
||||
|
||||
#include "pt_malloc.h"
|
||||
#include "global.h"
|
||||
#include "field.h"
|
||||
#include "col_expand.h"
|
||||
#include "table_def_manager.h"
|
||||
#include "node.h"
|
||||
|
||||
#define PRE_DECODE_ROW 1
|
||||
|
||||
typedef enum _EnumDataType
|
||||
{
|
||||
DATA_TYPE_RAW, // 平板数据结构
|
||||
DATA_TYPE_TREE_ROOT, // 树的根节点
|
||||
DATA_TYPE_TREE_NODE // 树的节点
|
||||
} EnumDataType;
|
||||
|
||||
typedef enum _enum_oper_type_
|
||||
{
|
||||
OPER_DIRTY = 0x02, // cover INSERT, DELETE, UPDATE
|
||||
OPER_SELECT = 0x30,
|
||||
OPER_INSERT_OLD = 0x31, // old stuff, same as SELECT aka useless
|
||||
OPER_UPDATE = 0x32,
|
||||
OPER_DELETE_NA = 0x33, // async DELETE require quite a lot change
|
||||
OPER_FLUSH = 0x34, // useless too, same as SELECT
|
||||
OPER_RESV1 = 0x35,
|
||||
OPER_INSERT = 0x36,
|
||||
OPER_RESV2 = 0x37,
|
||||
} TOperType;
|
||||
|
||||
struct RawFormat
|
||||
{
|
||||
unsigned char m_uchDataType; // 数据类型EnumDataType
|
||||
uint32_t m_uiDataSize; // 数据总大小
|
||||
uint32_t m_uiRowCnt; // 行数
|
||||
uint8_t m_uchGetCount; // get次数
|
||||
uint16_t m_LastAccessHour; // 最近访问时间
|
||||
uint16_t m_LastUpdateHour; // 最近更新时间
|
||||
uint16_t m_CreateHour; // 创建时间
|
||||
char m_achKey[0]; // key
|
||||
char m_achRows[0]; // 行数据
|
||||
} __attribute__((packed));
|
||||
|
||||
// 注意:修改操作可能会导致handle改变,因此需要检查重新保存
|
||||
class RawData
|
||||
{
|
||||
private:
|
||||
char *m_pchContent; // 注意:地址可能会因为realloc而改变
|
||||
uint32_t m_uiDataSize; // 包括data_type,data_size,rowcnt,key,rows等总数据大小
|
||||
uint32_t m_uiRowCnt;
|
||||
uint8_t m_uchKeyIdx;
|
||||
int m_iKeySize;
|
||||
int m_iLAId;
|
||||
int m_iLCmodId;
|
||||
int m_iExpireId;
|
||||
int m_iTableIdx;
|
||||
|
||||
ALLOC_SIZE_T m_uiKeyStart;
|
||||
ALLOC_SIZE_T m_uiDataStart;
|
||||
ALLOC_SIZE_T m_uiRowOffset;
|
||||
ALLOC_SIZE_T m_uiOffset;
|
||||
ALLOC_SIZE_T m_uiLAOffset;
|
||||
int m_uiGetCountOffset;
|
||||
int m_uiTimeStampOffSet;
|
||||
uint8_t m_uchGetCount;
|
||||
uint16_t m_LastAccessHour;
|
||||
uint16_t m_LastUpdateHour;
|
||||
uint16_t m_CreateHour;
|
||||
ALLOC_SIZE_T m_uiNeedSize; // 最近一次分配内存失败需要的大小
|
||||
|
||||
MEM_HANDLE_T _handle;
|
||||
uint64_t _size;
|
||||
Mallocator *_mallocator;
|
||||
int _autodestroy;
|
||||
|
||||
RawData *m_pstRef;
|
||||
char m_szErr[200];
|
||||
|
||||
DTCTableDefinition *_tabledef;
|
||||
|
||||
protected:
|
||||
template <class T>
|
||||
T *Pointer(void) const { return reinterpret_cast<T *>(_mallocator->handle_to_ptr(_handle)); }
|
||||
|
||||
int set_data_size();
|
||||
int set_row_count();
|
||||
int expand_chunk(ALLOC_SIZE_T tExpSize);
|
||||
int re_alloc_chunk(ALLOC_SIZE_T tSize);
|
||||
int skip_row(const RowValue &stRow);
|
||||
int encode_row(const RowValue &stRow, unsigned char uchOp, bool expendBuf = true);
|
||||
|
||||
public:
|
||||
/*************************************************
|
||||
Description: 构造函数
|
||||
Input: pstMalloc 内存分配器
|
||||
iAutoDestroy 析构的时候是否自动释放内存
|
||||
Output:
|
||||
Return:
|
||||
*************************************************/
|
||||
RawData(Mallocator *pstMalloc, int iAutoDestroy = 0);
|
||||
|
||||
~RawData();
|
||||
|
||||
void change_mallocator(Mallocator *pstMalloc)
|
||||
{
|
||||
_mallocator = pstMalloc;
|
||||
}
|
||||
|
||||
const char *get_err_msg() { return m_szErr; }
|
||||
|
||||
/*************************************************
|
||||
Description: 新分配一块内存,并初始化
|
||||
Input: uchKeyIdx 作为key的字段在table里的下标
|
||||
iKeySize key的格式,0为变长,非0为定长长度
|
||||
pchKey 为格式化后的key,变长key的第0字节为长度
|
||||
uiDataSize 为数据的大小,用于一次分配足够大的chunk。如果设置为0,则insert row的时候再realloc扩大
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int Init(uint8_t uchKeyIdx, int iKeySize, const char *pchKey, ALLOC_SIZE_T uiDataSize = 0, int laid = -1, int expireid = -1, int nodeIdx = -1);
|
||||
int Init(const char *pchKey, ALLOC_SIZE_T uiDataSize = 0);
|
||||
|
||||
/*************************************************
|
||||
Description: attach一块已经格式化好的内存
|
||||
Input: hHandle 内存的句柄
|
||||
uchKeyIdx 作为key的字段在table里的下标
|
||||
iKeySize key的格式,0为变长,非0为定长长度
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int Attach(MEM_HANDLE_T hHandle, uint8_t uchKeyIdx, int iKeySize, int laid = -1, int lastcmod = -1, int expireid = -1);
|
||||
int Attach(MEM_HANDLE_T hHandle);
|
||||
|
||||
/*************************************************
|
||||
Description: 获取内存块的句柄
|
||||
Input:
|
||||
Output:
|
||||
Return: 句柄。 注意:任何修改操作可能会导致handle改变,因此需要检查重新保存
|
||||
*************************************************/
|
||||
MEM_HANDLE_T get_handle() { return _handle; }
|
||||
|
||||
const char *get_addr() const { return m_pchContent; }
|
||||
|
||||
/*************************************************
|
||||
Description: 设置一个refrence,在调用CopyRow()或者CopyAll()的时候使用
|
||||
Input: pstRef refrence指针
|
||||
Output:
|
||||
Return:
|
||||
*************************************************/
|
||||
void set_refrence(RawData *pstRef) { m_pstRef = pstRef; }
|
||||
|
||||
/*************************************************
|
||||
Description: 包括key、rows等所有内存的大小
|
||||
Input:
|
||||
Output:
|
||||
Return: 所有内存的大小
|
||||
*************************************************/
|
||||
uint32_t data_size() const { return m_uiDataSize; }
|
||||
|
||||
/*************************************************
|
||||
Description: rows的开始偏移量
|
||||
Input:
|
||||
Output:
|
||||
Return: rows的开始偏移量
|
||||
*************************************************/
|
||||
uint32_t data_start() const { return m_uiDataStart; }
|
||||
|
||||
/*************************************************
|
||||
Description: 内存分配失败时,返回所需要的内存大小
|
||||
Input:
|
||||
Output:
|
||||
Return: 返回所需要的内存大小
|
||||
*************************************************/
|
||||
ALLOC_SIZE_T need_size() { return m_uiNeedSize; }
|
||||
|
||||
/*************************************************
|
||||
Description: 计算插入该行所需要的内存大小
|
||||
Input: stRow 行数据
|
||||
Output:
|
||||
Return: 返回所需要的内存大小
|
||||
*************************************************/
|
||||
ALLOC_SIZE_T calc_row_size(const RowValue &stRow, int keyIndex);
|
||||
|
||||
/*************************************************
|
||||
Description: 获取格式化后的key
|
||||
Input:
|
||||
Output:
|
||||
Return: 格式化后的key
|
||||
*************************************************/
|
||||
const char *Key() const { return m_pchContent ? (m_pchContent + m_uiKeyStart) : NULL; }
|
||||
char *Key() { return m_pchContent ? (m_pchContent + m_uiKeyStart) : NULL; }
|
||||
|
||||
/*************************************************
|
||||
Description: 获取key的格式
|
||||
Input:
|
||||
Output:
|
||||
Return: 变长返回0,定长key返回定长的长度
|
||||
*************************************************/
|
||||
int key_format() const { return m_iKeySize; }
|
||||
|
||||
/*************************************************
|
||||
Description: 获取key的实际长度
|
||||
Input:
|
||||
Output:
|
||||
Return: key的实际长度
|
||||
*************************************************/
|
||||
int key_size();
|
||||
|
||||
unsigned int total_rows() const { return m_uiRowCnt; }
|
||||
void rewind(void)
|
||||
{
|
||||
m_uiOffset = m_uiDataStart;
|
||||
m_uiRowOffset = m_uiDataStart;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 销毁释放内存
|
||||
Input:
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int Destroy();
|
||||
|
||||
/*************************************************
|
||||
Description: 释放多余的内存(通常在delete一些row后调用一次)
|
||||
Input:
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int strip_mem();
|
||||
|
||||
/*************************************************
|
||||
Description: 读取一行数据
|
||||
Input:
|
||||
Output: stRow 保存行数据
|
||||
uchRowFlags 行数据是否脏数据等flag
|
||||
iDecodeFlag 是否只是pre-read,不fetch_row移动指针
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int decode_row(RowValue &stRow, unsigned char &uchRowFlags, int iDecodeFlag = 0);
|
||||
|
||||
/*************************************************
|
||||
Description: 插入一行数据
|
||||
Input: stRow 需要插入的行数据
|
||||
Output:
|
||||
byFirst 是否插入到最前面,默认添加到最后面
|
||||
isDirty 是否脏数据
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int insert_row(const RowValue &stRow, bool byFirst, bool isDirty);
|
||||
|
||||
/*************************************************
|
||||
Description: 插入一行数据
|
||||
Input: stRow 需要插入的行数据
|
||||
Output:
|
||||
byFirst 是否插入到最前面,默认添加到最后面
|
||||
uchOp row的标记
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int insert_row_flag(const RowValue &stRow, bool byFirst, unsigned char uchOp);
|
||||
|
||||
/*************************************************
|
||||
Description: 插入若干行数据
|
||||
Input: uiNRows 行数
|
||||
stRow 需要插入的行数据
|
||||
Output:
|
||||
byFirst 是否插入到最前面,默认添加到最后面
|
||||
isDirty 是否脏数据
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int insert_n_rows(unsigned int uiNRows, const RowValue *pstRow, bool byFirst, bool isDirty);
|
||||
|
||||
/*************************************************
|
||||
Description: 用指定数据替换当前行
|
||||
Input: stRow 新的行数据
|
||||
Output:
|
||||
isDirty 是否脏数据
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int replace_cur_row(const RowValue &stRow, bool isDirty);
|
||||
|
||||
/*************************************************
|
||||
Description: 删除当前行
|
||||
Input: stRow 仅使用row的字段类型等信息,不需要实际数据
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int delete_cur_row(const RowValue &stRow);
|
||||
|
||||
/*************************************************
|
||||
Description: 删除所有行
|
||||
Input:
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int delete_all_rows();
|
||||
|
||||
/*************************************************
|
||||
Description: 设置当前行的标记
|
||||
Input: uchFlag 行的标记
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int set_cur_row_flag(unsigned char uchFlag);
|
||||
|
||||
/*************************************************
|
||||
Description: 从refrence copy当前行到本地buffer末尾
|
||||
Input:
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int copy_row();
|
||||
|
||||
/*************************************************
|
||||
Description: 用refrence的数据替换本地数据
|
||||
Input:
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int copy_all();
|
||||
|
||||
/*************************************************
|
||||
Description: 添加N行已经格式化好的数据到末尾
|
||||
Input:
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int append_n_records(unsigned int uiNRows, const char *pchData, const unsigned int uiLen);
|
||||
|
||||
/*************************************************
|
||||
Description: 更新最后访问时间戳
|
||||
Input: 时间戳
|
||||
Output:
|
||||
Return:
|
||||
*************************************************/
|
||||
void update_lastacc(uint32_t now)
|
||||
{
|
||||
if (m_uiLAOffset > 0)
|
||||
*(uint32_t *)(m_pchContent + m_uiLAOffset) = now;
|
||||
}
|
||||
int get_expire_time(DTCTableDefinition *t, uint32_t &expire);
|
||||
/*************************************************
|
||||
Description: 获取最后需改时间
|
||||
Input: 时间戳
|
||||
Output:
|
||||
Return:
|
||||
*************************************************/
|
||||
int get_lastcmod(uint32_t &lastcmod);
|
||||
int check_size(MEM_HANDLE_T hHandle, uint8_t uchKeyIdx, int iKeySize, int size);
|
||||
|
||||
/*************************************************
|
||||
Description: 初始化时间戳,包括最后访问时间
|
||||
、最后更新时间、创建时间三部分
|
||||
Input: 时间戳(以某个绝对事件为开始的小时数)
|
||||
虽然名字为Update,其实只会被调用一次
|
||||
tomchen
|
||||
*************************************************/
|
||||
void init_timp_stamp();
|
||||
/*************************************************
|
||||
Description: 更新节点最后访问时间
|
||||
Input: 时间戳(以某个绝对事件为开始的小时数)
|
||||
tomchen
|
||||
*************************************************/
|
||||
void update_last_access_time_by_hour();
|
||||
/*************************************************
|
||||
Description: 更新节点最后更新时间
|
||||
Input: 时间戳(以某个绝对事件为开始的小时数)
|
||||
tomchen
|
||||
*************************************************/
|
||||
void update_last_update_time_by_hour();
|
||||
/*************************************************
|
||||
Description: 增加节点被select请求的次数
|
||||
tomchen
|
||||
*************************************************/
|
||||
void inc_select_count();
|
||||
/*************************************************
|
||||
Description: 获取节点创建时间
|
||||
tomchen
|
||||
*************************************************/
|
||||
uint32_t get_create_time_by_hour();
|
||||
/*************************************************
|
||||
Description: 获取节点最后访问时间
|
||||
tomchen
|
||||
*************************************************/
|
||||
uint32_t get_last_access_time_by_hour();
|
||||
/*************************************************
|
||||
Description: 获取节点最后更新时间
|
||||
tomchen
|
||||
*************************************************/
|
||||
uint32_t get_last_update_time_by_hour();
|
||||
/*************************************************
|
||||
Description: 获取节点被select操作的次数
|
||||
tomchen
|
||||
*************************************************/
|
||||
uint32_t get_select_op_count();
|
||||
/*************************************************
|
||||
Description: attach上时间戳
|
||||
tomchen
|
||||
*************************************************/
|
||||
void attach_time_stamp();
|
||||
|
||||
DTCTableDefinition *get_node_table_def();
|
||||
};
|
||||
|
||||
inline int RawData::key_size()
|
||||
{
|
||||
return m_iKeySize > 0 ? m_iKeySize : (sizeof(char) + *(unsigned char *)Key());
|
||||
}
|
||||
|
||||
#endif
|
1137
src/search_local/index_storage/cache/raw_data_process.cc
vendored
Normal file
1137
src/search_local/index_storage/cache/raw_data_process.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
212
src/search_local/index_storage/cache/raw_data_process.h
vendored
Normal file
212
src/search_local/index_storage/cache/raw_data_process.h
vendored
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: raw_data_process.h
|
||||
*
|
||||
* Description: raw data process interface
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef RAW_DATA_PROCESS_H
|
||||
#define RAW_DATA_PROCESS_H
|
||||
|
||||
#include "buffer_def.h"
|
||||
#include "protocol.h"
|
||||
#include "value.h"
|
||||
#include "field.h"
|
||||
#include "section.h"
|
||||
#include "table_def.h"
|
||||
#include "task_request.h"
|
||||
#include "stat_dtc.h"
|
||||
#include "raw_data.h"
|
||||
#include "node.h"
|
||||
#include "data_process.h"
|
||||
#include "buffer_pool.h"
|
||||
#include "namespace.h"
|
||||
#include "stat_manager.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
class TaskRequest;
|
||||
class DTCFlushRequest;
|
||||
|
||||
class RawDataProcess
|
||||
: public DataProcess
|
||||
{
|
||||
private:
|
||||
RawData m_stRawData;
|
||||
DTCTableDefinition *m_pstTab;
|
||||
Mallocator *m_pMallocator;
|
||||
DTCBufferPool *m_pstPool;
|
||||
UpdateMode m_stUpdateMode;
|
||||
int64_t m_llRowsInc;
|
||||
int64_t m_llDirtyRowsInc;
|
||||
char m_szErr[200];
|
||||
|
||||
unsigned int nodeSizeLimit; // -DEBUG-
|
||||
|
||||
/*对历史节点数据的采样统计,放在高端内存操作管理的地方,便于收敛统计点 , modify by tomchen 2014.08.27*/
|
||||
StatSample history_datasize;
|
||||
StatSample history_rowsize;
|
||||
|
||||
protected:
|
||||
int init_data(Node *pstNode, RawData *pstAffectedRows, const char *ptrKey);
|
||||
int attach_data(Node *pstNode, RawData *pstAffectedRows);
|
||||
int destroy_data(Node *pstNode);
|
||||
|
||||
private:
|
||||
int encode_to_private_area(RawData &, RowValue &, unsigned char);
|
||||
|
||||
public:
|
||||
RawDataProcess(Mallocator *pstMalloc, DTCTableDefinition *pstTab, DTCBufferPool *pstPool, const UpdateMode *pstUpdateMode);
|
||||
|
||||
~RawDataProcess();
|
||||
|
||||
void set_limit_node_size(int node_size) { nodeSizeLimit = node_size; } // -DEBUG-
|
||||
|
||||
const char *get_err_msg() { return m_szErr; }
|
||||
void set_insert_mode(EUpdateMode iMode) { m_stUpdateMode.m_iInsertMode = iMode; }
|
||||
void set_insert_order(int iOrder) { m_stUpdateMode.m_uchInsertOrder = iOrder; }
|
||||
|
||||
void change_mallocator(Mallocator *pstMalloc)
|
||||
{
|
||||
log_debug("oring mallc: %p, new mallc: %p", m_pMallocator, pstMalloc);
|
||||
m_pMallocator = pstMalloc;
|
||||
m_stRawData.change_mallocator(pstMalloc);
|
||||
}
|
||||
|
||||
/* expire time for nodb mode */
|
||||
int get_expire_time(DTCTableDefinition *t, Node *node, uint32_t &expire);
|
||||
|
||||
/*count dirty row, cache process will use it when buffer_delete_rows in task->all_rows case*/
|
||||
int dirty_rows_in_node(TaskRequest &stTask, Node *node);
|
||||
|
||||
/*************************************************
|
||||
Description: 查询本次操作增加的行数(可以为负数)
|
||||
Input:
|
||||
Output:
|
||||
Return: 行数
|
||||
*************************************************/
|
||||
int64_t rows_inc() { return m_llRowsInc; }
|
||||
|
||||
/*************************************************
|
||||
Description: 查询本次操作增加的脏行数(可以为负数)
|
||||
Input:
|
||||
Output:
|
||||
Return: 行数
|
||||
*************************************************/
|
||||
int64_t dirty_rows_inc() { return m_llDirtyRowsInc; }
|
||||
|
||||
/*************************************************
|
||||
Description: 查询node里的所有数据
|
||||
Input: pstNode node节点
|
||||
Output: pstRows 保存数据的结构
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int get_all_rows(Node *pstNode, RawData *pstRows);
|
||||
|
||||
/*************************************************
|
||||
Description: 扩展node的列
|
||||
Input: pstNode node节点
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int expand_node(TaskRequest &stTask, Node *pstNode);
|
||||
|
||||
/*************************************************
|
||||
Description: 用pstRows的数据替换cache里的数据
|
||||
Input: pstRows 新数据
|
||||
pstNode node节点
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int replace_data(Node *pstNode, RawData *pstRawData);
|
||||
|
||||
/*************************************************
|
||||
Description: 根据task请求删除数据
|
||||
Input: stTask task请求
|
||||
pstNode node节点
|
||||
Output: pstAffectedRows 保存被删除的数据(为NULL时不保存)
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int delete_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows);
|
||||
|
||||
/*************************************************
|
||||
Description: 根据task请求查询数据
|
||||
Input: stTask task请求
|
||||
pstNode node节点
|
||||
Output: stTask 保存查找到的数据
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int get_data(TaskRequest &stTask, Node *pstNode);
|
||||
|
||||
/*************************************************
|
||||
Description: 根据task请求添加一行数据
|
||||
Input: stTask task请求
|
||||
pstNode node节点
|
||||
isDirty 是否脏数据
|
||||
Output: pstAffectedRows 保存被删除的数据(为NULL时不保存)
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int append_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool isDirty, bool uniq);
|
||||
|
||||
/*************************************************
|
||||
Description: 用task的数据替换cache里的数据
|
||||
Input: stTask task请求
|
||||
pstNode node节点
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int replace_data(TaskRequest &stTask, Node *pstNode);
|
||||
|
||||
/*************************************************
|
||||
Description: 用task的数据替换cache里的数据
|
||||
Input: stTask task请求
|
||||
pstNode node节点
|
||||
async 是否异步操作
|
||||
Output: pstAffectedRows 保存被更新后的数据(为NULL时不保存)
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int replace_rows(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool async, bool setrows = false);
|
||||
|
||||
/*************************************************
|
||||
Description: 根据task请求更新cache数据
|
||||
Input: stTask task请求
|
||||
pstNode node节点
|
||||
async 是否异步操作
|
||||
Output: pstAffectedRows 保存被更新后的数据(为NULL时不保存)
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int update_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool async, bool setrows = false);
|
||||
|
||||
/*************************************************
|
||||
Description: 将node节点的脏数据组成若干个flush请求
|
||||
Input: pstNode node节点
|
||||
Output: pstFlushReq 保存flush请求
|
||||
uiFlushRowsCnt 被flush的行数
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int flush_data(DTCFlushRequest *pstFlushReq, Node *pstNode, unsigned int &uiFlushRowsCnt);
|
||||
|
||||
/*************************************************
|
||||
Description: 删除cache里的数据,如果有脏数据会生成flush请求
|
||||
Input: pstNode node节点
|
||||
Output: pstFlushReq 保存flush请求
|
||||
uiFlushRowsCnt 被flush的行数
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int purge_data(DTCFlushRequest *pstFlushReq, Node *pstNode, unsigned int &uiFlushRowsCnt);
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
35
src/search_local/index_storage/cache/reader_interface.h
vendored
Normal file
35
src/search_local/index_storage/cache/reader_interface.h
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: reader_interface.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __READER_INTERFACE_H
|
||||
#define __READER_INTERFACE_H
|
||||
|
||||
#include "field.h"
|
||||
|
||||
class ReaderInterface
|
||||
{
|
||||
public:
|
||||
ReaderInterface() {}
|
||||
virtual ~ReaderInterface() {}
|
||||
|
||||
virtual const char *err_msg() = 0;
|
||||
virtual int begin_read() { return 0; }
|
||||
virtual int read_row(RowValue &row) = 0;
|
||||
virtual int end() = 0;
|
||||
};
|
||||
|
||||
#endif
|
20
src/search_local/index_storage/cache/sys_malloc.cc
vendored
Normal file
20
src/search_local/index_storage/cache/sys_malloc.cc
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: sys_malloc.cc
|
||||
*
|
||||
* Description: packaging system malloc memory method.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include "sys_malloc.h"
|
||||
|
||||
SysMalloc g_stSysMalloc;
|
186
src/search_local/index_storage/cache/sys_malloc.h
vendored
Normal file
186
src/search_local/index_storage/cache/sys_malloc.h
vendored
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: sys_malloc.h
|
||||
*
|
||||
* Description: packaging system malloc memory method.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef SYS_MALLOC_H
|
||||
#define SYS_MALLOC_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "namespace.h"
|
||||
#include "mallocator.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
class SysMalloc : public Mallocator
|
||||
{
|
||||
private:
|
||||
char m_szErr[200];
|
||||
|
||||
public:
|
||||
SysMalloc() {}
|
||||
virtual ~SysMalloc() {}
|
||||
|
||||
template <class T>
|
||||
T *Pointer(ALLOC_HANDLE_T hHandle) { return reinterpret_cast<T *>(handle_to_ptr(hHandle)); }
|
||||
|
||||
ALLOC_HANDLE_T Handle(void *p) { return (ALLOC_HANDLE_T)((char *)p - (char *)0); }
|
||||
|
||||
const char *get_err_msg() { return m_szErr; }
|
||||
|
||||
/*************************************************
|
||||
Description: 分配内存
|
||||
Input: tSize 分配的内存大小
|
||||
Output:
|
||||
Return: 内存块句柄,INVALID_HANDLE为失败
|
||||
*************************************************/
|
||||
ALLOC_HANDLE_T Malloc(ALLOC_SIZE_T tSize)
|
||||
{
|
||||
void *p = malloc(sizeof(ALLOC_SIZE_T) + tSize);
|
||||
if (p == NULL)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "%m");
|
||||
return (INVALID_HANDLE);
|
||||
}
|
||||
*(ALLOC_SIZE_T *)p = tSize;
|
||||
return Handle((void *)((char *)p + sizeof(ALLOC_SIZE_T)));
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 分配内存,并将内存初始化为0
|
||||
Input: tSize 分配的内存大小
|
||||
Output:
|
||||
Return: 内存块句柄,INVALID_HANDLE为失败
|
||||
*************************************************/
|
||||
ALLOC_HANDLE_T Calloc(ALLOC_SIZE_T tSize)
|
||||
{
|
||||
void *p = calloc(1, sizeof(ALLOC_SIZE_T) + tSize);
|
||||
if (p == NULL)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "%m");
|
||||
return (INVALID_HANDLE);
|
||||
}
|
||||
*(ALLOC_SIZE_T *)p = tSize;
|
||||
return Handle((void *)((char *)p + sizeof(ALLOC_SIZE_T)));
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 重新分配内存
|
||||
Input: hHandle 老内存句柄
|
||||
tSize 新分配的内存大小
|
||||
Output:
|
||||
Return: 内存块句柄,INVALID_HANDLE为失败(失败时不会释放老内存块)
|
||||
*************************************************/
|
||||
ALLOC_HANDLE_T ReAlloc(ALLOC_HANDLE_T hHandle, ALLOC_SIZE_T tSize)
|
||||
{
|
||||
char *old;
|
||||
if (hHandle == INVALID_HANDLE)
|
||||
old = NULL;
|
||||
else
|
||||
old = (char *)0 + (hHandle - sizeof(ALLOC_SIZE_T));
|
||||
if (tSize == 0)
|
||||
{
|
||||
free(old);
|
||||
return (INVALID_HANDLE);
|
||||
}
|
||||
void *p = realloc(old, sizeof(ALLOC_SIZE_T) + tSize);
|
||||
if (p == NULL)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "%m");
|
||||
return (INVALID_HANDLE);
|
||||
}
|
||||
*(ALLOC_SIZE_T *)p = tSize;
|
||||
return Handle((void *)((char *)p + sizeof(ALLOC_SIZE_T)));
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 释放内存
|
||||
Input: hHandle 内存句柄
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int Free(ALLOC_HANDLE_T hHandle)
|
||||
{
|
||||
if (hHandle == INVALID_HANDLE)
|
||||
return (0);
|
||||
|
||||
char *old = (char *)0 + (hHandle - sizeof(ALLOC_SIZE_T));
|
||||
free(old);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 获取内存块大小
|
||||
Input: hHandle 内存句柄
|
||||
Output:
|
||||
Return: 内存大小
|
||||
*************************************************/
|
||||
ALLOC_SIZE_T chunk_size(ALLOC_HANDLE_T hHandle)
|
||||
{
|
||||
if (hHandle == INVALID_HANDLE)
|
||||
return (0);
|
||||
|
||||
char *old = (char *)0 + (hHandle - sizeof(ALLOC_SIZE_T));
|
||||
return *(ALLOC_SIZE_T *)old;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 将句柄转换成内存地址
|
||||
Input: 内存句柄
|
||||
Output:
|
||||
Return: 内存地址,如果句柄无效返回NULL
|
||||
*************************************************/
|
||||
void *handle_to_ptr(ALLOC_HANDLE_T hHandle)
|
||||
{
|
||||
return (char *)0 + hHandle;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 将内存地址转换为句柄
|
||||
Input: 内存地址
|
||||
Output:
|
||||
Return: 内存句柄,如果地址无效返回INVALID_HANDLE
|
||||
*************************************************/
|
||||
ALLOC_HANDLE_T ptr_to_handle(void *p)
|
||||
{
|
||||
return Handle(p);
|
||||
}
|
||||
|
||||
/* not implement */
|
||||
ALLOC_SIZE_T ask_for_destroy_size(ALLOC_HANDLE_T hHandle)
|
||||
{
|
||||
return (ALLOC_SIZE_T)0;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
Description: 检测handle是否有效
|
||||
Input: 内存句柄
|
||||
Output:
|
||||
Return: 0: 有效; -1:无效
|
||||
*************************************************/
|
||||
virtual int handle_is_valid(ALLOC_HANDLE_T mem_handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
extern SysMalloc g_stSysMalloc;
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
1741
src/search_local/index_storage/cache/t_tree.cc
vendored
Normal file
1741
src/search_local/index_storage/cache/t_tree.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
290
src/search_local/index_storage/cache/t_tree.h
vendored
Normal file
290
src/search_local/index_storage/cache/t_tree.h
vendored
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: t_tree.h
|
||||
*
|
||||
* Description: T-tree fundamental operation. only for TreeData invoke.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef T_TREE_H
|
||||
#define T_TREE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mallocator.h"
|
||||
|
||||
int64_t KeyCompare(const char *pchKey, void *pCmpCookie, Mallocator &stMalloc, ALLOC_HANDLE_T hOtherKey);
|
||||
int Visit(Mallocator &stMalloc, ALLOC_HANDLE_T &hRecord, void *pCookie);
|
||||
|
||||
typedef int64_t (*KeyComparator)(const char *pchKey, void *pCmpCookie, Mallocator &stMalloc, ALLOC_HANDLE_T hOtherKey);
|
||||
typedef int (*ItemVisit)(Mallocator &stMalloc, ALLOC_HANDLE_T &hRecord, void *pCookie);
|
||||
|
||||
class Ttree
|
||||
{
|
||||
protected:
|
||||
ALLOC_HANDLE_T m_hRoot;
|
||||
Mallocator &m_stMalloc;
|
||||
char m_szErr[100];
|
||||
|
||||
public:
|
||||
Ttree(Mallocator &stMalloc);
|
||||
~Ttree();
|
||||
|
||||
const char *get_err_msg() { return m_szErr; }
|
||||
const ALLOC_HANDLE_T Root() const { return m_hRoot; }
|
||||
ALLOC_HANDLE_T first_node();
|
||||
|
||||
/*************************************************
|
||||
Description: attach一块已经格式化好的内存
|
||||
Input:
|
||||
Output:
|
||||
Return:
|
||||
*************************************************/
|
||||
void Attach(ALLOC_HANDLE_T hRoot) { m_hRoot = hRoot; }
|
||||
|
||||
/*************************************************
|
||||
Description: 将key insert到树里,hRecord为key对应的数据(包含key)
|
||||
Input: pchKey 插入的key
|
||||
pCmpCookie 调用用户自定义的pfComp函数跟树里的节点比较时作为输入参数
|
||||
pfComp 用户自定义的key比较函数
|
||||
hRecord 保存着要插入的key以及其他数据的句柄
|
||||
Output:
|
||||
Return: 0为成功,EC_NO_MEM为内存不足,EC_KEY_EXIST为key已经存在,其他值为错误
|
||||
*************************************************/
|
||||
int Insert(const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ALLOC_HANDLE_T hRecord, bool &isAllocNode);
|
||||
|
||||
/*************************************************
|
||||
Description: 删除key以及对应的数据(但不会自动释放key对应的内存)
|
||||
Input: pchKey 插入的key
|
||||
pCmpCookie 调用用户自定义的pfComp函数跟树里的节点比较时作为输入参数
|
||||
pfComp 用户自定义的key比较函数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int Delete(const char *pchKey, void *pCmpCookie, KeyComparator pfComp, bool &isFreeNode);
|
||||
|
||||
int find_handle(ALLOC_HANDLE_T hRecord);
|
||||
|
||||
/*************************************************
|
||||
Description: 查找key对应的数据
|
||||
Input: pchKey 插入的key
|
||||
pCmpCookie 调用用户自定义的pfComp函数跟树里的节点比较时作为输入参数
|
||||
pfComp 用户自定义的key比较函数
|
||||
Output: hRecord 保存查找到的key以及其他数据的句柄
|
||||
Return: 0为查找不到,1为找到数据
|
||||
*************************************************/
|
||||
int Find(const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ALLOC_HANDLE_T &hRecord);
|
||||
|
||||
/*************************************************
|
||||
Description: 查找key对应的数据
|
||||
Input: pchKey 插入的key
|
||||
pCmpCookie 调用用户自定义的pfComp函数跟树里的节点比较时作为输入参数
|
||||
pfComp 用户自定义的key比较函数
|
||||
Output: phRecord 指向树节点的item指针
|
||||
Return: 0为查找不到,1为找到数据
|
||||
*************************************************/
|
||||
int Find(const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ALLOC_HANDLE_T *&phRecord);
|
||||
|
||||
/*************************************************
|
||||
Description: 销毁整棵树,并释放相应的内存
|
||||
Input:
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int Destroy();
|
||||
|
||||
/*************************************************
|
||||
Description: 查询销毁整棵树可以释放多少空闲内存
|
||||
Input:
|
||||
Output:
|
||||
Return: >0 成功, 0 失败
|
||||
*************************************************/
|
||||
unsigned ask_for_destroy_size(void);
|
||||
|
||||
/*************************************************
|
||||
Description: 从小到大遍历整棵树
|
||||
Input: pfVisit 访问数据记录的用户自定义函数
|
||||
pCookie 自定义函数的cookie参数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int traverse_forward(ItemVisit pfVisit, void *pCookie);
|
||||
|
||||
/*************************************************
|
||||
Description: 从大到小遍历整棵树
|
||||
Input: pfVisit 访问数据记录的用户自定义函数
|
||||
pCookie 自定义函数的cookie参数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int traverse_backward(ItemVisit pfVisit, void *pCookie);
|
||||
|
||||
/*************************************************
|
||||
Description: 后序遍历整棵树
|
||||
Input: pfVisit 访问数据记录的用户自定义函数
|
||||
pCookie 自定义函数的cookie参数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int post_order_traverse(ItemVisit pfVisit, void *pCookie);
|
||||
|
||||
/*************************************************
|
||||
Description: 从指定的key开始,从小到大遍历树,遍历的范围为[key, key+iInclusion]
|
||||
Input: pchKey 开始的key
|
||||
pCmpCookie 调用用户自定义的pfComp函数跟树里的节点比较时作为输入参数
|
||||
pfComp 用户自定义的key比较函数
|
||||
iInclusion key的范围
|
||||
pfVisit 访问数据记录的用户自定义函数
|
||||
pCookie 自定义函数的cookie参数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int traverse_forward(const char *pchKey, void *pCmpCookie, KeyComparator pfComp, int64_t iInclusion, ItemVisit pfVisit, void *pCookie);
|
||||
|
||||
/*************************************************
|
||||
Description: 从指定的key开始,从小到大遍历树, 遍历的范围为[key, key1]
|
||||
Input: pchKey 开始的key
|
||||
pchKey1 结束的key
|
||||
pCmpCookie 调用用户自定义的pfComp函数跟树里的节点比较时作为输入参数
|
||||
pfComp 用户自定义的key比较函数
|
||||
pfVisit 访问数据记录的用户自定义函数
|
||||
pCookie 自定义函数的cookie参数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int traverse_forward(const char *pchKey, const char *pchKey1, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
|
||||
/*************************************************
|
||||
Description: 从指定的key开始,从小到大遍历树(遍历大于等于key的所有记录)
|
||||
Input: pchKey 开始的key
|
||||
pCmpCookie 调用用户自定义的pfComp函数跟树里的节点比较时作为输入参数
|
||||
pfComp 用户自定义的key比较函数
|
||||
pfVisit 访问数据记录的用户自定义函数
|
||||
pCookie 自定义函数的cookie参数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int traverse_forward(const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
|
||||
/*************************************************
|
||||
Description: 从指定的key开始,从大到小遍历树(遍历小于等于key的所有记录)
|
||||
Input: pchKey 开始的key
|
||||
pCmpCookie 调用用户自定义的pfComp函数跟树里的节点比较时作为输入参数
|
||||
pfComp 用户自定义的key比较函数
|
||||
pfVisit 访问数据记录的用户自定义函数
|
||||
pCookie 自定义函数的cookie参数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int traverse_backward(const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
|
||||
/*************************************************
|
||||
Description: 从指定的key开始,从大到小遍历树,遍历的范围为[key, key1]
|
||||
Input: pchKey 开始的key
|
||||
pCmpCookie 调用用户自定义的pfComp函数跟树里的节点比较时作为输入参数
|
||||
pfComp 用户自定义的key比较函数
|
||||
pfVisit 访问数据记录的用户自定义函数
|
||||
pCookie 自定义函数的cookie参数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int traverse_backward(const char *pchKey, const char *pchKey1, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
|
||||
/*************************************************
|
||||
Description: 从指定的key开始,先左右树,后根结点, 遍历的范围为[key, key1]
|
||||
Input: pchKey 开始的key
|
||||
pchKey1 结束的key
|
||||
pCmpCookie 调用用户自定义的pfComp函数跟树里的节点比较时作为输入参数
|
||||
pfComp 用户自定义的key比较函数
|
||||
pfVisit 访问数据记录的用户自定义函数
|
||||
pCookie 自定义函数的cookie参数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int post_order_traverse(const char *pchKey, const char *pchKey1, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
|
||||
/*************************************************
|
||||
Description: 从指定的key开始,后序遍历树(遍历大于等于key的所有记录)
|
||||
Input: pchKey 开始的key
|
||||
pCmpCookie 调用用户自定义的pfComp函数跟树里的节点比较时作为输入参数
|
||||
pfComp 用户自定义的key比较函数
|
||||
pfVisit 访问数据记录的用户自定义函数
|
||||
pCookie 自定义函数的cookie参数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int post_order_traverse_ge(const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
|
||||
/*************************************************
|
||||
Description: 从指定的key开始,后序遍历树(遍历小于等于key的所有记录)
|
||||
Input: pchKey 开始的key
|
||||
pCmpCookie 调用用户自定义的pfComp函数跟树里的节点比较时作为输入参数
|
||||
pfComp 用户自定义的key比较函数
|
||||
pfVisit 访问数据记录的用户自定义函数
|
||||
pCookie 自定义函数的cookie参数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int post_order_traverse_le(const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
};
|
||||
|
||||
/************************************************************
|
||||
Description: 封装了T-tree node的各种操作,仅供t-tree内部使用
|
||||
Version: DTC 3.0
|
||||
***********************************************************/
|
||||
struct _TtreeNode
|
||||
{
|
||||
enum
|
||||
{
|
||||
PAGE_SIZE = 20, // 每个节点保存多少条记录
|
||||
MIN_ITEMS = PAGE_SIZE - 2 // minimal number of items in internal node
|
||||
};
|
||||
|
||||
ALLOC_HANDLE_T m_hLeft;
|
||||
ALLOC_HANDLE_T m_hRight;
|
||||
int8_t m_chBalance;
|
||||
uint16_t m_ushNItems;
|
||||
ALLOC_HANDLE_T m_ahItems[PAGE_SIZE];
|
||||
|
||||
int Init();
|
||||
static ALLOC_HANDLE_T Alloc(Mallocator &stMalloc, ALLOC_HANDLE_T hRecord);
|
||||
static int Insert(Mallocator &stMalloc, ALLOC_HANDLE_T &hNode, const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ALLOC_HANDLE_T hRecord, bool &isAllocNode);
|
||||
static int Delete(Mallocator &stMalloc, ALLOC_HANDLE_T &hNode, const char *pchKey, void *pCmpCookie, KeyComparator pfComp, bool &isFreeNode);
|
||||
static int balance_left_branch(Mallocator &stMalloc, ALLOC_HANDLE_T &hNode);
|
||||
static int balance_right_branch(Mallocator &stMalloc, ALLOC_HANDLE_T &hNode);
|
||||
static int Destroy(Mallocator &stMalloc, ALLOC_HANDLE_T hNode);
|
||||
static unsigned ask_for_destroy_size(Mallocator &, ALLOC_HANDLE_T hNode);
|
||||
|
||||
// 查找指定的key。找到返回1,否则返回0
|
||||
int Find(Mallocator &stMalloc, const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ALLOC_HANDLE_T &hRecord);
|
||||
int Find(Mallocator &stMalloc, const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ALLOC_HANDLE_T *&phRecord);
|
||||
int find_handle(Mallocator &stMalloc, ALLOC_HANDLE_T hRecord);
|
||||
// 假设node包含key-k1~kn,查找这样的node节点:k1<= key <=kn
|
||||
int find_node(Mallocator &stMalloc, const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ALLOC_HANDLE_T &hNode);
|
||||
int traverse_forward(Mallocator &stMalloc, ItemVisit pfVisit, void *pCookie);
|
||||
int traverse_backward(Mallocator &stMalloc, ItemVisit pfVisit, void *pCookie);
|
||||
int post_order_traverse(Mallocator &stMalloc, ItemVisit pfVisit, void *pCookie);
|
||||
|
||||
int traverse_forward(Mallocator &stMalloc, const char *pchKey, void *pCmpCookie, KeyComparator pfComp, int iInclusion, ItemVisit pfVisit, void *pCookie);
|
||||
int traverse_forward(Mallocator &stMalloc, const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
int traverse_forward(Mallocator &stMalloc, const char *pchKey, const char *pchKey1, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
|
||||
int traverse_backward(Mallocator &stMalloc, const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
int traverse_backward(Mallocator &stMalloc, const char *pchKey, const char *pchKey1, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
|
||||
int post_order_traverse(Mallocator &stMalloc, const char *pchKey, const char *pchKey1, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
int post_order_traverse_ge(Mallocator &stMalloc, const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
int post_order_traverse_le(Mallocator &stMalloc, const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ItemVisit pfVisit, void *pCookie);
|
||||
} __attribute__((packed));
|
||||
typedef struct _TtreeNode TtreeNode;
|
||||
|
||||
#endif
|
137
src/search_local/index_storage/cache/task_control.cc
vendored
Normal file
137
src/search_local/index_storage/cache/task_control.cc
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: task_control.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <task_control.h>
|
||||
#include <log.h>
|
||||
#include "protocol.h"
|
||||
|
||||
TaskControl *TaskControl::serverControl = NULL;
|
||||
|
||||
TaskControl::TaskControl(PollThread *o) : TaskDispatcher<TaskRequest>(o), m_output(o)
|
||||
{
|
||||
atomic8_set(&m_readOnly, 0);
|
||||
m_statReadonly = statmgr.get_item_u32(SERVER_READONLY);
|
||||
m_statReadonly.set((0 == atomic8_read(&m_readOnly)) ? 0 : 1);
|
||||
}
|
||||
|
||||
TaskControl::~TaskControl(void)
|
||||
{
|
||||
}
|
||||
|
||||
TaskControl *TaskControl::get_instance(PollThread *o)
|
||||
{
|
||||
if (NULL == serverControl)
|
||||
{
|
||||
NEW(TaskControl(o), serverControl);
|
||||
}
|
||||
return serverControl;
|
||||
}
|
||||
|
||||
TaskControl *TaskControl::get_instance()
|
||||
{
|
||||
return serverControl;
|
||||
}
|
||||
|
||||
bool TaskControl::is_read_only()
|
||||
{
|
||||
return 0 != atomic8_read(&m_readOnly);
|
||||
}
|
||||
void TaskControl::query_mem_info(TaskRequest *cur)
|
||||
{
|
||||
struct DTCServerInfo s_info;
|
||||
memset(&s_info, 0x00, sizeof(s_info));
|
||||
|
||||
s_info.version = 0x1;
|
||||
s_info.datasize = statmgr.get10_s_item_value(DTC_DATA_SIZE);
|
||||
s_info.memsize = statmgr.get10_s_item_value(DTC_CACHE_SIZE);
|
||||
log_debug("Memory info is: memsize is %lu , datasize is %lu", s_info.memsize, s_info.datasize);
|
||||
cur->resultInfo.set_server_info(&s_info);
|
||||
}
|
||||
void TaskControl::deal_server_admin(TaskRequest *cur)
|
||||
{
|
||||
switch (cur->requestInfo.admin_code())
|
||||
{
|
||||
case DRequest::ServerAdminCmd::SET_READONLY:
|
||||
{
|
||||
atomic8_set(&m_readOnly, 1);
|
||||
m_statReadonly.set(1);
|
||||
log_info("set server status to readonly.");
|
||||
break;
|
||||
}
|
||||
case DRequest::ServerAdminCmd::SET_READWRITE:
|
||||
{
|
||||
atomic8_set(&m_readOnly, 0);
|
||||
m_statReadonly.set(0);
|
||||
log_info("set server status to read/write.");
|
||||
break;
|
||||
}
|
||||
case DRequest::ServerAdminCmd::QUERY_MEM_INFO:
|
||||
{
|
||||
log_debug("query meminfo.");
|
||||
query_mem_info(cur);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
log_debug("unknow cmd: %d", cur->requestInfo.admin_code());
|
||||
cur->set_error(-EC_REQUEST_ABORTED, "RequestControl", "Unknown svrAdmin command.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cur->reply_notify();
|
||||
}
|
||||
|
||||
void TaskControl::task_notify(TaskRequest *cur)
|
||||
{
|
||||
log_debug("TaskControl::task_notify Cmd is %d, AdminCmd is %u", cur->request_code(), cur->requestInfo.admin_code());
|
||||
//处理ServerAdmin命令
|
||||
if (DRequest::SvrAdmin == cur->request_code())
|
||||
{
|
||||
switch (cur->requestInfo.admin_code())
|
||||
{
|
||||
case DRequest::ServerAdminCmd::SET_READONLY:
|
||||
case DRequest::ServerAdminCmd::SET_READWRITE:
|
||||
case DRequest::ServerAdminCmd::QUERY_MEM_INFO:
|
||||
deal_server_admin(cur);
|
||||
return;
|
||||
|
||||
//allow all admin_code pass
|
||||
default:
|
||||
{
|
||||
log_debug("TaskControl::task_notify admincmd, tasknotify next process ");
|
||||
m_output.task_notify(cur);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//当server为readonly,对非查询请求直接返回错误
|
||||
if (0 != atomic8_read(&m_readOnly))
|
||||
{
|
||||
if (DRequest::Get != cur->request_code())
|
||||
{
|
||||
log_info("server is readonly, reject write operation");
|
||||
cur->set_error(-EC_SERVER_READONLY, "RequestControl", "Server is readonly.");
|
||||
cur->reply_notify();
|
||||
return;
|
||||
}
|
||||
}
|
||||
log_debug("TaskControl::task_notify tasknotify next process ");
|
||||
m_output.task_notify(cur);
|
||||
}
|
53
src/search_local/index_storage/cache/task_control.h
vendored
Normal file
53
src/search_local/index_storage/cache/task_control.h
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: task_control.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __REQUEST_CONTROL_H
|
||||
#define __REQUEST_CONTROL_H
|
||||
|
||||
#include <task_request.h>
|
||||
#include <stat_dtc.h>
|
||||
|
||||
class TaskControl : public TaskDispatcher<TaskRequest>
|
||||
{
|
||||
protected:
|
||||
static TaskControl *serverControl;
|
||||
TaskControl(PollThread *o);
|
||||
|
||||
public:
|
||||
//返回实例,如果实例尚未构造,则构造一个新的实例返回
|
||||
static TaskControl *get_instance(PollThread *o);
|
||||
//仅是返回,如果实例尚未构造,则返回空
|
||||
static TaskControl *get_instance();
|
||||
virtual ~TaskControl(void);
|
||||
void bind_dispatcher(TaskDispatcher<TaskRequest> *p) { m_output.bind_dispatcher(p); }
|
||||
bool is_read_only();
|
||||
|
||||
private:
|
||||
RequestOutput<TaskRequest> m_output;
|
||||
//server是否为只读状态
|
||||
atomic8_t m_readOnly;
|
||||
//Readonly的统计对象
|
||||
StatItemU32 m_statReadonly;
|
||||
|
||||
private:
|
||||
virtual void task_notify(TaskRequest *);
|
||||
//处理serveradmin 命令
|
||||
void deal_server_admin(TaskRequest *cur);
|
||||
void query_mem_info(TaskRequest *cur);
|
||||
};
|
||||
|
||||
#endif
|
111
src/search_local/index_storage/cache/task_pendlist.cc
vendored
Normal file
111
src/search_local/index_storage/cache/task_pendlist.cc
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: task_pendlist.cc
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include "task_pendlist.h"
|
||||
#include "buffer_process.h"
|
||||
#include "log.h"
|
||||
|
||||
DTC_USING_NAMESPACE
|
||||
|
||||
TaskPendingList::TaskPendingList(TaskDispatcher<TaskRequest> *o, int to) : _timeout(to),
|
||||
_timelist(0),
|
||||
_owner(o),
|
||||
_wakeup(0)
|
||||
{
|
||||
_timelist = _owner->owner->get_timer_list(_timeout);
|
||||
}
|
||||
|
||||
TaskPendingList::~TaskPendingList()
|
||||
{
|
||||
std::list<slot_t>::iterator it;
|
||||
for (it = _pendlist.begin(); it != _pendlist.end(); ++it)
|
||||
{
|
||||
//把所有请求踢回客户端
|
||||
it->first->set_error(-ETIMEDOUT, __FUNCTION__, "object deconstruct");
|
||||
it->first->reply_notify();
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPendingList::add2_list(TaskRequest *task)
|
||||
{
|
||||
|
||||
if (task)
|
||||
{
|
||||
if (_pendlist.empty())
|
||||
attach_timer(_timelist);
|
||||
|
||||
_pendlist.push_back(std::make_pair(task, time(NULL)));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 唤醒队列中所有已经pending的task
|
||||
void TaskPendingList::Wakeup(void)
|
||||
{
|
||||
|
||||
log_debug("TaskPendingList Wakeup");
|
||||
|
||||
//唤醒所有task
|
||||
_wakeup = 1;
|
||||
|
||||
attach_ready_timer(_owner->owner);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void TaskPendingList::timer_notify(void)
|
||||
{
|
||||
|
||||
std::list<slot_t> copy;
|
||||
copy.swap(_pendlist);
|
||||
std::list<slot_t>::iterator it;
|
||||
|
||||
if (_wakeup)
|
||||
{
|
||||
for (it = copy.begin(); it != copy.end(); ++it)
|
||||
{
|
||||
_owner->task_notify(it->first);
|
||||
}
|
||||
|
||||
_wakeup = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
time_t now = time(NULL);
|
||||
|
||||
for (it = copy.begin(); it != copy.end(); ++it)
|
||||
{
|
||||
//超时处理
|
||||
if (it->second + _timeout >= now)
|
||||
{
|
||||
_pendlist.push_back(*it);
|
||||
}
|
||||
else
|
||||
{
|
||||
it->first->set_error(-ETIMEDOUT, __FUNCTION__, "pending task is timedout");
|
||||
it->first->reply_notify();
|
||||
}
|
||||
}
|
||||
|
||||
if (!_pendlist.empty())
|
||||
attach_timer(_timelist);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
65
src/search_local/index_storage/cache/task_pendlist.h
vendored
Normal file
65
src/search_local/index_storage/cache/task_pendlist.h
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: task_pendlist.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef __TASK_REQUEST_PENDINGLIST_H
|
||||
#define __TASK_REQUEST_PENDINGLIST_H
|
||||
|
||||
#include "timer_list.h"
|
||||
#include "namespace.h"
|
||||
#include "task_request.h"
|
||||
#include <list>
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
/*
|
||||
* 请求挂起列表。
|
||||
*
|
||||
* 如果发现请求暂时没法满足,则挂起,直到
|
||||
* 1. 超时
|
||||
* 2. 条件满足被唤醒
|
||||
*/
|
||||
class BufferProcess;
|
||||
class CacheBase;
|
||||
class TaskReqeust;
|
||||
class TimerObject;
|
||||
class TaskPendingList : private TimerObject
|
||||
{
|
||||
public:
|
||||
TaskPendingList(TaskDispatcher<TaskRequest> *o, int timeout = 5);
|
||||
~TaskPendingList();
|
||||
|
||||
void add2_list(TaskRequest *); //加入pending list
|
||||
void Wakeup(void); //唤醒队列中的所有task
|
||||
|
||||
private:
|
||||
virtual void timer_notify(void);
|
||||
|
||||
private:
|
||||
TaskPendingList(const TaskPendingList &);
|
||||
const TaskPendingList &operator=(const TaskPendingList &);
|
||||
|
||||
private:
|
||||
int _timeout;
|
||||
TimerList *_timelist;
|
||||
TaskDispatcher<TaskRequest> *_owner;
|
||||
int _wakeup;
|
||||
typedef std::pair<TaskRequest *, time_t> slot_t;
|
||||
std::list<slot_t> _pendlist;
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
2014
src/search_local/index_storage/cache/tree_data.cc
vendored
Normal file
2014
src/search_local/index_storage/cache/tree_data.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
502
src/search_local/index_storage/cache/tree_data.h
vendored
Normal file
502
src/search_local/index_storage/cache/tree_data.h
vendored
Normal file
@ -0,0 +1,502 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: tree_data.h
|
||||
*
|
||||
* Description: T-tree data struct operation. For user invoke.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef TREE_DATA_H
|
||||
#define TREE_DATA_H
|
||||
|
||||
#include "raw_data.h"
|
||||
#include "t_tree.h"
|
||||
#include "protocol.h"
|
||||
#include "task_request.h"
|
||||
#include "value.h"
|
||||
#include "field.h"
|
||||
#include "section.h"
|
||||
#include "table_def.h"
|
||||
|
||||
typedef enum _TreeCheckResult
|
||||
{
|
||||
CHK_CONTINUE, // 继续访问这棵子树
|
||||
CHK_SKIP, // 忽略这棵子树,继续访问其他节点
|
||||
CHK_STOP, // 终止访问循环
|
||||
CHK_DESTROY // 销毁这棵子树
|
||||
} TreeCheckResult;
|
||||
|
||||
#define TTREE_INDEX_POS 1
|
||||
|
||||
typedef TreeCheckResult (*CheckTreeFunc)(Mallocator &stMalloc, uint8_t uchIndexCnt, uint8_t uchCurIdxCnt, const RowValue *pstIndexValue, const uint32_t uiTreeRowNum, void *pCookie);
|
||||
typedef int (*VisitRawData)(Mallocator &stMalloc, uint8_t uchIndexCnt, const RowValue *pstIndexValue, ALLOC_HANDLE_T &hHandle, int64_t &llRowNumInc, void *pCookie);
|
||||
class TreeData;
|
||||
typedef int (TreeData::*SubRowProcess)(TaskRequest &stTask, MEM_HANDLE_T hRecord);
|
||||
|
||||
class DTCFlushRequest;
|
||||
|
||||
/************************************************************
|
||||
Description: t-tree根节点的数据结构
|
||||
Version: DTC 3.0
|
||||
***********************************************************/
|
||||
struct _RootData
|
||||
{
|
||||
unsigned char m_uchDataType;
|
||||
uint32_t m_treeSize;
|
||||
uint32_t m_uiTotalRawSize; //所有RawData总和,不包含Header
|
||||
uint32_t m_uiNodeCnts; //索引T树中Node总计个数
|
||||
uint32_t m_uiRowCnt; //索引T树中总计行数
|
||||
uint8_t m_uchGetCount;
|
||||
uint16_t m_LastAccessHour;
|
||||
uint16_t m_LastUpdateHour;
|
||||
uint16_t m_CreateHour;
|
||||
MEM_HANDLE_T m_hRoot;
|
||||
char m_achKey[0];
|
||||
} __attribute__((packed));
|
||||
typedef struct _RootData RootData;
|
||||
|
||||
class DTCTableDefinition;
|
||||
typedef struct _CmpCookie
|
||||
{
|
||||
const DTCTableDefinition *m_pstTab;
|
||||
uint8_t m_uchIdx;
|
||||
_CmpCookie(const DTCTableDefinition *pstTab, uint8_t uchIdx)
|
||||
{
|
||||
m_pstTab = pstTab;
|
||||
m_uchIdx = uchIdx;
|
||||
}
|
||||
} CmpCookie;
|
||||
|
||||
typedef struct _pCookie
|
||||
{
|
||||
MEM_HANDLE_T *m_handle;
|
||||
uint32_t nodesGot; //已经遍历到的节点个数
|
||||
uint32_t nodesNum; //需要遍历的节点个数,0代表不限
|
||||
uint32_t rowsGot; //已经遍历到的数据行数
|
||||
_pCookie() : m_handle(NULL), nodesGot(0), nodesNum(0), rowsGot(0) {}
|
||||
} pResCookie;
|
||||
|
||||
typedef enum _CondType
|
||||
{
|
||||
COND_VAL_SET, // 查询特定的值列表
|
||||
COND_RANGE, // 查询value[0] ~ Key-value[0]<=value[1].s64
|
||||
COND_GE, // 查询大于等于value[0]的key
|
||||
COND_LE, // 查询小于等于value[0]的key
|
||||
COND_ALL // 遍历所有key
|
||||
}CondType;
|
||||
|
||||
typedef enum _Order
|
||||
{
|
||||
ORDER_ASC, // 升序
|
||||
ORDER_DEC, // 降序
|
||||
ORDER_POS, // 后序访问
|
||||
} Order;
|
||||
|
||||
/************************************************************
|
||||
Description: 查找数据的条件
|
||||
Version: DTC 3.0
|
||||
***********************************************************/
|
||||
typedef struct
|
||||
{
|
||||
unsigned char m_uchCondType;
|
||||
unsigned char m_uchOrder;
|
||||
unsigned int m_uiValNum;
|
||||
DTCValue *m_pstValue;
|
||||
} TtreeCondition;
|
||||
|
||||
class TreeData
|
||||
{
|
||||
private:
|
||||
RootData *m_pstRootData; // 注意:地址可能会因为realloc而改变
|
||||
Ttree m_stTree;
|
||||
DTCTableDefinition *m_pstTab;
|
||||
uint8_t m_uchIndexDepth;
|
||||
int m_iTableIdx;
|
||||
char m_szErr[100];
|
||||
|
||||
ALLOC_SIZE_T m_uiNeedSize; // 最近一次分配内存失败需要的大小
|
||||
uint64_t m_ullAffectedrows;
|
||||
|
||||
MEM_HANDLE_T _handle;
|
||||
uint32_t _size;
|
||||
uint32_t _root_size;
|
||||
Mallocator *_mallocator;
|
||||
Node *m_pstNode;
|
||||
bool m_async;
|
||||
int64_t m_llRowsInc;
|
||||
int64_t m_llDirtyRowsInc;
|
||||
|
||||
int m_iKeySize;
|
||||
uint8_t m_uchKeyIdx;
|
||||
int m_iExpireId;
|
||||
int m_iLAId;
|
||||
int m_iLCmodId;
|
||||
ALLOC_SIZE_T m_uiLAOffset;
|
||||
|
||||
ALLOC_SIZE_T m_uiOffset;
|
||||
ALLOC_SIZE_T m_uiRowOffset;
|
||||
char *m_pchContent;
|
||||
|
||||
bool m_IndexPartOfUniqField;
|
||||
MEM_HANDLE_T m_hRecord;
|
||||
|
||||
/************************************************************
|
||||
Description: 递归查找数据的cookie参数
|
||||
Version: DTC 3.0
|
||||
***********************************************************/
|
||||
typedef struct
|
||||
{
|
||||
TreeData *m_pstTree;
|
||||
uint8_t m_uchCondIdxCnt;
|
||||
uint8_t m_uchCurIndex;
|
||||
MEM_HANDLE_T m_hHandle;
|
||||
int64_t m_llAffectRows;
|
||||
const int *piInclusion;
|
||||
KeyComparator m_pfComp;
|
||||
const RowValue *m_pstCond;
|
||||
RowValue *m_pstIndexValue;
|
||||
VisitRawData m_pfVisit;
|
||||
void *m_pCookie;
|
||||
} CIndexCookie;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TreeData *m_pstTree;
|
||||
uint8_t m_uchCurCond;
|
||||
MEM_HANDLE_T m_hHandle;
|
||||
int64_t m_llAffectRows;
|
||||
const TtreeCondition *m_pstCond;
|
||||
KeyComparator m_pfComp;
|
||||
RowValue *m_pstIndexValue;
|
||||
CheckTreeFunc m_pfCheck;
|
||||
VisitRawData m_pfVisit;
|
||||
void *m_pCookie;
|
||||
} CSearchCookie;
|
||||
|
||||
int set_data_size(unsigned int data_size);
|
||||
int set_row_count(unsigned int count);
|
||||
unsigned int get_data_size();
|
||||
unsigned int get_row_count();
|
||||
|
||||
protected:
|
||||
template <class T>
|
||||
T *Pointer(void) const { return reinterpret_cast<T *>(_mallocator->handle_to_ptr(_handle)); }
|
||||
|
||||
template <class T>
|
||||
T *Pointer(MEM_HANDLE_T handle) const { return reinterpret_cast<T *>(_mallocator->handle_to_ptr(handle)); }
|
||||
|
||||
int encode_to_private_area(RawData &raw, RowValue &value, unsigned char value_flag);
|
||||
|
||||
inline int pack_key(const RowValue &stRow, uint8_t uchKeyIdx, int &iKeySize, char *&pchKey, unsigned char achKeyBuf[]);
|
||||
inline int pack_key(const DTCValue *pstVal, uint8_t uchKeyIdx, int &iKeySize, char *&pchKey, unsigned char achKeyBuf[]);
|
||||
inline int unpack_key(char *pchKey, uint8_t uchKeyIdx, RowValue &stRow);
|
||||
|
||||
int insert_sub_tree(uint8_t uchCurIndex, uint8_t uchCondIdxCnt, const RowValue &stCondition, KeyComparator pfComp, ALLOC_HANDLE_T hRoot);
|
||||
int insert_sub_tree(uint8_t uchCondIdxCnt, const RowValue &stCondition, KeyComparator pfComp, ALLOC_HANDLE_T hRoot);
|
||||
int insert_sub_tree(uint8_t uchCondIdxCnt, KeyComparator pfComp, ALLOC_HANDLE_T hRoot);
|
||||
int insert_row_flag(uint8_t uchCurIndex, const RowValue &stRow, KeyComparator pfComp, unsigned char uchFlag);
|
||||
int Find(CIndexCookie *pstIdxCookie);
|
||||
int Find(uint8_t uchCondIdxCnt, const RowValue &stCondition, KeyComparator pfComp, ALLOC_HANDLE_T &hRecord);
|
||||
int Find(uint8_t uchCondIdxCnt, const RowValue &stCondition, KeyComparator pfComp, ALLOC_HANDLE_T *&hRecord);
|
||||
static int search_visit(Mallocator &stMalloc, ALLOC_HANDLE_T &hRecord, void *pCookie);
|
||||
int Search(CSearchCookie *pstSearchCookie);
|
||||
int Delete(CIndexCookie *pstIdxCookie);
|
||||
int Delete(uint8_t uchCondIdxCnt, const RowValue &stCondition, KeyComparator pfComp, ALLOC_HANDLE_T &hRecord);
|
||||
|
||||
public:
|
||||
TreeData(Mallocator *pstMalloc);
|
||||
~TreeData();
|
||||
|
||||
const char *get_err_msg() { return m_szErr; }
|
||||
MEM_HANDLE_T get_handle() { return _handle; }
|
||||
int Attach(MEM_HANDLE_T hHandle);
|
||||
int Attach(MEM_HANDLE_T hHandle, uint8_t uchKeyIdx, int iKeySize, int laid = -1, int lcmodid = -1, int expireid = -1);
|
||||
|
||||
const MEM_HANDLE_T get_tree_root() const { return m_stTree.Root(); }
|
||||
|
||||
/*************************************************
|
||||
Description: 新分配一块内存,并初始化
|
||||
Input: iKeySize key的格式,0为变长,非0为定长长度
|
||||
pchKey 为格式化后的key,变长key的第0字节为长度
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int Init(int iKeySize, const char *pchKey);
|
||||
int Init(uint8_t uchKeyIdx, int iKeySize, const char *pchKey, int laId = -1, int expireId = -1, int nodeIdx = -1);
|
||||
int Init(const char *pchKey);
|
||||
|
||||
const char *Key() const { return m_pstRootData ? m_pstRootData->m_achKey : NULL; }
|
||||
char *Key() { return m_pstRootData ? m_pstRootData->m_achKey : NULL; }
|
||||
|
||||
unsigned int total_rows() { return m_pstRootData->m_uiRowCnt; }
|
||||
uint64_t get_affectedrows() { return m_ullAffectedrows; }
|
||||
void set_affected_rows(int num) { m_ullAffectedrows = num; }
|
||||
|
||||
/*************************************************
|
||||
Description: 最近一次分配内存失败所需要的内存大小
|
||||
Input:
|
||||
Output:
|
||||
Return: 返回所需要的内存大小
|
||||
*************************************************/
|
||||
ALLOC_SIZE_T need_size() { return m_uiNeedSize; }
|
||||
|
||||
/*************************************************
|
||||
Description: 销毁uchLevel以及以下级别的子树
|
||||
Input: uchLevel 销毁uchLevel以及以下级别的子树,显然uchLevel应该在1到uchIndexDepth之间
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
// int Destroy(uint8_t uchLevel=1);
|
||||
int Destroy();
|
||||
|
||||
/*************************************************
|
||||
Description: 插入一行数据
|
||||
Input: stRow 包含index字段以及后面字段的值
|
||||
pfComp 用户自定义的key比较函数
|
||||
uchFlag 行标记
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int insert_row_flag(const RowValue &stRow, KeyComparator pfComp, unsigned char uchFlag);
|
||||
|
||||
/*************************************************
|
||||
Description: 插入一行数据
|
||||
Input: stRow 包含index字段以及后面字段的值
|
||||
pfComp 用户自定义的key比较函数
|
||||
isDirty 是否脏数据
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int insert_row(const RowValue &stRow, KeyComparator pfComp, bool isDirty);
|
||||
|
||||
/*************************************************
|
||||
Description: 查找一行数据
|
||||
Input: stCondition 包含各级index字段的值
|
||||
pfComp 用户自定义的key比较函数
|
||||
|
||||
Output: hRecord 查找到的一个指向CRawData的句柄
|
||||
Return: 0为找不到,1为找到数据
|
||||
*************************************************/
|
||||
int Find(const RowValue &stCondition, KeyComparator pfComp, ALLOC_HANDLE_T &hRecord);
|
||||
|
||||
/*************************************************
|
||||
Description: 按索引条件查找
|
||||
Input: pstCond 一个数组,而且大小刚好是uchIndexDepth
|
||||
pfComp 用户自定义的key比较函数
|
||||
pfVisit 当查找到记录时,用户自定义的访问数据函数
|
||||
pCookie 访问数据函数使用的cookie参数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int Search(const TtreeCondition *pstCond, KeyComparator pfComp, VisitRawData pfVisit, CheckTreeFunc pfCheck, void *pCookie);
|
||||
|
||||
/*************************************************
|
||||
Description: 从小到大遍历所有数据
|
||||
Input: pfComp 用户自定义的key比较函数
|
||||
pfVisit 当查找到记录时,用户自定义的访问数据函数
|
||||
pCookie 访问数据函数使用的cookie参数
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int traverse_forward(KeyComparator pfComp, VisitRawData pfVisit, void *pCookie);
|
||||
|
||||
/*************************************************
|
||||
Description: 根据指定的index值,删除符合条件的所有行(包括子树)
|
||||
Input: uchCondIdxCnt 条件index的数量
|
||||
stCondition 包含各级index字段的值
|
||||
pfComp 用户自定义的key比较函数
|
||||
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int delete_sub_row(uint8_t uchCondIdxCnt, const RowValue &stCondition, KeyComparator pfComp);
|
||||
|
||||
/*************************************************
|
||||
Description: 将某个级别的index值修改为另外一个值
|
||||
Input: uchCondIdxCnt 条件index的数量
|
||||
stCondition 包含各级index字段的值
|
||||
pfComp 用户自定义的key比较函数
|
||||
pstNewValue 对应最后一个条件字段的新index值
|
||||
Output:
|
||||
Return: 0为成功,其他值为错误
|
||||
*************************************************/
|
||||
int update_index(uint8_t uchCondIdxCnt, const RowValue &stCondition, KeyComparator pfComp, const DTCValue *pstNewValue);
|
||||
unsigned ask_for_destroy_size(void);
|
||||
|
||||
DTCTableDefinition *get_node_table_def() { return m_pstTab; }
|
||||
|
||||
void change_mallocator(Mallocator *pstMalloc)
|
||||
{
|
||||
_mallocator = pstMalloc;
|
||||
}
|
||||
|
||||
int expand_tree_chunk(MEM_HANDLE_T *pRecord, ALLOC_SIZE_T tExpSize);
|
||||
|
||||
/*************************************************
|
||||
Description: destroy data in t-tree
|
||||
Output:
|
||||
*************************************************/
|
||||
int destroy_sub_tree();
|
||||
|
||||
/*************************************************
|
||||
Description: copy data from raw to t-tree
|
||||
Output:
|
||||
*************************************************/
|
||||
int copy_tree_all(RawData *pstRawData);
|
||||
|
||||
/*************************************************
|
||||
Description: copy data from t-tree to raw
|
||||
Output:
|
||||
*************************************************/
|
||||
int copy_raw_all(RawData *pstRawData);
|
||||
|
||||
/*************************************************
|
||||
Description: get tree data from t-tree
|
||||
Output:
|
||||
*************************************************/
|
||||
int decode_tree_row(RowValue &stRow, unsigned char &uchRowFlags, int iDecodeFlag = 0);
|
||||
|
||||
/*************************************************
|
||||
Description: set tree data from t-tree
|
||||
Output:
|
||||
*************************************************/
|
||||
int encode_tree_row(const RowValue &stRow, unsigned char uchOp);
|
||||
|
||||
/*************************************************
|
||||
Description: compare row data value
|
||||
Output:
|
||||
*************************************************/
|
||||
int compare_tree_data(RowValue *stpNodeRow);
|
||||
|
||||
/*************************************************
|
||||
Description: get data in t-tree
|
||||
Output:
|
||||
*************************************************/
|
||||
int get_tree_data(TaskRequest &stTask);
|
||||
|
||||
/*************************************************
|
||||
Description: flush data in t-tree
|
||||
Output:
|
||||
*************************************************/
|
||||
int flush_tree_data(DTCFlushRequest *pstFlushReq, Node *pstNode, unsigned int &uiFlushRowsCnt);
|
||||
|
||||
/*************************************************
|
||||
Description: get data in t-tree
|
||||
Output:
|
||||
*************************************************/
|
||||
int delete_tree_data(TaskRequest &stTask);
|
||||
|
||||
/*************************************************
|
||||
Description: 获得T树中的Raw类型的每一行的数据
|
||||
Output:
|
||||
*************************************************/
|
||||
int get_sub_raw_data(TaskRequest &stTask, MEM_HANDLE_T hRecord);
|
||||
|
||||
/*************************************************
|
||||
Description: 删除T树中的Raw类型的行的数据
|
||||
Output:
|
||||
*************************************************/
|
||||
int delete_sub_raw_data(TaskRequest &stTask, MEM_HANDLE_T hRecord);
|
||||
|
||||
/*************************************************
|
||||
Description: 修改T树中的Raw类型的行的数据
|
||||
Output:
|
||||
*************************************************/
|
||||
int update_sub_raw_data(TaskRequest &stTask, MEM_HANDLE_T hRecord);
|
||||
|
||||
/*************************************************
|
||||
Description: 替换T树中的Raw类型的行的数据,如没有此行则创建
|
||||
Output:
|
||||
*************************************************/
|
||||
int replace_sub_raw_data(TaskRequest &stTask, MEM_HANDLE_T hRecord);
|
||||
|
||||
/*************************************************
|
||||
Description: 处理T树中平板类型业务
|
||||
Output:
|
||||
*************************************************/
|
||||
int get_sub_raw(TaskRequest &stTask, unsigned int nodeCnt, bool isAsc, SubRowProcess subRowProc);
|
||||
|
||||
/*************************************************
|
||||
Description: 匹配索引
|
||||
Output:
|
||||
*************************************************/
|
||||
int match_index_condition(TaskRequest &stTask, unsigned int rowCnt, SubRowProcess subRowProc);
|
||||
|
||||
/*************************************************
|
||||
Description: update data in t-tree
|
||||
Output:
|
||||
*************************************************/
|
||||
int update_tree_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool async, bool setrows);
|
||||
|
||||
/*************************************************
|
||||
Description: replace data in t-tree
|
||||
Output:
|
||||
*************************************************/
|
||||
int replace_tree_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool async, unsigned char &RowFlag, bool setrows);
|
||||
|
||||
/*************************************************
|
||||
Description: calculate row data size
|
||||
Output:
|
||||
*************************************************/
|
||||
ALLOC_SIZE_T calc_tree_row_size(const RowValue &stRow, int keyIdx);
|
||||
|
||||
/*************************************************
|
||||
Description: get expire time
|
||||
Output:
|
||||
*************************************************/
|
||||
int get_expire_time(DTCTableDefinition *t, uint32_t &expire);
|
||||
|
||||
/*************************************************
|
||||
Description: 替换当前行
|
||||
Input: stRow 仅使用row的字段类型等信息,不需要实际数据
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int replace_cur_row(const RowValue &stRow, bool isDirty, MEM_HANDLE_T *hRecord);
|
||||
|
||||
/*************************************************
|
||||
Description: 删除当前行
|
||||
Input: stRow 仅使用row的字段类型等信息,不需要实际数据
|
||||
Output:
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int delete_cur_row(const RowValue &stRow);
|
||||
|
||||
/*************************************************
|
||||
Description: 调到下一行
|
||||
Input: stRow 仅使用row的字段类型等信息,不需要实际数据
|
||||
Output: m_uiOffset会指向下一行数据的偏移
|
||||
Return: 0为成功,非0失败
|
||||
*************************************************/
|
||||
int skip_row(const RowValue &stRow);
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Output:
|
||||
*************************************************/
|
||||
int64_t dirty_rows_inc() { return m_llDirtyRowsInc; }
|
||||
|
||||
/*************************************************
|
||||
Description: 查询本次操作增加的行数(可以为负数)
|
||||
Input:
|
||||
Output:
|
||||
Return: 行数
|
||||
*************************************************/
|
||||
int64_t rows_inc() { return m_llRowsInc; }
|
||||
|
||||
int set_cur_row_flag(unsigned char uchFlag);
|
||||
|
||||
int dirty_rows_in_node();
|
||||
};
|
||||
|
||||
#endif
|
93
src/search_local/index_storage/cache/tree_data_keycmp.h
vendored
Normal file
93
src/search_local/index_storage/cache/tree_data_keycmp.h
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: tree_data_keycmp.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <ctype.h>
|
||||
|
||||
static inline int stricmp(const char *p, const char *q)
|
||||
{
|
||||
while (toupper(*(unsigned char *)p) == toupper(*(unsigned char *)q))
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
p += 1;
|
||||
q += 1;
|
||||
}
|
||||
return toupper(*(unsigned char *)p) - toupper(*(unsigned char *)q);
|
||||
}
|
||||
|
||||
static inline int strincmp(const char *p, const char *q, size_t n)
|
||||
{
|
||||
while (n > 0)
|
||||
{
|
||||
int diff = toupper(*(unsigned char *)p) - toupper(*(unsigned char *)q);
|
||||
if (diff != 0)
|
||||
{
|
||||
return diff;
|
||||
}
|
||||
else if (*p == '\0')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
p += 1;
|
||||
q += 1;
|
||||
n -= 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int stricoll(const char *p, const char *q)
|
||||
{
|
||||
char p_buf[256];
|
||||
char q_buf[256];
|
||||
size_t p_len = strlen(p);
|
||||
size_t q_len = strlen(q);
|
||||
char *p_dst = p_buf;
|
||||
char *q_dst = q_buf;
|
||||
int i;
|
||||
if (p_len >= sizeof(p_buf))
|
||||
{
|
||||
p_dst = new char[p_len + 1];
|
||||
}
|
||||
if (q_len >= sizeof(q_buf))
|
||||
{
|
||||
q_dst = new char[q_len + 1];
|
||||
}
|
||||
for (i = 0; p[i] != '\0'; i++)
|
||||
{
|
||||
p_dst[i] = toupper(p[i] & 0xFF);
|
||||
}
|
||||
p_dst[i] = '\0';
|
||||
|
||||
for (i = 0; q[i] != '\0'; i++)
|
||||
{
|
||||
q_dst[i] = toupper(q[i] & 0xFF);
|
||||
}
|
||||
q_dst[i] = '\0';
|
||||
|
||||
int diff = strcoll(p_dst, q_dst);
|
||||
if (p_dst != p_buf)
|
||||
{
|
||||
delete[] p_dst;
|
||||
}
|
||||
if (q_dst != q_buf)
|
||||
{
|
||||
delete[] q_dst;
|
||||
}
|
||||
return diff;
|
||||
}
|
682
src/search_local/index_storage/cache/tree_data_process.cc
vendored
Normal file
682
src/search_local/index_storage/cache/tree_data_process.cc
vendored
Normal file
@ -0,0 +1,682 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: tree_data_process.cc
|
||||
*
|
||||
* Description: tree data process interface.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tree_data_process.h"
|
||||
#include "global.h"
|
||||
#include "log.h"
|
||||
#include "sys_malloc.h"
|
||||
|
||||
DTC_USING_NAMESPACE
|
||||
|
||||
TreeDataProcess::TreeDataProcess(Mallocator *pstMalloc, DTCTableDefinition *pstTab, DTCBufferPool *pstPool, const UpdateMode *pstUpdateMode) : m_stTreeData(pstMalloc), m_pstTab(pstTab), m_pMallocator(pstMalloc), m_pstPool(pstPool)
|
||||
{
|
||||
memcpy(&m_stUpdateMode, pstUpdateMode, sizeof(m_stUpdateMode));
|
||||
nodeSizeLimit = 0;
|
||||
history_rowsize = statmgr.get_sample(ROW_SIZE_HISTORY_STAT);
|
||||
}
|
||||
|
||||
TreeDataProcess::~TreeDataProcess()
|
||||
{
|
||||
}
|
||||
|
||||
int TreeDataProcess::get_expire_time(DTCTableDefinition *t, Node *pstNode, uint32_t &expire)
|
||||
{
|
||||
int iRet = 0;
|
||||
|
||||
iRet = m_stTreeData.Attach(pstNode->vd_handle());
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "attach data error");
|
||||
log_error("tree-data attach[handle:" UINT64FMT "] error: %d,%s", pstNode->vd_handle(), iRet, m_stTreeData.get_err_msg());
|
||||
return (iRet);
|
||||
}
|
||||
|
||||
iRet = m_stTreeData.get_expire_time(t, expire);
|
||||
if (iRet != 0)
|
||||
{
|
||||
log_error("tree data get expire time error: %d", iRet);
|
||||
return iRet;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeDataProcess::replace_data(Node *pstNode, RawData *pstRawData)
|
||||
{
|
||||
int iRet;
|
||||
|
||||
log_debug("Replace TreeData start ");
|
||||
|
||||
m_llRowsInc = 0;
|
||||
m_llDirtyRowsInc = 0;
|
||||
|
||||
TreeData tmpTreeData(m_pMallocator);
|
||||
|
||||
iRet = tmpTreeData.Init(pstRawData->Key());
|
||||
if (iRet == EC_NO_MEM)
|
||||
{
|
||||
if (m_pstPool->try_purge_size(tmpTreeData.need_size(), *pstNode) == 0)
|
||||
iRet = tmpTreeData.Init(pstRawData->Key());
|
||||
}
|
||||
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "root-data init error: %s", tmpTreeData.get_err_msg());
|
||||
tmpTreeData.Destroy();
|
||||
return (-2);
|
||||
}
|
||||
|
||||
iRet = tmpTreeData.copy_tree_all(pstRawData);
|
||||
if (iRet == EC_NO_MEM)
|
||||
{
|
||||
if (m_pstPool->try_purge_size(tmpTreeData.need_size(), *pstNode) == 0)
|
||||
iRet = tmpTreeData.copy_tree_all(pstRawData);
|
||||
}
|
||||
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "root-data init error: %s", tmpTreeData.get_err_msg());
|
||||
tmpTreeData.Destroy();
|
||||
return (-2);
|
||||
}
|
||||
|
||||
if (pstNode->vd_handle() != INVALID_HANDLE)
|
||||
destroy_data(pstNode);
|
||||
pstNode->vd_handle() = tmpTreeData.get_handle();
|
||||
|
||||
if (tmpTreeData.total_rows() > 0)
|
||||
{
|
||||
history_rowsize.push(tmpTreeData.total_rows());
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int TreeDataProcess::append_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool isDirty, bool setrows)
|
||||
{
|
||||
int iRet;
|
||||
DTCTableDefinition *stpNodeTab, *stpTaskTab;
|
||||
RowValue *stpNodeRow, *stpTaskRow;
|
||||
|
||||
iRet = m_stTreeData.Attach(pstNode->vd_handle());
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "attach data error");
|
||||
log_error("tree-data attach[handle:" UINT64FMT "] error: %d,%s", pstNode->vd_handle(), iRet, m_stTreeData.get_err_msg());
|
||||
return (iRet);
|
||||
}
|
||||
|
||||
stpNodeTab = m_stTreeData.get_node_table_def();
|
||||
stpTaskTab = stTask.table_definition();
|
||||
RowValue stTaskRow(stpTaskTab);
|
||||
RowValue stNodeRow(stpNodeTab);
|
||||
stpTaskRow = &stTaskRow;
|
||||
stpTaskRow->default_value();
|
||||
stTask.update_row(*stpTaskRow);
|
||||
|
||||
if (stpTaskTab->auto_increment_field_id() >= stpTaskTab->key_fields() && stTask.resultInfo.insert_id())
|
||||
{
|
||||
const int iFieldID = stpTaskTab->auto_increment_field_id();
|
||||
const uint64_t iVal = stTask.resultInfo.insert_id();
|
||||
stpTaskRow->field_value(iFieldID)->Set(iVal);
|
||||
}
|
||||
|
||||
if (stpNodeTab == stpTaskTab)
|
||||
{
|
||||
stpNodeRow = stpTaskRow;
|
||||
}
|
||||
else
|
||||
{
|
||||
stpNodeRow = &stNodeRow;
|
||||
stpNodeRow->default_value();
|
||||
stpNodeRow->Copy(stpTaskRow);
|
||||
}
|
||||
|
||||
log_debug("AppendTreeData start! ");
|
||||
|
||||
m_llRowsInc = 0;
|
||||
m_llDirtyRowsInc = 0;
|
||||
|
||||
unsigned int uiTotalRows = m_stTreeData.total_rows();
|
||||
if (uiTotalRows > 0)
|
||||
{
|
||||
if ((isDirty || setrows) && stTask.table_definition()->key_as_uniq_field())
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "duplicate key error");
|
||||
return (-1062);
|
||||
}
|
||||
if (setrows && stTask.table_definition()->key_part_of_uniq_field())
|
||||
{
|
||||
iRet = m_stTreeData.compare_tree_data(stpNodeRow);
|
||||
if (iRet < 0)
|
||||
{
|
||||
log_error("tree-data decode row error: %d,%s", iRet, m_stTreeData.get_err_msg());
|
||||
return iRet;
|
||||
}
|
||||
else if (iRet == 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "duplicate key error");
|
||||
return (-1062);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// insert clean row
|
||||
iRet = m_stTreeData.insert_row(*stpNodeRow, KeyCompare, isDirty);
|
||||
if (iRet == EC_NO_MEM)
|
||||
{
|
||||
if (m_pstPool->try_purge_size(m_stTreeData.need_size(), *pstNode) == 0)
|
||||
iRet = m_stTreeData.insert_row(*stpNodeRow, KeyCompare, isDirty);
|
||||
}
|
||||
if (iRet != EC_NO_MEM)
|
||||
pstNode->vd_handle() = m_stTreeData.get_handle();
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "tree-data insert row error: %s,%d", m_stTreeData.get_err_msg(), iRet);
|
||||
/*标记加入黑名单*/
|
||||
stTask.push_black_list_size(m_stTreeData.need_size());
|
||||
return (-2);
|
||||
}
|
||||
|
||||
if (stTask.resultInfo.affected_rows() == 0 || setrows == true)
|
||||
stTask.resultInfo.set_affected_rows(1);
|
||||
m_llRowsInc++;
|
||||
if (isDirty)
|
||||
m_llDirtyRowsInc++;
|
||||
history_rowsize.push(m_stTreeData.total_rows());
|
||||
return (0);
|
||||
}
|
||||
|
||||
int TreeDataProcess::get_data(TaskRequest &stTask, Node *pstNode)
|
||||
{
|
||||
int iRet;
|
||||
log_debug("Get TreeData start! ");
|
||||
|
||||
m_llRowsInc = 0;
|
||||
m_llDirtyRowsInc = 0;
|
||||
|
||||
iRet = m_stTreeData.Attach(pstNode->vd_handle());
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "attach data error");
|
||||
log_error("tree-data attach[handle:" UINT64FMT "] error: %d,%s", pstNode->vd_handle(), iRet, m_stTreeData.get_err_msg());
|
||||
return (-1);
|
||||
}
|
||||
|
||||
iRet = m_stTreeData.get_tree_data(stTask);
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "get tree data error");
|
||||
log_error("tree-data get[handle:" UINT64FMT "] error: %d,%s", pstNode->vd_handle(), iRet, m_stTreeData.get_err_msg());
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*更新访问时间和查找操作计数*/
|
||||
log_debug("node[id:%u] ,Get Count is %d", pstNode->node_id(), m_stTreeData.total_rows());
|
||||
return (0);
|
||||
}
|
||||
|
||||
int TreeDataProcess::expand_node(TaskRequest &stTask, Node *pstNode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeDataProcess::dirty_rows_in_node(TaskRequest &stTask, Node *pstNode)
|
||||
{
|
||||
int iRet = m_stTreeData.Attach(pstNode->vd_handle());
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "attach data error");
|
||||
log_error("tree-data attach[handle:" UINT64FMT "] error: %d,%s", pstNode->vd_handle(), iRet, m_stTreeData.get_err_msg());
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return m_stTreeData.dirty_rows_in_node();
|
||||
}
|
||||
|
||||
int TreeDataProcess::attach_data(Node *pstNode, RawData *pstAffectedRows)
|
||||
{
|
||||
int iRet;
|
||||
|
||||
iRet = m_stTreeData.Attach(pstNode->vd_handle());
|
||||
if (iRet != 0)
|
||||
{
|
||||
log_error("tree-data attach[handle:" UINT64FMT "] error: %d,%s", pstNode->vd_handle(), iRet, m_stTreeData.get_err_msg());
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (pstAffectedRows != NULL)
|
||||
{
|
||||
iRet = pstAffectedRows->Init(m_stTreeData.Key(), 0);
|
||||
if (iRet != 0)
|
||||
{
|
||||
log_error("tree-data init error: %d,%s", iRet, pstAffectedRows->get_err_msg());
|
||||
return (-2);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int TreeDataProcess::get_all_rows(Node *pstNode, RawData *pstRows)
|
||||
{
|
||||
int iRet = 0;
|
||||
|
||||
m_llRowsInc = 0;
|
||||
m_llDirtyRowsInc = 0;
|
||||
|
||||
iRet = attach_data(pstNode, pstRows);
|
||||
if (iRet != 0)
|
||||
{
|
||||
log_error("attach data error: %d", iRet);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
iRet = m_stTreeData.copy_raw_all(pstRows);
|
||||
if (iRet != 0)
|
||||
{
|
||||
log_error("copy data error: %d,%s", iRet, m_stTreeData.get_err_msg());
|
||||
return (-2);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int TreeDataProcess::delete_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows)
|
||||
{
|
||||
int iRet;
|
||||
log_debug("Delete TreeData start! ");
|
||||
|
||||
iRet = m_stTreeData.Attach(pstNode->vd_handle());
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "attach data error");
|
||||
log_error("tree-data attach[handle:" UINT64FMT "] error: %d,%s", pstNode->vd_handle(), iRet, m_stTreeData.get_err_msg());
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int start = m_stTreeData.total_rows();
|
||||
|
||||
iRet = m_stTreeData.delete_tree_data(stTask);
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "get tree data error");
|
||||
log_error("tree-data get[handle:" UINT64FMT "] error: %d,%s", pstNode->vd_handle(), iRet, m_stTreeData.get_err_msg());
|
||||
return iRet;
|
||||
}
|
||||
|
||||
int iAffectRows = start - m_stTreeData.total_rows();
|
||||
if (iAffectRows > 0)
|
||||
{
|
||||
if (stTask.resultInfo.affected_rows() == 0 ||
|
||||
(stTask.request_condition() && stTask.request_condition()->has_type_timestamp()))
|
||||
{
|
||||
stTask.resultInfo.set_affected_rows(iAffectRows);
|
||||
}
|
||||
}
|
||||
|
||||
m_llRowsInc = m_stTreeData.rows_inc();
|
||||
m_llDirtyRowsInc = m_stTreeData.dirty_rows_inc();
|
||||
|
||||
log_debug("node[id:%u] ,Get Count is %d", pstNode->node_id(), m_stTreeData.total_rows());
|
||||
return (0);
|
||||
}
|
||||
|
||||
int TreeDataProcess::replace_data(TaskRequest &stTask, Node *pstNode)
|
||||
{
|
||||
log_debug("replace_data start! ");
|
||||
DTCTableDefinition *stpNodeTab, *stpTaskTab;
|
||||
RowValue *stpNodeRow;
|
||||
|
||||
int iRet;
|
||||
int try_purge_count = 0;
|
||||
uint64_t all_rows_size = 0;
|
||||
int laid = stTask.flag_no_cache() || stTask.count_only() ? -1 : stTask.table_definition()->lastacc_field_id();
|
||||
int matchedCount = 0;
|
||||
int limitStart = 0;
|
||||
int limitStop = 0x10000000;
|
||||
|
||||
stpTaskTab = stTask.table_definition();
|
||||
if (DTCColExpand::Instance()->is_expanding())
|
||||
stpNodeTab = TableDefinitionManager::Instance()->get_new_table_def();
|
||||
else
|
||||
stpNodeTab = TableDefinitionManager::Instance()->get_cur_table_def();
|
||||
RowValue stNodeRow(stpNodeTab);
|
||||
stpNodeRow = &stNodeRow;
|
||||
stpNodeRow->default_value();
|
||||
|
||||
if (laid > 0 && stTask.requestInfo.limit_count() > 0)
|
||||
{
|
||||
limitStart = stTask.requestInfo.limit_start();
|
||||
if (stTask.requestInfo.limit_start() > 0x10000000)
|
||||
{
|
||||
laid = -1;
|
||||
}
|
||||
else if (stTask.requestInfo.limit_count() < 0x10000000)
|
||||
{
|
||||
limitStop = limitStart + stTask.requestInfo.limit_count();
|
||||
}
|
||||
}
|
||||
|
||||
m_llRowsInc = 0;
|
||||
m_llDirtyRowsInc = 0;
|
||||
|
||||
if (pstNode->vd_handle() != INVALID_HANDLE)
|
||||
{
|
||||
iRet = destroy_data(pstNode);
|
||||
if (iRet != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
iRet = m_stTreeData.Init(stTask.packed_key());
|
||||
if (iRet == EC_NO_MEM)
|
||||
{
|
||||
if (m_pstPool->try_purge_size(m_stTreeData.need_size(), *pstNode) == 0)
|
||||
iRet = m_stTreeData.Init(m_pstTab->key_fields() - 1, m_pstTab->key_format(), stTask.packed_key());
|
||||
}
|
||||
if (iRet != EC_NO_MEM)
|
||||
pstNode->vd_handle() = m_stTreeData.get_handle();
|
||||
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "raw-data init error: %s", m_stTreeData.get_err_msg());
|
||||
/*标记加入黑名单*/
|
||||
stTask.push_black_list_size(m_stTreeData.need_size());
|
||||
m_pstPool->purge_node(stTask.packed_key(), *pstNode);
|
||||
return (-2);
|
||||
}
|
||||
|
||||
if (stTask.result != NULL)
|
||||
{
|
||||
ResultSet *pstResultSet = stTask.result;
|
||||
for (int i = 0; i < pstResultSet->total_rows(); i++)
|
||||
{
|
||||
RowValue *pstRow = pstResultSet->_fetch_row();
|
||||
if (pstRow == NULL)
|
||||
{
|
||||
log_debug("%s!", "call fetch_row func error");
|
||||
m_pstPool->purge_node(stTask.packed_key(), *pstNode);
|
||||
m_stTreeData.Destroy();
|
||||
return (-3);
|
||||
}
|
||||
|
||||
if (laid > 0 && stTask.compare_row(*pstRow))
|
||||
{
|
||||
if (matchedCount >= limitStart && matchedCount < limitStop)
|
||||
{
|
||||
(*pstRow)[laid].s64 = stTask.Timestamp();
|
||||
}
|
||||
matchedCount++;
|
||||
}
|
||||
|
||||
if (stpTaskTab != stpNodeTab)
|
||||
{
|
||||
stpNodeRow->Copy(pstRow);
|
||||
}
|
||||
else
|
||||
{
|
||||
stpNodeRow = pstRow;
|
||||
}
|
||||
|
||||
/* 插入当前行 */
|
||||
iRet = m_stTreeData.insert_row(*stpNodeRow, KeyCompare, false);
|
||||
|
||||
/* 如果内存空间不足,尝试扩大最多两次 */
|
||||
if (iRet == EC_NO_MEM)
|
||||
{
|
||||
|
||||
if (try_purge_count >= 2)
|
||||
{
|
||||
goto ERROR_PROCESS;
|
||||
}
|
||||
|
||||
/* 尝试次数 */
|
||||
++try_purge_count;
|
||||
if (m_pstPool->try_purge_size(m_stTreeData.need_size(), *pstNode) == 0)
|
||||
iRet = m_stTreeData.insert_row(*stpNodeRow, KeyCompare, false);
|
||||
}
|
||||
if (iRet != EC_NO_MEM)
|
||||
pstNode->vd_handle() = m_stTreeData.get_handle();
|
||||
|
||||
/* 当前行操作成功 */
|
||||
if (0 == iRet)
|
||||
continue;
|
||||
ERROR_PROCESS:
|
||||
snprintf(m_szErr, sizeof(m_szErr), "raw-data insert row error: ret=%d,err=%s, cnt=%d",
|
||||
iRet, m_stTreeData.get_err_msg(), try_purge_count);
|
||||
/*标记加入黑名单*/
|
||||
stTask.push_black_list_size(all_rows_size);
|
||||
m_pstPool->purge_node(stTask.packed_key(), *pstNode);
|
||||
m_stTreeData.Destroy();
|
||||
return (-4);
|
||||
}
|
||||
|
||||
m_llRowsInc += pstResultSet->total_rows();
|
||||
}
|
||||
|
||||
history_rowsize.push(m_stTreeData.total_rows());
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int TreeDataProcess::replace_rows(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool async, bool setrows = false)
|
||||
{
|
||||
int iRet;
|
||||
log_debug("Replace TreeData start! ");
|
||||
|
||||
m_llRowsInc = 0;
|
||||
m_llDirtyRowsInc = 0;
|
||||
|
||||
if (pstNode)
|
||||
{
|
||||
iRet = m_stTreeData.Attach(pstNode->vd_handle());
|
||||
if (iRet != 0)
|
||||
{
|
||||
log_error("attach tree data error: %d", iRet);
|
||||
return (iRet);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iRet = m_stTreeData.Init(stTask.packed_key());
|
||||
if (iRet == EC_NO_MEM)
|
||||
{
|
||||
if (m_pstPool->try_purge_size(m_stTreeData.need_size(), *pstNode) == 0)
|
||||
iRet = m_stTreeData.Init(stTask.packed_key());
|
||||
}
|
||||
|
||||
if (iRet != 0)
|
||||
{
|
||||
log_error("tree-data replace[handle:" UINT64FMT "] error: %d,%s", pstNode->vd_handle(), iRet, m_stTreeData.get_err_msg());
|
||||
return iRet;
|
||||
}
|
||||
|
||||
pstNode->vd_handle() = m_stTreeData.get_handle();
|
||||
}
|
||||
|
||||
unsigned char uchRowFlags;
|
||||
iRet = m_stTreeData.replace_tree_data(stTask, pstNode, pstAffectedRows, async, uchRowFlags, setrows);
|
||||
if (iRet == EC_NO_MEM)
|
||||
{
|
||||
if (m_pstPool->try_purge_size(m_stTreeData.need_size(), *pstNode) == 0)
|
||||
iRet = m_stTreeData.replace_tree_data(stTask, pstNode, pstAffectedRows, async, uchRowFlags, setrows);
|
||||
}
|
||||
|
||||
if (iRet != 0)
|
||||
{
|
||||
log_error("tree-data replace[handle:" UINT64FMT "] error: %d,%s", pstNode->vd_handle(), iRet, m_stTreeData.get_err_msg());
|
||||
return iRet;
|
||||
}
|
||||
|
||||
if (uchRowFlags & OPER_DIRTY)
|
||||
m_llDirtyRowsInc--;
|
||||
if (async)
|
||||
m_llDirtyRowsInc++;
|
||||
|
||||
uint64_t ullAffectedRows = m_stTreeData.get_affectedrows();
|
||||
if (ullAffectedRows == 0) //insert
|
||||
{
|
||||
DTCTableDefinition *stpTaskTab;
|
||||
RowValue *stpNewRow;
|
||||
stpTaskTab = stTask.table_definition();
|
||||
RowValue stNewRow(stpTaskTab);
|
||||
stNewRow.default_value();
|
||||
stpNewRow = &stNewRow;
|
||||
stTask.update_row(*stpNewRow); //获取Replace的行
|
||||
iRet = m_stTreeData.insert_row(*stpNewRow, KeyCompare, async); // 加进cache
|
||||
if (iRet == EC_NO_MEM)
|
||||
{
|
||||
if (m_pstPool->try_purge_size(m_stTreeData.need_size(), *pstNode) == 0)
|
||||
iRet = m_stTreeData.insert_row(*stpNewRow, KeyCompare, async);
|
||||
}
|
||||
if (iRet != EC_NO_MEM)
|
||||
pstNode->vd_handle() = m_stTreeData.get_handle();
|
||||
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "raw-data replace row error: %d, %s",
|
||||
iRet, m_stTreeData.get_err_msg());
|
||||
/*标记加入黑名单*/
|
||||
stTask.push_black_list_size(m_stTreeData.need_size());
|
||||
return (-3);
|
||||
}
|
||||
m_llRowsInc++;
|
||||
ullAffectedRows++;
|
||||
if (async)
|
||||
m_llDirtyRowsInc++;
|
||||
}
|
||||
if (async == true || setrows == true)
|
||||
{
|
||||
stTask.resultInfo.set_affected_rows(ullAffectedRows);
|
||||
}
|
||||
else if (ullAffectedRows != stTask.resultInfo.affected_rows())
|
||||
{
|
||||
//如果cache更新纪录数和helper更新的纪录数不相等
|
||||
log_debug("unequal affected rows, cache[%lld], helper[%lld]",
|
||||
(long long)ullAffectedRows,
|
||||
(long long)stTask.resultInfo.affected_rows());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeDataProcess::update_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool async, bool setrows = false)
|
||||
{
|
||||
int iRet;
|
||||
log_debug("Update TreeData start! ");
|
||||
|
||||
m_llRowsInc = 0;
|
||||
m_llDirtyRowsInc = 0;
|
||||
|
||||
iRet = m_stTreeData.Attach(pstNode->vd_handle());
|
||||
if (iRet != 0)
|
||||
{
|
||||
log_error("attach tree data error: %d", iRet);
|
||||
return (iRet);
|
||||
}
|
||||
|
||||
m_stTreeData.set_affected_rows(0);
|
||||
|
||||
iRet = m_stTreeData.update_tree_data(stTask, pstNode, pstAffectedRows, async, setrows);
|
||||
if (iRet == EC_NO_MEM)
|
||||
{
|
||||
if (m_pstPool->try_purge_size(m_stTreeData.need_size(), *pstNode) == 0)
|
||||
iRet = m_stTreeData.update_tree_data(stTask, pstNode, pstAffectedRows, async, setrows);
|
||||
}
|
||||
|
||||
if (iRet != 0)
|
||||
{
|
||||
log_error("tree-data update[handle:" UINT64FMT "] error: %d,%s", pstNode->vd_handle(), iRet, m_stTreeData.get_err_msg());
|
||||
return iRet;
|
||||
}
|
||||
|
||||
uint64_t ullAffectedRows = m_stTreeData.get_affectedrows();
|
||||
m_llDirtyRowsInc = m_stTreeData.dirty_rows_inc();
|
||||
|
||||
if (async == true || setrows == true)
|
||||
{
|
||||
stTask.resultInfo.set_affected_rows(ullAffectedRows);
|
||||
}
|
||||
else if (ullAffectedRows != stTask.resultInfo.affected_rows())
|
||||
{
|
||||
//如果cache更新纪录数和helper更新的纪录数不相等
|
||||
log_debug("unequal affected rows, cache[%lld], helper[%lld]",
|
||||
(long long)ullAffectedRows,
|
||||
(long long)stTask.resultInfo.affected_rows());
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int TreeDataProcess::flush_data(DTCFlushRequest *pstFlushReq, Node *pstNode, unsigned int &uiFlushRowsCnt)
|
||||
{
|
||||
int iRet;
|
||||
|
||||
log_debug("flush_data start! ");
|
||||
|
||||
m_llRowsInc = 0;
|
||||
m_llDirtyRowsInc = 0;
|
||||
|
||||
iRet = m_stTreeData.Attach(pstNode->vd_handle());
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "attach data error");
|
||||
log_error("tree-data attach[handle:" UINT64FMT "] error: %d,%s", pstNode->vd_handle(), iRet, m_stTreeData.get_err_msg());
|
||||
return (-1);
|
||||
}
|
||||
|
||||
iRet = m_stTreeData.flush_tree_data(pstFlushReq, pstNode, uiFlushRowsCnt);
|
||||
if (iRet != 0)
|
||||
{
|
||||
snprintf(m_szErr, sizeof(m_szErr), "flush tree data error");
|
||||
log_error("tree-data flush[handle:" UINT64FMT "] error: %d,%s", pstNode->vd_handle(), iRet, m_stTreeData.get_err_msg());
|
||||
return iRet;
|
||||
}
|
||||
|
||||
m_llDirtyRowsInc = m_stTreeData.dirty_rows_inc();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int TreeDataProcess::purge_data(DTCFlushRequest *pstFlushReq, Node *pstNode, unsigned int &uiFlushRowsCnt)
|
||||
{
|
||||
int iRet;
|
||||
|
||||
log_debug("purge_data start! ");
|
||||
|
||||
iRet = flush_data(pstFlushReq, pstNode, uiFlushRowsCnt);
|
||||
if (iRet != 0)
|
||||
{
|
||||
return (iRet);
|
||||
}
|
||||
m_llRowsInc = 0LL - m_stTreeData.total_rows();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeDataProcess::destroy_data(Node *pstNode)
|
||||
{
|
||||
if (pstNode->vd_handle() == INVALID_HANDLE)
|
||||
return 0;
|
||||
TreeData treeData(m_pMallocator);
|
||||
treeData.Attach(pstNode->vd_handle());
|
||||
treeData.Destroy();
|
||||
pstNode->vd_handle() = INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
178
src/search_local/index_storage/cache/tree_data_process.h
vendored
Normal file
178
src/search_local/index_storage/cache/tree_data_process.h
vendored
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: tree_data_process.h
|
||||
*
|
||||
* Description: tree data process interface.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 09/08/2020 10:02:05 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Norton, yangshuang68@jd.com
|
||||
* Company: JD.com, Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef TREE_DATA_PROCESS_H
|
||||
#define TREE_DATA_PROCESS_H
|
||||
|
||||
#include "buffer_def.h"
|
||||
#include "protocol.h"
|
||||
#include "value.h"
|
||||
#include "field.h"
|
||||
#include "section.h"
|
||||
#include "table_def.h"
|
||||
#include "task_request.h"
|
||||
#include "stat_dtc.h"
|
||||
#include "tree_data.h"
|
||||
#include "node.h"
|
||||
#include "data_process.h"
|
||||
#include "buffer_pool.h"
|
||||
#include "namespace.h"
|
||||
#include "stat_manager.h"
|
||||
#include "data_chunk.h"
|
||||
|
||||
DTC_BEGIN_NAMESPACE
|
||||
|
||||
class TaskRequest;
|
||||
class DTCFlushRequest;
|
||||
|
||||
class TreeDataProcess
|
||||
: public DataProcess
|
||||
{
|
||||
private:
|
||||
TreeData m_stTreeData;
|
||||
DTCTableDefinition *m_pstTab;
|
||||
Mallocator *m_pMallocator;
|
||||
DTCBufferPool *m_pstPool;
|
||||
UpdateMode m_stUpdateMode;
|
||||
int64_t m_llRowsInc;
|
||||
int64_t m_llDirtyRowsInc;
|
||||
char m_szErr[200];
|
||||
|
||||
unsigned int nodeSizeLimit; // -DEBUG-
|
||||
|
||||
StatSample history_datasize;
|
||||
StatSample history_rowsize;
|
||||
|
||||
protected:
|
||||
int attach_data(Node *pstNode, RawData *pstAffectedRows);
|
||||
|
||||
public:
|
||||
void change_mallocator(Mallocator *pstMalloc)
|
||||
{
|
||||
log_debug("oring mallc: %p, new mallc: %p", m_pMallocator, pstMalloc);
|
||||
m_pMallocator = pstMalloc;
|
||||
m_stTreeData.change_mallocator(pstMalloc);
|
||||
}
|
||||
|
||||
TreeDataProcess(Mallocator *pstMalloc, DTCTableDefinition *pstTab, DTCBufferPool *pstPool, const UpdateMode *pstUpdateMode);
|
||||
~TreeDataProcess();
|
||||
|
||||
const char *get_err_msg() { return m_szErr; }
|
||||
void set_insert_mode(EUpdateMode iMode) {}
|
||||
void set_insert_order(int iOrder) {}
|
||||
|
||||
/*************************************************
|
||||
Description: get expire time
|
||||
Output:
|
||||
*************************************************/
|
||||
int get_expire_time(DTCTableDefinition *t, Node *pstNode, uint32_t &expire);
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Output:
|
||||
*************************************************/
|
||||
int expand_node(TaskRequest &stTask, Node *pstNode);
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Output:
|
||||
*************************************************/
|
||||
int dirty_rows_in_node(TaskRequest &stTask, Node *pstNode);
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Output:
|
||||
*************************************************/
|
||||
int64_t rows_inc() { return m_llRowsInc; };
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Output:
|
||||
*************************************************/
|
||||
int64_t dirty_rows_inc() { return m_llDirtyRowsInc; }
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Output:
|
||||
*************************************************/
|
||||
int get_all_rows(Node *pstNode, RawData *pstRows);
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Output:
|
||||
*************************************************/
|
||||
int delete_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows);
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Output:
|
||||
*************************************************/
|
||||
int replace_data(TaskRequest &stTask, Node *pstNode);
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Output:
|
||||
*************************************************/
|
||||
int replace_rows(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool async, bool setrows);
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Output:
|
||||
*************************************************/
|
||||
int update_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool async, bool setrows);
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Output:
|
||||
*************************************************/
|
||||
int flush_data(DTCFlushRequest *pstFlushReq, Node *pstNode, unsigned int &uiFlushRowsCnt);
|
||||
|
||||
/*************************************************
|
||||
Description:
|
||||
Output:
|
||||
*************************************************/
|
||||
int purge_data(DTCFlushRequest *pstFlushReq, Node *pstNode, unsigned int &uiFlushRowsCnt);
|
||||
|
||||
/*************************************************
|
||||
Description: append data in t-tree
|
||||
Output:
|
||||
*************************************************/
|
||||
int append_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool isDirty, bool setrows);
|
||||
|
||||
/*************************************************
|
||||
Description: replace data in t-tree
|
||||
Output:
|
||||
*************************************************/
|
||||
int replace_data(Node *pstNode, RawData *pstRawData);
|
||||
|
||||
/*************************************************
|
||||
Description: get data in t-tree
|
||||
Output:
|
||||
*************************************************/
|
||||
int get_data(TaskRequest &stTask, Node *pstNode);
|
||||
|
||||
/*************************************************
|
||||
Description: destroy t-tree
|
||||
Output:
|
||||
*************************************************/
|
||||
int destroy_data(Node *pstNode);
|
||||
};
|
||||
|
||||
DTC_END_NAMESPACE
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user