add index storage cache

This commit is contained in:
choulu 2021-03-19 18:55:11 +08:00
parent b65424de02
commit 1c3429f4bb
80 changed files with 25937 additions and 0 deletions

View 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

File diff suppressed because it is too large Load Diff

View 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();
}

View 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 *);
};

View 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);
}

View 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 *);
};

View 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

View 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;
}
}

View 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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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;
}

View 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

View 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

View 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();
}

View 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;
}

View 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

View 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;
}

View 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

View 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();
}
}

View 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的chunkdata_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: 00
*************************************************/
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

View 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: 00
*************************************************/
virtual int get_all_rows(Node *pstNode, RawData *pstRows) = 0;
/*************************************************
Description: pstRows的数据替换cache里的数据
Input: pstRows
pstNode node节点
Output:
Return: 00
*************************************************/
virtual int replace_data(Node *pstNode, RawData *pstRawData) = 0;
/*************************************************
Description: task请求删除数据
Input: stTask task请求
pstNode node节点
Output: pstAffectedRows NULL时不保存
Return: 00
*************************************************/
virtual int delete_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows) = 0;
/*************************************************
Description: task请求查询数据
Input: stTask task请求
pstNode node节点
Output: stTask
Return: 00
*************************************************/
virtual int get_data(TaskRequest &stTask, Node *pstNode) = 0;
/*************************************************
Description: task请求添加一行数据
Input: stTask task请求
pstNode node节点
isDirty
Output: pstAffectedRows NULL时不保存
Return: 00
*************************************************/
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: 00
*************************************************/
virtual int replace_data(TaskRequest &stTask, Node *pstNode) = 0;
/*************************************************
Description: task的数据替换cache里的数据
Input: stTask task请求
pstNode node节点
async
Output: pstAffectedRows NULL时不保存
Return: 00
*************************************************/
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: 00
*************************************************/
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: 00
*************************************************/
virtual int flush_data(DTCFlushRequest *pstFlushReq, Node *pstNode, unsigned int &uiFlushRowsCnt) = 0;
/*************************************************
Description: cache里的数据flush请求
Input: pstNode node节点
Output: pstFlushReq flush请求
uiFlushRowsCnt flush的行数
Return: 00
*************************************************/
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

View 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;
};

View File

@ -0,0 +1,3 @@
{
global: _QueryInternalService;
};

View 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;
}

View 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

View 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;
}

View 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

View 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;
}

View 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

View 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

View 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();
}

View 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

View 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

View 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;
}

View 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

View 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;
}

View 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

View 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();
}

View 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

View 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;
}

View 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

View 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;
}

View 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

View 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();
}

View 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

File diff suppressed because it is too large Load Diff

View 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: 00
*************************************************/
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

View 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

View 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;
}

View 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

View 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

View 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

View 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)
{
/*
* 2NodeIndex
* 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;
}

View 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

View 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

View 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));
}

View 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

File diff suppressed because it is too large Load Diff

View 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: 00
*************************************************/
int Init(void *pAddr, INTER_SIZE_T tSize);
/*************************************************
Description: attach已经格式化好的内存块
Input: pAddr
tSize
Return: 00
*************************************************/
int Attach(void *pAddr, INTER_SIZE_T tSize);
/*************************************************
Description: dtc版本
Input: pAddr
tSize
Output:
Return: 00
*************************************************/
int detect_version();
/* 共享内存完整性检测接口 */
int share_memory_integrity();
void set_share_memory_integrity(const int flag);
/*************************************************
Description: bin是否正确
Input:
Output:
Return: 00
*************************************************/
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: 00
*************************************************/
int Free(ALLOC_HANDLE_T hHandle);
/*************************************************
Description: free空间
Input: hHandle
Output:
Return: >00
*************************************************/
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_SIZE4K
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

File diff suppressed because it is too large Load Diff

View 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的格式00
pchKey keykey的第0字节为长度
uiDataSize chunk0insert row的时候再realloc扩大
Output:
Return: 00
*************************************************/
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的格式00
Output:
Return: 00
*************************************************/
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: refrenceCopyRow()CopyAll()使
Input: pstRef refrence指针
Output:
Return:
*************************************************/
void set_refrence(RawData *pstRef) { m_pstRef = pstRef; }
/*************************************************
Description: keyrows等所有内存的大小
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: 0key返回定长的长度
*************************************************/
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: 00
*************************************************/
int Destroy();
/*************************************************
Description: delete一些row后调用一次
Input:
Output:
Return: 00
*************************************************/
int strip_mem();
/*************************************************
Description:
Input:
Output: stRow
uchRowFlags flag
iDecodeFlag pre-readfetch_row移动指针
Return: 00
*************************************************/
int decode_row(RowValue &stRow, unsigned char &uchRowFlags, int iDecodeFlag = 0);
/*************************************************
Description:
Input: stRow
Output:
byFirst
isDirty
Return: 00
*************************************************/
int insert_row(const RowValue &stRow, bool byFirst, bool isDirty);
/*************************************************
Description:
Input: stRow
Output:
byFirst
uchOp row的标记
Return: 00
*************************************************/
int insert_row_flag(const RowValue &stRow, bool byFirst, unsigned char uchOp);
/*************************************************
Description:
Input: uiNRows
stRow
Output:
byFirst
isDirty
Return: 00
*************************************************/
int insert_n_rows(unsigned int uiNRows, const RowValue *pstRow, bool byFirst, bool isDirty);
/*************************************************
Description:
Input: stRow
Output:
isDirty
Return: 00
*************************************************/
int replace_cur_row(const RowValue &stRow, bool isDirty);
/*************************************************
Description:
Input: stRow 使row的字段类型等信息
Output:
Return: 00
*************************************************/
int delete_cur_row(const RowValue &stRow);
/*************************************************
Description:
Input:
Output:
Return: 00
*************************************************/
int delete_all_rows();
/*************************************************
Description:
Input: uchFlag
Output:
Return: 00
*************************************************/
int set_cur_row_flag(unsigned char uchFlag);
/*************************************************
Description: refrence copy当前行到本地buffer末尾
Input:
Output:
Return: 00
*************************************************/
int copy_row();
/*************************************************
Description: refrence的数据替换本地数据
Input:
Output:
Return: 00
*************************************************/
int copy_all();
/*************************************************
Description: N行已经格式化好的数据到末尾
Input:
Output:
Return: 00
*************************************************/
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

File diff suppressed because it is too large Load Diff

View 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: 00
*************************************************/
int get_all_rows(Node *pstNode, RawData *pstRows);
/*************************************************
Description: node的列
Input: pstNode node节点
Output:
Return: 00
*************************************************/
int expand_node(TaskRequest &stTask, Node *pstNode);
/*************************************************
Description: pstRows的数据替换cache里的数据
Input: pstRows
pstNode node节点
Output:
Return: 00
*************************************************/
int replace_data(Node *pstNode, RawData *pstRawData);
/*************************************************
Description: task请求删除数据
Input: stTask task请求
pstNode node节点
Output: pstAffectedRows NULL时不保存
Return: 00
*************************************************/
int delete_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows);
/*************************************************
Description: task请求查询数据
Input: stTask task请求
pstNode node节点
Output: stTask
Return: 00
*************************************************/
int get_data(TaskRequest &stTask, Node *pstNode);
/*************************************************
Description: task请求添加一行数据
Input: stTask task请求
pstNode node节点
isDirty
Output: pstAffectedRows NULL时不保存
Return: 00
*************************************************/
int append_data(TaskRequest &stTask, Node *pstNode, RawData *pstAffectedRows, bool isDirty, bool uniq);
/*************************************************
Description: task的数据替换cache里的数据
Input: stTask task请求
pstNode node节点
Output:
Return: 00
*************************************************/
int replace_data(TaskRequest &stTask, Node *pstNode);
/*************************************************
Description: task的数据替换cache里的数据
Input: stTask task请求
pstNode node节点
async
Output: pstAffectedRows NULL时不保存
Return: 00
*************************************************/
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: 00
*************************************************/
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: 00
*************************************************/
int flush_data(DTCFlushRequest *pstFlushReq, Node *pstNode, unsigned int &uiFlushRowsCnt);
/*************************************************
Description: cache里的数据flush请求
Input: pstNode node节点
Output: pstFlushReq flush请求
uiFlushRowsCnt flush的行数
Return: 00
*************************************************/
int purge_data(DTCFlushRequest *pstFlushReq, Node *pstNode, unsigned int &uiFlushRowsCnt);
};
DTC_END_NAMESPACE
#endif

View 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

View 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;

View 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: 00
*************************************************/
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

File diff suppressed because it is too large Load Diff

View 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: 0EC_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: 01
*************************************************/
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: 01
*************************************************/
int Find(const char *pchKey, void *pCmpCookie, KeyComparator pfComp, ALLOC_HANDLE_T *&phRecord);
/*************************************************
Description:
Input:
Output:
Return: 00
*************************************************/
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

View 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);
}

View 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

View 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;
}

View 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

File diff suppressed because it is too large Load Diff

View 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的格式00
pchKey keykey的第0字节为长度
Output:
Return: 00
*************************************************/
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: 00
*************************************************/
// int Destroy(uint8_t uchLevel=1);
int Destroy();
/*************************************************
Description:
Input: stRow index字段以及后面字段的值
pfComp key比较函数
uchFlag
Output:
Return: 00
*************************************************/
int insert_row_flag(const RowValue &stRow, KeyComparator pfComp, unsigned char uchFlag);
/*************************************************
Description:
Input: stRow index字段以及后面字段的值
pfComp key比较函数
isDirty
Output:
Return: 00
*************************************************/
int insert_row(const RowValue &stRow, KeyComparator pfComp, bool isDirty);
/*************************************************
Description:
Input: stCondition index字段的值
pfComp key比较函数
Output: hRecord CRawData的句柄
Return: 01
*************************************************/
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: 00
*************************************************/
int replace_cur_row(const RowValue &stRow, bool isDirty, MEM_HANDLE_T *hRecord);
/*************************************************
Description:
Input: stRow 使row的字段类型等信息
Output:
Return: 00
*************************************************/
int delete_cur_row(const RowValue &stRow);
/*************************************************
Description:
Input: stRow 使row的字段类型等信息
Output: m_uiOffset会指向下一行数据的偏移
Return: 00
*************************************************/
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

View 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;
}

View 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;
}

View 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