* Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* ---------------------------------------------------------------------------------------
*/
#include "utils/knl_localsysdbcache.h"
#include "utils/knl_globalsysdbcache.h"
#include "utils/resowner.h"
#include "knl/knl_instance.h"
#include "executor/executor.h"
#include "utils/postinit.h"
#include "storage/sinvaladt.h"
#include "utils/hashutils.h"
#include "utils/knl_relcache.h"
#include "utils/acl.h"
#include "utils/spccache.h"
#include "commands/dbcommands.h"
#include "tsearch/ts_cache.h"
#include "optimizer/predtest.h"
#include "utils/attoptcache.h"
#include "parser/parse_oper.h"
#include "utils/typcache.h"
#include "utils/relfilenodemap.h"
#include "postmaster/bgworker.h"
#include "storage/lmgr.h"
#if defined(USE_ASSERT_CHECKING) && !defined(ENABLE_MEMORY_CHECK)
class LSCCloseCheck {
public:
LSCCloseCheck()
{
m_lsc_closed = true;
}
~LSCCloseCheck()
{
Assert(!EnableGlobalSysCache() || m_lsc_closed || t_thrd.role == DMS_WORKER ||
g_instance.distribute_test_param_instance->elevel == PANIC);
}
void setCloseFlag(bool value)
{
m_lsc_closed = value;
}
private:
bool m_lsc_closed;
};
thread_local LSCCloseCheck lsc_close_check = LSCCloseCheck();
#endif
void ReLoadLSCWhenWaitMission()
{
if (!EnableLocalSysCache()) {
return;
}
LocalSysDBCache *lsc = t_thrd.lsc_cxt.lsc;
if (unlikely(lsc == NULL)) {
return;
}
if (IsTransactionOrTransactionBlock()) {
return;
}
if (lsc->GetMyGlobalDBEntry() != NULL && lsc->GetMyGlobalDBEntry()->m_isDead) {
t_thrd.proc_cxt.PostInit->InitLoadLocalSysCache(u_sess->proc_cxt.MyDatabaseId,
u_sess->proc_cxt.MyProcPort->database_name);
}
g_instance.global_sysdbcache.GSCMemThresholdCheck();
}
void RememberRelSonMemCxtSpace(Relation rel)
{
if (rel->rd_rulescxt != NULL) {
t_thrd.lsc_cxt.lsc->rel_index_rule_space += ((AllocSet)rel->rd_rulescxt)->totalSpace;
}
if (rel->rd_indexcxt != NULL) {
t_thrd.lsc_cxt.lsc->rel_index_rule_space += ((AllocSet)rel->rd_indexcxt)->totalSpace;
}
}
void ForgetRelSonMemCxtSpace(Relation rel)
{
if (rel->rd_rulescxt != NULL) {
t_thrd.lsc_cxt.lsc->rel_index_rule_space -= ((AllocSet)rel->rd_rulescxt)->totalSpace;
}
if (rel->rd_indexcxt != NULL) {
t_thrd.lsc_cxt.lsc->rel_index_rule_space -= ((AllocSet)rel->rd_indexcxt)->totalSpace;
}
if (t_thrd.lsc_cxt.lsc->rel_index_rule_space < 0) {
t_thrd.lsc_cxt.lsc->rel_index_rule_space = 0;
}
}
bool CheckMyDatabaseMatch()
{
if (EnableLocalSysCache()) {
return u_sess->proc_cxt.MyDatabaseId == InvalidOid ||
u_sess->proc_cxt.MyDatabaseId == t_thrd.lsc_cxt.lsc->my_database_id;
} else {
return true;
}
}
bool IsGotPoolReload()
{
if (EnableLocalSysCache()) {
return u_sess->sig_cxt.got_pool_reload || t_thrd.lsc_cxt.lsc->got_pool_reload;
} else {
return u_sess->sig_cxt.got_pool_reload;
}
}
void ResetGotPoolReload(bool value)
{
if (!t_thrd.int_cxt.ignoreSessionBackendSignal) {
u_sess->sig_cxt.got_pool_reload = value;
}
if (EnableLocalSysCache()) {
t_thrd.lsc_cxt.lsc->got_pool_reload = value;
}
}
bool DeepthInAcceptInvalidationMessageNotZero()
{
if (EnableLocalSysCache()) {
return u_sess->inval_cxt.DeepthInAcceptInvalidationMessage > 0 ||
t_thrd.lsc_cxt.lsc->inval_cxt.DeepthInAcceptInvalidationMessage > 0;
} else {
return u_sess->inval_cxt.DeepthInAcceptInvalidationMessage > 0;
}
}
void ResetDeepthInAcceptInvalidationMessage(int value)
{
if (EnableLocalSysCache()) {
u_sess->inval_cxt.DeepthInAcceptInvalidationMessage = value;
t_thrd.lsc_cxt.lsc->inval_cxt.DeepthInAcceptInvalidationMessage = value;
} else {
u_sess->inval_cxt.DeepthInAcceptInvalidationMessage = value;
}
}
static bool SwitchToSessionSysCache()
{
if (FencedUDFMasterMode) {
return true;
}
if (
#ifdef ENABLE_MULTIPLE_NODES
t_thrd.role != TS_COMPACTION &&
t_thrd.role != TS_COMPACTION_CONSUMER &&
t_thrd.role != TS_COMPACTION_AUXILIAY
#else
true
#endif
) {
return false;
}
return true;
}
void CloseLocalSysDBCache()
{
if (!EnableLocalSysCache()) {
closeAllVfds();
}
if (t_thrd.lsc_cxt.lsc == NULL) {
return;
}
t_thrd.lsc_cxt.lsc->CloseLocalSysDBCache();
}
static inline HeapTuple GetTupleFromLscCatList(CatCList *cl, int index)
{
Assert(EnableLocalSysCache());
return &(((GlobalCatCTup **)cl->systups)[index]->tuple);
}
static inline HeapTuple GetTupleFromSessCatList(CatCList *cl, int index)
{
Assert(!EnableLocalSysCache());
return &(cl->systups[index]->tuple);
}
void CreateLocalSysDBCache()
{
if (!EnableGlobalSysCache()) {
t_thrd.lsc_cxt.enable_lsc = false;
t_thrd.lsc_cxt.FetchTupleFromCatCList = GetTupleFromSessCatList;
return;
}
Assert(t_thrd.lsc_cxt.lsc == NULL);
t_thrd.lsc_cxt.lsc = New(THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT))LocalSysDBCache();
t_thrd.lsc_cxt.enable_lsc = true;
t_thrd.lsc_cxt.lsc->CreateDBObject();
t_thrd.lsc_cxt.FetchTupleFromCatCList = GetTupleFromLscCatList;
t_thrd.lsc_cxt.lsc->recovery_finished = g_instance.global_sysdbcache.recovery_finished;
t_thrd.lsc_cxt.enable_lsc = !SwitchToSessionSysCache();
if (!t_thrd.lsc_cxt.enable_lsc) {
t_thrd.lsc_cxt.FetchTupleFromCatCList = GetTupleFromSessCatList;
t_thrd.lsc_cxt.lsc->is_closed = true;
#if defined(USE_ASSERT_CHECKING) && !defined(ENABLE_MEMORY_CHECK)
lsc_close_check.setCloseFlag(true);
} else {
lsc_close_check.setCloseFlag(false);
#endif
}
}
#if defined(USE_ASSERT_CHECKING) && !defined(ENABLE_MEMORY_CHECK)
void CloseLSCCheck()
{
lsc_close_check.setCloseFlag(true);
}
#endif
static void ReleaseBadPtrList(bool isCommit);
static void ThreadNodeGroupCallback(Datum arg, int cacheid, uint32 hashvalue)
{
RelationCacheInvalidateBuckets();
}
bool EnableGlobalSysCache()
{
return g_instance.attr.attr_common.enable_global_syscache;
}
MemoryContext LocalSharedCacheMemCxt()
{
if (EnableLocalSysCache()) {
return t_thrd.lsc_cxt.lsc->lsc_share_memcxt;
} else {
return u_sess->cache_mem_cxt;
}
}
MemoryContext LocalMyDBCacheMemCxt()
{
if (EnableLocalSysCache()) {
return t_thrd.lsc_cxt.lsc->lsc_mydb_memcxt;
} else {
return u_sess->cache_mem_cxt;
}
}
extern MemoryContext LocalGBucketMapMemCxt()
{
if (EnableLocalSysCache()) {
return t_thrd.lsc_cxt.lsc->lsc_share_memcxt;
} else {
return SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_EXECUTOR);
}
}
MemoryContext LocalSmgrStorageMemoryCxt(bool inter_xact)
{
if (EnableLocalSysCache() && !inter_xact) {
return t_thrd.lsc_cxt.lsc->lsc_mydb_memcxt;
} else {
return SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_STORAGE);
}
}
struct HTAB *GetTypeCacheHash()
{
if (EnableLocalSysCache()) {
return t_thrd.lsc_cxt.lsc->TypeCacheHash;
} else {
return u_sess->tycache_cxt.TypeCacheHash;
}
}
knl_u_inval_context *GetInvalCxt()
{
if (EnableLocalSysCache()) {
return &t_thrd.lsc_cxt.lsc->inval_cxt;
} else {
return &u_sess->inval_cxt;
}
}
void UnRegisterSysCacheCallBack(knl_u_inval_context *inval_cxt, int cacheid, SyscacheCallbackFunction func)
{
for (int i = 0; i < inval_cxt->syscache_callback_count; i++) {
if (inval_cxt->syscache_callback_list[i].id != cacheid ||
inval_cxt->syscache_callback_list[i].function != func) {
continue;
}
for (; i < inval_cxt->syscache_callback_count - 1; i++) {
inval_cxt->syscache_callback_list[i].id = inval_cxt->syscache_callback_list[i + 1].id;
inval_cxt->syscache_callback_list[i].function = inval_cxt->syscache_callback_list[i + 1].function;
inval_cxt->syscache_callback_list[i].arg = inval_cxt->syscache_callback_list[i + 1].arg;
}
--inval_cxt->syscache_callback_count;
break;
}
}
void UnRegisterRelCacheCallBack(knl_u_inval_context *inval_cxt, RelcacheCallbackFunction func)
{
for (int i = 0; i < inval_cxt->relcache_callback_count; i++) {
if (inval_cxt->relcache_callback_list[i].function != func) {
continue;
}
for (; i < inval_cxt->relcache_callback_count - 1; i++) {
inval_cxt->relcache_callback_list[i].function = inval_cxt->relcache_callback_list[i + 1].function;
inval_cxt->relcache_callback_list[i].arg = inval_cxt->relcache_callback_list[i + 1].arg;
}
--inval_cxt->relcache_callback_count;
break;
}
}
void UnRegisterPartCacheCallBack(knl_u_inval_context *inval_cxt, PartcacheCallbackFunction func)
{
for (int i = 0; i < inval_cxt->partcache_callback_count; i++) {
if (inval_cxt->partcache_callback_list[i].function != func) {
continue;
}
for (; i < inval_cxt->partcache_callback_count - 1; i++) {
inval_cxt->partcache_callback_list[i].function = inval_cxt->partcache_callback_list[i + 1].function;
inval_cxt->partcache_callback_list[i].arg = inval_cxt->partcache_callback_list[i + 1].arg;
}
--inval_cxt->partcache_callback_count;
break;
}
}
static void ClearMyDBOfRelMapCxt(knl_u_relmap_context *relmap_cxt)
{
relmap_cxt->local_map->magic = 0;
relmap_cxt->local_map->num_mappings = 0;
relmap_cxt->active_shared_updates->num_mappings = 0;
relmap_cxt->active_local_updates->num_mappings = 0;
relmap_cxt->pending_shared_updates->num_mappings = 0;
relmap_cxt->pending_local_updates->num_mappings = 0;
relmap_cxt->RelfilenodeMapHash = NULL;
relmap_cxt->UHeapRelfilenodeMapHash = NULL;
relmap_cxt->PartfilenodeMapHash = NULL;
}
static void ResetRelMapCxt(knl_u_relmap_context *relmap_cxt)
{
ClearMyDBOfRelMapCxt(relmap_cxt);
relmap_cxt->shared_map->magic = 0;
relmap_cxt->shared_map->num_mappings = 0;
}
struct HTAB *GetTableSpaceCacheHash()
{
if (EnableLocalSysCache()) {
return t_thrd.lsc_cxt.lsc->TableSpaceCacheHash;
} else {
return u_sess->cache_cxt.TableSpaceCacheHash;
}
}
struct HTAB *GetSMgrRelationHash()
{
if (EnableLocalSysCache()) {
return t_thrd.lsc_cxt.lsc->SMgrRelationHash;
} else {
return u_sess->storage_cxt.SMgrRelationHash;
}
}
struct vfd *GetVfdCache(bool inter_xact)
{
if (EnableLocalSysCache() && !inter_xact) {
return t_thrd.lsc_cxt.lsc->VfdCache;
} else {
if (u_sess->storage_cxt.VfdCache == NULL) {
InitSessionFileAccess();
}
return u_sess->storage_cxt.VfdCache;
}
}
struct vfd **GetVfdCachePtr(bool inter_xact)
{
if (EnableLocalSysCache() && !inter_xact) {
return &t_thrd.lsc_cxt.lsc->VfdCache;
} else {
return &u_sess->storage_cxt.VfdCache;
}
}
void SetVfdCache(vfd *value, bool inter_xact)
{
if (EnableLocalSysCache() && !inter_xact) {
t_thrd.lsc_cxt.lsc->VfdCache = value;
} else {
u_sess->storage_cxt.VfdCache = value;
}
}
void SetSizeVfdCache(Size value, bool inter_xact)
{
if (EnableLocalSysCache() && !inter_xact) {
t_thrd.lsc_cxt.lsc->SizeVfdCache = value;
} else {
u_sess->storage_cxt.SizeVfdCache = value;
}
}
Size GetSizeVfdCache(bool inter_xact)
{
if (EnableLocalSysCache() && !inter_xact) {
return t_thrd.lsc_cxt.lsc->SizeVfdCache;
} else {
return u_sess->storage_cxt.SizeVfdCache;
}
}
Size *GetSizeVfdCachePtr(bool inter_xact)
{
if (EnableLocalSysCache() && !inter_xact) {
return &t_thrd.lsc_cxt.lsc->SizeVfdCache;
} else {
return &u_sess->storage_cxt.SizeVfdCache;
}
}
int GetVfdNfile(bool inter_xact)
{
if (EnableLocalSysCache() && !inter_xact) {
return t_thrd.lsc_cxt.lsc->nfile;
} else {
return u_sess->storage_cxt.nfile;
}
}
void AddVfdNfile(int n, bool inter_xact)
{
Assert(n == 1 || n == -1);
if (EnableLocalSysCache() && !inter_xact) {
t_thrd.lsc_cxt.lsc->nfile += n;
} else {
u_sess->storage_cxt.nfile += n;
}
}
dlist_head *getUnownedReln()
{
if (EnableLocalSysCache()) {
return &t_thrd.lsc_cxt.lsc->unowned_reln;
} else {
return &u_sess->storage_cxt.unowned_reln;
}
}
knl_u_relmap_context *GetRelMapCxt()
{
if (EnableLocalSysCache()) {
return &t_thrd.lsc_cxt.lsc->relmap_cxt;
} else {
return &u_sess->relmap_cxt;
}
}
void LocalSysDBCache::LocalSysDBCacheReleaseGlobalReSource(bool is_commit)
{
ResourceOwnerReleaseRWLock(t_thrd.lsc_cxt.local_sysdb_resowner, is_commit);
ResourceOwnerReleaseGlobalCatCList(t_thrd.lsc_cxt.local_sysdb_resowner, is_commit);
ResourceOwnerReleaseGlobalCatCTup(t_thrd.lsc_cxt.local_sysdb_resowner, is_commit);
ResourceOwnerReleaseGlobalBaseEntry(t_thrd.lsc_cxt.local_sysdb_resowner, is_commit);
ResourceOwnerReleaseGlobalDBEntry(t_thrd.lsc_cxt.local_sysdb_resowner, is_commit);
ResourceOwnerReleaseGlobalIsExclusive(t_thrd.lsc_cxt.local_sysdb_resowner, is_commit);
}
void LocalSysDBCache::LocalSysDBCacheReleaseCritialReSource(bool include_shared)
{
closeAllVfds();
LocalSysDBCacheReleaseGlobalReSource(false);
ReleaseBadPtrList(false);
systabcache.ReleaseGlobalRefcount(include_shared);
if (m_global_db != NULL) {
m_global_db->Release();
m_global_db = NULL;
}
rdlock_info.count = 0;
tabdefcache.ResetInitFlag(include_shared);
partdefcache.ResetInitFlag();
systabcache.ResetInitFlag(include_shared);
SetThreadDefExclusive(IS_THREAD_POOL_STREAM || IsBgWorkerProcess());
}
bool LocalSysDBCache::DBStandbyChanged()
{
bool isStandby = t_thrd.postmaster_cxt.HaShmData->current_mode == STANDBY_MODE || (ENABLE_DMS && SS_STANDBY_MODE);
if (unlikely(isStandby && my_database_id != InvalidOid)) {
if (unlikely(my_database_id != u_sess->proc_cxt.MyDatabaseId)) {
return true;
}
Assert(u_sess->proc_cxt.MyDatabaseId != InvalidOid);
HeapTuple tup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(my_database_id));
if (unlikely(!HeapTupleIsValid(tup))) {
return true;
}
Form_pg_database dbform = (Form_pg_database)GETSTRUCT(tup);
if (unlikely(strcmp(my_database_name, NameStr(dbform->datname)) != 0 ||
my_database_tablespace != dbform->dattablespace)) {
ReleaseSysCache(tup);
return true;
}
ReleaseSysCache(tup);
}
return false;
}
bool LocalSysDBCache::DBNotMatch(Oid db_id, const char *db_name)
{
if (likely(db_name != NULL && db_id == InvalidOid)) {
if (strcmp(my_database_name, db_name) != 0) {
return true;
}
} else if (unlikely(db_name == NULL && db_id != InvalidOid)) {
if (my_database_id != db_id) {
return true;
}
} else if (unlikely(db_name != NULL && db_id != InvalidOid)) {
if (strcmp(my_database_name, db_name) != 0 || my_database_id != db_id) {
return true;
}
} else {
return true;
Assert(t_thrd.role == AUTOVACUUM_LAUNCHER || t_thrd.role == UNDO_LAUNCHER || t_thrd.role == CATCHUP ||
(IsBootstrapProcessingMode() &&
t_thrd.role == MASTER_THREAD &&
strcmp(t_thrd.proc_cxt.MyProgName, "BootStrap") == 0
));
}
return false;
}
bool LocalSysDBCache::LockAndAttachDBFailed()
{
* but for GSC mode, we do need aquire lock when cache hit and there are invalid msgs
* with session uninited and so u_sess->proc_cxt.MyDatabaseId is InvalidOid.
* 1 the publication feature will send all rels' invalmsgs even no refered ddl.
* 2 relations may have refcount leak, so we must rebuild them if cache hit.
* when we rebuild a relation, the session may be not uninited,
* and so u_sess->proc_cxt.MyDatabaseId is InvalidOid,
* so we use t_thrd.lsc_cxt.lsc->my_database_id on GSC mode */
Assert(CheckMyDatabaseMatch());
Assert(m_global_db != NULL);
* we will call SetDatabase to rewrite it.
* but before SetDatabase, we need the dbid to Accept Invalid msg */
bool lock_db_advance = u_sess->proc_cxt.MyDatabaseId == InvalidOid;
Assert(!lock_db_advance || IS_THREAD_POOL_WORKER);
if (lock_db_advance) {
Assert(t_thrd.proc->databaseId == InvalidOid);
LockSharedObjectForSession(DatabaseRelationId, my_database_id, 0, RowExclusiveLock);
t_thrd.proc->databaseId = my_database_id;
UnlockSharedObjectForSession(DatabaseRelationId, my_database_id, 0, RowExclusiveLock);
if (m_global_db->m_isDead) {
t_thrd.proc->databaseId = InvalidOid;
return true;
} else {
Assert(u_sess->proc_cxt.MyDatabaseTableSpace == InvalidOid);
Assert(u_sess->proc_cxt.DatabasePath == NULL);
u_sess->proc_cxt.MyDatabaseId = my_database_id;
u_sess->proc_cxt.MyDatabaseTableSpace = my_database_tablespace;
u_sess->proc_cxt.DatabasePath = my_database_path;
}
}
return false;
}
bool LocalSysDBCache::LocalSysDBCacheNeedClearMyDB(Oid db_id, const char *db_name)
{
if (DBNotMatch(db_id, db_name)) {
return true;
}
if (m_global_db->m_isDead) {
return true;
}
Assert(u_sess->proc_cxt.MyDatabaseId == InvalidOid || u_sess->proc_cxt.MyDatabaseId == my_database_id);
if (LockAndAttachDBFailed()) {
return true;
}
Assert(u_sess->proc_cxt.MyDatabaseId == my_database_id);
return false;
}
void LocalSysDBCache::LocalSysDBCacheResetMyDBStat()
{
TypeCacheHash = NULL;
SMgrRelationHash = NULL;
VfdCache = NULL;
SizeVfdCache = 0;
Assert(nfile == 0);
nfile = 0;
bad_ptr_obj.ResetInitFlag();
my_database_id = InvalidOid;
my_database_tablespace = InvalidOid;
my_database_name[0] = '\0';
dlist_init(&unowned_reln);
pfree_ext(my_database_path);
UnRegisterRelCacheCallBack(&inval_cxt, TypeCacheRelCallback);
UnRegisterRelCacheCallBack(&inval_cxt, RelfilenodeMapInvalidateCallback);
UnRegisterRelCacheCallBack(&inval_cxt, PartfilenodeMapInvalidateCallback);
}
void LocalSysDBCache::LocalSysDBCacheClearMyDB()
{
LocalSysDBCacheReleaseCritialReSource(false);
LocalSysDBCacheResetMyDBStat();
ClearMyDBOfRelMapCxt(&relmap_cxt);
MemoryContextResetAndDeleteChildren(lsc_mydb_memcxt);
ResetInitStatus();
rel_index_rule_space = 0;
}
bool LocalSysDBCache::LocalSysDBCacheNeedCleanCache()
{
if (unlikely(!recovery_finished && g_instance.global_sysdbcache.recovery_finished)) {
recovery_finished = g_instance.global_sysdbcache.recovery_finished;
return true;
} else if (!g_instance.global_sysdbcache.hot_standby) {
return true;
}
if (StreamThreadAmI()) {
return true;
}
return false;
}
void LocalSysDBCache::LocalSysDBCacheCleanCache()
{
Assert(!IsTransactionOrTransactionBlock());
LocalSysDBCacheClearMyDB();
systabcache.ResetCatalogCaches();
relmap_cxt.shared_map->magic = 0;
relmap_cxt.shared_map->num_mappings = 0;
if (TableSpaceCacheHash != NULL) {
InvalidateTableSpaceCacheCallback(0, TABLESPACEOID, 0);
}
}
void LocalSysDBCache::LocalSysDBCacheReSet()
{
LocalSysDBCacheReleaseCritialReSource(true);
LocalSysDBCacheResetMyDBStat();
abort_count = 0;
TableSpaceCacheHash = NULL;
UnRegisterSysCacheCallBack(&inval_cxt, TABLESPACEOID, InvalidateTableSpaceCacheCallback);
MemoryContextResetAndDeleteChildren(lsc_mydb_memcxt);
MemoryContextResetAndDeleteChildren(lsc_share_memcxt);
ResetRelMapCxt(&relmap_cxt);
rel_index_rule_space = 0;
ResetInitStatus();
is_closed = false;
is_lsc_catbucket_created = false;
}
bool LocalSysDBCache::LocalSysDBCacheNeedReBuild()
{
if (unlikely(init_status == LscIniting)) {
return true;
}
if (unlikely(abort_count > (uint64)u_sess->attr.attr_memory.local_syscache_threshold)) {
return true;
}
uint64 total_space =
((AllocSet)lsc_top_memcxt)->totalSpace +
((AllocSet)lsc_share_memcxt)->totalSpace +
((AllocSet)lsc_mydb_memcxt)->totalSpace +
((AllocSet)u_sess->cache_mem_cxt)->totalSpace +
rel_index_rule_space;
uint64 memory_upper_limit = ((uint64)u_sess->attr.attr_memory.local_syscache_threshold) << 10;
return total_space * (1 - MAX_LSC_FREESIZE_RATIO) > memory_upper_limit;
}
void LocalSysDBCache::LocalSysDBCacheReBuild()
{
int i;
knl_u_inval_context *inval_cxt = &u_sess->inval_cxt;
for (i = 0; i < inval_cxt->syscache_callback_count; i++) {
struct SYSCACHECALLBACK* ccitem = inval_cxt->syscache_callback_list + i;
(*ccitem->function)(ccitem->arg, ccitem->id, 0);
}
for (i = 0; i < inval_cxt->relcache_callback_count; i++) {
struct RELCACHECALLBACK* ccitem = inval_cxt->relcache_callback_list + i;
(*ccitem->function)(ccitem->arg, InvalidOid);
}
for (i = 0; i < inval_cxt->partcache_callback_count; i++) {
struct PARTCACHECALLBACK* ccitem = inval_cxt->partcache_callback_list + i;
(*ccitem->function)(ccitem->arg, InvalidOid);
}
LocalSysDBCacheReSet();
CreateCatBucket();
}
bool LocalSysDBCache::LocalSysDBCacheNeedSwapOut()
{
uint64 used_space =
AllocSetContextUsedSpace((AllocSet)lsc_top_memcxt) +
AllocSetContextUsedSpace((AllocSet)lsc_share_memcxt) +
AllocSetContextUsedSpace((AllocSet)lsc_mydb_memcxt) +
AllocSetContextUsedSpace((AllocSet)u_sess->cache_mem_cxt) +
rel_index_rule_space;
uint64 memory_upper_limit =
(((uint64)u_sess->attr.attr_memory.local_syscache_threshold) << 10) * cur_swapout_ratio;
bool need_swapout = used_space > memory_upper_limit;
if (unlikely(need_swapout && cur_swapout_ratio == MAX_LSC_SWAPOUT_RATIO)) {
cur_swapout_ratio = MIN_LSC_SWAPOUT_RATIO;
} else if (unlikely(!need_swapout && cur_swapout_ratio == MIN_LSC_SWAPOUT_RATIO)) {
cur_swapout_ratio = MAX_LSC_SWAPOUT_RATIO;
}
return need_swapout;
}
void LocalSysDBCache::CloseLocalSysDBCache()
{
if (is_closed) {
return;
}
LocalSysDBCacheReleaseCritialReSource(true);
ResetInitStatus();
is_closed = true;
#if defined(USE_ASSERT_CHECKING) && !defined(ENABLE_MEMORY_CHECK)
lsc_close_check.setCloseFlag(true);
#endif
}
void LocalSysDBCache::ClearSysCacheIfNecessary(Oid db_id, const char *db_name)
{
t_thrd.lsc_cxt.xact_seqno++;
CreateCatBucket();
if (unlikely(init_status == LscNotInit)) {
return;
}
Assert(!IsTransactionOrTransactionBlock());
if (unlikely(LocalSysDBCacheNeedReBuild())) {
LocalSysDBCacheReBuild();
return;
}
Assert(init_status == LscInitfinished);
if (unlikely(LocalSysDBCacheNeedCleanCache())) {
LocalSysDBCacheCleanCache();
} else if (LocalSysDBCacheNeedClearMyDB(db_id, db_name)) {
LocalSysDBCacheClearMyDB();
}
g_instance.global_sysdbcache.Refresh();
}
void LocalSysDBCache::CreateDBObject()
{
Assert(lsc_top_memcxt == NULL);
lsc_top_memcxt = AllocSetContextCreate(
THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT), "LocalSysCacheTopMemoryContext", ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, STANDARD_CONTEXT);
lsc_share_memcxt =
AllocSetContextCreate(lsc_top_memcxt, "LocalSysCacheShareMemoryContext", ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, STANDARD_CONTEXT);
lsc_mydb_memcxt =
AllocSetContextCreate(lsc_top_memcxt, "LocalSysCacheMyDBMemoryContext", ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, STANDARD_CONTEXT);
MemoryContext old = MemoryContextSwitchTo(lsc_top_memcxt);
systabcache.CreateObject();
tabdefcache.CreateDefBucket();
partdefcache.CreateDefBucket();
knl_u_inval_init(&inval_cxt);
dlist_init(&unowned_reln);
knl_u_relmap_init(&relmap_cxt);
MemoryContextSwitchTo(old);
if (IS_PGXC_COORDINATOR) {
CacheRegisterThreadSyscacheCallback(PGXCGROUPOID, ThreadNodeGroupCallback, (Datum)0);
}
m_shared_global_db = g_instance.global_sysdbcache.GetSharedGSCEntry();
rel_index_rule_space = 0;
is_lsc_catbucket_created = false;
}
void LocalSysDBCache::CreateCatBucket()
{
if (likely(is_lsc_catbucket_created)) {
return;
}
MemoryContext old = MemoryContextSwitchTo(lsc_share_memcxt);
systabcache.CreateCatBuckets();
MemoryContextSwitchTo(old);
rel_index_rule_space = 0;
is_lsc_catbucket_created = true;
cur_swapout_ratio = MAX_LSC_SWAPOUT_RATIO;
}
void LocalSysDBCache::SetDatabaseName(const char *db_name)
{
if (db_name != NULL && db_name[0] != '\0') {
size_t len = strlen(db_name);
Assert(len > 0 && len < NAMEDATALEN);
errno_t rc = memcpy_s(my_database_name, len + 1, db_name, len + 1);
securec_check(rc, "\0", "\0");
return;
}
if (my_database_name[0] == '\0') {
t_thrd.proc_cxt.PostInit->GetDatabaseName(my_database_name);
}
if (my_database_name[0] == '\0') {
char *tmp = get_database_name(my_database_id);
size_t len = strlen(tmp);
errno_t rc = memcpy_s(my_database_name, len + 1, tmp, len + 1);
securec_check(rc, "\0", "\0");
pfree_ext(tmp);
}
}
void LocalSysDBCache::InitThreadDatabase(Oid db_id, const char *db_name, Oid db_tabspc)
{
Assert(db_id != InvalidOid);
if (my_database_id == db_id) {
Assert(my_database_name[0] != '\0');
Assert(my_database_tablespace == db_tabspc);
Assert(db_name == NULL || strcmp(my_database_name, db_name) == 0);
return;
} else if (my_database_id != InvalidOid) {
Assert(false);
ereport(ERROR, (errno, errmsg("lsc has some error, please try again!")));
}
Assert(db_id == u_sess->proc_cxt.MyDatabaseId);
Assert(my_database_id == InvalidOid);
Assert(my_database_tablespace == InvalidOid);
Assert(my_database_name[0] == '\0');
my_database_id = db_id;
my_database_tablespace = db_tabspc;
if (db_id == TemplateDbOid) {
my_database_name[0] = '\0';
return;
}
SetDatabaseName(db_name);
}
void LocalSysDBCache::FixWrongCacheStat(Oid db_id, Oid db_tabspc)
{
if (!(
unlikely(m_global_db != NULL && m_global_db->m_isDead) ||
unlikely(my_database_id != db_id && my_database_id != InvalidOid)
)) {
return;
}
Assert((m_global_db != NULL && m_global_db->m_isDead) || DBStandbyChanged());
Oid old_db_id = u_sess->proc_cxt.MyDatabaseId;
Oid old_db_tabspc = u_sess->proc_cxt.MyDatabaseTableSpace;
Assert(old_db_id == db_id && old_db_tabspc == db_tabspc);
Assert(u_sess->proc_cxt.DatabasePath == NULL || u_sess->proc_cxt.DatabasePath == my_database_path);
if (u_sess->proc_cxt.DatabasePath == my_database_path) {
u_sess->proc_cxt.DatabasePath = NULL;
}
* for now, we reset them to zero, but clearmydb dont clear shared rels is better
* whatever, we dont care error when init, if we failed, the sess will exit, the old status does not matter */
u_sess->proc_cxt.MyDatabaseId = InvalidOid;
u_sess->proc_cxt.MyDatabaseTableSpace = InvalidOid;
* otherwise, it should not happen */
Assert(t_thrd.postmaster_cxt.HaShmData->current_mode == STANDBY_MODE || (ENABLE_DMS && SS_STANDBY_MODE));
LocalSysDBCacheClearMyDB();
InitFileAccess();
t_thrd.lsc_cxt.lsc->StartInit();
t_thrd.lsc_cxt.lsc->tabdefcache.Init();
t_thrd.lsc_cxt.lsc->tabdefcache.InitPhase2();
t_thrd.lsc_cxt.lsc->systabcache.Init();
u_sess->proc_cxt.MyDatabaseId = old_db_id;
u_sess->proc_cxt.MyDatabaseTableSpace = old_db_tabspc;
}
void LocalSysDBCache::InitSessionDatabase(Oid db_id, const char *db_name, Oid db_tabspc)
{
FixWrongCacheStat(db_id, db_tabspc);
Assert(db_id != InvalidOid);
Assert(init_status == LscIniting);
if (my_database_id != db_id) {
Assert(my_database_id == InvalidOid);
Assert(my_database_tablespace == InvalidOid);
Assert(my_database_name[0] == '\0');
my_database_id = db_id;
if (db_name != NULL && !IsBootstrapProcessingMode()) {
SetDatabaseName(db_name);
}
my_database_tablespace = db_tabspc;
} else {
Assert(my_database_id == db_id);
Assert(my_database_tablespace == db_tabspc);
Assert(strcmp(my_database_name, db_name) == 0);
}
}
void LocalSysDBCache::InitDatabasePath(const char *db_path)
{
Assert(db_path != NULL);
if (my_database_path == NULL) {
my_database_path = MemoryContextStrdup(lsc_share_memcxt, db_path);
} else if (strcmp(my_database_path, db_path) != 0) {
pfree_ext(my_database_path);
my_database_path = MemoryContextStrdup(lsc_share_memcxt, db_path);
}
}
void LocalSysDBCache::InitDBRef()
{
Assert(m_global_db == NULL);
Assert(my_database_id != InvalidOid);
Assert(my_database_id == u_sess->proc_cxt.MyDatabaseId);
m_global_db = g_instance.global_sysdbcache.GetGSCEntry(my_database_id, my_database_name);
}
void LocalSysDBCache::InitRelMapPhase2()
{
Assert(m_shared_global_db != NULL);
m_shared_global_db->m_relmapCache->InitPhase2();
if (!IS_MAGIC_EXIST(relmap_cxt.shared_map->magic)) {
m_shared_global_db->m_relmapCache->CopyInto(relmap_cxt.shared_map);
}
}
void LocalSysDBCache::InitRelMapPhase3()
{
Assert(m_global_db != NULL);
m_global_db->m_relmapCache->InitPhase2();
if (!IS_MAGIC_EXIST(relmap_cxt.local_map->magic)) {
m_global_db->m_relmapCache->CopyInto(relmap_cxt.local_map);
}
}
void LocalSysDBCache::LoadRelMapFromGlobal(bool shared)
{
GlobalSysDBCacheEntry *global_db = shared ? m_shared_global_db : m_global_db;
RelMapFile *rel_map = shared ? relmap_cxt.shared_map : relmap_cxt.local_map;
Assert(global_db != NULL);
global_db->m_relmapCache->CopyInto(rel_map);
}
void LocalSysDBCache::InvalidateGlobalRelMap(bool shared, Oid db_id, RelMapFile *rel_map)
{
if (shared) {
Assert(m_shared_global_db != NULL);
GlobalSysDBCacheEntry *global_db = m_shared_global_db;
global_db->m_relmapCache->UpdateBy(rel_map);
} else if (m_global_db == NULL) {
Assert(init_status != LscInitfinished);
GlobalSysDBCacheEntry *entry = g_instance.global_sysdbcache.FindTempGSCEntry(db_id);
if (entry == NULL) {
return;
}
entry->m_relmapCache->UpdateBy(rel_map);
g_instance.global_sysdbcache.ReleaseTempGSCEntry(entry);
} else {
Assert(my_database_id == db_id);
m_global_db->m_relmapCache->UpdateBy(rel_map);
}
}
void LocalSysDBCache::SetThreadDefExclusive(bool is_exclusive)
{
m_is_def_exclusive = is_exclusive;
}
LocalSysDBCache::LocalSysDBCache()
{
lsc_top_memcxt = NULL;
lsc_share_memcxt = NULL;
lsc_mydb_memcxt = NULL;
m_global_db = NULL;
my_database_id = InvalidOid;
my_database_name[0] = '\0';
my_database_path = NULL;
my_database_tablespace = InvalidOid;
TableSpaceCacheHash = NULL;
TypeCacheHash = NULL;
SMgrRelationHash = NULL;
VfdCache = NULL;
SizeVfdCache = 0;
nfile = 0;
abort_count = 0;
rdlock_info.count = 0;
got_pool_reload = false;
m_shared_global_db = NULL;
cur_swapout_ratio = MAX_LSC_SWAPOUT_RATIO;
is_lsc_catbucket_created = false;
is_closed = false;
ResetInitStatus();
#if defined(USE_ASSERT_CHECKING) && !defined(ENABLE_MEMORY_CHECK)
lsc_close_check.setCloseFlag(false);
#endif
}
void AtEOXact_SysDBCache(bool is_commit)
{
ResourceOwnerReleasePthreadMutex(t_thrd.lsc_cxt.local_sysdb_resowner, is_commit);
if (!EnableLocalSysCache()) {
ResourceOwnerReleaseRelationRef(t_thrd.lsc_cxt.local_sysdb_resowner, is_commit);
return;
}
Assert(t_thrd.lsc_cxt.lsc != NULL);
ResourceOwnerReleaseLocalCatCList(t_thrd.lsc_cxt.local_sysdb_resowner, is_commit);
ResourceOwnerReleaseLocalCatCTup(t_thrd.lsc_cxt.local_sysdb_resowner, is_commit);
ResourceOwnerReleaseRelationRef(t_thrd.lsc_cxt.local_sysdb_resowner, is_commit);
t_thrd.lsc_cxt.lsc->LocalSysDBCacheReleaseGlobalReSource(is_commit);
Assert(CurrentResourceOwnerIsEmpty(t_thrd.lsc_cxt.local_sysdb_resowner));
ReleaseBadPtrList(is_commit);
if (!is_commit) {
t_thrd.lsc_cxt.lsc->abort_count++;
}
t_thrd.lsc_cxt.lsc->rdlock_info.count = 0;
t_thrd.lsc_cxt.lsc->SetThreadDefExclusive(IS_THREAD_POOL_STREAM || IsBgWorkerProcess());
}
void AppendBadPtr(void *elem)
{
BadPtrObj *obj = &t_thrd.lsc_cxt.lsc->bad_ptr_obj;
int newmax = 0;
if (obj->nbadptr >= obj->maxbadptr) {
if (obj->bad_ptr_lists == NULL) {
newmax = 16;
obj->bad_ptr_lists = (void **)MemoryContextAlloc(t_thrd.lsc_cxt.lsc->lsc_share_memcxt,
newmax * sizeof(void *));
obj->maxbadptr = newmax;
} else {
newmax = obj->maxbadptr * 2;
obj->bad_ptr_lists = (void **)repalloc(obj->bad_ptr_lists, newmax * sizeof(void *));
obj->maxbadptr = newmax;
}
}
Assert(obj->nbadptr < obj->maxbadptr);
obj->bad_ptr_lists[obj->nbadptr] = elem;
obj->nbadptr++;
}
void RemoveBadPtr(void *elem)
{
BadPtrObj *obj = &t_thrd.lsc_cxt.lsc->bad_ptr_obj;
void **bad_lists = obj->bad_ptr_lists;
int nc = obj->nbadptr - 1;
for (int i = nc; i >= 0; i--) {
if (bad_lists[i] == elem) {
while (i < nc) {
bad_lists[i] = bad_lists[i + 1];
i++;
}
obj->nbadptr = nc;
return;
}
}
}
static void ReleaseBadPtrList(bool isCommit)
{
BadPtrObj *obj = &t_thrd.lsc_cxt.lsc->bad_ptr_obj;
while (obj->nbadptr > 0) {
if (isCommit) {
}
pfree_ext(obj->bad_ptr_lists[obj->nbadptr - 1]);
obj->nbadptr--;
}
}
void StreamTxnContextSaveInvalidMsg(void *stc)
{
if (!EnableLocalSysCache()) {
STCSaveElem(((StreamTxnContext *)stc)->lsc_dbcache, NULL);
return;
}
STCSaveElem(((StreamTxnContext *)stc)->lsc_dbcache, t_thrd.lsc_cxt.lsc);
* just stop insert rel/part into gsc,
* tuple has its flag to decide hot to do insert*/
t_thrd.lsc_cxt.lsc->SetThreadDefExclusive(true);
}
void StreamTxnContextRestoreInvalidMsg(void *stc)
{
if (!EnableLocalSysCache()) {
return;
}
LocalSysDBCache *lsc_dbcache = ((StreamTxnContext *)stc)->lsc_dbcache;
InvalidBaseEntry *src_part = &lsc_dbcache->partdefcache.invalid_entries;
InvalidBaseEntry *dst_part = &t_thrd.lsc_cxt.lsc->partdefcache.invalid_entries;
dst_part->CopyFrom(src_part);
InvalidBaseEntry *src_rel = &lsc_dbcache->tabdefcache.invalid_entries;
InvalidBaseEntry *dst_rel = &t_thrd.lsc_cxt.lsc->tabdefcache.invalid_entries;
dst_rel->CopyFrom(src_rel);
for (int i = 0; i < SysCacheSize; i++) {
InvalidBaseEntry *src_tup = &lsc_dbcache->systabcache.local_systupcaches[i]->invalid_entries;
InvalidBaseEntry *dst_tup = &t_thrd.lsc_cxt.lsc->systabcache.local_systupcaches[i]->invalid_entries;
dst_tup->CopyFrom(src_tup);
dst_tup->is_reset |= src_tup->is_reset;
}
}
void ReleaseAllGSCRdConcurrentLock()
{
if (!EnableLocalSysCache() || t_thrd.lsc_cxt.lsc->rdlock_info.count == 0) {
return;
}
while (t_thrd.lsc_cxt.lsc->rdlock_info.count > 0) {
int cur_index = t_thrd.lsc_cxt.lsc->rdlock_info.count - 1;
ReleaseGSCTableReadLock(t_thrd.lsc_cxt.lsc->rdlock_info.has_concurrent_lock[cur_index],
t_thrd.lsc_cxt.lsc->rdlock_info.concurrent_lock[cur_index]);
}
}
void TryFreshSmgrCache(struct SMgrRelationData *smgr)
{
if (!EnableLocalSysCache()) {
return;
}
if (!IS_THREAD_POOL_WORKER) {
return;
}
if (likely(smgr->xact_seqno == t_thrd.lsc_cxt.xact_seqno)) {
return;
}
smgr->xact_seqno = t_thrd.lsc_cxt.xact_seqno;
smgr->smgr_targblock = InvalidBlockNumber;
}