Compare commits
7 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
6f2c3b2e35 | |
|
|
a4f9a64af5 | |
|
|
78f019ea24 | |
|
|
b853cac071 | |
|
|
2b15429137 | |
|
|
7a019315de | |
|
|
6dec3d3715 |
|
|
@ -11,7 +11,7 @@ project(openGauss)
|
|||
if(POLICY CMP0068)
|
||||
cmake_policy(SET CMP0068 NEW)
|
||||
endif()
|
||||
|
||||
//This is a test
|
||||
if(POLICY CMP0075)
|
||||
cmake_policy(SET CMP0075 NEW)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -351,7 +351,16 @@ void GsCodeGen::loadIRFile()
|
|||
if (NULL != exec_path && strcmp(exec_path, "\0") != 0) {
|
||||
char* exec_path_r = realpath(exec_path, NULL);
|
||||
if (exec_path_r) {
|
||||
appendStringInfo(filename, "%s/share/llvmir/GaussDB_expr.ir", exec_path_r);
|
||||
char *llvmIrFilePath = "share/llvmir/GaussDB_expr.ir";
|
||||
#if (!defined(ENABLE_MULTIPLE_NODES)) && (!defined(ENABLE_PRIVATEGAUSS))
|
||||
if (u_sess->attr.attr_sql.whale || u_sess->attr.attr_sql.dolphin) {
|
||||
int id = GetCustomParserId();
|
||||
if (id >= 0 && g_instance.llvmIrFilePath[id] != NULL) {
|
||||
llvmIrFilePath = g_instance.llvmIrFilePath[id];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
appendStringInfo(filename, "%s/%s", exec_path_r, llvmIrFilePath);
|
||||
check_backend_env(exec_path);
|
||||
free(exec_path_r);
|
||||
} else {
|
||||
|
|
@ -380,7 +389,15 @@ void GsCodeGen::loadIRFile()
|
|||
pfree_ext(filename->data);
|
||||
pfree_ext(filename);
|
||||
}
|
||||
|
||||
/* function name:compileCurrentModule
|
||||
function purpose:Compile the current llvm module and generate machine code
|
||||
input: enable_jitcache indicates whether to enable JIT caching
|
||||
output:none
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/09/23 16:24:35
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
void GsCodeGen::compileCurrentModule(bool enable_jitcache)
|
||||
{
|
||||
/* m_currentModule == NULL when we hit a cache */
|
||||
|
|
@ -613,7 +630,15 @@ bool GsCodeGen::verifyFunction(Function* fn)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* function name:FinalizeFunction
|
||||
function purpose:Complete the final processing steps of the llvm function
|
||||
input:
|
||||
output:none
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/09/23 16:30:43
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
void GsCodeGen::FinalizeFunction(Function* function, int plan_node_id)
|
||||
{
|
||||
bool is_valid = false;
|
||||
|
|
@ -1027,7 +1052,8 @@ void CodeGenThreadInitialize()
|
|||
|
||||
bool CodeGenThreadObjectReady()
|
||||
{
|
||||
return t_thrd.codegen_cxt.thr_codegen_obj != NULL && !t_thrd.codegen_cxt.g_runningInFmgr;
|
||||
return t_thrd.codegen_cxt.thr_codegen_obj != NULL && !t_thrd.codegen_cxt.g_runningInFmgr
|
||||
&& !((dorado::GsCodeGen*)t_thrd.codegen_cxt.thr_codegen_obj)->IsCompiled();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -23,11 +23,10 @@
|
|||
*/
|
||||
|
||||
#include "occ_transaction_manager.h"
|
||||
#include "../utils/utilities.h"
|
||||
#include "utilities.h"
|
||||
#include "cycles.h"
|
||||
#include "mot_engine.h"
|
||||
#include "row.h"
|
||||
#include "row_header.h"
|
||||
#include "txn.h"
|
||||
#include "txn_access.h"
|
||||
#include "checkpoint_manager.h"
|
||||
|
|
@ -42,82 +41,151 @@ OccTransactionManager::OccTransactionManager()
|
|||
: m_txnCounter(0),
|
||||
m_abortsCounter(0),
|
||||
m_writeSetSize(0),
|
||||
m_rowsSetSize(0),
|
||||
m_deleteSetSize(0),
|
||||
m_insertSetSize(0),
|
||||
m_dynamicSleep(100),
|
||||
m_rowsLocked(false),
|
||||
m_preAbort(true),
|
||||
m_validationNoWait(true)
|
||||
m_validationNoWait(true),
|
||||
m_isTransactionCommited(false)
|
||||
{}
|
||||
|
||||
OccTransactionManager::~OccTransactionManager()
|
||||
{}
|
||||
|
||||
bool OccTransactionManager::Init()
|
||||
bool OccTransactionManager::PreAbortCheck(TxnManager* txMan, GcMaintenanceInfo& gcMemoryReserve)
|
||||
{
|
||||
bool result = true;
|
||||
return result;
|
||||
TxnAccess* tx = txMan->m_accessMgr;
|
||||
TxnOrderedSet_t& orderedSet = tx->GetOrderedRowSet();
|
||||
auto itr = orderedSet.begin();
|
||||
while (itr != orderedSet.end()) {
|
||||
Access* ac = (*itr).second;
|
||||
switch (ac->m_type) {
|
||||
case WR:
|
||||
m_writeSetSize++;
|
||||
gcMemoryReserve.m_version_queue++;
|
||||
break;
|
||||
case DEL:
|
||||
m_writeSetSize++;
|
||||
if (ac->m_params.IsPrimarySentinel()) {
|
||||
gcMemoryReserve.m_delete_queue++;
|
||||
} else {
|
||||
if (ac->m_params.IsIndexUpdate()) {
|
||||
gcMemoryReserve.m_update_column_queue++;
|
||||
}
|
||||
}
|
||||
gcMemoryReserve.m_generic_queue++;
|
||||
break;
|
||||
case INS:
|
||||
m_insertSetSize++;
|
||||
m_writeSetSize++;
|
||||
if (ac->m_params.IsUpgradeInsert()) {
|
||||
gcMemoryReserve.m_version_queue++;
|
||||
}
|
||||
break;
|
||||
case RD_FOR_UPDATE:
|
||||
case RD:
|
||||
itr = orderedSet.erase(itr);
|
||||
txMan->m_accessMgr->PubReleaseAccess(ac);
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_preAbort) {
|
||||
if (!QuickHeaderValidation(ac)) {
|
||||
if (MOTEngine::GetInstance()->IsRecovering() && ResolveRecoveryOccConflict(txMan, ac) == RC_OK) {
|
||||
(void)++itr;
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
(void)++itr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OccTransactionManager::CheckVersion(const Access* access)
|
||||
bool OccTransactionManager::QuickVersionCheck(const Access* access)
|
||||
{
|
||||
// We always validate on committed rows!
|
||||
const Row* row = access->GetRowFromHeader();
|
||||
return (row->m_rowHeader.GetCSN() == access->m_tid);
|
||||
if (access->m_params.IsPrimarySentinel()) {
|
||||
// For Upgrade IOD - Verify the sentinel snapshot is still valid
|
||||
// Check if the key is still visible
|
||||
if (access->m_snapshot <= access->m_origSentinel->GetStartCSN()) {
|
||||
return false;
|
||||
}
|
||||
MOT_ASSERT(access->m_csn == access->m_globalRow->GetCommitSequenceNumber());
|
||||
return (access->m_csn == access->m_origSentinel->GetData()->GetCommitSequenceNumber());
|
||||
} else {
|
||||
if (access->m_params.IsSecondaryUniqueSentinel()) {
|
||||
PrimarySentinelNode* node = static_cast<SecondarySentinelUnique*>(access->m_origSentinel)->GetTopNode();
|
||||
if (node->GetEndCSN() != Sentinel::SENTINEL_INIT_CSN) {
|
||||
return false;
|
||||
}
|
||||
return (access->m_secondaryUniqueNode == node);
|
||||
} else {
|
||||
MOT_ASSERT(access->GetType() == AccessType::DEL);
|
||||
// Check that the Sentinel is not deleted!
|
||||
return (static_cast<SecondarySentinel*>(access->GetSentinel())->GetEndCSN() == Sentinel::SENTINEL_INIT_CSN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OccTransactionManager::QuickInsertCheck(const Access* access)
|
||||
{
|
||||
// Lets verify the inserts
|
||||
Sentinel* sent = access->m_origSentinel;
|
||||
if (access->m_params.IsUpgradeInsert() == false) {
|
||||
// if the sent is committed we abort!
|
||||
if (sent->IsCommited()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (access->m_params.IsPrimarySentinel()) {
|
||||
// For Upgrade IOD - Verify the sentinel snapshot is still valid
|
||||
if (access->m_params.IsInsertOnDeletedRow()) {
|
||||
if (access->m_origSentinel->GetData()->IsRowDeleted() == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (access->m_csn == access->m_origSentinel->GetData()->GetCommitSequenceNumber());
|
||||
} else {
|
||||
if (access->m_params.IsSecondaryUniqueSentinel()) {
|
||||
PrimarySentinelNode* node = static_cast<SecondarySentinelUnique*>(access->m_origSentinel)->GetTopNode();
|
||||
if (access->m_params.IsInsertOnDeletedRow()) {
|
||||
// Check if node is deleted
|
||||
if (node->GetEndCSN() == Sentinel::SENTINEL_INIT_CSN) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Check if node is committed
|
||||
if (node->GetEndCSN() != Sentinel::SENTINEL_INIT_CSN) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (access->m_secondaryUniqueNode == node);
|
||||
} else {
|
||||
MOT_ASSERT(access->GetType() == AccessType::INS);
|
||||
MOT_ASSERT(access->m_params.IsIndexUpdate() == true);
|
||||
if (static_cast<SecondarySentinel*>(access->GetSentinel())->GetEndCSN() ==
|
||||
Sentinel::SENTINEL_INIT_CSN) {
|
||||
return false;
|
||||
}
|
||||
return (static_cast<SecondarySentinel*>(access->GetSentinel())->GetStartCSN() == access->m_csn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OccTransactionManager::QuickHeaderValidation(const Access* access)
|
||||
{
|
||||
if (access->m_type != INS) {
|
||||
// For WR/DEL/RD_FOR_UPDATE lets verify CSN
|
||||
return CheckVersion(access);
|
||||
return QuickVersionCheck(access);
|
||||
} else {
|
||||
// Lets verify the inserts
|
||||
// For upgrade we verify the row
|
||||
// csn has not changed!
|
||||
Sentinel* sent = access->m_origSentinel;
|
||||
if (access->m_params.IsUpgradeInsert()) {
|
||||
if (access->m_params.IsDummyDeletedRow()) {
|
||||
// Check is sentinel is deleted and CSN is VALID - ABA problem
|
||||
if (sent->IsCommited() == false) {
|
||||
if (sent->GetData()->GetCommitSequenceNumber() != access->m_tid) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// We deleted internally!, we only need to check version
|
||||
if (sent->GetData()->GetCommitSequenceNumber() != access->m_tid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the sent is committed or inserted-deleted we abort!
|
||||
if (sent->IsCommited() or sent->GetData() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return QuickInsertCheck(access);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OccTransactionManager::ValidateReadSet(TxnManager* txMan)
|
||||
{
|
||||
TxnOrderedSet_t& orderedSet = txMan->m_accessMgr->GetOrderedRowSet();
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* ac = raPair.second;
|
||||
if (ac->m_type != RD) {
|
||||
continue;
|
||||
}
|
||||
if (!ac->GetRowFromHeader()->m_rowHeader.ValidateRead(ac->m_tid)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OccTransactionManager::ValidateWriteSet(TxnManager* txMan)
|
||||
|
|
@ -125,10 +193,6 @@ bool OccTransactionManager::ValidateWriteSet(TxnManager* txMan)
|
|||
TxnOrderedSet_t& orderedSet = txMan->m_accessMgr->GetOrderedRowSet();
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* ac = raPair.second;
|
||||
if (ac->m_type == RD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!QuickHeaderValidation(ac)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -136,106 +200,65 @@ bool OccTransactionManager::ValidateWriteSet(TxnManager* txMan)
|
|||
return true;
|
||||
}
|
||||
|
||||
RC OccTransactionManager::LockRows(TxnManager* txMan, uint32_t& numRowsLock)
|
||||
RC OccTransactionManager::LockHeaders(TxnManager* txMan, uint32_t& numSentinelsLock)
|
||||
{
|
||||
RC rc = RC_OK;
|
||||
TxnOrderedSet_t& orderedSet = txMan->m_accessMgr->GetOrderedRowSet();
|
||||
numRowsLock = 0;
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* ac = raPair.second;
|
||||
if (ac->m_type == RD) {
|
||||
continue;
|
||||
}
|
||||
if (ac->m_params.IsPrimarySentinel()) {
|
||||
Row* row = ac->GetRowFromHeader();
|
||||
row->m_rowHeader.Lock();
|
||||
numRowsLock++;
|
||||
MOT_ASSERT(row->GetPrimarySentinel()->IsLocked() == true);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool OccTransactionManager::LockHeadersNoWait(TxnManager* txMan, uint32_t& numSentinelsLock)
|
||||
{
|
||||
uint64_t sleepTime = 1;
|
||||
uint64_t thdId = txMan->GetThdId();
|
||||
TxnOrderedSet_t& orderedSet = txMan->m_accessMgr->GetOrderedRowSet();
|
||||
numSentinelsLock = 0;
|
||||
while (numSentinelsLock != m_writeSetSize) {
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* ac = raPair.second;
|
||||
if (ac->m_type == RD) {
|
||||
continue;
|
||||
if (m_validationNoWait) {
|
||||
while (numSentinelsLock != m_writeSetSize) {
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* ac = raPair.second;
|
||||
Sentinel* sent = ac->m_origSentinel;
|
||||
if (!sent->TryLock(thdId)) {
|
||||
break;
|
||||
}
|
||||
numSentinelsLock++;
|
||||
// New insert row is already committed!
|
||||
// Check if row has changed in sentinel
|
||||
if (!QuickHeaderValidation(ac)) {
|
||||
rc = RC_ABORT;
|
||||
goto final;
|
||||
}
|
||||
}
|
||||
Sentinel* sent = ac->m_origSentinel;
|
||||
if (!sent->TryLock(thdId)) {
|
||||
break;
|
||||
}
|
||||
numSentinelsLock++;
|
||||
if (ac->m_params.IsPrimaryUpgrade()) {
|
||||
ac->m_auxRow->m_rowHeader.Lock();
|
||||
}
|
||||
// New insert row is already committed!
|
||||
// Check if row has changed in sentinel
|
||||
if (!QuickHeaderValidation(ac)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (numSentinelsLock != m_writeSetSize) {
|
||||
ReleaseHeaderLocks(txMan, numSentinelsLock);
|
||||
numSentinelsLock = 0;
|
||||
if (m_preAbort) {
|
||||
for (const auto& acPair : orderedSet) {
|
||||
const Access* ac = acPair.second;
|
||||
if (!QuickHeaderValidation(ac)) {
|
||||
return false;
|
||||
if (numSentinelsLock != m_writeSetSize) {
|
||||
ReleaseHeaderLocks(txMan, numSentinelsLock);
|
||||
numSentinelsLock = 0;
|
||||
if (m_preAbort) {
|
||||
for (const auto& acPair : orderedSet) {
|
||||
const Access* ac = acPair.second;
|
||||
if (!QuickHeaderValidation(ac)) {
|
||||
return RC_ABORT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sleepTime > LOCK_TIME_OUT) {
|
||||
return false;
|
||||
} else {
|
||||
if (IsHighContention() == false) {
|
||||
CpuCyclesLevelTime::Sleep(5);
|
||||
if (!MOTEngine::GetInstance()->IsRecovering()) {
|
||||
if (sleepTime > LOCK_TIME_OUT) {
|
||||
return RC_ABORT;
|
||||
} else {
|
||||
if (!IsHighContention()) {
|
||||
CpuCyclesLevelTime::Sleep(5);
|
||||
} else {
|
||||
(void)usleep(m_dynamicSleep);
|
||||
}
|
||||
sleepTime = sleepTime << 1;
|
||||
}
|
||||
} else {
|
||||
usleep(m_dynamicSleep);
|
||||
(void)usleep(1000);
|
||||
}
|
||||
sleepTime = sleepTime << 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RC OccTransactionManager::LockHeaders(TxnManager* txMan, uint32_t& numSentinelsLock)
|
||||
{
|
||||
RC rc = RC_OK;
|
||||
uint64_t thdId = txMan->GetThdId();
|
||||
TxnOrderedSet_t& orderedSet = txMan->m_accessMgr->GetOrderedRowSet();
|
||||
numSentinelsLock = 0;
|
||||
if (m_validationNoWait) {
|
||||
if (!LockHeadersNoWait(txMan, numSentinelsLock)) {
|
||||
rc = RC_ABORT;
|
||||
goto final;
|
||||
}
|
||||
} else {
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* ac = raPair.second;
|
||||
if (ac->m_type == RD) {
|
||||
continue;
|
||||
}
|
||||
Sentinel* sent = ac->m_origSentinel;
|
||||
sent->Lock(thdId);
|
||||
numSentinelsLock++;
|
||||
if (ac->m_params.IsPrimaryUpgrade()) {
|
||||
ac->m_auxRow->m_rowHeader.Lock();
|
||||
}
|
||||
// New insert row is already committed!
|
||||
// Check if row has chained in sentinel
|
||||
// Check if row has changed in sentinel
|
||||
if (!QuickHeaderValidation(ac)) {
|
||||
rc = RC_ABORT;
|
||||
goto final;
|
||||
|
|
@ -249,18 +272,15 @@ final:
|
|||
bool OccTransactionManager::PreAllocStableRow(TxnManager* txMan)
|
||||
{
|
||||
if (GetGlobalConfiguration().m_enableCheckpoint) {
|
||||
GetCheckpointManager()->BeginCommit(txMan);
|
||||
|
||||
TxnOrderedSet_t& orderedSet = txMan->m_accessMgr->GetOrderedRowSet();
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* access = raPair.second;
|
||||
if (access->m_type == RD) {
|
||||
if (access->m_type == RD || (access->m_type == INS && access->m_params.IsUpgradeInsert() == false)) {
|
||||
continue;
|
||||
}
|
||||
if (access->m_params.IsPrimarySentinel()) {
|
||||
if (!GetCheckpointManager()->PreAllocStableRow(txMan, access->GetRowFromHeader(), access->m_type)) {
|
||||
GetCheckpointManager()->FreePreAllocStableRows(txMan);
|
||||
GetCheckpointManager()->EndCommit(txMan);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -269,108 +289,98 @@ bool OccTransactionManager::PreAllocStableRow(TxnManager* txMan)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool OccTransactionManager::QuickVersionCheck(TxnManager* txMan, uint32_t& readSetSize)
|
||||
bool OccTransactionManager::ReserveGcMemory(TxnManager* txMan, const GcMaintenanceInfo& gcMemoryReserve)
|
||||
{
|
||||
int isolationLevel = txMan->GetTxnIsoLevel();
|
||||
TxnOrderedSet_t& orderedSet = txMan->m_accessMgr->GetOrderedRowSet();
|
||||
readSetSize = 0;
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* ac = raPair.second;
|
||||
if (ac->m_params.IsPrimarySentinel()) {
|
||||
m_rowsSetSize++;
|
||||
}
|
||||
switch (ac->m_type) {
|
||||
case RD_FOR_UPDATE:
|
||||
case WR:
|
||||
m_writeSetSize++;
|
||||
break;
|
||||
case DEL:
|
||||
m_writeSetSize++;
|
||||
m_deleteSetSize++;
|
||||
break;
|
||||
case INS:
|
||||
m_insertSetSize++;
|
||||
m_writeSetSize++;
|
||||
break;
|
||||
case RD:
|
||||
if (isolationLevel > READ_COMMITED) {
|
||||
readSetSize++;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_preAbort) {
|
||||
if (!QuickHeaderValidation(ac)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool res = true;
|
||||
GcManager* gc_manager = txMan->GetGcSession();
|
||||
MOT_ASSERT(gc_manager != nullptr);
|
||||
res = gc_manager->ReserveGCMemoryPerQueue(GC_QUEUE_TYPE::DELETE_QUEUE, gcMemoryReserve.m_delete_queue);
|
||||
if (!res) {
|
||||
return false;
|
||||
}
|
||||
res = gc_manager->ReserveGCMemoryPerQueue(GC_QUEUE_TYPE::VERSION_QUEUE, gcMemoryReserve.m_version_queue);
|
||||
if (!res) {
|
||||
return false;
|
||||
}
|
||||
res =
|
||||
gc_manager->ReserveGCMemoryPerQueue(GC_QUEUE_TYPE::UPDATE_COLUMN_QUEUE, gcMemoryReserve.m_update_column_queue);
|
||||
if (!res) {
|
||||
return false;
|
||||
}
|
||||
res = gc_manager->ReserveGCMemoryPerQueue(GC_QUEUE_TYPE::GENERIC_QUEUE, gcMemoryReserve.m_generic_queue, true);
|
||||
if (!res) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
/* function name:ValidateOcc
|
||||
function purpose:Verify that all operations done by the transaction are legal before the transaction is committed,
|
||||
that is, they do not conflict with other concurrent transactions
|
||||
input:transaction manager
|
||||
output:Validation results(enum variable).
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/08/25 10:59:07
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
RC OccTransactionManager::ValidateOcc(TxnManager* txMan)
|
||||
{
|
||||
{ // Initialize the number of locked sentinels to 0
|
||||
uint32_t numSentinelLock = 0;
|
||||
m_rowsLocked = false;
|
||||
TxnAccess* tx = txMan->m_accessMgr.Get();
|
||||
// Get the access manager for the transaction
|
||||
TxnAccess* txnAccess = txMan->m_accessMgr;
|
||||
RC rc = RC_OK;
|
||||
const uint32_t rowCount = tx->m_rowCnt;
|
||||
const uint32_t rowCount = txnAccess->Size();
|
||||
|
||||
m_writeSetSize = 0;
|
||||
m_rowsSetSize = 0;
|
||||
m_deleteSetSize = 0;
|
||||
m_insertSetSize = 0;
|
||||
m_txnCounter++;
|
||||
|
||||
// If no rows are accessed, the transaction is read-only and returns success directly
|
||||
if (rowCount == 0) {
|
||||
// READONLY
|
||||
return rc;
|
||||
}
|
||||
// Initialize garbage collection maintenance information
|
||||
GcMaintenanceInfo gcMemoryReserve{};
|
||||
|
||||
uint32_t readSetSize = 0;
|
||||
TxnOrderedSet_t& orderedSet = tx->GetOrderedRowSet();
|
||||
MOT_ASSERT(rowCount == orderedSet.size());
|
||||
MOT_ASSERT(rowCount == txnAccess->GetOrderedRowSet().size());
|
||||
|
||||
/* Perform Quick Version check */
|
||||
if (!QuickVersionCheck(txMan, readSetSize)) {
|
||||
rc = RC_ABORT;
|
||||
goto final;
|
||||
}
|
||||
|
||||
MOT_LOG_DEBUG("Validate OCC rowCnt=%u RD=%u WR=%u\n", tx->m_rowCnt, tx->m_rowCnt - m_writeSetSize, m_writeSetSize);
|
||||
rc = LockHeaders(txMan, numSentinelLock);
|
||||
if (rc != RC_OK) {
|
||||
goto final;
|
||||
}
|
||||
|
||||
// Validate rows in the read set and write set
|
||||
if (readSetSize > 0) {
|
||||
if (!ValidateReadSet(txMan)) {
|
||||
do {
|
||||
/* 1.Perform pre-abort check and pre-processing */
|
||||
if (!PreAbortCheck(txMan, gcMemoryReserve)) {
|
||||
rc = RC_ABORT;
|
||||
goto final;
|
||||
break;
|
||||
}
|
||||
// try to lock all headers
|
||||
rc = LockHeaders(txMan, numSentinelLock);
|
||||
if (rc != RC_OK) {
|
||||
break;
|
||||
}
|
||||
// verify write set
|
||||
if (!ValidateWriteSet(txMan)) {
|
||||
rc = RC_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ValidateWriteSet(txMan)) {
|
||||
rc = RC_ABORT;
|
||||
goto final;
|
||||
}
|
||||
|
||||
// Pre-allocate stable row according to the checkpoint state.
|
||||
if (!PreAllocStableRow(txMan)) {
|
||||
rc = RC_MEMORY_ALLOCATION_ERROR;
|
||||
goto final;
|
||||
}
|
||||
|
||||
final:
|
||||
// Pre-allocate stable row according to the checkpoint state.
|
||||
if (!PreAllocStableRow(txMan)) {
|
||||
rc = RC_MEMORY_ALLOCATION_ERROR;
|
||||
break;
|
||||
}
|
||||
// Reserve memory for possible garbage collection operations
|
||||
if (!ReserveGcMemory(txMan, gcMemoryReserve)) {
|
||||
rc = RC_MEMORY_ALLOCATION_ERROR;
|
||||
break;
|
||||
}
|
||||
} while (0);
|
||||
// If all the above steps are successful
|
||||
if (likely(rc == RC_OK)) {
|
||||
MOT_ASSERT(numSentinelLock == m_writeSetSize);
|
||||
// mark the row as locked
|
||||
m_rowsLocked = true;
|
||||
} else {
|
||||
// Release all header locks
|
||||
ReleaseHeaderLocks(txMan, numSentinelLock);
|
||||
if (likely(rc == RC_ABORT)) {
|
||||
m_abortsCounter++;
|
||||
|
|
@ -380,15 +390,85 @@ final:
|
|||
return rc;
|
||||
}
|
||||
|
||||
void OccTransactionManager::RollbackInserts(TxnManager* txMan)
|
||||
RC OccTransactionManager::ResolveRecoveryOccConflict(TxnManager* txMan, Access* access)
|
||||
{
|
||||
return txMan->UndoInserts();
|
||||
Row* row = nullptr;
|
||||
RC rc = RC_ABORT;
|
||||
uint64_t endCSN = static_cast<uint64_t>(-1);
|
||||
MOT_ASSERT(access->m_type == INS);
|
||||
switch (access->m_origSentinel->GetIndexOrder()) {
|
||||
case IndexOrder::INDEX_ORDER_PRIMARY:
|
||||
// Check what is the current row the sentinel is pointing
|
||||
row = access->m_origSentinel->GetData();
|
||||
if (row) {
|
||||
// Row must be deleted with Smaller CSN
|
||||
if (row->IsRowDeleted() == false) {
|
||||
MOT_LOG_ERROR("ERROR In Recovery Order!");
|
||||
return RC_ABORT;
|
||||
}
|
||||
MOT_ASSERT(access->m_origSentinel->GetData()->GetCommitSequenceNumber() > access->m_csn);
|
||||
// Reset the global version and set to insert on delete
|
||||
access->m_params.SetUpgradeInsert();
|
||||
access->m_params.SetInsertOnDeletedRow();
|
||||
access->m_globalRow = row;
|
||||
access->m_csn = row->GetCommitSequenceNumber();
|
||||
access->m_snapshot = static_cast<uint64_t>(-1);
|
||||
rc = RC_OK;
|
||||
} else {
|
||||
MOT_ASSERT(false);
|
||||
return RC_ABORT;
|
||||
}
|
||||
break;
|
||||
case IndexOrder::INDEX_ORDER_SECONDARY:
|
||||
endCSN = static_cast<SecondarySentinel*>(access->m_origSentinel)->GetEndCSN();
|
||||
if (txMan->GetCommitSequenceNumber() <= endCSN) {
|
||||
MOT_LOG_ERROR("ERROR In Recovery Order!");
|
||||
return RC_ABORT;
|
||||
}
|
||||
if (endCSN == Sentinel::SENTINEL_INIT_CSN) {
|
||||
MOT_LOG_ERROR("ERROR In Recovery Order!");
|
||||
return RC_ABORT;
|
||||
}
|
||||
access->m_params.SetUpgradeInsert();
|
||||
access->m_params.SetInsertOnDeletedRow();
|
||||
access->m_csn = static_cast<SecondarySentinel*>(access->m_origSentinel)->GetStartCSN();
|
||||
rc = RC_OK;
|
||||
break;
|
||||
case IndexOrder::INDEX_ORDER_SECONDARY_UNIQUE:
|
||||
PrimarySentinelNode* node = static_cast<SecondarySentinelUnique*>(access->m_origSentinel)->GetTopNode();
|
||||
if (node != nullptr) {
|
||||
if (txMan->GetCommitSequenceNumber() <= node->GetEndCSN()) {
|
||||
MOT_LOG_ERROR("ERROR In Recovery Order!");
|
||||
return RC_ABORT;
|
||||
}
|
||||
}
|
||||
// Reset Visible node
|
||||
access->m_params.SetUpgradeInsert();
|
||||
if (node->GetEndCSN() < Sentinel::SENTINEL_INIT_CSN) {
|
||||
access->m_params.SetInsertOnDeletedRow();
|
||||
} else {
|
||||
MOT_LOG_ERROR("ERROR In Recovery Order!");
|
||||
return RC_ABORT;
|
||||
}
|
||||
access->m_secondaryUniqueNode = node;
|
||||
rc = RC_OK;
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void OccTransactionManager::ApplyWrite(TxnManager* txMan)
|
||||
void OccTransactionManager::WriteChanges(TxnManager* txMan)
|
||||
{
|
||||
if (GetGlobalConfiguration().m_enableCheckpoint) {
|
||||
TxnOrderedSet_t& orderedSet = txMan->m_accessMgr->GetOrderedRowSet();
|
||||
if (m_writeSetSize == 0 && m_insertSetSize == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOTConfiguration& cfg = GetGlobalConfiguration();
|
||||
uint64_t commit_csn = txMan->GetCommitSequenceNumber();
|
||||
uint64_t transaction_id = txMan->GetInternalTransactionId();
|
||||
TxnOrderedSet_t& orderedSet = txMan->m_accessMgr->GetOrderedRowSet();
|
||||
|
||||
// Stable rows for checkpoint needs to be created (copied from original row) before modifying the global rows.
|
||||
if (cfg.m_enableCheckpoint) {
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* access = raPair.second;
|
||||
if (access->m_type == RD) {
|
||||
|
|
@ -397,33 +477,40 @@ void OccTransactionManager::ApplyWrite(TxnManager* txMan)
|
|||
if (access->m_params.IsPrimarySentinel()) {
|
||||
// Pass the actual global row (access->GetRowFromHeader()), so that the stable row will have the
|
||||
// same CSN, rowid, etc as the original row before the modifications are applied.
|
||||
GetCheckpointManager()->ApplyWrite(txMan, access->GetRowFromHeader(), access->m_type);
|
||||
GetCheckpointManager()->ApplyWrite(txMan, access->GetRowFromHeader(), access);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OccTransactionManager::WriteChanges(TxnManager* txMan)
|
||||
{
|
||||
if (m_writeSetSize == 0 && m_insertSetSize == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
LockRows(txMan, m_rowsSetSize);
|
||||
|
||||
// Stable rows for checkpoint needs to be created (copied from original row) before modifying the global rows.
|
||||
ApplyWrite(txMan);
|
||||
|
||||
TxnOrderedSet_t& orderedSet = txMan->m_accessMgr->GetOrderedRowSet();
|
||||
|
||||
// Update CSN with all relevant information on global rows
|
||||
// For deletes invalidate sentinels - rows still locked!
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* access = raPair.second;
|
||||
access->GetRowFromHeader()->m_rowHeader.WriteChangesToRow(access, txMan->GetCommitSequenceNumber());
|
||||
Access* access = raPair.second;
|
||||
access->WriteGlobalChanges(commit_csn, transaction_id);
|
||||
}
|
||||
|
||||
// Treat Inserts
|
||||
WriteSentinelChanges(txMan);
|
||||
|
||||
// For Recovery operation:Update transactionID
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* access = raPair.second;
|
||||
if (access->m_type == RD) {
|
||||
continue;
|
||||
}
|
||||
if (access->m_params.IsPrimarySentinel()) {
|
||||
static_cast<PrimarySentinel*>(access->m_origSentinel)->SetTransactionId(transaction_id);
|
||||
}
|
||||
}
|
||||
|
||||
m_isTransactionCommited = true;
|
||||
}
|
||||
|
||||
void OccTransactionManager::WriteSentinelChanges(TxnManager* txMan)
|
||||
{
|
||||
uint64_t commit_csn = txMan->GetCommitSequenceNumber();
|
||||
S_SentinelNodePool* sentinelObjectPool = txMan->m_accessMgr->GetSentinelObjectPool();
|
||||
TxnOrderedSet_t& orderedSet = txMan->m_accessMgr->GetOrderedRowSet();
|
||||
|
||||
if (m_insertSetSize > 0) {
|
||||
for (const auto& raPair : orderedSet) {
|
||||
Access* access = raPair.second;
|
||||
|
|
@ -434,92 +521,92 @@ void OccTransactionManager::WriteChanges(TxnManager* txMan)
|
|||
if (access->m_params.IsUpgradeInsert() == false) {
|
||||
if (access->m_params.IsPrimarySentinel()) {
|
||||
MOT_ASSERT(access->m_origSentinel->IsDirty() == true);
|
||||
MOT_ASSERT(access->m_origSentinel->IsLocked() == true);
|
||||
// Connect row and sentinel, row is set to absent and locked
|
||||
access->m_origSentinel->SetNextPtr(access->GetRowFromHeader());
|
||||
access->m_origSentinel->SetStartCSN(commit_csn);
|
||||
access->m_origSentinel->SetNextPtr(access->GetLocalInsertRow());
|
||||
// Current state: row is set to absent,sentinel is locked and not dirty
|
||||
// Readers will not see the row
|
||||
COMPILER_BARRIER;
|
||||
access->m_origSentinel->SetWriteBit();
|
||||
access->GetTxnRow()->GetTable()->UpdateRowCount(1);
|
||||
} else {
|
||||
// We only set the in the secondary sentinel!
|
||||
access->m_origSentinel->SetNextPtr(access->GetRowFromHeader()->GetPrimarySentinel());
|
||||
if (access->m_params.IsSecondaryUniqueSentinel() == false) {
|
||||
// We only set the in the secondary sentinel!
|
||||
access->m_origSentinel->SetStartCSN(commit_csn);
|
||||
access->m_origSentinel->SetEndCSN(Sentinel::SENTINEL_INIT_CSN);
|
||||
access->m_origSentinel->SetNextPtr(access->GetLocalInsertRow()->GetPrimarySentinel());
|
||||
} else {
|
||||
access->m_origSentinel->SetStartCSN(commit_csn);
|
||||
auto object = sentinelObjectPool->find(access->m_origSentinel->GetIndex());
|
||||
PrimarySentinelNode* node = object->second;
|
||||
(void)sentinelObjectPool->erase(object);
|
||||
node->Init(
|
||||
commit_csn, Sentinel::SENTINEL_INIT_CSN, access->GetLocalInsertRow()->GetPrimarySentinel());
|
||||
access->m_origSentinel->SetNextPtr(node);
|
||||
}
|
||||
}
|
||||
// Unset Dirty - still locked!
|
||||
access->m_origSentinel->UnSetDirty();
|
||||
} else {
|
||||
MOT_ASSERT(access->m_params.IsUniqueIndex() == true);
|
||||
// Rows are locked and marked as deleted
|
||||
if (access->m_params.IsPrimarySentinel()) {
|
||||
/* Switch the locked row's in the sentinel
|
||||
* The old row is locked and marked deleted
|
||||
* The new row is locked
|
||||
* Save previous row in the access!
|
||||
* We need it for the row release!
|
||||
*/
|
||||
Row* row = access->GetRowFromHeader();
|
||||
access->m_localInsertRow = row;
|
||||
access->m_origSentinel->SetNextPtr(access->m_auxRow);
|
||||
// Add row to GC!
|
||||
txMan->GetGcSession()->GcRecordObject(row->GetTable()->GetPrimaryIndex()->GetIndexId(),
|
||||
row,
|
||||
nullptr,
|
||||
Row::RowDtor,
|
||||
ROW_SIZE_FROM_POOL(row->GetTable()));
|
||||
if (access->m_params.IsInsertOnDeletedRow()) {
|
||||
if (access->m_params.IsPrimarySentinel()) {
|
||||
access->GetTxnRow()->GetTable()->UpdateRowCount(1);
|
||||
access->m_origSentinel->SetNextPtr(access->GetLocalInsertRow());
|
||||
COMPILER_BARRIER;
|
||||
access->m_origSentinel->SetWriteBit();
|
||||
} else if (access->m_params.IsUniqueIndex() == true) {
|
||||
auto object = sentinelObjectPool->find(access->m_origSentinel->GetIndex());
|
||||
PrimarySentinelNode* node = object->second;
|
||||
(void)sentinelObjectPool->erase(object);
|
||||
node->Init(
|
||||
commit_csn, Sentinel::SENTINEL_INIT_CSN, access->GetLocalInsertRow()->GetPrimarySentinel());
|
||||
auto oldNode = static_cast<SecondarySentinelUnique*>(access->m_origSentinel)->GetTopNode();
|
||||
node->SetNextVersion(oldNode);
|
||||
access->m_origSentinel->SetNextPtr(node);
|
||||
} else {
|
||||
MOT_ASSERT(access->m_params.IsIndexUpdate());
|
||||
// Revalidate End CSN
|
||||
static_cast<SecondarySentinel*>(access->m_origSentinel)->SetEndCSN(Sentinel::SENTINEL_INIT_CSN);
|
||||
}
|
||||
} else {
|
||||
// Set Sentinel for
|
||||
access->m_origSentinel->SetNextPtr(access->m_auxRow->GetPrimarySentinel());
|
||||
}
|
||||
// upgrade should not change the reference count!
|
||||
if (access->m_origSentinel->IsCommited()) {
|
||||
access->m_origSentinel->SetUpgradeCounter();
|
||||
// We delete row internally and insert a new row
|
||||
if (access->m_params.IsPrimarySentinel()) {
|
||||
access->m_origSentinel->SetNextPtr(access->GetLocalInsertRow());
|
||||
COMPILER_BARRIER;
|
||||
access->m_origSentinel->SetWriteBit();
|
||||
} else {
|
||||
auto object = sentinelObjectPool->find(access->m_origSentinel->GetIndex());
|
||||
PrimarySentinelNode* node = object->second;
|
||||
(void)sentinelObjectPool->erase(object);
|
||||
node->Init(
|
||||
commit_csn, Sentinel::SENTINEL_INIT_CSN, access->GetLocalInsertRow()->GetPrimarySentinel());
|
||||
auto oldNode = static_cast<SecondarySentinelUnique*>(access->m_origSentinel)->GetTopNode();
|
||||
oldNode->SetEndCSN(commit_csn);
|
||||
node->SetNextVersion(oldNode);
|
||||
access->m_origSentinel->SetNextPtr(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Treat Inserts
|
||||
if (m_insertSetSize > 0) {
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* access = raPair.second;
|
||||
if (access->m_type != INS) {
|
||||
continue;
|
||||
}
|
||||
access->m_origSentinel->UnSetDirty();
|
||||
}
|
||||
}
|
||||
|
||||
CleanRowsFromIndexes(txMan);
|
||||
}
|
||||
|
||||
void OccTransactionManager::CleanRowsFromIndexes(TxnManager* txMan)
|
||||
{
|
||||
if (m_deleteSetSize == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
TxnAccess* tx = txMan->m_accessMgr.Get();
|
||||
TxnOrderedSet_t& orderedSet = tx->GetOrderedRowSet();
|
||||
uint32_t numOfDeletes = m_deleteSetSize;
|
||||
// use local counter to optimize
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* access = raPair.second;
|
||||
if (access->m_type == DEL) {
|
||||
numOfDeletes--;
|
||||
access->GetTxnRow()->GetTable()->UpdateRowCount(-1);
|
||||
MOT_ASSERT(access->m_params.IsUpgradeInsert() == false);
|
||||
// Use Txn Row as row may change INSERT after DELETE leaves residue
|
||||
txMan->RemoveKeyFromIndex(access->GetTxnRow(), access->m_origSentinel);
|
||||
}
|
||||
if (!numOfDeletes) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* function name:ReleaseHeaderLocks
|
||||
function purpose:Releases any row header locks acquired by the transaction during its execution.
|
||||
input:transaction managers and number of locks
|
||||
output:none
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/08/25 11:19:14
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
void OccTransactionManager::ReleaseHeaderLocks(TxnManager* txMan, uint32_t numOfLocks)
|
||||
{
|
||||
if (numOfLocks == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
TxnAccess* tx = txMan->m_accessMgr.Get();
|
||||
TxnAccess* tx = txMan->m_accessMgr;
|
||||
TxnOrderedSet_t& orderedSet = tx->GetOrderedRowSet();
|
||||
// use local counter to optimize
|
||||
for (const auto& raPair : orderedSet) {
|
||||
|
|
@ -528,41 +615,7 @@ void OccTransactionManager::ReleaseHeaderLocks(TxnManager* txMan, uint32_t numOf
|
|||
continue;
|
||||
} else {
|
||||
numOfLocks--;
|
||||
access->m_origSentinel->Release();
|
||||
if (access->m_params.IsPrimaryUpgrade()) {
|
||||
access->m_auxRow->m_rowHeader.Release();
|
||||
}
|
||||
}
|
||||
if (!numOfLocks) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OccTransactionManager::ReleaseRowsLocks(TxnManager* txMan, uint32_t numOfLocks)
|
||||
{
|
||||
if (numOfLocks == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
TxnAccess* tx = txMan->m_accessMgr.Get();
|
||||
TxnOrderedSet_t& orderedSet = tx->GetOrderedRowSet();
|
||||
|
||||
// use local counter to optimize
|
||||
for (const auto& raPair : orderedSet) {
|
||||
const Access* access = raPair.second;
|
||||
if (access->m_type == RD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (access->m_params.IsPrimarySentinel()) {
|
||||
numOfLocks--;
|
||||
access->GetRowFromHeader()->m_rowHeader.Release();
|
||||
if (access->m_params.IsUpgradeInsert()) {
|
||||
// This is the global row that we switched!
|
||||
// Currently it's in the gc!
|
||||
access->m_localInsertRow->m_rowHeader.Release();
|
||||
}
|
||||
access->m_origSentinel->Unlock();
|
||||
}
|
||||
if (!numOfLocks) {
|
||||
break;
|
||||
|
|
@ -574,6 +627,6 @@ void OccTransactionManager::CleanUp()
|
|||
{
|
||||
m_writeSetSize = 0;
|
||||
m_insertSetSize = 0;
|
||||
m_rowsSetSize = 0;
|
||||
m_isTransactionCommited = false;
|
||||
}
|
||||
} // namespace MOT
|
||||
|
|
|
|||
|
|
@ -33,6 +33,14 @@ class Access;
|
|||
class TxnManager;
|
||||
|
||||
constexpr uint64_t LOCK_TIME_OUT = 1 << 16;
|
||||
|
||||
struct GcMaintenanceInfo {
|
||||
GcMaintenanceInfo() = default;
|
||||
uint32_t m_version_queue = 0;
|
||||
uint32_t m_delete_queue = 0;
|
||||
uint32_t m_update_column_queue = 0;
|
||||
uint32_t m_generic_queue = 0;
|
||||
};
|
||||
/**
|
||||
* @class OccTransactionManager
|
||||
* @brief Optimistic concurrency control implementation.
|
||||
|
|
@ -45,11 +53,6 @@ public:
|
|||
/** @brief Destructor. */
|
||||
~OccTransactionManager();
|
||||
|
||||
/**
|
||||
* @brief Initialize _writeSet, _readSet and _insertSet array.
|
||||
*/
|
||||
bool Init();
|
||||
|
||||
/**
|
||||
* @brief Sets or clears the pre-abort flag.
|
||||
* @detail Determines whether to call quickVersionCheck() during
|
||||
|
|
@ -81,10 +84,6 @@ public:
|
|||
*/
|
||||
RC ValidateOcc(TxnManager* tx);
|
||||
|
||||
RC LockHeaders(TxnManager* txMan, uint32_t& numSentinelsLock);
|
||||
|
||||
RC LockRows(TxnManager* txMan, uint32_t& numRowsLock);
|
||||
|
||||
/**
|
||||
* @brief Writes all the changes in the write set of a transaction and
|
||||
* release the locks associated with all the write access items.
|
||||
|
|
@ -92,17 +91,25 @@ public:
|
|||
*/
|
||||
void WriteChanges(TxnManager* txMan);
|
||||
|
||||
/** @brief remove all deleted keys from the global indices */
|
||||
void CleanRowsFromIndexes(TxnManager* txMan);
|
||||
|
||||
/** @brief Rollack insert-set due to an abort */
|
||||
void RollbackInserts(TxnManager* txMan);
|
||||
|
||||
/**
|
||||
* @brief Writes all the changes in the insert set of a transaction
|
||||
* and release the locks associated with all the write access items.
|
||||
* @param txMan The committing transaction.
|
||||
*/
|
||||
void WriteSentinelChanges(TxnManager* txMan);
|
||||
/* function name:ReleaseLocks
|
||||
function purpose:Release the locks associated with the transaction. This may be done after the transaction commits or aborts.
|
||||
input:transaction manager
|
||||
output:none
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/08/23 23:46:41
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
void ReleaseLocks(TxnManager* txMan)
|
||||
{
|
||||
if (m_rowsLocked) {
|
||||
ReleaseHeaderLocks(txMan, m_writeSetSize);
|
||||
ReleaseRowsLocks(txMan, m_rowsSetSize);
|
||||
m_rowsLocked = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -138,58 +145,73 @@ public:
|
|||
return false;
|
||||
}
|
||||
}
|
||||
/* function name:IsTransactionCommited
|
||||
function purpose:Indicates whether the transaction has committed
|
||||
input:none
|
||||
output:Boolean value
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/08/23 23:48:34
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
inline bool IsTransactionCommited() const
|
||||
{
|
||||
return m_isTransactionCommited;
|
||||
}
|
||||
/* function name:GetTxnCounter
|
||||
function purpose:Returns the number of transactions processed.
|
||||
input:none
|
||||
output:the number of transactions processed.
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/08/23 23:49:40
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
inline uint64_t GetTxnCounter() const
|
||||
{
|
||||
return m_txnCounter;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Checks whether the transaction identifier in the original row
|
||||
* in the access matches the transaction identifier in the access object.
|
||||
* @detail The check is faster than a cc validate, but it does not
|
||||
* guarantee correctness. If the versions do not match, cc
|
||||
* verification will always fail too. However, if the function returns
|
||||
* true, cc may fail during the verification (i.e. it may produce
|
||||
* false positive reports).
|
||||
*/
|
||||
bool CheckVersion(const Access* access);
|
||||
/** @brief Perform validation of current access */
|
||||
bool QuickVersionCheck(const Access* access);
|
||||
|
||||
/** @brief Validate Header for insert */
|
||||
/** @brief Perform validation of current access */
|
||||
bool QuickInsertCheck(const Access* access);
|
||||
|
||||
/** @brief Perform pre-processing and validation */
|
||||
bool PreAbortCheck(TxnManager* txMan, GcMaintenanceInfo& gcMemoryReserve);
|
||||
|
||||
/** @brief Validate Header for insert */
|
||||
bool QuickHeaderValidation(const Access* access);
|
||||
|
||||
bool QuickVersionCheck(TxnManager* txMan, uint32_t& readSetSize);
|
||||
|
||||
bool LockHeadersNoWait(TxnManager* txMan, uint32_t& numSentinelsLock);
|
||||
/** @brief Lock all keys */
|
||||
RC LockHeaders(TxnManager* txMan, uint32_t& numSentinelsLock);
|
||||
|
||||
/** @brief Release Header locks */
|
||||
void ReleaseHeaderLocks(TxnManager* txMan, uint32_t numOfLocks);
|
||||
|
||||
/** @brief Release all the locked rows */
|
||||
void ReleaseRowsLocks(TxnManager* txMan, uint32_t numOfLocks);
|
||||
/** For Recovery, takes care of IDI (Insert, Delete, Insert) use case */
|
||||
RC ResolveRecoveryOccConflict(TxnManager* txMan, Access* access);
|
||||
|
||||
/** @brief Validate the read set */
|
||||
bool ValidateReadSet(TxnManager* txMan);
|
||||
|
||||
/** @brief Validate the write set */
|
||||
/** @brief validate the write set */
|
||||
bool ValidateWriteSet(TxnManager* txMan);
|
||||
|
||||
/** @brief Pre-allocates stable row according to the checkpoint state. */
|
||||
bool PreAllocStableRow(TxnManager* txMan);
|
||||
|
||||
/** @brief Sets stable row according to the checkpoint state. */
|
||||
void ApplyWrite(TxnManager* txMan);
|
||||
/** @brief Pre-allocates GC memory for reclamation. */
|
||||
bool ReserveGcMemory(TxnManager* txMan, const GcMaintenanceInfo& gcMemoryReserve);
|
||||
|
||||
/** @var transaction counter */
|
||||
uint32_t m_txnCounter;
|
||||
uint64_t m_txnCounter;
|
||||
|
||||
/** @var aborts counter */
|
||||
uint32_t m_abortsCounter;
|
||||
uint64_t m_abortsCounter;
|
||||
|
||||
/** @var Write set size. */
|
||||
uint32_t m_writeSetSize;
|
||||
|
||||
/** @var total number of rows */
|
||||
uint32_t m_rowsSetSize;
|
||||
|
||||
/** @var Write set size. */
|
||||
uint32_t m_deleteSetSize;
|
||||
|
||||
/** @var Write set size. */
|
||||
uint32_t m_insertSetSize;
|
||||
|
||||
|
|
@ -203,6 +225,9 @@ private:
|
|||
|
||||
/** @var Validate-no-wait configuration. */
|
||||
bool m_validationNoWait;
|
||||
|
||||
/** @var flag indicating whether transaction committed */
|
||||
bool m_isTransactionCommited;
|
||||
};
|
||||
} // namespace MOT
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
#include "cycles.h"
|
||||
#include "debug_utils.h"
|
||||
#include "mot_engine.h"
|
||||
|
||||
//this is a test
|
||||
namespace MOT {
|
||||
DECLARE_LOGGER(RowHeader, ConcurrenyControl);
|
||||
|
||||
|
|
@ -89,7 +89,15 @@ bool RowHeader::ValidateWrite(TransactionId tid) const
|
|||
{
|
||||
return (tid == GetCSN());
|
||||
}
|
||||
|
||||
/* function name:ValidateRead
|
||||
function purpose:Validates the read operation on a row by checking its lock status and transaction id.
|
||||
input:tid The transaction id of the current operation
|
||||
output: True if the row can be safely read, otherwise false.
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/10/05 22:51:42
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
bool RowHeader::ValidateRead(TransactionId tid) const
|
||||
{
|
||||
if (IsLocked() or (tid != GetCSN())) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "affinity.h"
|
||||
#include "global.h"
|
||||
|
|
@ -47,81 +47,81 @@ void Affinity::Configure(uint64_t numaNodes, uint64_t physicalCoresNuma, Affinit
|
|||
m_affinityMode = affinityMode;
|
||||
}
|
||||
|
||||
uint32_t Affinity::GetAffineProcessor(uint64_t threadId) const
|
||||
int Affinity::GetAffineProcessor(uint64_t threadId) const
|
||||
{
|
||||
uint32_t result = INVALID_CPU_ID;
|
||||
int result = INVALID_CPU_ID;
|
||||
threadId = threadId % (m_numaNodes * m_physicalCoresNuma);
|
||||
|
||||
switch (m_affinityMode) {
|
||||
case AffinityMode::FILL_SOCKET_FIRST: {
|
||||
result = (uint32_t)GetGlobalConfiguration().GetMappedCore(threadId);
|
||||
result = GetGlobalConfiguration().GetMappedCore(threadId);
|
||||
break;
|
||||
}
|
||||
|
||||
case AffinityMode::EQUAL_PER_SOCKET: {
|
||||
threadId = threadId % (m_numaNodes * m_physicalCoresNuma);
|
||||
uint32_t numaId = threadId % m_numaNodes;
|
||||
uint32_t localProc = threadId / m_numaNodes;
|
||||
result = (uint32_t)(numaId * m_physicalCoresNuma + localProc);
|
||||
int numaId = threadId % m_numaNodes;
|
||||
int localProc = threadId / m_numaNodes;
|
||||
result = GetGlobalConfiguration().GetCoreFromNumaNodeByIndex(numaId, localProc);
|
||||
break;
|
||||
}
|
||||
|
||||
case AffinityMode::FILL_PHYSICAL_FIRST:
|
||||
result = (uint32_t)GetGlobalConfiguration().GetCoreByConnidFP(threadId);
|
||||
result = GetGlobalConfiguration().GetCoreByConnidFP((int)threadId);
|
||||
break;
|
||||
|
||||
default:
|
||||
MOT_LOG_ERROR("%s: Invalid affinity configuration: %d", __func__, (int)m_affinityMode);
|
||||
result = INVALID_CPU_ID;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t Affinity::GetAffineNuma(uint64_t threadId) const
|
||||
/* function name:GetAffineNuma
|
||||
function purpose:To get the NUMA (Non-Uniform Memory Access) node ID associated with the specified thread Id
|
||||
input:threadId
|
||||
output:NUMA ID,If the query fails, INVALID_NODE_ID is returned.
|
||||
note:no
|
||||
annotator:liushifa
|
||||
annotate time:2023/09/11 17:01:32
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
int Affinity::GetAffineNuma(uint64_t threadId) const
|
||||
{
|
||||
uint32_t result = INVALID_NODE_ID;
|
||||
threadId = threadId % (m_numaNodes * m_physicalCoresNuma);
|
||||
|
||||
int result = INVALID_NODE_ID;
|
||||
// Determine how to obtain the NUMA node ID based on the current affinity mode
|
||||
switch (m_affinityMode) {
|
||||
case AffinityMode::FILL_SOCKET_FIRST: {
|
||||
result = (uint32_t)GetGlobalConfiguration().GetCpuNode(GetGlobalConfiguration().GetMappedCore(threadId));
|
||||
break;
|
||||
}
|
||||
|
||||
case AffinityMode::FILL_SOCKET_FIRST:
|
||||
case AffinityMode::EQUAL_PER_SOCKET:
|
||||
result = (uint32_t)threadId % m_numaNodes;
|
||||
break;
|
||||
|
||||
case AffinityMode::FILL_PHYSICAL_FIRST: {
|
||||
uint64_t realCoreCount = 0;
|
||||
if (GetGlobalConfiguration().IsHyperThread() == true) {
|
||||
realCoreCount = m_physicalCoresNuma / 2;
|
||||
} else {
|
||||
realCoreCount = m_physicalCoresNuma;
|
||||
}
|
||||
threadId = threadId % (m_numaNodes * realCoreCount);
|
||||
result = (uint32_t)(threadId / realCoreCount);
|
||||
int coreId = GetAffineProcessor(threadId);
|
||||
result = GetGlobalConfiguration().GetCpuNode(coreId);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
MOT_LOG_ERROR("%s: Invalid affinity configuration: %d", __func__, (int)m_affinityMode);
|
||||
result = (uint32_t)INVALID_NODE_ID;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Affinity::SetAffinity(uint64_t threadId, uint32_t* threadCore /* = nullptr */) const
|
||||
/* function name:SetAffinity
|
||||
function purpose:Set CPU affinity for threads
|
||||
input:thread id
|
||||
output:Whether the affinity is successfully set
|
||||
note:no
|
||||
annotator:liushifa
|
||||
annotate time:2023/09/11 16:57:04
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
bool Affinity::SetAffinity(uint64_t threadId, int* threadCore /* = nullptr */) const
|
||||
{
|
||||
bool result = true;
|
||||
uint32_t coreId = GetAffineProcessor(threadId);
|
||||
int coreId = GetAffineProcessor(threadId);
|
||||
|
||||
cpu_set_t mask;
|
||||
// Clear the mask, used to represent the CPU collection
|
||||
CPU_ZERO(&mask);
|
||||
GetGlobalConfiguration().SetMaskToAllCoresinNumaSocket(mask, coreId);
|
||||
GetGlobalConfiguration().SetMaskToAllCoresinNumaSocketByCoreId(mask, coreId);
|
||||
|
||||
pthread_t currentThread = pthread_self();
|
||||
// The following call forces migration of the thread if it is
|
||||
|
|
@ -141,6 +141,7 @@ bool Affinity::SetAffinity(uint64_t threadId, uint32_t* threadCore /* = nullptr
|
|||
MOT_LOG_TRACE("Set current thread %u affinity to core %u (socket %u)",
|
||||
(unsigned)threadId,
|
||||
(unsigned)coreId,
|
||||
//Gets the NUMA (Non-Uniform Memory Access) node ID associated with the specified thread Id
|
||||
(unsigned)GetAffineNuma(threadId));
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +156,7 @@ bool Affinity::SetNodeAffinity(int nodeId)
|
|||
bool result = true;
|
||||
cpu_set_t mask;
|
||||
CPU_ZERO(&mask);
|
||||
GetGlobalConfiguration().SetMaskToAllCoresinNumaSocket2(mask, nodeId);
|
||||
GetGlobalConfiguration().SetMaskToAllCoresinNumaSocketByNodeId(mask, nodeId);
|
||||
|
||||
pthread_t currentThread = pthread_self();
|
||||
// The following call forces migration of the thread if it is incorrectly placed
|
||||
|
|
@ -173,10 +174,10 @@ bool Affinity::SetNodeAffinity(int nodeId)
|
|||
return result;
|
||||
}
|
||||
|
||||
static const char* AFFINITY_FILL_SOCKET_FIRST_STR = "fill-socket-first";
|
||||
static const char* AFFINITY_EQUAL_PER_SOCKET_STR = "equal-per-socket";
|
||||
static const char* AFFINITY_FILL_PHYSICAL_FIRST_STR = "fill-physical-first";
|
||||
static const char* AFFINITY_NONE_STR = "none";
|
||||
static const char* const AFFINITY_FILL_SOCKET_FIRST_STR = "fill-socket-first";
|
||||
static const char* const AFFINITY_EQUAL_PER_SOCKET_STR = "equal-per-socket";
|
||||
static const char* const AFFINITY_FILL_PHYSICAL_FIRST_STR = "fill-physical-first";
|
||||
static const char* const AFFINITY_NONE_STR = "none";
|
||||
|
||||
extern AffinityMode AffinityModeFromString(const char* affinityModeStr)
|
||||
{
|
||||
|
|
@ -212,4 +213,12 @@ extern const char* AffinityModeToString(AffinityMode affinityMode)
|
|||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
extern bool ValidateAffinityMode(const char* affinityModeStr)
|
||||
{
|
||||
if (AffinityModeFromString(affinityModeStr) == AffinityMode::AFFINITY_INVALID) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace MOT
|
||||
|
|
|
|||
|
|
@ -36,6 +36,19 @@ DECLARE_LOGGER(CpuCyclesLevelTime, System)
|
|||
double CpuCyclesLevelTime::m_cyclesPerSecond = 1.0;
|
||||
static constexpr double EPSILON = 1.0E-06;
|
||||
|
||||
/* function name:CpuCyclesLevelTime
|
||||
function purpose:Initializes the cycles per second measurement.
|
||||
The function measures the CPU cycles per second in order to convert CPU cycle durations
|
||||
to real time durations. The measurement is done by capturing the CPU cycle count at
|
||||
two different time intervals and then computing the difference. The result is then
|
||||
adjusted to compute cycles per second.
|
||||
input:none
|
||||
output:none
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/10/05 22:52:55
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
void CpuCyclesLevelTime::Init()
|
||||
{
|
||||
if (m_cyclesPerSecond > 1.0) {
|
||||
|
|
|
|||
|
|
@ -108,7 +108,15 @@ extern int MemBufferAllocatorInit(MemBufferAllocator* bufferAllocator, int node,
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* function name: FreeToBufferHeap
|
||||
function purpose:Frees a given object to a specified buffer heap.
|
||||
input:object Pointer to the object to be freed.serData Pointer to the buffer heap where the object will be freed.
|
||||
output:none
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/10/05 22:52:42
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
static void FreeToBufferHeap(void* object, void* userData)
|
||||
{
|
||||
MemBufferHeap* bufferHeap = (MemBufferHeap*)userData;
|
||||
|
|
|
|||
|
|
@ -118,9 +118,20 @@ extern void MemBufferChunkInit(MemBufferChunkHeader* chunkHeader, int16_t node,
|
|||
bufferHeader->m_prev = nullptr; // MM_CHUNK_BUFFER_HEADER_AT(chunkHeader, bufferIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* function name:MemBufferChunkOnDoubleFree
|
||||
function purpose:Handles a scenario where a buffer chunk is freed twice (double free error).
|
||||
input:
|
||||
@param chunkHeader Pointer to the header of the buffer chunk that is being double-freed.
|
||||
@param bufferHeader Pointer to the header of the buffer that contains the chunk being double-freed.
|
||||
output:none
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/10/05 22:53:42
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
extern void MemBufferChunkOnDoubleFree(MemBufferChunkHeader* chunkHeader, MemBufferHeader* bufferHeader)
|
||||
{
|
||||
// Log a panic message indicating a double free scenario with details
|
||||
MOT_LOG_PANIC(
|
||||
"Double free of buffer header %p [@%u -->%p] in chunk %p (node: %d, buffer-size=%u KB, allocated=%u/%u)",
|
||||
bufferHeader,
|
||||
|
|
|
|||
|
|
@ -65,7 +65,19 @@ static void AssertChunkRemoved(MemBufferHeap* bufferHeap, MemBufferChunkHeader*
|
|||
#define ASSERT_HEAP_VALID(X)
|
||||
#define ASSERT_CHUNK_REMOVED(X, Y)
|
||||
#endif
|
||||
|
||||
/* function name:MemBufferHeapInit
|
||||
function purpose:Initializes a memory buffer heap.
|
||||
input:
|
||||
@param bufferHeap Pointer to the buffer heap to initialize.
|
||||
@param node Specifies the NUMA node in which the memory buffer heap will be initialized.
|
||||
@param bufferClass Classification of buffer based on its size.
|
||||
@param allocType Specifies the type of allocation mechanism to use.
|
||||
output:return Zero on successful initialization, and a non-zero error code otherwise.
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/10/05 22:55:42
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
extern int MemBufferHeapInit(MemBufferHeap* bufferHeap, int node, MemBufferClass bufferClass, MemAllocType allocType)
|
||||
{
|
||||
int result = MemLockInitialize(&bufferHeap->m_lock);
|
||||
|
|
|
|||
|
|
@ -266,7 +266,20 @@ extern void MemNumaGetStats(MemNumaStats* stats)
|
|||
stats->m_peakLocalMemoryBytes[i] = MOT_ATOMIC_LOAD(peakLocalMemoryBytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* function name: MemNumaFormatStats
|
||||
function purpose:Formats the NUMA statistics into a string buffer based on the report mode specified.
|
||||
input:
|
||||
@param indent The amount of whitespace to add before the statistics for readability.
|
||||
* @param name Name of the allocation for the report.
|
||||
* @param stringBuffer Pointer to the string buffer to which the formatted stats will be appended.
|
||||
* @param stats Pointer to the statistics to format.
|
||||
* @param reportMode Determines the mode of the report - summary or detailed.
|
||||
output:none
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/10/05 22:59:42
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
extern void MemNumaFormatStats(int indent, const char* name, StringBuffer* stringBuffer, MemNumaStats* stats,
|
||||
MemReportMode reportMode /* = MEM_REPORT_SUMMARY */)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -117,7 +117,15 @@ extern int MemSessionApiInit()
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* function name:MemSessionApiDestroy
|
||||
function purpose:Destroys the memory session API, which primarily manages memory allocations for each session/thread.
|
||||
input:none
|
||||
output:none
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/10/01 22:51:42
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
extern void MemSessionApiDestroy()
|
||||
{
|
||||
MOT_LOG_TRACE("Destroying Session API");
|
||||
|
|
|
|||
|
|
@ -32,15 +32,15 @@
|
|||
#include "postgres.h"
|
||||
#include "knl/knl_thread.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <cerrno>
|
||||
#include <cstdarg>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -52,19 +52,19 @@
|
|||
#endif
|
||||
|
||||
/* Flags for mbind */
|
||||
#define MPOL_MF_STRICT (1 << 0) /* Verify existing pages in the mapping */
|
||||
#define MPOL_MF_MOVE (1 << 1) /* Move pages owned by this process to conform to mapping */
|
||||
#define MPOL_MF_MOVE_ALL (1 << 2) /* Move every page to conform to mapping */
|
||||
#define MPOL_MF_STRICT (1U) /* Verify existing pages in the mapping */
|
||||
#define MPOL_MF_MOVE (1U << 1) /* Move pages owned by this process to conform to mapping */
|
||||
#define MPOL_MF_MOVE_ALL (1U << 2) /* Move every page to conform to mapping */
|
||||
|
||||
// some required utility macros
|
||||
#define ROUND_UP(x, y) (((x) + (y)-1) & ~((y)-1))
|
||||
#define ROUND_UP(x, y) (((x) + (y) - 1) & ~((y) - 1))
|
||||
#define CPU_BYTES(x) (ROUND_UP(x, sizeof(long)))
|
||||
#define CPU_LONGS(x) (CPU_BYTES(x) / sizeof(long))
|
||||
|
||||
#define HOW_MANY(x, y) (((x) + ((y)-1)) / (y))
|
||||
#define BITS_PER_LONG (8 * sizeof(unsigned long))
|
||||
#define BITS_PER_INT (8 * sizeof(unsigned int))
|
||||
#define LONGS_PER_BITS(n) HOW_MANY(n, BITS_PER_LONG)
|
||||
#define HOW_MANY(x, y) (((x) + ((y) - 1)) / (y))
|
||||
#define BITS_PER_ULONG ((unsigned int)8 * sizeof(unsigned long))
|
||||
#define BITS_PER_UINT ((unsigned int)8 * sizeof(unsigned int))
|
||||
#define LONGS_PER_BITS(n) HOW_MANY(n, BITS_PER_ULONG)
|
||||
#define BYTES_PER_BITS(x) ((x + 7) / 8)
|
||||
|
||||
// define maximum number of NUMA nodes
|
||||
|
|
@ -93,16 +93,21 @@ typedef struct PACKED BitMask_ST {
|
|||
unsigned long m_maskp[0];
|
||||
} BitMaskSt;
|
||||
|
||||
#define BITMASK_NBYTES(bmp) (LONGS_PER_BITS(bmp->m_size) * sizeof(unsigned long))
|
||||
#define BITMASK_GETBIT(bmp, n) \
|
||||
(((unsigned int)n < bmp->m_size) ? ((bmp->m_maskp[n / BITS_PER_LONG] >> (n % BITS_PER_LONG)) & 1) : 0)
|
||||
#define BITMASK_SETBIT(bmp, n) \
|
||||
if ((unsigned int)n < bmp->m_size) { \
|
||||
bmp->m_maskp[n / BITS_PER_LONG] |= 1UL << (n % BITS_PER_LONG); \
|
||||
#define BITMASK_NBYTES(bmp) (LONGS_PER_BITS((bmp)->m_size) * sizeof(unsigned long))
|
||||
|
||||
#define BITMASK_GETBIT(bmp, n) \
|
||||
(((unsigned int)(n) < (bmp)->m_size) \
|
||||
? (((bmp)->m_maskp[(unsigned int)(n) / BITS_PER_ULONG] >> ((unsigned int)(n) % BITS_PER_ULONG)) & 1) \
|
||||
: 0)
|
||||
|
||||
#define BITMASK_SETBIT(bmp, n) \
|
||||
if ((unsigned int)(n) < (bmp)->m_size) { \
|
||||
(bmp)->m_maskp[(unsigned int)(n) / BITS_PER_ULONG] |= 1UL << ((unsigned int)(n) % BITS_PER_ULONG); \
|
||||
}
|
||||
#define BITMASK_CLEARBIT(bmp, n) \
|
||||
if ((unsigned int)n < bmp->m_size) { \
|
||||
bmp->m_maskp[n / BITS_PER_LONG] &= ~(1UL << (n % BITS_PER_LONG)); \
|
||||
|
||||
#define BITMASK_CLEARBIT(bmp, n) \
|
||||
if ((unsigned int)(n) < (bmp)->m_size) { \
|
||||
(bmp)->m_maskp[(unsigned int)(n) / BITS_PER_ULONG] &= ~(1UL << ((unsigned int)(n) % BITS_PER_ULONG)); \
|
||||
}
|
||||
|
||||
#define BITMASK_FREE(x) \
|
||||
|
|
@ -111,11 +116,11 @@ typedef struct PACKED BitMask_ST {
|
|||
x = nullptr; \
|
||||
}
|
||||
|
||||
#define BITMASK_ONSTACK(name, x) \
|
||||
int sz = sizeof(BitMaskSt) + (LONGS_PER_BITS(x) * sizeof(unsigned long)); \
|
||||
char _bmp_buf[sz]; \
|
||||
BitMaskSt* name = (BitMaskSt*)_bmp_buf; \
|
||||
bzero(name, sz); \
|
||||
#define BITMASK_ONSTACK(name, x) \
|
||||
size_t sz = sizeof(BitMaskSt) + (LONGS_PER_BITS(x) * sizeof(unsigned long)); \
|
||||
char _bmp_buf[sz]; \
|
||||
BitMaskSt* name = (BitMaskSt*)_bmp_buf; \
|
||||
bzero(name, sz); \
|
||||
name->m_size = x;
|
||||
|
||||
// Report errors/warnings
|
||||
|
|
@ -145,13 +150,13 @@ extern void MotSysNumaDumpMMapError(
|
|||
int errnum, void* address, size_t length, int prot, int flags, int fd, off_t offset);
|
||||
|
||||
// Static variables
|
||||
static const char* MASK_SIZE_FILE = "/proc/self/status";
|
||||
static const char* NODE_MASK_PREFIX = "Mems_allowed:\t";
|
||||
static const char* const MASK_SIZE_FILE = "/proc/self/status";
|
||||
static const char* const NODE_MASK_PREFIX = "Mems_allowed:\t";
|
||||
static const int NODE_MASK_PREFIX_SIZE = strlen(NODE_MASK_PREFIX);
|
||||
static const char* NODE_CPU_MAP_FILE = "/sys/devices/system/node/node%d/cpumap";
|
||||
static const char* const NODE_CPU_MAP_FILE = "/sys/devices/system/node/node%d/cpumap";
|
||||
#define MOTBindPolicy t_thrd.mot_cxt.bindPolicy
|
||||
#define MOTMBindFlags t_thrd.mot_cxt.mbindFlags
|
||||
static int g_nodeMaskSize = 0;
|
||||
static unsigned int g_nodeMaskSize = 0;
|
||||
static int g_cpuMaskSize = 0;
|
||||
static int g_maxConfNode = -1;
|
||||
static int g_maxConfCpu = -1;
|
||||
|
|
@ -163,13 +168,33 @@ static BitMaskSt* g_nodesBm = nullptr;
|
|||
static BitMaskSt* g_memNodeBm = nullptr;
|
||||
static BitMaskSt** g_nodeCpuBm = nullptr;
|
||||
|
||||
/* function name:MotSysNumaInit
|
||||
function purpose:Initialization of numa system
|
||||
input:none
|
||||
output:none
|
||||
note:no
|
||||
annotator:liushifa
|
||||
annotate time:2023/09/16 11:05:20
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
void MotSysNumaInit()
|
||||
{
|
||||
// Set the size of the node mask representing available NUMA nodes in the system
|
||||
MotSysNumaSetNodemaskSize();
|
||||
|
||||
// Set or retrieve the number of configured NUMA nodes in the system
|
||||
MotSysNumaSetConfiguredNodes();
|
||||
|
||||
// Set or retrieve the maximum number of CPUs in the NUMA system
|
||||
MotSysNumaSetNumaMaxCpu();
|
||||
|
||||
// Set or retrieve the number of configured CPUs in the system
|
||||
MotSysNumaSetConfiguredCpus();
|
||||
|
||||
// Apply constraints to tasks to ensure they run on the correct NUMA nodes and aren't migrated elsewhere
|
||||
MotSysNumaSetTaskConstraints();
|
||||
|
||||
// Initialize the CPU mask for each NUMA node, representing the CPUs present on each node
|
||||
MotSysNumaNodeCpuMaskInit();
|
||||
}
|
||||
|
||||
|
|
@ -210,7 +235,9 @@ void* MotSysNumaAllocInterleaved(size_t size)
|
|||
g_allNodesBm->m_size + 1,
|
||||
MOTMBindFlags) != 0) {
|
||||
MotSysNumaReportError("mbind");
|
||||
munmap(mem, size);
|
||||
if (munmap(mem, size) != 0) {
|
||||
MotSysNumaReportError("munmap");
|
||||
}
|
||||
mem = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -237,7 +264,9 @@ void* MotSysNumaAllocOnNode(size_t size, int node)
|
|||
bmp->m_size + 1,
|
||||
MOTMBindFlags) != 0) {
|
||||
MotSysNumaReportError("mbind");
|
||||
munmap(mem, size);
|
||||
if (munmap(mem, size) != 0) {
|
||||
MotSysNumaReportError("munmap");
|
||||
}
|
||||
mem = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -256,7 +285,9 @@ void* MotSysNumaAllocLocal(size_t size)
|
|||
} else {
|
||||
if (syscall(__NR_mbind, (intptr_t)mem, size, MPOL_PREFERRED, nullptr, 0, MOTMBindFlags) != 0) {
|
||||
MotSysNumaReportError("mbind");
|
||||
munmap(mem, size);
|
||||
if (munmap(mem, size) != 0) {
|
||||
MotSysNumaReportError("munmap");
|
||||
}
|
||||
mem = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -277,19 +308,19 @@ static void* MotSysNumaMapAligned(size_t size, size_t align)
|
|||
|
||||
if (((uint64_t)mem) % align != 0) {
|
||||
// take the slow route
|
||||
munmap(mem, size);
|
||||
(void)munmap(mem, size);
|
||||
mem = MOTSysNumaMmap(0, size + align, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
|
||||
if (mem == MAP_FAILED) {
|
||||
return mem;
|
||||
} else {
|
||||
uint64_t offset = ((uint64_t)mem) % align;
|
||||
if (offset == 0) { // aligned this time so we only need to unmap suffix of align bytes
|
||||
munmap(((char*)mem) + size, align);
|
||||
(void)munmap(((char*)mem) + size, align);
|
||||
} else {
|
||||
size_t leadingUseless = align - offset; // guaranteed to be non-negative
|
||||
munmap(mem, leadingUseless);
|
||||
(void)munmap(mem, leadingUseless);
|
||||
void* alignedMem = ((char*)mem) + leadingUseless;
|
||||
munmap(((char*)alignedMem) + size, offset);
|
||||
(void)munmap(((char*)alignedMem) + size, offset);
|
||||
mem = alignedMem;
|
||||
}
|
||||
}
|
||||
|
|
@ -317,7 +348,9 @@ void* MotSysNumaAllocAlignedInterleaved(size_t size, size_t align)
|
|||
g_allNodesBm->m_size + 1,
|
||||
MOTMBindFlags) != 0) {
|
||||
MotSysNumaReportError("mbind");
|
||||
munmap(mem, size);
|
||||
if (munmap(mem, size) != 0) {
|
||||
MotSysNumaReportError("munmap");
|
||||
}
|
||||
mem = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -345,7 +378,9 @@ void* MotSysNumaAllocAlignedOnNode(size_t size, size_t align, int node)
|
|||
bmp->m_size + 1,
|
||||
MOTMBindFlags) != 0) {
|
||||
MotSysNumaReportError("mbind");
|
||||
munmap(mem, size);
|
||||
if (munmap(mem, size) != 0) {
|
||||
MotSysNumaReportError("munmap");
|
||||
}
|
||||
mem = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -365,7 +400,9 @@ void* MotSysNumaAllocAlignedLocal(size_t size, size_t align)
|
|||
} else {
|
||||
if (syscall(__NR_mbind, (intptr_t)mem, size, MPOL_PREFERRED, nullptr, 0, MOTMBindFlags) != 0) {
|
||||
MotSysNumaReportError("mbind");
|
||||
munmap(mem, size);
|
||||
if (munmap(mem, size) != 0) {
|
||||
MotSysNumaReportError("munmap");
|
||||
}
|
||||
mem = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -374,7 +411,9 @@ void* MotSysNumaAllocAlignedLocal(size_t size, size_t align)
|
|||
|
||||
void MotSysNumaFree(void* mem, size_t size)
|
||||
{
|
||||
munmap(mem, size);
|
||||
if (munmap(mem, size) != 0) {
|
||||
MotSysNumaReportError("munmap");
|
||||
}
|
||||
}
|
||||
|
||||
int MotSysNumaAvailable()
|
||||
|
|
@ -420,18 +459,36 @@ int MotSysNumaGetNode(int cpu)
|
|||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* function name:MotSysNumaSetBindPolicy
|
||||
function purpose:Set the binding policy for memory allocation
|
||||
input:
|
||||
output:none
|
||||
note:no
|
||||
annotator:liushifa
|
||||
annotate time:2023/09/16 15:18:03
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
void MotSysNumaSetBindPolicy(int strict)
|
||||
{
|
||||
MOTBindPolicy = (strict ? MPOL_BIND : MPOL_PREFERRED);
|
||||
}
|
||||
/* function name:MotSysNumaSetStrict
|
||||
function purpose:Set the strictness flag for memory binding
|
||||
input:flag
|
||||
output:none
|
||||
note:no
|
||||
annotator:liushifa
|
||||
annotate time:2023/09/16 15:18:45
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
|
||||
void MotSysNumaSetStrict(int flag)
|
||||
{
|
||||
if (flag)
|
||||
if (flag) {
|
||||
MOTMBindFlags |= MPOL_MF_STRICT;
|
||||
else
|
||||
} else {
|
||||
MOTMBindFlags &= ~MPOL_MF_STRICT;
|
||||
}
|
||||
}
|
||||
|
||||
void MotSysNumaSetPreferred(int node)
|
||||
|
|
@ -448,19 +505,28 @@ void MotSysNumaSetPreferred(int node)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* function name:MotSysNumaCpuAllowed
|
||||
function purpose:Determine whether the cpu is available to use the numa node
|
||||
input:id of cpu
|
||||
output:yes or no
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/09/20 16:44:09
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
bool MotSysNumaCpuAllowed(int cpu)
|
||||
{
|
||||
// Determine whether the given cpu number is greater than the preset maximum value
|
||||
if (cpu > g_cpuMaskSize) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check whether the global CPU bitmask has been initialized
|
||||
if (g_allCpusBm == nullptr) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use the BITMASK_GETBIT macro to check if the given cpu number is set to 1 in the bitmask
|
||||
if (BITMASK_GETBIT(g_allCpusBm, cpu) == 1) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -490,7 +556,7 @@ static int MotSysNumaParseBitmap(char* line, BitMaskSt* mask)
|
|||
|
||||
if (p > line && sizeof(unsigned long) == 8) {
|
||||
oldp--;
|
||||
errno_t erc = memmove_s(p, oldp - p + 1, p + 1, oldp - p + 1);
|
||||
errno_t erc = memmove_s(p, (oldp - p) + 1, p + 1, (oldp - p) + 1);
|
||||
securec_check(erc, "\0", "\0");
|
||||
while (p > line && *p != ',') {
|
||||
--p;
|
||||
|
|
@ -540,51 +606,64 @@ static void MotSysNumaSetConfiguredNodes()
|
|||
g_maxConfNode = node;
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
(void)closedir(d);
|
||||
}
|
||||
}
|
||||
|
||||
/* function name:MotSysNumaSetConfiguredNodes
|
||||
function purpose:Set numa constraints for system tasks
|
||||
input:none
|
||||
output:none
|
||||
note:no
|
||||
annotator:liushifa
|
||||
annotate time:2023/09/16 11:13:50
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
static void MotSysNumaSetTaskConstraints()
|
||||
{
|
||||
int i;
|
||||
char* buffer = nullptr;
|
||||
size_t buflen = 0;
|
||||
FILE* f;
|
||||
|
||||
// Allocate bitmask space to represent all CPUs and NUMA nodes
|
||||
g_allCpusBm = MotSysNumaBitmaskAlloc(g_cpuMaskSize);
|
||||
g_allNodesBm = MotSysNumaBitmaskAlloc(g_nodeMaskSize);
|
||||
|
||||
if ((f = fopen(MASK_SIZE_FILE, "r")) == nullptr)
|
||||
// Open the NUMA configuration file for reading
|
||||
if ((f = fopen(MASK_SIZE_FILE, "r")) == nullptr) {
|
||||
return;
|
||||
|
||||
while (getline(&buffer, &buflen, f) > 0) {
|
||||
char* mask = strrchr(buffer, '\t') + 1;
|
||||
|
||||
if (strncmp(buffer, "Cpus_allowed:", 13) == 0)
|
||||
g_numProcCpu = MotSysNumaReadBitmask(mask, g_allCpusBm);
|
||||
|
||||
if (strncmp(buffer, "Mems_allowed:", 13) == 0)
|
||||
g_numProcNode = MotSysNumaReadBitmask(mask, g_allNodesBm);
|
||||
}
|
||||
fclose(f);
|
||||
// Read the NUMA configuration file line by line
|
||||
while (getline(&buffer, &buflen, f) > 0) {
|
||||
MOT_ASSERT(buffer != nullptr);
|
||||
char* mask = strrchr(buffer, '\t') + 1;
|
||||
// Identify and process line for CPU configuration
|
||||
if (strncmp(buffer, "Cpus_allowed:", 13) == 0) {
|
||||
g_numProcCpu = MotSysNumaReadBitmask(mask, g_allCpusBm);
|
||||
}
|
||||
// Identify and process line for NUMA node configuration
|
||||
if (strncmp(buffer, "Mems_allowed:", 13) == 0) {
|
||||
g_numProcNode = MotSysNumaReadBitmask(mask, g_allNodesBm);
|
||||
}
|
||||
}
|
||||
// Close the file and free the buffer
|
||||
(void)fclose(f);
|
||||
if (buffer != nullptr) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
// If no valid CPUs are set, set all available CPUs as valid
|
||||
if (g_numProcCpu <= 0) {
|
||||
for (i = 0; i <= g_maxConfCpu; i++) {
|
||||
BITMASK_SETBIT(g_allCpusBm, i);
|
||||
}
|
||||
g_numProcCpu = g_maxConfCpu + 1;
|
||||
}
|
||||
|
||||
// Limit the number of CPUs and adjust the bitmask
|
||||
if (g_numProcCpu > g_maxConfCpu + 1) {
|
||||
g_numProcCpu = g_maxConfCpu + 1;
|
||||
for (i = g_maxConfCpu + 1; i < (int)g_allCpusBm->m_size; i++) {
|
||||
BITMASK_CLEARBIT(g_allCpusBm, i);
|
||||
}
|
||||
}
|
||||
|
||||
// If no valid NUMA nodes are set, set all available NUMA nodes as valid
|
||||
if (g_numProcNode <= 0) {
|
||||
for (i = 0; i <= g_maxConfNode; i++) {
|
||||
BITMASK_SETBIT(g_allNodesBm, i);
|
||||
|
|
@ -663,7 +742,7 @@ static unsigned int MotSysNumaBitmaskWeight(const BitMaskSt* bmp)
|
|||
static int MotSysNumaReadBitmask(char* s, BitMaskSt* bmp)
|
||||
{
|
||||
char* end = s;
|
||||
unsigned tmplen = (bmp->m_size + BITS_PER_INT - 1) / BITS_PER_INT;
|
||||
unsigned tmplen = (bmp->m_size + BITS_PER_UINT - 1) / BITS_PER_UINT;
|
||||
unsigned int tmp[tmplen];
|
||||
unsigned int* start = tmp;
|
||||
unsigned int n = 0;
|
||||
|
|
@ -696,7 +775,7 @@ static int MotSysNumaReadBitmask(char* s, BitMaskSt* bmp)
|
|||
while (n) {
|
||||
unsigned int w;
|
||||
unsigned long x = 0;
|
||||
for (w = 0; n && w < BITS_PER_LONG; w += BITS_PER_INT) {
|
||||
for (w = 0; n && w < BITS_PER_ULONG; w += BITS_PER_UINT) {
|
||||
x |= ((unsigned long)start[n-- - 1] << w);
|
||||
}
|
||||
|
||||
|
|
@ -708,7 +787,7 @@ static int MotSysNumaReadBitmask(char* s, BitMaskSt* bmp)
|
|||
static void MotSysNumaNodeCpuMaskCleanup(void)
|
||||
{
|
||||
if (g_nodeCpuBm != nullptr) {
|
||||
for (int i = 0; i < g_nodeMaskSize; i++) {
|
||||
for (unsigned int i = 0; i < g_nodeMaskSize; i++) {
|
||||
BITMASK_FREE(g_nodeCpuBm[i]);
|
||||
}
|
||||
free(g_nodeCpuBm);
|
||||
|
|
@ -728,7 +807,7 @@ static void MotSysNumaNodeCpuMaskInit(void)
|
|||
|
||||
g_nodeCpuBm = (BitMaskSt**)calloc(g_nodeMaskSize, sizeof(BitMaskSt*));
|
||||
|
||||
for (int i = 0; i < g_nodeMaskSize; i++) {
|
||||
for (unsigned int i = 0; i < g_nodeMaskSize; i++) {
|
||||
len = 0;
|
||||
FILE* f = nullptr;
|
||||
char* line = nullptr;
|
||||
|
|
@ -762,7 +841,7 @@ static void MotSysNumaNodeCpuMaskInit(void)
|
|||
}
|
||||
|
||||
if (f != nullptr) {
|
||||
fclose(f);
|
||||
(void)fclose(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -782,7 +861,7 @@ static void MotSysNumaSetNodemaskSize()
|
|||
}
|
||||
if (line != nullptr)
|
||||
free(line);
|
||||
fclose(fp);
|
||||
(void)fclose(fp);
|
||||
}
|
||||
|
||||
if (g_nodeMaskSize == 0) {
|
||||
|
|
|
|||
|
|
@ -115,7 +115,15 @@ const char* Column::ColumnErrorMsg(RC err)
|
|||
return "Foreign table does not support this column definition";
|
||||
}
|
||||
}
|
||||
|
||||
/* function name:Column
|
||||
function purpose:Default constructor for the Column class. Initializes all member variables to their default values.
|
||||
input:none
|
||||
output:none
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/10/02 22:51:42
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
Column::Column()
|
||||
{
|
||||
this->m_id = 0;
|
||||
|
|
|
|||
|
|
@ -27,18 +27,32 @@
|
|||
#include "utilities.h"
|
||||
|
||||
namespace MOT {
|
||||
DECLARE_LOGGER(IndexFactory, Storage)
|
||||
|
||||
IMPLEMENT_CLASS_LOGGER(IndexFactory, Storage);
|
||||
|
||||
|
||||
/* function name:CreateIndex
|
||||
function purpose:Creates a new index based on the provided parameters.
|
||||
input:
|
||||
@param indexOrder The order in which the index should be created.
|
||||
@param indexingMethod The method to be used for indexing.
|
||||
@param flavor The flavor/variant of the indexing tree to be used.
|
||||
output:Returns a pointer to the newly created Index, or nullptr if the index creation fails.
|
||||
note:no
|
||||
annotator:liushifa
|
||||
annotate time:2023/08/22 11:42:16
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
Index* IndexFactory::CreateIndex(IndexOrder indexOrder, IndexingMethod indexingMethod, IndexTreeFlavor flavor)
|
||||
{
|
||||
Index* newIx = nullptr;
|
||||
|
||||
// Attempt to create a primary index based on the specified method and flavor.
|
||||
newIx = CreatePrimaryIndex(indexingMethod, flavor);
|
||||
|
||||
// If index creation was successful, set the order of the index.
|
||||
if (newIx != nullptr) {
|
||||
newIx->SetOrder(indexOrder);
|
||||
} else {
|
||||
// Log an error if index creation failed.
|
||||
MOT_REPORT_ERROR(MOT_ERROR_INTERNAL, "Create Index", "Failed to create primary index");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,9 +47,6 @@ constexpr uint64_t MOTConfiguration::SCALE_SECONDS;
|
|||
constexpr bool MOTConfiguration::DEFAULT_ENABLE_REDO_LOG;
|
||||
constexpr LoggerType MOTConfiguration::DEFAULT_LOGGER_TYPE;
|
||||
constexpr RedoLogHandlerType MOTConfiguration::DEFAULT_REDO_LOG_HANDLER_TYPE;
|
||||
constexpr uint32_t MOTConfiguration::DEFAULT_ASYNC_REDO_LOG_BUFFER_ARRAY_COUNT;
|
||||
constexpr uint32_t MOTConfiguration::MIN_ASYNC_REDO_LOG_BUFFER_ARRAY_COUNT;
|
||||
constexpr uint32_t MOTConfiguration::MAX_ASYNC_REDO_LOG_BUFFER_ARRAY_COUNT;
|
||||
constexpr bool MOTConfiguration::DEFAULT_ENABLE_GROUP_COMMIT;
|
||||
constexpr uint64_t MOTConfiguration::DEFAULT_GROUP_COMMIT_SIZE;
|
||||
constexpr uint64_t MOTConfiguration::MIN_GROUP_COMMIT_SIZE;
|
||||
|
|
@ -74,6 +71,13 @@ constexpr uint32_t MOTConfiguration::DEFAULT_CHECKPOINT_RECOVERY_WORKERS;
|
|||
constexpr uint32_t MOTConfiguration::MIN_CHECKPOINT_RECOVERY_WORKERS;
|
||||
constexpr uint32_t MOTConfiguration::MAX_CHECKPOINT_RECOVERY_WORKERS;
|
||||
constexpr bool MOTConfiguration::DEFAULT_ENABLE_LOG_RECOVERY_STATS;
|
||||
constexpr RecoveryMode MOTConfiguration::DEFAULT_RECOVERY_MODE;
|
||||
constexpr uint32_t MOTConfiguration::DEFAULT_PARALLEL_RECOVERY_WORKERS;
|
||||
constexpr uint32_t MOTConfiguration::MIN_PARALLEL_RECOVERY_WORKERS;
|
||||
constexpr uint32_t MOTConfiguration::MAX_PARALLEL_RECOVERY_WORKERS;
|
||||
constexpr uint32_t MOTConfiguration::DEFAULT_PARALLEL_RECOVERY_QUEUE_SIZE;
|
||||
constexpr uint32_t MOTConfiguration::MIN_PARALLEL_RECOVERY_QUEUE_SIZE;
|
||||
constexpr uint32_t MOTConfiguration::MAX_PARALLEL_RECOVERY_QUEUE_SIZE;
|
||||
// machine configuration members
|
||||
constexpr uint16_t MOTConfiguration::DEFAULT_NUMA_NODES;
|
||||
constexpr uint16_t MOTConfiguration::DEFAULT_CORES_PER_CPU;
|
||||
|
|
@ -169,11 +173,16 @@ constexpr uint64_t MOTConfiguration::MIN_GC_HIGH_RECLAIM_THRESHOLD_BYTES;
|
|||
constexpr uint64_t MOTConfiguration::MAX_GC_HIGH_RECLAIM_THRESHOLD_BYTES;
|
||||
// JIT configuration members
|
||||
constexpr bool MOTConfiguration::DEFAULT_ENABLE_MOT_CODEGEN;
|
||||
constexpr bool MOTConfiguration::DEFAULT_FORCE_MOT_PSEUDO_CODEGEN;
|
||||
constexpr bool MOTConfiguration::DEFAULT_ENABLE_MOT_QUERY_CODEGEN;
|
||||
constexpr bool MOTConfiguration::DEFAULT_ENABLE_MOT_SP_CODEGEN;
|
||||
constexpr const char* MOTConfiguration::DEFAULT_MOT_SP_CODEGEN_ALLOWED;
|
||||
constexpr const char* MOTConfiguration::DEFAULT_MOT_SP_CODEGEN_PROHIBITED;
|
||||
constexpr const char* MOTConfiguration::DEFAULT_MOT_PURE_SP_CODEGEN;
|
||||
constexpr bool MOTConfiguration::DEFAULT_ENABLE_MOT_CODEGEN_PRINT;
|
||||
constexpr uint32_t MOTConfiguration::DEFAULT_MOT_CODEGEN_LIMIT;
|
||||
constexpr uint32_t MOTConfiguration::MIN_MOT_CODEGEN_LIMIT;
|
||||
constexpr uint32_t MOTConfiguration::MAX_MOT_CODEGEN_LIMIT;
|
||||
constexpr bool MOTConfiguration::DEFAULT_ENABLE_MOT_CODEGEN_PROFILE;
|
||||
// storage configuration
|
||||
constexpr bool MOTConfiguration::DEFAULT_ALLOW_INDEX_ON_NULLABLE_COLUMN;
|
||||
constexpr IndexTreeFlavor MOTConfiguration::DEFAULT_INDEX_TREE_FLAVOR;
|
||||
|
|
@ -185,7 +194,8 @@ constexpr uint64_t MOTConfiguration::MAX_CFG_MONITOR_PERIOD_SECONDS;
|
|||
constexpr bool MOTConfiguration::DEFAULT_RUN_INTERNAL_CONSISTENCY_VALIDATION;
|
||||
constexpr uint64_t MOTConfiguration::DEFAULT_TOTAL_MEMORY_MB;
|
||||
|
||||
static constexpr unsigned int MAX_NUMA_NODES = 16u;
|
||||
static constexpr int MAX_NUMA_NODES = 16;
|
||||
|
||||
#define IS_HYPER_THREAD_CMD "lscpu | grep \"Thread(s) per core:\" | awk '{print $4}'"
|
||||
|
||||
static bool ParseLoggerType(
|
||||
|
|
@ -256,6 +266,19 @@ static bool ParseRedoLogHandlerType(const std::string& cfgName, const std::strin
|
|||
return result;
|
||||
}
|
||||
|
||||
static bool ParseRecoveryMode(const std::string& cfgName, const std::string& variableName, const std::string& newValue,
|
||||
RecoveryMode* variableValue)
|
||||
{
|
||||
bool result = (cfgName == variableName);
|
||||
if (result) {
|
||||
*variableValue = RecoveryModeFromString(newValue.c_str());
|
||||
if (*variableValue == RecoveryMode::RECOVERY_INVALID) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool ParseBool(
|
||||
const std::string& cfgName, const std::string& variableName, const std::string& newValue, bool* variableValue)
|
||||
{
|
||||
|
|
@ -305,7 +328,7 @@ static bool ParseUint16(
|
|||
{
|
||||
bool result = (cfgName == variableName);
|
||||
if (result) {
|
||||
*variableValue = (uint16_t)std::stoul(newValue);
|
||||
*variableValue = static_cast<uint16_t>(std::stoul(newValue));
|
||||
MOT_ASSERT(!newValue.empty());
|
||||
}
|
||||
return result;
|
||||
|
|
@ -365,8 +388,8 @@ bool MOTConfiguration::FindNumaNodes(int* maxNodes)
|
|||
return false;
|
||||
}
|
||||
|
||||
if ((unsigned int)*maxNodes >= MAX_NUMA_NODES) {
|
||||
MOT_LOG_ERROR("sys_numa_num_configured_nodes() => %d, while MAX_NUMA_NODES=%u - cannot proceed",
|
||||
if (*maxNodes >= MAX_NUMA_NODES) {
|
||||
MOT_LOG_ERROR("sys_numa_num_configured_nodes() => %d, while MAX_NUMA_NODES=%d - cannot proceed",
|
||||
*maxNodes,
|
||||
MAX_NUMA_NODES);
|
||||
return false;
|
||||
|
|
@ -374,9 +397,17 @@ bool MOTConfiguration::FindNumaNodes(int* maxNodes)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* function name:FindNumProcessors
|
||||
function purpose:Discover the number of processors in the system and associate these processors with the numa nodes on which they reside.
|
||||
input:CpuNodeMap,CpuMap.maxCoresPerNode
|
||||
output:Whether the configuration is successful?
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/09/20 17:33:02
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
bool MOTConfiguration::FindNumProcessors(uint16_t* maxCoresPerNode, CpuNodeMap* cpuNodeMapper, CpuMap* cpuOsMapper)
|
||||
{
|
||||
{ //Get the number of processors
|
||||
int nprocs = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (nprocs <= 0) {
|
||||
MOT_LOG(LogLevel::LL_ERROR, "Invalid system configuration _SC_NPROCESSORS_ONLN=%d", nprocs);
|
||||
|
|
@ -386,26 +417,27 @@ bool MOTConfiguration::FindNumProcessors(uint16_t* maxCoresPerNode, CpuNodeMap*
|
|||
uint16_t cpusPerNode[MAX_NUMA_NODES];
|
||||
errno_t erc = memset_s(&(cpusPerNode[0]), sizeof(cpusPerNode), 0, sizeof(cpusPerNode));
|
||||
securec_check(erc, "\0", "\0");
|
||||
//Iterate through each processor and associate its numa node
|
||||
for (int i = 0; i < nprocs; i++) {
|
||||
int node = MotSysNumaGetNode(i);
|
||||
if (node < 0) {
|
||||
MOT_LOG_ERROR("Invalid NUMA configuration numa_node_of_cpu(%d) => %d", i, node);
|
||||
return false;
|
||||
}
|
||||
if ((unsigned int)node >= MAX_NUMA_NODES) {
|
||||
if (node >= MAX_NUMA_NODES) {
|
||||
MOT_LOG_ERROR(
|
||||
"CPU %d is located in node %d, while MAX_NUMA_NODES=%u - cannot proceed", i, node, MAX_NUMA_NODES);
|
||||
"CPU %d is located in node %d, while MAX_NUMA_NODES=%d - cannot proceed", i, node, MAX_NUMA_NODES);
|
||||
return false;
|
||||
}
|
||||
cpusPerNode[node]++;
|
||||
(*cpuNodeMapper)[i] = node;
|
||||
(*cpuOsMapper)[node].insert(i);
|
||||
(void)(*cpuOsMapper)[node].insert(i);
|
||||
}
|
||||
|
||||
// dynamically calculate number of CPU cores per NUMA node instead of hard-coded config value
|
||||
if (maxCoresPerNode != nullptr) {
|
||||
*maxCoresPerNode = 0;
|
||||
for (unsigned int j = 0; j < MAX_NUMA_NODES; j++) {
|
||||
for (int j = 0; j < MAX_NUMA_NODES; j++) {
|
||||
if (cpusPerNode[j] > *maxCoresPerNode) {
|
||||
*maxCoresPerNode = cpusPerNode[j];
|
||||
}
|
||||
|
|
@ -414,22 +446,34 @@ bool MOTConfiguration::FindNumProcessors(uint16_t* maxCoresPerNode, CpuNodeMap*
|
|||
|
||||
return true;
|
||||
}
|
||||
/* function name:SetMaskToAllCoresinNumaSocketByCoreId
|
||||
function purpose:Find all the cores of the NUMA node where the given core ID is located,and update the mask to represent these cores
|
||||
input:cpu_set, core id
|
||||
output:none
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/09/20 17:22:14
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
|
||||
void MOTConfiguration::SetMaskToAllCoresinNumaSocket(cpu_set_t& mask, uint64_t threadId)
|
||||
void MOTConfiguration::SetMaskToAllCoresinNumaSocketByCoreId(cpu_set_t& mask, int coreId)
|
||||
{
|
||||
int nodeId = GetCpuNode(threadId);
|
||||
// Get the NUMA node ID of the given core ID
|
||||
int nodeId = GetCpuNode(coreId);
|
||||
// Get all cores on the node from the map based on the node ID
|
||||
auto nodeMap = m_osCpuMap[nodeId];
|
||||
for (auto it = nodeMap.begin(); it != nodeMap.end(); ++it) {
|
||||
for (auto it = nodeMap.begin(); it != nodeMap.end(); (void)++it) {
|
||||
//Set the core in the CPU collection mask (that is, mark the core as available)
|
||||
if (MotSysNumaCpuAllowed(*it)) {
|
||||
CPU_SET(*it, &mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MOTConfiguration::SetMaskToAllCoresinNumaSocket2(cpu_set_t& mask, int nodeId)
|
||||
void MOTConfiguration::SetMaskToAllCoresinNumaSocketByNodeId(cpu_set_t& mask, int nodeId)
|
||||
{
|
||||
auto nodeMap = m_osCpuMap[nodeId];
|
||||
for (auto it = nodeMap.begin(); it != nodeMap.end(); ++it) {
|
||||
for (auto it = nodeMap.begin(); it != nodeMap.end(); (void)++it) {
|
||||
if (MotSysNumaCpuAllowed(*it)) {
|
||||
CPU_SET(*it, &mask);
|
||||
}
|
||||
|
|
@ -440,7 +484,6 @@ MOTConfiguration::MOTConfiguration()
|
|||
: m_enableRedoLog(DEFAULT_ENABLE_REDO_LOG),
|
||||
m_loggerType(DEFAULT_LOGGER_TYPE),
|
||||
m_redoLogHandlerType(DEFAULT_REDO_LOG_HANDLER_TYPE),
|
||||
m_asyncRedoLogBufferArrayCount(DEFAULT_ASYNC_REDO_LOG_BUFFER_ARRAY_COUNT),
|
||||
m_enableGroupCommit(DEFAULT_ENABLE_GROUP_COMMIT),
|
||||
m_groupCommitSize(DEFAULT_GROUP_COMMIT_SIZE),
|
||||
m_groupCommitTimeoutUSec(DEFAULT_GROUP_COMMIT_TIMEOUT_USEC),
|
||||
|
|
@ -449,6 +492,9 @@ MOTConfiguration::MOTConfiguration()
|
|||
m_checkpointDir(DEFAULT_CHECKPOINT_DIR),
|
||||
m_checkpointSegThreshold(DEFAULT_CHECKPOINT_SEGSIZE_BYTES),
|
||||
m_checkpointWorkers(DEFAULT_CHECKPOINT_WORKERS),
|
||||
m_recoveryMode(DEFAULT_RECOVERY_MODE),
|
||||
m_parallelRecoveryWorkers(DEFAULT_PARALLEL_RECOVERY_WORKERS),
|
||||
m_parallelRecoveryQueueSize(DEFAULT_PARALLEL_RECOVERY_QUEUE_SIZE),
|
||||
m_checkpointRecoveryWorkers(DEFAULT_CHECKPOINT_RECOVERY_WORKERS),
|
||||
m_abortBufferEnable(true),
|
||||
m_preAbort(true),
|
||||
|
|
@ -492,18 +538,23 @@ MOTConfiguration::MOTConfiguration()
|
|||
m_sessionLargeBufferStoreSizeMB(DEFAULT_SESSION_LARGE_BUFFER_STORE_SIZE_MB),
|
||||
m_sessionLargeBufferStoreMaxObjectSizeMB(DEFAULT_SESSION_LARGE_BUFFER_STORE_MAX_OBJECT_SIZE_MB),
|
||||
m_sessionMaxHugeObjectSizeMB(DEFAULT_SESSION_MAX_HUGE_OBJECT_SIZE_MB),
|
||||
m_gcEnable(DEFAULT_GC_ENABLE),
|
||||
m_gcReclaimThresholdBytes(DEFAULT_GC_RECLAIM_THRESHOLD_BYTES),
|
||||
m_gcReclaimBatchSize(DEFAULT_GC_RECLAIM_BATCH_SIZE),
|
||||
m_gcHighReclaimThresholdBytes(DEFAULT_GC_HIGH_RECLAIM_THRESHOLD_BYTES),
|
||||
m_enableCodegen(DEFAULT_ENABLE_MOT_CODEGEN),
|
||||
m_forcePseudoCodegen(DEFAULT_FORCE_MOT_PSEUDO_CODEGEN),
|
||||
m_enableQueryCodegen(DEFAULT_ENABLE_MOT_QUERY_CODEGEN),
|
||||
m_enableSPCodegen(DEFAULT_ENABLE_MOT_SP_CODEGEN),
|
||||
m_spCodegenAllowed(DEFAULT_MOT_SP_CODEGEN_ALLOWED),
|
||||
m_spCodegenProhibited(DEFAULT_MOT_SP_CODEGEN_PROHIBITED),
|
||||
m_pureSPCodegen(DEFAULT_MOT_PURE_SP_CODEGEN),
|
||||
m_enableCodegenPrint(DEFAULT_ENABLE_MOT_CODEGEN_PRINT),
|
||||
m_codegenLimit(DEFAULT_MOT_CODEGEN_LIMIT),
|
||||
m_enableCodegenProfile(DEFAULT_ENABLE_MOT_CODEGEN_PROFILE),
|
||||
m_allowIndexOnNullableColumn(DEFAULT_ALLOW_INDEX_ON_NULLABLE_COLUMN),
|
||||
m_indexTreeFlavor(DEFAULT_INDEX_TREE_FLAVOR),
|
||||
m_configMonitorPeriodSeconds(DEFAULT_CFG_MONITOR_PERIOD_SECONDS),
|
||||
m_runInternalConsistencyValidation(DEFAULT_RUN_INTERNAL_CONSISTENCY_VALIDATION),
|
||||
m_runInternalMvccConsistencyValidation(DEFAULT_RUN_INTERNAL_CONSISTENCY_VALIDATION),
|
||||
m_totalMemoryMb(DEFAULT_TOTAL_MEMORY_MB),
|
||||
m_suppressLog(0),
|
||||
m_loadExtraParams(false)
|
||||
|
|
@ -516,7 +567,7 @@ void MOTConfiguration::Initialize()
|
|||
MotSysNumaInit();
|
||||
int numa = DEFAULT_NUMA_NODES;
|
||||
if (FindNumaNodes(&numa)) {
|
||||
m_numaNodes = (uint16_t)numa;
|
||||
m_numaNodes = static_cast<uint16_t>(numa);
|
||||
} else {
|
||||
MOT_LOG_WARN("Failed to infer the number of NUMA nodes on current machine, defaulting to %d", numa);
|
||||
m_numaAvailable = false;
|
||||
|
|
@ -526,7 +577,7 @@ void MOTConfiguration::Initialize()
|
|||
if (FindNumProcessors(&cores, &m_cpuNodeMapper, &m_osCpuMap)) {
|
||||
m_coresPerCpu = cores;
|
||||
} else {
|
||||
MOT_LOG_WARN("Failed to infer the number of cores on the current machine, defaulting to %u", (unsigned)cores);
|
||||
MOT_LOG_WARN("Failed to infer the number of cores on the current machine, defaulting to %" PRIu16, cores);
|
||||
m_numaAvailable = false;
|
||||
}
|
||||
|
||||
|
|
@ -546,7 +597,6 @@ bool MOTConfiguration::SetFlag(const std::string& name, const std::string& value
|
|||
if (ParseBool(name, "enable_redo_log", value, &m_enableRedoLog)) {
|
||||
} else if (ParseLoggerType(name, "logger_type", value, &m_loggerType)) {
|
||||
} else if (ParseRedoLogHandlerType(name, "redo_log_handler_type", value, &m_redoLogHandlerType)) {
|
||||
} else if (ParseUint32(name, "async_log_buffer_count", value, &m_asyncRedoLogBufferArrayCount)) {
|
||||
} else if (ParseBool(name, "enable_group_commit", value, &m_enableGroupCommit)) {
|
||||
} else if (ParseUint64(name, "group_commit_size", value, &m_groupCommitSize)) {
|
||||
} else if (ParseUint64(name, "group_commit_timeout_usec", value, &m_groupCommitTimeoutUSec)) {
|
||||
|
|
@ -556,6 +606,9 @@ bool MOTConfiguration::SetFlag(const std::string& name, const std::string& value
|
|||
} else if (ParseUint64(name, "checkpoint_segsize", value, &m_checkpointSegThreshold)) {
|
||||
} else if (ParseUint32(name, "checkpoint_workers", value, &m_checkpointWorkers)) {
|
||||
} else if (ParseUint32(name, "checkpoint_recovery_workers", value, &m_checkpointRecoveryWorkers)) {
|
||||
} else if (ParseRecoveryMode(name, "recovery_mode", value, &m_recoveryMode)) {
|
||||
} else if (ParseUint32(name, "parallel_recovery_workers", value, &m_parallelRecoveryWorkers)) {
|
||||
} else if (ParseUint32(name, "parallel_recovery_queue_size", value, &m_parallelRecoveryQueueSize)) {
|
||||
} else if (ParseBool(name, "abort_buffer_enable", value, &m_abortBufferEnable)) {
|
||||
} else if (ParseBool(name, "pre_abort", value, &m_preAbort)) {
|
||||
} else if (ParseValidation(name, "validation_lock", value, &m_validationLock)) {
|
||||
|
|
@ -598,9 +651,11 @@ bool MOTConfiguration::SetFlag(const std::string& name, const std::string& value
|
|||
&m_sessionLargeBufferStoreMaxObjectSizeMB)) {
|
||||
} else if (ParseUint64(name, "session_max_huge_object_size_mb", value, &m_sessionMaxHugeObjectSizeMB)) {
|
||||
} else if (ParseBool(name, "enable_mot_codegen", value, &m_enableCodegen)) {
|
||||
} else if (ParseBool(name, "force_mot_pseudo_codegen", value, &m_forcePseudoCodegen)) {
|
||||
} else if (ParseBool(name, "enable_mot_query_codegen", value, &m_enableQueryCodegen)) {
|
||||
} else if (ParseBool(name, "enable_mot_sp_codegen", value, &m_enableSPCodegen)) {
|
||||
} else if (ParseBool(name, "enable_mot_codegen_print", value, &m_enableCodegenPrint)) {
|
||||
} else if (ParseUint32(name, "mot_codegen_limit", value, &m_codegenLimit)) {
|
||||
} else if (ParseBool(name, "enable_mot_codegen_profile", value, &m_enableCodegenProfile)) {
|
||||
} else if (ParseBool(name, "allow_index_on_nullable_column", value, &m_allowIndexOnNullableColumn)) {
|
||||
} else if (ParseIndexTreeFlavor(name, "index_tree_flavor", value, &m_indexTreeFlavor)) {
|
||||
} else if (ParseUint64(name, "config_monitor_period_seconds", value, &m_configMonitorPeriodSeconds)) {
|
||||
|
|
@ -625,18 +680,18 @@ int MOTConfiguration::GetCpuNode(int cpu) const
|
|||
return (itr != m_cpuNodeMapper.end()) ? itr->second : -1;
|
||||
}
|
||||
|
||||
uint16_t MOTConfiguration::GetCoreByConnidFP(uint16_t cpu) const
|
||||
int MOTConfiguration::GetCoreByConnidFP(int cpu) const
|
||||
{
|
||||
uint16_t numOfRealCores = (IsHyperThread() == true) ? m_coresPerCpu / 2 : m_coresPerCpu; // 2 is for HyperThread
|
||||
int numOfRealCores = (IsHyperThread()) ? m_coresPerCpu / 2 : m_coresPerCpu; // 2 is for HyperThread
|
||||
// Lets pin physical first
|
||||
// cpu is already modulu of(numaNodes*num_cores)
|
||||
if (cpu < m_numaNodes * numOfRealCores) {
|
||||
cpu = cpu % (m_numaNodes * numOfRealCores);
|
||||
uint16_t coreIndex = cpu % numOfRealCores;
|
||||
uint16_t numaId = cpu / numOfRealCores;
|
||||
// cpu is already modulo of (numaNodes * num_cores)
|
||||
if (cpu < ((int)m_numaNodes * numOfRealCores)) {
|
||||
cpu = cpu % ((int)m_numaNodes * numOfRealCores);
|
||||
int coreIndex = cpu % numOfRealCores;
|
||||
int numaId = cpu / numOfRealCores;
|
||||
int counter = 0;
|
||||
auto coreSet = m_osCpuMap.find(numaId);
|
||||
for (auto it = coreSet->second.begin(); it != coreSet->second.end(); ++it) {
|
||||
for (auto it = coreSet->second.begin(); it != coreSet->second.end(); (void)++it) {
|
||||
if (counter == coreIndex) {
|
||||
return *it;
|
||||
}
|
||||
|
|
@ -651,10 +706,9 @@ uint16_t MOTConfiguration::GetCoreByConnidFP(uint16_t cpu) const
|
|||
|
||||
int MOTConfiguration::GetMappedCore(int logicId) const
|
||||
{
|
||||
|
||||
int counter = 0;
|
||||
for (auto it = m_osCpuMap.begin(); it != m_osCpuMap.end(); ++it) {
|
||||
for (auto it2 = (*it).second.begin(); it2 != (*it).second.end(); ++it2) {
|
||||
for (auto it = m_osCpuMap.begin(); it != m_osCpuMap.end(); (void)++it) {
|
||||
for (auto it2 = (*it).second.begin(); it2 != (*it).second.end(); (void)++it2) {
|
||||
if (counter == logicId) {
|
||||
return *it2;
|
||||
}
|
||||
|
|
@ -664,6 +718,22 @@ int MOTConfiguration::GetMappedCore(int logicId) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
int MOTConfiguration::GetCoreFromNumaNodeByIndex(int numaId, int logicId) const
|
||||
{
|
||||
auto coreSet = m_osCpuMap.find(numaId);
|
||||
if (coreSet != m_osCpuMap.end()) {
|
||||
int counter = 0;
|
||||
for (auto it = coreSet->second.begin(); it != coreSet->second.end(); (void)++it) {
|
||||
if (counter == logicId) {
|
||||
return *it;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
return INVALID_CPU_ID;
|
||||
}
|
||||
|
||||
#define UPDATE_BOOL_CFG(var, cfgPath, defaultValue) \
|
||||
UpdateBoolConfigItem(var, cfg->GetConfigValue(cfgPath, defaultValue, m_suppressLog == 0), cfgPath)
|
||||
|
||||
|
|
@ -887,6 +957,9 @@ void MOTConfiguration::LoadConfig()
|
|||
MOT_LOG_TRACE("Loading main configuration");
|
||||
const LayeredConfigTree* cfg = ConfigManager::GetInstance().GetLayeredConfigTree();
|
||||
|
||||
// load component log levels so we can enable traces in this logger
|
||||
UpdateComponentLogLevel();
|
||||
|
||||
// logger configuration
|
||||
if (m_loadExtraParams) {
|
||||
UPDATE_BOOL_CFG(m_enableRedoLog, "enable_redo_log", DEFAULT_ENABLE_REDO_LOG);
|
||||
|
|
@ -897,11 +970,6 @@ void MOTConfiguration::LoadConfig()
|
|||
// overridden by the external configuration loader GaussdbConfigLoader (so in effect whatever is defined in
|
||||
// mot.conf is discarded). See GaussdbConfigLoader::ConfigureRedoLogHandler() for more details.
|
||||
UPDATE_USER_CFG(m_redoLogHandlerType, "redo_log_handler_type", DEFAULT_REDO_LOG_HANDLER_TYPE);
|
||||
UPDATE_INT_CFG(m_asyncRedoLogBufferArrayCount,
|
||||
"async_log_buffer_count",
|
||||
DEFAULT_ASYNC_REDO_LOG_BUFFER_ARRAY_COUNT,
|
||||
MIN_ASYNC_REDO_LOG_BUFFER_ARRAY_COUNT,
|
||||
MAX_ASYNC_REDO_LOG_BUFFER_ARRAY_COUNT);
|
||||
|
||||
// commit configuration
|
||||
UPDATE_BOOL_CFG(m_enableGroupCommit, "enable_group_commit", DEFAULT_ENABLE_GROUP_COMMIT);
|
||||
|
|
@ -922,7 +990,7 @@ void MOTConfiguration::LoadConfig()
|
|||
UPDATE_BOOL_CFG(m_enableCheckpoint, "enable_checkpoint", DEFAULT_ENABLE_CHECKPOINT);
|
||||
}
|
||||
|
||||
if (!m_enableCheckpoint && m_enableRedoLog) {
|
||||
if (!m_enableCheckpoint && !m_enableRedoLog) {
|
||||
if (m_suppressLog == 0) {
|
||||
MOT_LOG_WARN("Disabling redo_log forcibly as the checkpoint is disabled");
|
||||
}
|
||||
|
|
@ -949,6 +1017,34 @@ void MOTConfiguration::LoadConfig()
|
|||
MIN_CHECKPOINT_RECOVERY_WORKERS,
|
||||
MAX_CHECKPOINT_RECOVERY_WORKERS);
|
||||
|
||||
if (m_loadExtraParams) {
|
||||
UPDATE_USER_CFG(m_recoveryMode, "recovery_mode", DEFAULT_RECOVERY_MODE);
|
||||
}
|
||||
|
||||
UPDATE_INT_CFG(m_parallelRecoveryWorkers,
|
||||
"parallel_recovery_workers",
|
||||
DEFAULT_PARALLEL_RECOVERY_WORKERS,
|
||||
MIN_PARALLEL_RECOVERY_WORKERS,
|
||||
MAX_PARALLEL_RECOVERY_WORKERS);
|
||||
|
||||
UPDATE_INT_CFG(m_parallelRecoveryQueueSize,
|
||||
"parallel_recovery_queue_size",
|
||||
DEFAULT_PARALLEL_RECOVERY_QUEUE_SIZE,
|
||||
MIN_PARALLEL_RECOVERY_QUEUE_SIZE,
|
||||
MAX_PARALLEL_RECOVERY_QUEUE_SIZE);
|
||||
|
||||
if (m_parallelRecoveryQueueSize < m_parallelRecoveryWorkers) {
|
||||
if (m_suppressLog == 0) {
|
||||
MOT_LOG_WARN("Invalid recovery configuration: parallel_recovery_queue_size (%" PRIu32 ") is lesser than "
|
||||
"parallel_recovery_workers (%" PRIu32 "), changing parallel_recovery_queue_size to (%" PRIu32
|
||||
")",
|
||||
m_parallelRecoveryQueueSize,
|
||||
m_parallelRecoveryWorkers,
|
||||
m_parallelRecoveryWorkers);
|
||||
}
|
||||
m_parallelRecoveryQueueSize = m_parallelRecoveryWorkers; // At least one transaction per processor
|
||||
}
|
||||
|
||||
// Tx configuration - not configurable yet
|
||||
if (m_loadExtraParams) {
|
||||
UPDATE_BOOL_CFG(m_abortBufferEnable, "tx_abort_buffers_enable", true);
|
||||
|
|
@ -983,7 +1079,7 @@ void MOTConfiguration::LoadConfig()
|
|||
|
||||
// log configuration
|
||||
UPDATE_USER_CFG(m_logLevel, "log_level", DEFAULT_LOG_LEVEL);
|
||||
SetGlobalLogLevel(m_logLevel);
|
||||
(void)SetGlobalLogLevel(m_logLevel);
|
||||
if (m_loadExtraParams) {
|
||||
UPDATE_USER_CFG(m_numaErrorsLogLevel, "numa_errors_log_level", DEFAULT_NUMA_ERRORS_LOG_LEVEL);
|
||||
UPDATE_USER_CFG(m_numaWarningsLogLevel, "numa_warnings_log_level", DEFAULT_NUMA_WARNINGS_LOG_LEVEL);
|
||||
|
|
@ -994,7 +1090,6 @@ void MOTConfiguration::LoadConfig()
|
|||
LoadMemConfig();
|
||||
|
||||
// GC configuration
|
||||
UPDATE_BOOL_CFG(m_gcEnable, "enable_gc", DEFAULT_GC_ENABLE);
|
||||
UPDATE_ABS_MEM_CFG(m_gcReclaimThresholdBytes,
|
||||
"reclaim_threshold",
|
||||
DEFAULT_GC_RECLAIM_THRESHOLD,
|
||||
|
|
@ -1015,10 +1110,19 @@ void MOTConfiguration::LoadConfig()
|
|||
|
||||
// JIT configuration
|
||||
UPDATE_BOOL_CFG(m_enableCodegen, "enable_mot_codegen", DEFAULT_ENABLE_MOT_CODEGEN);
|
||||
UPDATE_BOOL_CFG(m_forcePseudoCodegen, "force_mot_pseudo_codegen", DEFAULT_FORCE_MOT_PSEUDO_CODEGEN);
|
||||
UPDATE_BOOL_CFG(m_enableQueryCodegen, "enable_mot_query_codegen", DEFAULT_ENABLE_MOT_QUERY_CODEGEN);
|
||||
UPDATE_BOOL_CFG(m_enableSPCodegen, "enable_mot_sp_codegen", DEFAULT_ENABLE_MOT_SP_CODEGEN);
|
||||
|
||||
if (m_loadExtraParams) {
|
||||
UPDATE_STRING_CFG(m_spCodegenAllowed, "mot_sp_codegen_allowed", DEFAULT_MOT_SP_CODEGEN_ALLOWED);
|
||||
UPDATE_STRING_CFG(m_spCodegenProhibited, "mot_sp_codegen_prohibited", DEFAULT_MOT_SP_CODEGEN_PROHIBITED);
|
||||
UPDATE_STRING_CFG(m_pureSPCodegen, "mot_pure_sp_codegen", DEFAULT_MOT_PURE_SP_CODEGEN);
|
||||
}
|
||||
|
||||
UPDATE_BOOL_CFG(m_enableCodegenPrint, "enable_mot_codegen_print", DEFAULT_ENABLE_MOT_CODEGEN_PRINT);
|
||||
UPDATE_INT_CFG(
|
||||
m_codegenLimit, "mot_codegen_limit", DEFAULT_MOT_CODEGEN_LIMIT, MIN_MOT_CODEGEN_LIMIT, MAX_MOT_CODEGEN_LIMIT);
|
||||
UPDATE_BOOL_CFG(m_enableCodegenProfile, "enable_mot_codegen_profile", DEFAULT_ENABLE_MOT_CODEGEN_PROFILE);
|
||||
|
||||
// storage configuration
|
||||
if (m_loadExtraParams) {
|
||||
|
|
@ -1038,11 +1142,11 @@ void MOTConfiguration::LoadConfig()
|
|||
UPDATE_BOOL_CFG(m_runInternalConsistencyValidation,
|
||||
"internal_consistency_validation",
|
||||
DEFAULT_RUN_INTERNAL_CONSISTENCY_VALIDATION);
|
||||
UPDATE_BOOL_CFG(m_runInternalMvccConsistencyValidation,
|
||||
"internal_mvcc_consistency_validation",
|
||||
DEFAULT_RUN_INTERNAL_CONSISTENCY_VALIDATION);
|
||||
}
|
||||
|
||||
// load component log levels
|
||||
UpdateComponentLogLevel();
|
||||
|
||||
MOT_LOG_TRACE("Main configuration loaded");
|
||||
}
|
||||
|
||||
|
|
@ -1083,7 +1187,7 @@ void MOTConfiguration::UpdateMemConfigItem(uint64_t& oldValue, const char* name,
|
|||
UpdateIntConfigItem(oldValue, defaultValueBytes / scale, name, lowerBound, upperBound);
|
||||
} else {
|
||||
// now we carefully examine the value type
|
||||
ConfigValue* cfgValue = (ConfigValue*)cfgItem;
|
||||
const ConfigValue* cfgValue = (const ConfigValue*)cfgItem;
|
||||
if (cfgValue->IsIntegral()) {
|
||||
// only a number was specified, so it is interpreted as bytes
|
||||
uint64_t memoryValueBytes =
|
||||
|
|
@ -1155,7 +1259,7 @@ void MOTConfiguration::UpdateTimeConfigItem(uint64_t& oldValue, const char* name
|
|||
UpdateIntConfigItem(oldValue, defaultValueUSecs / scale, name, lowerBound, upperBound);
|
||||
} else {
|
||||
// now we carefully examine the value type
|
||||
ConfigValue* cfgValue = (ConfigValue*)cfgItem;
|
||||
const ConfigValue* cfgValue = (const ConfigValue*)cfgItem;
|
||||
if (cfgValue->IsIntegral()) {
|
||||
// only a number was specified, so it is interpreted as micro-seconds
|
||||
uint64_t timeValueUSecs = cfg->GetIntegerConfigValue<uint64_t>(name, defaultValueUSecs, m_suppressLog == 0);
|
||||
|
|
@ -1212,7 +1316,7 @@ void MOTConfiguration::UpdateComponentLogLevel()
|
|||
componentName.c_str(),
|
||||
TypeFormatter<LogLevel>::ToString(componentLevel, logLevelStr));
|
||||
}
|
||||
SetLogComponentLogLevel(componentName.c_str(), componentLevel);
|
||||
(void)SetLogComponentLogLevel(componentName.c_str(), componentLevel);
|
||||
}
|
||||
|
||||
// all configuration values are logger configuration pairs (loggerName=log_level)
|
||||
|
|
@ -1238,7 +1342,7 @@ void MOTConfiguration::UpdateComponentLogLevel()
|
|||
componentName.c_str(),
|
||||
TypeFormatter<LogLevel>::ToString(loggerLevel, logLevelStr));
|
||||
}
|
||||
SetLoggerLogLevel(componentName.c_str(), loggerName.c_str(), loggerLevel);
|
||||
(void)SetLoggerLogLevel(componentName.c_str(), loggerName.c_str(), loggerLevel);
|
||||
}
|
||||
++loggerItr;
|
||||
}
|
||||
|
|
@ -1278,12 +1382,16 @@ int MOTConfiguration::ParseMemoryPercent(const char* memoryValue)
|
|||
MOT_LOG_WARN("Invalid memory value format: %s (percentage value not in the range [0, 100])", memoryValue);
|
||||
} else {
|
||||
mot_string extra(endptr + 1);
|
||||
extra.trim();
|
||||
if (extra.length() != 0) {
|
||||
MOT_LOG_WARN("Invalid memory value format: %s (trailing characters after %%)", memoryValue);
|
||||
if (!extra.is_valid()) {
|
||||
MOT_LOG_ERROR("Failed to allocate memory string: %s", endptr + 1);
|
||||
} else {
|
||||
MOT_LOG_TRACE("Parsed percentage: %d%%", percent);
|
||||
result = percent;
|
||||
extra.trim();
|
||||
if (extra.length() != 0) {
|
||||
MOT_LOG_WARN("Invalid memory value format: %s (trailing characters after %%)", memoryValue);
|
||||
} else {
|
||||
MOT_LOG_TRACE("Parsed percentage: %d%%", percent);
|
||||
result = percent;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
|
@ -1314,7 +1422,7 @@ uint64_t MOTConfiguration::ParseMemoryPercentTotal(const char* memoryValue, uint
|
|||
memoryValueBytes = m_totalMemoryMb * MEGA_BYTE * percent / 100;
|
||||
if (m_suppressLog == 0) {
|
||||
MOT_LOG_INFO(
|
||||
"Loaded %s: %d%% from total = %" PRIu64 " MB", cfgPath, percent, memoryValueBytes / 1024ul / 1024ul);
|
||||
"Loaded %s: %d%% from total = %" PRIu64 " MB", cfgPath, percent, (memoryValueBytes / 1024ul) / 1024ul);
|
||||
}
|
||||
} else {
|
||||
MOT_LOG_WARN("Invalid %s memory format: illegal percent specification", cfgPath);
|
||||
|
|
@ -1330,39 +1438,40 @@ uint64_t MOTConfiguration::ParseMemoryUnit(const char* memoryValue, uint64_t def
|
|||
if (endptr == memoryValue) {
|
||||
MOT_LOG_WARN("Invalid %s memory value format: %s (expecting value digits)", cfgPath, memoryValue);
|
||||
} else if (*endptr == 0) {
|
||||
MOT_LOG_TRACE("Missing %s memory value units: bytes assumed", cfgPath, memoryValue);
|
||||
memoryValueBytes = value;
|
||||
MOT_LOG_TRACE("Missing %s memory value units: %s (kilobytes assumed)", cfgPath, memoryValue);
|
||||
memoryValueBytes = ((uint64_t)value) * 1024;
|
||||
} else {
|
||||
// get unit type and convert to mega-bytes
|
||||
mot_string suffix(endptr);
|
||||
suffix.trim();
|
||||
if (suffix.compare_no_case("TB") == 0) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u TB", cfgPath, value);
|
||||
memoryValueBytes = ((uint64_t)value) * 1024ull * 1024ull * 1024ull * 1024ull;
|
||||
} else if (suffix.compare_no_case("GB") == 0) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u GB", cfgPath, value);
|
||||
memoryValueBytes = ((uint64_t)value) * 1024ull * 1024ull * 1024ull;
|
||||
} else if (suffix.compare_no_case("MB") == 0) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u MB", cfgPath, value);
|
||||
memoryValueBytes = ((uint64_t)value) * 1024ull * 1024ull;
|
||||
} else if (suffix.compare_no_case("KB") == 0) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u KB", cfgPath, value);
|
||||
memoryValueBytes = ((uint64_t)value) * 1024;
|
||||
} else if (suffix.compare_no_case("bytes") == 0) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u bytes", cfgPath, value);
|
||||
memoryValueBytes = value;
|
||||
if (!suffix.is_valid()) {
|
||||
MOT_LOG_ERROR("Failed to allocate memory string: %s", endptr);
|
||||
} else {
|
||||
MOT_LOG_WARN("Invalid %s memory value format: %s (invalid unit specifier '%s' - should be one of TB, GB, "
|
||||
"MB, KB or bytes)",
|
||||
cfgPath,
|
||||
memoryValue,
|
||||
suffix.c_str());
|
||||
suffix.trim();
|
||||
if (suffix.compare_no_case("TB") == 0) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u TB", cfgPath, value);
|
||||
memoryValueBytes = ((uint64_t)value) * 1024ull * 1024ull * 1024ull * 1024ull;
|
||||
} else if (suffix.compare_no_case("GB") == 0) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u GB", cfgPath, value);
|
||||
memoryValueBytes = ((uint64_t)value) * 1024ull * 1024ull * 1024ull;
|
||||
} else if (suffix.compare_no_case("MB") == 0) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u MB", cfgPath, value);
|
||||
memoryValueBytes = ((uint64_t)value) * 1024ull * 1024ull;
|
||||
} else if (suffix.compare_no_case("KB") == 0) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u KB", cfgPath, value);
|
||||
memoryValueBytes = ((uint64_t)value) * 1024;
|
||||
} else {
|
||||
MOT_LOG_WARN("Invalid %s memory value format: %s (invalid unit specifier '%s' - should be one of TB, "
|
||||
"GB, MB or KB)",
|
||||
cfgPath,
|
||||
memoryValue,
|
||||
suffix.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
return memoryValueBytes;
|
||||
}
|
||||
|
||||
static inline bool IsTimeUnitDays(mot_string& suffix)
|
||||
static inline bool IsTimeUnitDays(const mot_string& suffix)
|
||||
{
|
||||
if ((suffix.compare_no_case("d") == 0) || (suffix.compare_no_case("days") == 0) ||
|
||||
(suffix.compare_no_case("day") == 0)) {
|
||||
|
|
@ -1371,7 +1480,7 @@ static inline bool IsTimeUnitDays(mot_string& suffix)
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline bool IsTimeUnitHours(mot_string& suffix)
|
||||
static inline bool IsTimeUnitHours(const mot_string& suffix)
|
||||
{
|
||||
if ((suffix.compare_no_case("h") == 0) || (suffix.compare_no_case("hours") == 0) ||
|
||||
(suffix.compare_no_case("hour") == 0)) {
|
||||
|
|
@ -1380,7 +1489,7 @@ static inline bool IsTimeUnitHours(mot_string& suffix)
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline bool IsTimeUnitMinutes(mot_string& suffix)
|
||||
static inline bool IsTimeUnitMinutes(const mot_string& suffix)
|
||||
{
|
||||
if ((suffix.compare_no_case("m") == 0) || (suffix.compare_no_case("mins") == 0) ||
|
||||
(suffix.compare_no_case("minutes") == 0) || (suffix.compare_no_case("min") == 0) ||
|
||||
|
|
@ -1390,7 +1499,7 @@ static inline bool IsTimeUnitMinutes(mot_string& suffix)
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline bool IsTimeUnitSeconds(mot_string& suffix)
|
||||
static inline bool IsTimeUnitSeconds(const mot_string& suffix)
|
||||
{
|
||||
if ((suffix.compare_no_case("s") == 0) || (suffix.compare_no_case("secs") == 0) ||
|
||||
(suffix.compare_no_case("seconds") == 0) || (suffix.compare_no_case("sec") == 0) ||
|
||||
|
|
@ -1400,7 +1509,7 @@ static inline bool IsTimeUnitSeconds(mot_string& suffix)
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline bool IsTimeUnitMilliSeconds(mot_string& suffix)
|
||||
static inline bool IsTimeUnitMilliSeconds(const mot_string& suffix)
|
||||
{
|
||||
if ((suffix.compare_no_case("ms") == 0) || (suffix.compare_no_case("millis") == 0) ||
|
||||
(suffix.compare_no_case("milliseconds") == 0) || (suffix.compare_no_case("milli") == 0) ||
|
||||
|
|
@ -1410,7 +1519,7 @@ static inline bool IsTimeUnitMilliSeconds(mot_string& suffix)
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline bool IsTimeUnitMicroSeconds(mot_string& suffix)
|
||||
static inline bool IsTimeUnitMicroSeconds(const mot_string& suffix)
|
||||
{
|
||||
if ((suffix.compare_no_case("us") == 0) || (suffix.compare_no_case("micros") == 0) ||
|
||||
(suffix.compare_no_case("microseconds") == 0) || (suffix.compare_no_case("micro") == 0) ||
|
||||
|
|
@ -1428,35 +1537,37 @@ uint64_t MOTConfiguration::ParseTimeValueMicros(const char* timeValue, uint64_t
|
|||
if (endptr == timeValue) {
|
||||
MOT_LOG_WARN("Invalid %s time value format: %s (expecting value digits)", cfgPath, timeValue);
|
||||
} else if (*endptr == 0) {
|
||||
MOT_LOG_WARN("Invalid %s time value format: %s (expecting unit type after value)", cfgPath, timeValue);
|
||||
MOT_LOG_TRACE("Missing %s time value units: %s (milliseconds assumed)", cfgPath, timeValue);
|
||||
timeValueMicros = ((uint64_t)value) * 1000ull;
|
||||
} else {
|
||||
// get unit type and convert to micro-seconds
|
||||
mot_string suffix(endptr);
|
||||
suffix.trim();
|
||||
if (IsTimeUnitDays(suffix)) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u days", cfgPath, value);
|
||||
timeValueMicros = ((uint64_t)value) * 24ull * 60ull * 60ull * 1000ull * 1000ull;
|
||||
} else if (IsTimeUnitHours(suffix)) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u hours", cfgPath, value);
|
||||
timeValueMicros = ((uint64_t)value) * 60ull * 60ull * 1000ull * 1000ull;
|
||||
} else if (IsTimeUnitMinutes(suffix)) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u minutes", cfgPath, value);
|
||||
timeValueMicros = ((uint64_t)value) * 60ull * 1000ull * 1000ull;
|
||||
} else if (IsTimeUnitSeconds(suffix)) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u seconds", cfgPath, value);
|
||||
timeValueMicros = ((uint64_t)value) * 1000ull * 1000ull;
|
||||
} else if (IsTimeUnitMilliSeconds(suffix)) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u milli-seconds", cfgPath, value);
|
||||
timeValueMicros = ((uint64_t)value) * 1000ull;
|
||||
} else if (IsTimeUnitMicroSeconds(suffix)) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u micro-seconds", cfgPath, value);
|
||||
timeValueMicros = ((uint64_t)value);
|
||||
if (!suffix.is_valid()) {
|
||||
MOT_LOG_ERROR("Failed to allocate time unit string: %s", endptr);
|
||||
} else {
|
||||
MOT_LOG_WARN("Invalid %s time value format: %s (invalid unit specifier '%s' - should be one of d, h, m, s, "
|
||||
"ms or us)",
|
||||
cfgPath,
|
||||
timeValue,
|
||||
suffix.c_str());
|
||||
suffix.trim();
|
||||
if (IsTimeUnitDays(suffix)) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u days", cfgPath, value);
|
||||
timeValueMicros = ((uint64_t)value) * 24ull * 60ull * 60ull * 1000ull * 1000ull;
|
||||
} else if (IsTimeUnitHours(suffix)) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u hours", cfgPath, value);
|
||||
timeValueMicros = ((uint64_t)value) * 60ull * 60ull * 1000ull * 1000ull;
|
||||
} else if (IsTimeUnitMinutes(suffix)) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u minutes", cfgPath, value);
|
||||
timeValueMicros = ((uint64_t)value) * 60ull * 1000ull * 1000ull;
|
||||
} else if (IsTimeUnitSeconds(suffix)) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u seconds", cfgPath, value);
|
||||
timeValueMicros = ((uint64_t)value) * 1000ull * 1000ull;
|
||||
} else if (IsTimeUnitMilliSeconds(suffix)) {
|
||||
MOT_LOG_TRACE("Loaded %s: %u milli-seconds", cfgPath, value);
|
||||
timeValueMicros = ((uint64_t)value) * 1000ull;
|
||||
} else {
|
||||
MOT_LOG_WARN("Invalid %s time value format: %s (invalid unit specifier '%s' - should be one of d, h, "
|
||||
"m, s or ms)",
|
||||
cfgPath,
|
||||
timeValue,
|
||||
suffix.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
return timeValueMicros;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include "commit_group.h"
|
||||
#include "utilities.h"
|
||||
#include "group_synchronous_redo_log_handler.h"
|
||||
#include "group_sync_redo_log_handler.h"
|
||||
|
||||
namespace MOT {
|
||||
DECLARE_LOGGER(CommitGroup, RedoLog);
|
||||
|
|
@ -52,6 +52,15 @@ CommitGroup::CommitGroup(RedoLogBuffer* buffer, GroupSyncRedoLogHandler* handler
|
|||
CommitGroup::~CommitGroup()
|
||||
{}
|
||||
|
||||
/* function name:AddToGroup
|
||||
function purpose:Add transaction to transaction commit group
|
||||
input:Redo Log Buffer
|
||||
output:Returns the position of the Redo Log Buffer in the Commit Group;
|
||||
note:no
|
||||
annotator:liushifa
|
||||
annotate time:2023/09/11 17:38:20
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
int CommitGroup::AddToGroup(RedoLogBuffer* buffer)
|
||||
{
|
||||
int val;
|
||||
|
|
@ -62,7 +71,7 @@ int CommitGroup::AddToGroup(RedoLogBuffer* buffer)
|
|||
val = (m_groupSize.fetch_add(1));
|
||||
if (val >= (int)m_maxGroupCommitSize) {
|
||||
// group is full... undo our add
|
||||
m_groupSize.fetch_sub(1);
|
||||
(void)m_groupSize.fetch_sub(1);
|
||||
m_rwlock.RdUnlock();
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -76,10 +85,10 @@ int CommitGroup::AddToGroup(RedoLogBuffer* buffer)
|
|||
void CommitGroup::LogGroup()
|
||||
{
|
||||
ILogger* logger = m_handler->GetLogger();
|
||||
logger->AddToLog(m_groupData, m_groupSize);
|
||||
(void)logger->AddToLog(m_groupData, m_groupSize);
|
||||
logger->FlushLog();
|
||||
m_commited = true;
|
||||
MOT_LOG_DEBUG("group committed. num entries: %d, handler id: %d", m_groupSize, m_handlerId);
|
||||
MOT_LOG_DEBUG("group committed. num entries: %d, handler id: %d", m_groupSize.load(), m_handlerId);
|
||||
}
|
||||
|
||||
void CommitGroup::Commit(bool isLeader, std::shared_ptr<CommitGroup> groupRef)
|
||||
|
|
@ -94,9 +103,9 @@ void CommitGroup::Commit(bool isLeader, std::shared_ptr<CommitGroup> groupRef)
|
|||
|
||||
void CommitGroup::WaitLeader(std::shared_ptr<CommitGroup> groupRef)
|
||||
{
|
||||
m_numWaiters.fetch_add(1);
|
||||
(void)m_numWaiters.fetch_add(1);
|
||||
std::unique_lock<std::mutex> lock(m_fullGroupMutex);
|
||||
m_fullGroupCV.wait_for(lock, m_groupTimeout, [this] { return m_groupSize >= m_maxGroupCommitSize; });
|
||||
(void)m_fullGroupCV.wait_for(lock, m_groupTimeout, [this] { return m_groupSize >= m_maxGroupCommitSize; });
|
||||
m_rwlock.WrLock();
|
||||
m_closed = true;
|
||||
m_handler->CloseGroup(groupRef);
|
||||
|
|
@ -110,9 +119,9 @@ void CommitGroup::WaitMember()
|
|||
if (val == m_maxGroupCommitSize - 1) { // i was the last one, all group txns are waiting
|
||||
MOT_LOG_DEBUG("all in, releasing group to commit. group size: %d, "
|
||||
"handler id: %d",
|
||||
m_groupSize,
|
||||
m_groupSize.load(),
|
||||
m_handlerId);
|
||||
std::lock_guard<std::mutex> lock(m_fullGroupMutex);
|
||||
std::lock_guard<std::mutex> groupLock(m_fullGroupMutex);
|
||||
m_fullGroupCV.notify_all();
|
||||
}
|
||||
m_groupCommitedCV.wait(lock, [this] { return m_commited; });
|
||||
|
|
|
|||
|
|
@ -416,44 +416,82 @@ static void MemoryEreportError()
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
/* function name: MOTGetForeignRelSize
|
||||
function purpose:Estimate and set the size and cost information of an external data table (Foreign Table).
|
||||
This information is usually used in the query plan generation phase to determine the shape and execution strategy of the query plan.
|
||||
input:
|
||||
'Planner Info* root': This is a pointer to the Planner Info structure, which is usually used to store query-related information during
|
||||
the query optimization phase. It contains global information about the entire query, such as the target list of the query, the scope of
|
||||
the query, and so on.
|
||||
'RelOptInfo* baserel':This is a pointer to a Rel Opt Info structure that describes which relations in a query can be optimized. The relation
|
||||
here is a core concept in a relational database, which can be simply understood as a table. Rel Opt Info usually includes information about
|
||||
the estimated size of the relationship, available access paths (Path), and so on.
|
||||
'Oid foreigntableid':This is an identifier for an external table, often referred to as an Object Identifier (OID for short). OID is a system
|
||||
data type used to assign a unique identifier to each database object, such as table, index, etc. Here, foreigntableid is used to identify
|
||||
the foreign table to be operated.
|
||||
output:NULL
|
||||
note:NULL
|
||||
annotator:liushifa
|
||||
annotate time:2023/08/02 15:20:24
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
static void MOTGetForeignRelSize(PlannerInfo* root, RelOptInfo* baserel, Oid foreigntableid)
|
||||
{
|
||||
// Allocate memory for an instance of the MOTFdwStateSt structure
|
||||
MOTFdwStateSt* planstate = (MOTFdwStateSt*)palloc0(sizeof(MOTFdwStateSt));
|
||||
|
||||
// Get the foreign table data using the foreign table id
|
||||
ForeignTable* ftable = GetForeignTable(foreigntableid);
|
||||
|
||||
// Get the current transaction manager
|
||||
MOT::TxnManager* currTxn = GetSafeTxn(__FUNCTION__);
|
||||
|
||||
// Declare some variables for later use
|
||||
Bitmapset* attrs = nullptr;
|
||||
ListCell* lc = nullptr;
|
||||
bool needWholeRow = false;
|
||||
TupleDesc desc;
|
||||
|
||||
// Get the Relation object for the foreign table
|
||||
Relation rel = RelationIdGetRelation(ftable->relid);
|
||||
|
||||
// Get the table from the current transaction using the Relation object's id
|
||||
planstate->m_table = currTxn->GetTableByExternalId(RelationGetRelid(rel));
|
||||
|
||||
// If the table is not found in the MOT engine, abort the transaction
|
||||
if (planstate->m_table == nullptr) {
|
||||
abortParentTransactionParamsNoDetail(
|
||||
ERRCODE_UNDEFINED_TABLE, MOT_TABLE_NOTFOUND, (char*)RelationGetRelationName(rel));
|
||||
return;
|
||||
}
|
||||
|
||||
// Save the planstate to the base relation object's private field
|
||||
baserel->fdw_private = planstate;
|
||||
|
||||
// Initialize some fields in the planstate
|
||||
planstate->m_hasForUpdate = root->parse->hasForUpdate;
|
||||
planstate->m_cmdOper = root->parse->commandType;
|
||||
planstate->m_foreignTableId = foreigntableid;
|
||||
|
||||
desc = RelationGetDescr(rel);
|
||||
planstate->m_numAttrs = RelationGetNumberOfAttributes(rel);
|
||||
|
||||
// More initialization of the planstate
|
||||
int len = BITMAP_GETLEN(planstate->m_numAttrs);
|
||||
planstate->m_attrsUsed = (uint8_t*)palloc0(len);
|
||||
planstate->m_attrsModified = (uint8_t*)palloc0(len);
|
||||
|
||||
// Check whether a whole row is needed based on whether there are any AFTER ROW INSERT triggers
|
||||
needWholeRow = rel->trigdesc && rel->trigdesc->trig_insert_after_row;
|
||||
|
||||
// If a whole row is not needed, pull the needed columns from the base relation
|
||||
// Otherwise, set all columns as used
|
||||
foreach (lc, baserel->baserestrictinfo) {
|
||||
RestrictInfo* ri = (RestrictInfo*)lfirst(lc);
|
||||
|
||||
if (!needWholeRow)
|
||||
pull_varattnos((Node*)ri->clause, baserel->relid, &attrs);
|
||||
}
|
||||
|
||||
if (needWholeRow) {
|
||||
for (int i = 0; i < desc->natts; i++) {
|
||||
if (!desc->attrs[i]->attisdropped) {
|
||||
|
|
@ -472,17 +510,23 @@ static void MOTGetForeignRelSize(PlannerInfo* root, RelOptInfo* baserel, Oid for
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the row count of the table from the MOT engine and set it to the base relation
|
||||
baserel->rows = planstate->m_table->GetRowCount();
|
||||
baserel->tuples = planstate->m_table->GetRowCount();
|
||||
|
||||
// If the row count is zero, default it to 100,000
|
||||
if (baserel->rows == 0)
|
||||
baserel->rows = baserel->tuples = 100000;
|
||||
|
||||
// Set the startup cost and total cost of the plan state
|
||||
planstate->m_startupCost = 0.1;
|
||||
planstate->m_totalCost = baserel->rows * planstate->m_startupCost;
|
||||
|
||||
// Close the Relation object
|
||||
RelationClose(rel);
|
||||
}
|
||||
|
||||
|
||||
static bool IsOrderingApplicable(PathKey* pathKey, RelOptInfo* rel, MOT::Index* ix, OrderSt* ord)
|
||||
{
|
||||
bool res = false;
|
||||
|
|
@ -531,11 +575,27 @@ static bool IsOrderingApplicable(PathKey* pathKey, RelOptInfo* rel, MOT::Index*
|
|||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
/* function name:MOTGetForeignPaths
|
||||
function purpose:Called in case of an index to determine which indexes are available for fetching data from
|
||||
the table in the current query
|
||||
input:'Planner Info* root': This is a pointer to the Planner Info structure, which is usually used to store query-related information during
|
||||
the query optimization phase. It contains global information about the entire query, such as the target list of the query, the scope of
|
||||
the query, and so on.
|
||||
'RelOptInfo* baserel':This is a pointer to a Rel Opt Info structure that describes which relations in a query can be optimized. The relation
|
||||
here is a core concept in a relational database, which can be simply understood as a table. Rel Opt Info usually includes information about
|
||||
the estimated size of the relationship, available access paths (Path), and so on.
|
||||
'Oid foreigntableid':This is an identifier for an external table, often referred to as an Object Identifier (OID for short). OID is a system
|
||||
data type used to assign a unique identifier to each database object, such as table, index, etc. Here, foreigntableid is used to identify
|
||||
the foreign table to be operated.
|
||||
output:NULL
|
||||
note:NULL
|
||||
annotator:liushifa
|
||||
annotate time:2023/08/02 15:29:51
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid foreigntableid)
|
||||
{
|
||||
// Retrieve the MOTFdwStateSt structure from the base relation object
|
||||
MOTFdwStateSt* planstate = (MOTFdwStateSt*)baserel->fdw_private;
|
||||
List* usablePathkeys = NIL;
|
||||
List* bestClause = nullptr;
|
||||
|
|
@ -546,17 +606,15 @@ static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid forei
|
|||
Path* fpReg = nullptr;
|
||||
Path* fpIx = nullptr;
|
||||
bool hasRegularPath = false;
|
||||
|
||||
planstate->m_order = SORTDIR_ENUM::SORTDIR_ASC;
|
||||
// first create regular path based on relation restrictions
|
||||
foreach (lc, baserel->baserestrictinfo) {
|
||||
RestrictInfo* ri = (RestrictInfo*)lfirst(lc);
|
||||
|
||||
// If the expression is not a MOT expression, add it to local conditions
|
||||
if (!IsMOTExpr(baserel, planstate, &marr, ri->clause, nullptr, true)) {
|
||||
planstate->m_localConds = lappend(planstate->m_localConds, ri->clause);
|
||||
}
|
||||
}
|
||||
|
||||
// get best index
|
||||
best = MOTAdaptor::GetBestMatchIndex(planstate, &marr, list_length(baserel->baserestrictinfo));
|
||||
if (best != nullptr) {
|
||||
|
|
@ -569,7 +627,6 @@ static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid forei
|
|||
planstate->m_startupCost = 0.001;
|
||||
planstate->m_totalCost = best->m_cost;
|
||||
planstate->m_bestIx = best;
|
||||
|
||||
foreach (lc, root->query_pathkeys) {
|
||||
PathKey* pathkey = (PathKey*)lfirst(lc);
|
||||
|
||||
|
|
@ -577,7 +634,6 @@ static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid forei
|
|||
usablePathkeys = lappend(usablePathkeys, pathkey);
|
||||
}
|
||||
}
|
||||
|
||||
if (!best->CanApplyOrdering(ord.m_cols)) {
|
||||
list_free(usablePathkeys);
|
||||
usablePathkeys = nullptr;
|
||||
|
|
@ -591,12 +647,10 @@ static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid forei
|
|||
ord.init();
|
||||
MOT::Index* ix = planstate->m_table->GetPrimaryIndex();
|
||||
List* keys;
|
||||
|
||||
if (root->query_level == 1)
|
||||
keys = root->query_pathkeys;
|
||||
else
|
||||
keys = root->sort_pathkeys;
|
||||
|
||||
foreach (lc, keys) {
|
||||
PathKey* pathkey = (PathKey*)lfirst(lc);
|
||||
|
||||
|
|
@ -604,7 +658,6 @@ static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid forei
|
|||
usablePathkeys = lappend(usablePathkeys, pathkey);
|
||||
}
|
||||
}
|
||||
|
||||
if (list_length(usablePathkeys) > 0) {
|
||||
if (ord.m_cols[0] != 0)
|
||||
planstate->m_order = ord.m_order;
|
||||
|
|
@ -615,7 +668,6 @@ static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid forei
|
|||
} else
|
||||
planstate->m_order = SORTDIR_ENUM::SORTDIR_ASC;
|
||||
}
|
||||
|
||||
fpReg = (Path*)create_foreignscan_path(root,
|
||||
baserel,
|
||||
planstate->m_startupCost,
|
||||
|
|
@ -624,7 +676,6 @@ static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid forei
|
|||
nullptr, /* no outer rel either */
|
||||
nullptr, // private data will be assigned later
|
||||
0);
|
||||
|
||||
foreach (lc, baserel->pathlist) {
|
||||
Path* path = (Path*)lfirst(lc);
|
||||
if (IsA(path, IndexPath) && path->param_info == nullptr) {
|
||||
|
|
@ -635,7 +686,6 @@ static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid forei
|
|||
if (!hasRegularPath)
|
||||
add_path(root, baserel, fpReg);
|
||||
set_cheapest(baserel);
|
||||
|
||||
if (!IS_PGXC_COORDINATOR && list_length(baserel->cheapest_parameterized_paths) > 0) {
|
||||
foreach (lc, baserel->cheapest_parameterized_paths) {
|
||||
bestPath = (Path*)lfirst(lc);
|
||||
|
|
@ -647,7 +697,6 @@ static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid forei
|
|||
}
|
||||
usablePathkeys = nullptr;
|
||||
}
|
||||
|
||||
if (bestClause != nullptr) {
|
||||
marr.Clear();
|
||||
|
||||
|
|
@ -657,7 +706,6 @@ static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid forei
|
|||
// In case we use index params DO NOT add it to envelope filter.
|
||||
(void)IsMOTExpr(baserel, planstate, &marr, ri->clause, nullptr, false);
|
||||
}
|
||||
|
||||
best = MOTAdaptor::GetBestMatchIndex(planstate, &marr, list_length(bestClause), false);
|
||||
if (best != nullptr) {
|
||||
OrderSt ord;
|
||||
|
|
@ -697,7 +745,6 @@ static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid forei
|
|||
fpIx->param_info = bestPath->param_info;
|
||||
}
|
||||
}
|
||||
|
||||
List* newPath = nullptr;
|
||||
List* origPath = baserel->pathlist;
|
||||
// disable index path
|
||||
|
|
@ -708,7 +755,6 @@ static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid forei
|
|||
else
|
||||
pfree(path);
|
||||
}
|
||||
|
||||
list_free(origPath);
|
||||
baserel->pathlist = newPath;
|
||||
if (hasRegularPath)
|
||||
|
|
@ -717,10 +763,23 @@ static void MOTGetForeignPaths(PlannerInfo* root, RelOptInfo* baserel, Oid forei
|
|||
add_path(root, baserel, fpIx);
|
||||
set_cheapest(baserel);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
/* function name:MOTGetForeignPlan
|
||||
function purpose:Create an execution plan for fetching data from the table
|
||||
input:'Planner Info* root': This is a pointer to the Planner Info structure, which is usually used to store query-related information during
|
||||
the query optimization phase. It contains global information about the entire query, such as the target list of the query, the scope of
|
||||
the query, and so on.
|
||||
'RelOptInfo* baserel':This is a pointer to a Rel Opt Info structure that describes which relations in a query can be optimized. The relation
|
||||
here is a core concept in a relational database, which can be simply understood as a table. Rel Opt Info usually includes information about
|
||||
the estimated size of the relationship, available access paths (Path), and so on.
|
||||
'Oid foreigntableid':This is an identifier for an external table, often referred to as an Object Identifier (OID for short). OID is a system
|
||||
data type used to assign a unique identifier to each database object, such as table, index, etc. Here, foreigntableid is used to identify
|
||||
the foreign table to be operated.
|
||||
output:ForeignScan plan for a foreign table.
|
||||
note:
|
||||
annotator:liushifa
|
||||
annotate time:2023/08/02 15:44:43
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
static ForeignScan* MOTGetForeignPlan(
|
||||
PlannerInfo* root, RelOptInfo* baserel, Oid foreigntableid, ForeignPath* best_path, List* tlist, List* scan_clauses)
|
||||
{
|
||||
|
|
@ -729,7 +788,8 @@ static ForeignScan* MOTGetForeignPlan(
|
|||
MOTFdwStateSt* planstate = (MOTFdwStateSt*)baserel->fdw_private;
|
||||
List* tmpLocal = nullptr;
|
||||
List* remote = nullptr;
|
||||
|
||||
// If there is a parameterized path and a best index match, clean and free the old best index match
|
||||
// Then set the best index match to the parameterized one
|
||||
if (best_path->path.param_info && planstate->m_paramBestIx) {
|
||||
if (planstate->m_bestIx != nullptr) {
|
||||
planstate->m_bestIx->Clean(planstate);
|
||||
|
|
@ -738,7 +798,8 @@ static ForeignScan* MOTGetForeignPlan(
|
|||
planstate->m_bestIx = planstate->m_paramBestIx;
|
||||
planstate->m_paramBestIx = nullptr;
|
||||
}
|
||||
|
||||
// If there is a best index match, concatenate the remote conditions and set the number of expressions
|
||||
// If there is no best index match, set the number of expressions to 0
|
||||
if (planstate->m_bestIx != nullptr) {
|
||||
planstate->m_numExpr = list_length(planstate->m_bestIx->m_remoteConds);
|
||||
remote = list_concat(planstate->m_bestIx->m_remoteConds, planstate->m_bestIx->m_remoteCondsOrig);
|
||||
|
|
@ -750,6 +811,7 @@ static ForeignScan* MOTGetForeignPlan(
|
|||
} else {
|
||||
planstate->m_numExpr = 0;
|
||||
}
|
||||
// Initialize local conditions
|
||||
baserel->fdw_private = nullptr;
|
||||
tmpLocal = planstate->m_localConds;
|
||||
planstate->m_localConds = nullptr;
|
||||
|
|
@ -785,6 +847,8 @@ static ForeignScan* MOTGetForeignPlan(
|
|||
list_free(tmpLocal);
|
||||
|
||||
List* quals = planstate->m_localConds;
|
||||
// Create a ForeignScan node with the target list, local conditions, scan relation ID, and other information
|
||||
// make_foreignscan is defined in /openGauss-server/src/gausskernel/optimizer/plan/createplan.cpp
|
||||
return make_foreignscan(tlist,
|
||||
quals,
|
||||
scanRelid,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -27,6 +27,9 @@
|
|||
#include "jit_common.h"
|
||||
#include "mot_engine.h"
|
||||
#include "utilities.h"
|
||||
#include "utils/timestamp.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "mot_internal.h"
|
||||
|
||||
namespace JitExec {
|
||||
DECLARE_LOGGER(JitExplain, JitExec)
|
||||
|
|
@ -38,75 +41,36 @@ static void ExplainRangeSelectPlan(Query* query, JitRangeSelectPlan* plan, bool
|
|||
|
||||
static void ExplainConstExpr(JitConstExpr* expr)
|
||||
{
|
||||
MOT_ASSERT(expr->_source_expr->type == T_Const);
|
||||
Const* constExpr = (Const*)expr->_source_expr;
|
||||
switch (constExpr->consttype) {
|
||||
case BOOLOID:
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[bool] %u", (unsigned)DatumGetBool(constExpr->constvalue));
|
||||
break;
|
||||
|
||||
case CHAROID:
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[char] %u", (unsigned)DatumGetChar(constExpr->constvalue));
|
||||
break;
|
||||
|
||||
case INT1OID:
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[int1] %u", (unsigned)DatumGetUInt8(constExpr->constvalue));
|
||||
break;
|
||||
|
||||
case INT2OID:
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[int2] %u", (unsigned)DatumGetUInt16(constExpr->constvalue));
|
||||
break;
|
||||
|
||||
case INT4OID:
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[int4] %u", (unsigned)DatumGetUInt32(constExpr->constvalue));
|
||||
break;
|
||||
|
||||
case INT8OID:
|
||||
MOT_LOG_APPEND(
|
||||
MOT::LogLevel::LL_TRACE, "[int8] %u" PRIu64, (uint64_t)DatumGetUInt64(constExpr->constvalue));
|
||||
break;
|
||||
|
||||
case TIMESTAMPOID:
|
||||
MOT_LOG_APPEND(
|
||||
MOT::LogLevel::LL_TRACE, "[timestamp] %" PRIu64, (uint64_t)DatumGetTimestamp(constExpr->constvalue));
|
||||
break;
|
||||
|
||||
case FLOAT4OID:
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[float4] %f", (double)DatumGetFloat4(constExpr->constvalue));
|
||||
break;
|
||||
|
||||
case FLOAT8OID:
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[float8] %f", (double)DatumGetFloat8(constExpr->constvalue));
|
||||
break;
|
||||
|
||||
case VARCHAROID: {
|
||||
VarChar* vc = DatumGetVarCharPP(constExpr->constvalue);
|
||||
int size = VARSIZE_ANY_EXHDR(vc);
|
||||
char* src = VARDATA_ANY(vc);
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[varchar] %.*s", size, src);
|
||||
} break;
|
||||
|
||||
case NUMERICOID: {
|
||||
Datum result = DirectFunctionCall1(numeric_out, constExpr->constvalue);
|
||||
char* cstring = DatumGetCString(result);
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[numeric] %s", cstring);
|
||||
} break;
|
||||
|
||||
default:
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE,
|
||||
"[type %d] %" PRIu64,
|
||||
(int)constExpr->consttype,
|
||||
(uint64_t)constExpr->constvalue);
|
||||
break;
|
||||
if (expr->_is_null) { // special case of default parameters
|
||||
PrintDatum(MOT::LogLevel::LL_TRACE, expr->_const_type, PointerGetDatum(nullptr), true);
|
||||
} else {
|
||||
MOT_ASSERT(expr->_source_expr != nullptr);
|
||||
MOT_ASSERT(expr->_source_expr->type == T_Const);
|
||||
Const* constExpr = (Const*)expr->_source_expr;
|
||||
PrintDatum(MOT::LogLevel::LL_TRACE, constExpr->consttype, constExpr->constvalue, constExpr->constisnull);
|
||||
}
|
||||
}
|
||||
|
||||
/* function name:ExplainRealColumnName
|
||||
function purpose:Retrieves the actual column name for a given query based on a table reference ID
|
||||
and a column ID. This is helpful to decipher real column names especially in complex queries where
|
||||
joins or aliasing might be involved.
|
||||
input:query The executed query. tableRefId The table reference ID from the query.columnId The column ID within the table.
|
||||
output:none
|
||||
note:none
|
||||
annotator:liushifa
|
||||
annotate time:2023/10/05 22:27:42
|
||||
contact:3325287047@qq.com
|
||||
*/
|
||||
static void ExplainRealColumnName(const Query* query, int tableRefId, int columnId)
|
||||
{
|
||||
// Acquire the current transaction manager instance
|
||||
MOT::TxnManager* currTxn = GetSafeTxn(__FUNCTION__);
|
||||
// Check if the tableRefId is valid
|
||||
MOT_ASSERT(currTxn != nullptr);
|
||||
if (tableRefId <= list_length(query->rtable)) { // varno index is 1-based
|
||||
RangeTblEntry* rte = (RangeTblEntry*)list_nth(query->rtable, tableRefId - 1);
|
||||
if (rte->rtekind == RTE_RELATION) {
|
||||
MOT::Table* table = MOT::GetTableManager()->GetTableByExternal(rte->relid);
|
||||
MOT::Table* table = currTxn->GetTableByExternalId(rte->relid);
|
||||
if (table != nullptr) {
|
||||
if (list_length(query->rtable) == 1) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "%s", table->GetFieldName(columnId));
|
||||
|
|
@ -121,7 +85,7 @@ static void ExplainRealColumnName(const Query* query, int tableRefId, int column
|
|||
tableRefId = aliasVar->varno;
|
||||
if (tableRefId <= list_length(query->rtable)) { // tableRefId is 1-based
|
||||
rte = (RangeTblEntry*)list_nth(query->rtable, tableRefId - 1);
|
||||
MOT::Table* table = MOT::GetTableManager()->GetTableByExternal(rte->relid);
|
||||
MOT::Table* table = currTxn->GetTableByExternalId(rte->relid);
|
||||
if (table != nullptr) {
|
||||
// take real column id and not column id from virtual join table
|
||||
columnId = aliasVar->varattno;
|
||||
|
|
@ -177,68 +141,36 @@ static void ExplainParamExpr(JitParamExpr* expr)
|
|||
}
|
||||
}
|
||||
|
||||
#define APPLY_UNARY_OPERATOR(funcid, name) \
|
||||
case funcid: \
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, #name "("); \
|
||||
ExplainExpr(query, plan, expr->_args[0]); \
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); \
|
||||
break;
|
||||
static void ExplainPGFunction(Query* query, JitPlan* plan, Oid functionId, JitExpr** args, int argCount)
|
||||
{
|
||||
// get PG function name
|
||||
char* functionName = get_func_name(functionId);
|
||||
if (functionName != nullptr) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "<%s %u>(", functionName, (unsigned)functionId);
|
||||
} else {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "<function %u>(", (unsigned)functionId);
|
||||
}
|
||||
pfree(functionName);
|
||||
|
||||
#define APPLY_BINARY_OPERATOR(funcid, name) \
|
||||
case funcid: \
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, #name "("); \
|
||||
ExplainExpr(query, plan, expr->_args[0]); \
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", "); \
|
||||
ExplainExpr(query, plan, expr->_args[1]); \
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); \
|
||||
break;
|
||||
|
||||
#define APPLY_TERNARY_OPERATOR(funcid, name) \
|
||||
case funcid: \
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, #name "("); \
|
||||
ExplainExpr(query, plan, expr->_args[0]); \
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", "); \
|
||||
ExplainExpr(query, plan, expr->_args[1]); \
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", "); \
|
||||
ExplainExpr(query, plan, expr->_args[2]); \
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); \
|
||||
break;
|
||||
|
||||
#define APPLY_UNARY_CAST_OPERATOR(funcid, name) APPLY_UNARY_OPERATOR(funcid, name)
|
||||
#define APPLY_BINARY_CAST_OPERATOR(funcid, name) APPLY_BINARY_OPERATOR(funcid, name)
|
||||
#define APPLY_TERNARY_CAST_OPERATOR(funcid, name) APPLY_TERNARY_OPERATOR(funcid, name)
|
||||
for (int i = 0; i < argCount; ++i) {
|
||||
ExplainExpr(query, plan, args[i]);
|
||||
if ((i + 1) < argCount) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", ");
|
||||
}
|
||||
}
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")");
|
||||
}
|
||||
|
||||
static void ExplainOpExpr(Query* query, JitPlan* plan, JitOpExpr* expr)
|
||||
{
|
||||
// explain the operator
|
||||
switch (expr->_op_func_id) {
|
||||
APPLY_OPERATORS()
|
||||
|
||||
default:
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[op_%u]", expr->_op_func_id);
|
||||
break;
|
||||
}
|
||||
ExplainPGFunction(query, plan, expr->_op_func_id, expr->_args, expr->_arg_count);
|
||||
}
|
||||
|
||||
static void ExplainFuncExpr(Query* query, JitPlan* plan, JitFuncExpr* expr)
|
||||
{
|
||||
// explain the function
|
||||
switch (expr->_func_id) {
|
||||
APPLY_OPERATORS()
|
||||
|
||||
default:
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[func_%d]", expr->_func_id);
|
||||
break;
|
||||
}
|
||||
ExplainPGFunction(query, plan, expr->_func_id, expr->_args, expr->_arg_count);
|
||||
}
|
||||
|
||||
#undef APPLY_UNARY_OPERATOR
|
||||
#undef APPLY_BINARY_OPERATOR
|
||||
#undef APPLY_TERNARY_OPERATOR
|
||||
#undef APPLY_UNARY_CAST_OPERATOR
|
||||
#undef APPLY_BINARY_CAST_OPERATOR
|
||||
#undef APPLY_TERNARY_CAST_OPERATOR
|
||||
|
||||
static void ExplainSubLinkExpr(Query* query, JitPlan* plan, JitSubLinkExpr* subLinkExpr)
|
||||
{
|
||||
// currently we support only one sub-query (so we don't use sub-query plan index)
|
||||
|
|
@ -261,6 +193,25 @@ static void ExplainSubLinkExpr(Query* query, JitPlan* plan, JitSubLinkExpr* subL
|
|||
}
|
||||
}
|
||||
|
||||
static void ExplainScalarArrayOpExpr(Query* query, JitPlan* plan, JitScalarArrayOpExpr* expr)
|
||||
{
|
||||
ExplainExpr(query, plan, expr->m_scalar);
|
||||
if (expr->m_useOr) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " IN ANY ");
|
||||
} else {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " IN ALL ");
|
||||
}
|
||||
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[");
|
||||
for (int i = 0; i < expr->m_arraySize; ++i) {
|
||||
ExplainExpr(query, plan, expr->m_arrayElements[i]);
|
||||
if ((i + 1) < expr->m_arraySize) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", ");
|
||||
}
|
||||
}
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "]");
|
||||
}
|
||||
|
||||
static void ExplainExpr(Query* query, JitPlan* plan, JitExpr* expr)
|
||||
{
|
||||
switch (expr->_expr_type) {
|
||||
|
|
@ -288,6 +239,10 @@ static void ExplainExpr(Query* query, JitPlan* plan, JitExpr* expr)
|
|||
ExplainSubLinkExpr(query, plan, (JitSubLinkExpr*)expr);
|
||||
break;
|
||||
|
||||
case JIT_EXPR_TYPE_SCALAR_ARRAY_OP:
|
||||
ExplainScalarArrayOpExpr(query, plan, (JitScalarArrayOpExpr*)expr);
|
||||
break;
|
||||
|
||||
default:
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[expr]");
|
||||
break;
|
||||
|
|
@ -312,19 +267,24 @@ static const char* JitWhereOperatorClassToString(JitWhereOperatorClass opClass)
|
|||
}
|
||||
}
|
||||
|
||||
static void ExplainFilterArray(
|
||||
Query* query, JitPlan* plan, int indent, JitFilterArray* filterArray, bool isSubQuery = false)
|
||||
static void ExplainFilterArray(Query* query, JitPlan* plan, int indent, JitFilterArray* filterArray,
|
||||
bool isSubQuery = false, bool isOneTime = false)
|
||||
{
|
||||
if (!isSubQuery) {
|
||||
MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sFILTER ON (", indent, "");
|
||||
if (isOneTime) {
|
||||
MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sONE-TIME FILTER ON (", indent, "");
|
||||
} else {
|
||||
MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sFILTER ON (", indent, "");
|
||||
}
|
||||
} else {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " FILTER ON (");
|
||||
if (isOneTime) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " FILTER ON (");
|
||||
} else {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " ONE-TIME FILTER ON (");
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < filterArray->_filter_count; ++i) {
|
||||
ExplainExpr(query, plan, filterArray->_scan_filters[i]._lhs_operand);
|
||||
JitWhereOperatorClass opClass = ClassifyWhereOperator(filterArray->_scan_filters[i]._filter_op);
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " %s ", JitWhereOperatorClassToString(opClass));
|
||||
ExplainExpr(query, plan, filterArray->_scan_filters[i]._rhs_operand);
|
||||
ExplainExpr(query, plan, filterArray->_scan_filters[i]);
|
||||
if (i < (filterArray->_filter_count - 1)) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " AND ");
|
||||
}
|
||||
|
|
@ -372,7 +332,7 @@ static void ExplainSelectExprArray(Query* query, JitPlan* plan, JitSelectExprArr
|
|||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "(");
|
||||
for (int i = 0; i < exprArray->_count; ++i) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "%%%d = ", exprArray->_exprs[i]._tuple_column_id);
|
||||
ExplainExpr(query, plan, (JitExpr*)exprArray->_exprs[i]._column_expr);
|
||||
ExplainExpr(query, plan, (JitExpr*)exprArray->_exprs[i]._expr);
|
||||
if (i < (exprArray->_count - 1)) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", ");
|
||||
}
|
||||
|
|
@ -435,6 +395,10 @@ static void ExplainPointQueryPlan(Query* query, JitPointQueryPlan* plan, bool is
|
|||
MOT_LOG_TRACE("[Plan] Point Query");
|
||||
}
|
||||
int indent = 0;
|
||||
if (plan->_query.m_oneTimeFilters._filter_count > 0) {
|
||||
ExplainFilterArray(query, (JitPlan*)plan, indent, &plan->_query.m_oneTimeFilters, isSubQuery, true);
|
||||
indent += 2;
|
||||
}
|
||||
if (plan->_query._filters._filter_count > 0) {
|
||||
ExplainFilterArray(query, (JitPlan*)plan, indent, &plan->_query._filters, isSubQuery);
|
||||
indent += 2;
|
||||
|
|
@ -556,11 +520,15 @@ static const char* JitIndexScanDirectionToString(JitIndexScanDirection scanDirec
|
|||
static void ExplainIndexScan(Query* query, JitPlan* plan, int indent, JitIndexScan* indexScan,
|
||||
const char* scanName = "", bool isSubQuery = false)
|
||||
{
|
||||
if (indexScan->m_oneTimeFilters._filter_count > 0) {
|
||||
ExplainFilterArray(query, plan, indent, &indexScan->m_oneTimeFilters, isSubQuery, true);
|
||||
indent += 2;
|
||||
}
|
||||
if (indexScan->_filters._filter_count > 0) {
|
||||
ExplainFilterArray(query, plan, indent, &indexScan->_filters, isSubQuery);
|
||||
indent += 2;
|
||||
}
|
||||
MOT::Index* index = indexScan->_table->GetIndex(indexScan->_index_id);
|
||||
MOT::Index* index = indexScan->_index;
|
||||
if (isSubQuery) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE,
|
||||
"%s%sSCAN %s index %s (%s, %s) ON (",
|
||||
|
|
@ -633,10 +601,15 @@ static void ExplainAggregateOperator(int indent, const JitAggregate* aggregate,
|
|||
if (aggregate->_distinct) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "DISTINCT(");
|
||||
}
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE,
|
||||
"%s.%s)",
|
||||
aggregate->_table->GetTableName().c_str(),
|
||||
aggregate->_table->GetFieldName(aggregate->_table_column_id));
|
||||
if (aggregate->_table == nullptr) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "*)");
|
||||
} else {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE,
|
||||
"%s.%s type %d)",
|
||||
aggregate->_table->GetTableName().c_str(),
|
||||
aggregate->_table->GetFieldName(aggregate->_table_column_id),
|
||||
aggregate->_element_type);
|
||||
}
|
||||
if (aggregate->_distinct) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")");
|
||||
}
|
||||
|
|
@ -645,6 +618,46 @@ static void ExplainAggregateOperator(int indent, const JitAggregate* aggregate,
|
|||
}
|
||||
}
|
||||
|
||||
static void ExplainColumnName(Query* query, JitExpr* expr)
|
||||
{
|
||||
if (expr->_expr_type == JIT_EXPR_TYPE_VAR) {
|
||||
Var* varExpr = (Var*)expr->_source_expr;
|
||||
int columnId = varExpr->varattno;
|
||||
int tableRefId = varExpr->varno;
|
||||
ExplainRealColumnName(query, tableRefId, columnId);
|
||||
}
|
||||
}
|
||||
|
||||
static void ExplainRangeSelectSort(Query* query, JitRangeSelectPlan* plan, int indent)
|
||||
{
|
||||
JitNonNativeSortParams* sortParams = plan->m_nonNativeSortParams;
|
||||
MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sSORT ", indent, "");
|
||||
if (ScanDirectionIsBackward(sortParams->scanDir)) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "DESC");
|
||||
} else if (ScanDirectionIsForward(sortParams->scanDir)) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "ASC");
|
||||
}
|
||||
for (int i = 0; i < sortParams->numCols; ++i) {
|
||||
AttrNumber colId = sortParams->sortColIdx[i];
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " {Column %d [", colId);
|
||||
ExplainColumnName(query, plan->_select_exprs._exprs[colId - 1]._expr);
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE,
|
||||
"], SortOp %u, Collation %u, nulls-first %s}",
|
||||
sortParams->sortOperators[i],
|
||||
sortParams->collations[i],
|
||||
sortParams->nullsFirst[i] ? "true" : "false");
|
||||
if (i + 1 < plan->m_nonNativeSortParams->numCols) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ",");
|
||||
}
|
||||
}
|
||||
if (plan->m_nonNativeSortParams->bound == 0) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " no bound");
|
||||
} else {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " bound %" PRIu64, plan->m_nonNativeSortParams->bound);
|
||||
}
|
||||
MOT_LOG_END(MOT::LogLevel::LL_TRACE);
|
||||
}
|
||||
|
||||
static void ExplainRangeSelectPlan(Query* query, JitRangeSelectPlan* plan, bool isSubQuery /* = false */)
|
||||
{
|
||||
if (isSubQuery) {
|
||||
|
|
@ -654,9 +667,13 @@ static void ExplainRangeSelectPlan(Query* query, JitRangeSelectPlan* plan, bool
|
|||
MOT_LOG_TRACE("[Plan] Range SELECT from table %s:", plan->_index_scan._table->GetTableName().c_str());
|
||||
}
|
||||
int indent = 0;
|
||||
if (plan->_aggregate._aggreaget_op != JIT_AGGREGATE_NONE) {
|
||||
for (int aggIndex = 0; aggIndex < plan->m_aggCount; ++aggIndex) {
|
||||
indent += 2;
|
||||
ExplainAggregateOperator(indent, &plan->_aggregate, isSubQuery);
|
||||
ExplainAggregateOperator(indent, &plan->m_aggregates[aggIndex], isSubQuery);
|
||||
if (aggIndex + 1 < plan->m_aggCount) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", ");
|
||||
}
|
||||
indent -= 2;
|
||||
}
|
||||
if (plan->_limit_count > 0) {
|
||||
if (isSubQuery) {
|
||||
|
|
@ -666,9 +683,13 @@ static void ExplainRangeSelectPlan(Query* query, JitRangeSelectPlan* plan, bool
|
|||
MOT_LOG_TRACE("%*sLIMIT %d", indent, "", plan->_limit_count);
|
||||
}
|
||||
}
|
||||
if (plan->_aggregate._aggreaget_op == JIT_AGGREGATE_NONE) {
|
||||
if (plan->m_nonNativeSortParams != nullptr) {
|
||||
indent += 2;
|
||||
ExplainRangeSelectSort(query, plan, indent);
|
||||
}
|
||||
if (plan->m_aggCount == 0) {
|
||||
if (isSubQuery) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " SELECT");
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "%*sSELECT", indent, "");
|
||||
ExplainSelectExprArray(query, (JitPlan*)plan, &plan->_select_exprs);
|
||||
} else {
|
||||
indent += 2;
|
||||
|
|
@ -681,18 +702,43 @@ static void ExplainRangeSelectPlan(Query* query, JitRangeSelectPlan* plan, bool
|
|||
ExplainIndexScan(query, (JitPlan*)plan, indent + 2, &plan->_index_scan, "", isSubQuery);
|
||||
}
|
||||
|
||||
static void ExplainRangeDeletePlan(Query* query, JitRangeDeletePlan* plan)
|
||||
{
|
||||
MOT_LOG_TRACE("[Plan] Range DELETE table %s:", plan->_index_scan._table->GetTableName().c_str());
|
||||
ExplainIndexScan(query, (JitPlan*)plan, 2, &plan->_index_scan);
|
||||
}
|
||||
|
||||
static void ExplainRangeScanPlan(Query* query, JitRangeScanPlan* plan)
|
||||
{
|
||||
if (plan->_command_type == JIT_COMMAND_UPDATE) {
|
||||
ExplainRangeUpdatePlan(query, (JitRangeUpdatePlan*)plan);
|
||||
} else if (plan->_command_type == JIT_COMMAND_SELECT) {
|
||||
ExplainRangeSelectPlan(query, (JitRangeSelectPlan*)plan);
|
||||
} else if (plan->_command_type == JIT_COMMAND_DELETE) {
|
||||
ExplainRangeDeletePlan(query, (JitRangeDeletePlan*)plan);
|
||||
} else {
|
||||
MOT_LOG_TRACE("Invalid plan command type");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* JitJoinTypeToString(JitJoinType joinType)
|
||||
{
|
||||
switch (joinType) {
|
||||
case JitJoinType::JIT_JOIN_INNER:
|
||||
return "INNER";
|
||||
case JitJoinType::JIT_JOIN_LEFT:
|
||||
return "LEFT";
|
||||
case JitJoinType::JIT_JOIN_FULL:
|
||||
return "FULL";
|
||||
case JitJoinType::JIT_JOIN_RIGHT:
|
||||
return "RIGHT";
|
||||
case JitJoinType::JIT_JOIN_INVALID:
|
||||
default:
|
||||
return "Invalid";
|
||||
}
|
||||
}
|
||||
|
||||
static const char* JitJoinScanTypeToString(JitJoinScanType scanType)
|
||||
{
|
||||
switch (scanType) {
|
||||
|
|
@ -712,15 +758,21 @@ static const char* JitJoinScanTypeToString(JitJoinScanType scanType)
|
|||
|
||||
static void ExplainJoinPlan(Query* query, JitJoinPlan* plan)
|
||||
{
|
||||
MOT_LOG_TRACE("[Plan] JOIN table %s on table %s (%s)",
|
||||
MOT_LOG_TRACE("[Plan] %s JOIN table %s on table %s (%s)",
|
||||
JitJoinTypeToString(plan->_join_type),
|
||||
plan->_outer_scan._table->GetTableName().c_str(),
|
||||
plan->_inner_scan._table->GetTableName().c_str(),
|
||||
JitJoinScanTypeToString(plan->_scan_type));
|
||||
int indent = 0;
|
||||
if (plan->_aggregate._aggreaget_op != JIT_AGGREGATE_NONE) {
|
||||
for (int aggIndex = 0; aggIndex < plan->m_aggCount; ++aggIndex) {
|
||||
indent += 2;
|
||||
ExplainAggregateOperator(indent, &plan->_aggregate);
|
||||
} else {
|
||||
ExplainAggregateOperator(indent, &plan->m_aggregates[aggIndex]);
|
||||
if (aggIndex + 1 < plan->m_aggCount) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", ");
|
||||
}
|
||||
indent -= 2;
|
||||
}
|
||||
if (plan->m_aggCount == 0) {
|
||||
indent += 2;
|
||||
MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sSELECT", indent, "");
|
||||
ExplainSelectExprArray(query, (JitPlan*)plan, &plan->_select_exprs);
|
||||
|
|
@ -749,6 +801,34 @@ static void ExplainCompoundPlan(Query* query, JitCompoundPlan* plan)
|
|||
ExplainSearchExprArray(query, (JitPlan*)plan, indent + 4, &plan->_outer_query_plan->_query._search_exprs, false);
|
||||
}
|
||||
|
||||
static void ExplainInvokePlan(Query* query, JitInvokePlan* plan)
|
||||
{
|
||||
MOT_LOG_TRACE("[Plan] Invoke stored procedure:");
|
||||
MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, " %s[id=%u] (", plan->_function_name, plan->_function_id);
|
||||
for (int i = 0; i < plan->_arg_count; ++i) {
|
||||
ExplainExpr(query, (JitPlan*)plan, plan->_args[i]);
|
||||
if (i < plan->_arg_count - 1) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", ");
|
||||
}
|
||||
}
|
||||
if ((plan->_arg_count > 0) && (plan->m_defaultParamCount > 0)) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", ");
|
||||
}
|
||||
for (int i = 0; i < plan->m_defaultParamCount; ++i) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "<DEFAULT> ");
|
||||
if (plan->m_defaultParams[i] == nullptr) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "null");
|
||||
} else {
|
||||
ExplainExpr(query, (JitPlan*)plan, plan->m_defaultParams[i]);
|
||||
}
|
||||
if (i < plan->m_defaultParamCount - 1) {
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", ");
|
||||
}
|
||||
}
|
||||
MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")");
|
||||
MOT_LOG_END(MOT::LogLevel::LL_TRACE);
|
||||
}
|
||||
|
||||
extern void JitExplainPlan(Query* query, JitPlan* plan)
|
||||
{
|
||||
if (plan != nullptr) {
|
||||
|
|
@ -773,10 +853,19 @@ extern void JitExplainPlan(Query* query, JitPlan* plan)
|
|||
ExplainCompoundPlan(query, (JitCompoundPlan*)plan);
|
||||
break;
|
||||
|
||||
case JIT_PLAN_INVOKE:
|
||||
ExplainInvokePlan(query, (JitInvokePlan*)plan);
|
||||
break;
|
||||
|
||||
case JIT_PLAN_INVALID:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern void JitExplainPlan(PLpgSQL_function* function, JitPlan* plan)
|
||||
{
|
||||
// not implemented yet
|
||||
}
|
||||
} // namespace JitExec
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue