* 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_localbasedefcache.h"
#include "knl/knl_instance.h"
#include "utils/knl_relcache.h"
#include "utils/knl_catcache.h"
#include "utils/knl_partcache.h"
#include "utils/relmapper.h"
#include "postmaster/autovacuum.h"
#include "pgxc/bucketmap.h"
LocalBaseEntry *LocalBaseDefCache::SearchEntryFromLocal(Oid oid, Index hash_index)
{
for (Dlelem *elt = DLGetHead(m_bucket_list.GetBucket(hash_index)); elt != NULL; elt = DLGetSucc(elt)) {
LocalBaseEntry *entry = (LocalBaseEntry *)DLE_VAL(elt);
if (unlikely(entry->oid != oid)) {
continue;
}
DLMoveToFront(&entry->cache_elem);
return entry;
}
return NULL;
}
void LocalBaseDefCache::CreateDefBucket(size_t size)
{
invalid_entries.Init();
m_nbuckets = ResizeHashBucket(size, g_instance.global_sysdbcache.dynamic_hash_bucket_strategy);
m_bucket_list.Init(m_nbuckets);
}
LocalBaseEntry *LocalBaseDefCache::CreateEntry(Index hash_index, size_t size)
{
MemoryContext old = MemoryContextSwitchTo(LocalMyDBCacheMemCxt());
LocalBaseEntry *entry = (LocalBaseEntry *)palloc(size);
MemoryContextSwitchTo(old);
DLInitElem(&entry->cache_elem, (void *)entry);
m_bucket_list.AddHeadToBucket(hash_index, &entry->cache_elem);
return entry;
}
template <bool is_relation>
void LocalBaseDefCache::RemoveTailDefElements()
{
Index tail_index = m_bucket_list.GetTailBucketIndex();
if (unlikely(tail_index == INVALID_INDEX)) {
return;
}
int swapout_count_once = 0;
int max_swapout_count_once = m_bucket_list.GetBucket(tail_index)->dll_len >> 1;
for (Dlelem *elt = DLGetTail(m_bucket_list.GetBucket(tail_index)); elt != NULL;) {
Dlelem *tmp = elt;
elt = DLGetPred(elt);
if (is_relation) {
LocalRelationEntry *entry = (LocalRelationEntry *)DLE_VAL(tmp);
if (RelationHasReferenceCountZero(entry->rel) && entry->rel->rd_createSubid == InvalidSubTransactionId &&
entry->rel->rd_newRelfilenodeSubid == InvalidSubTransactionId) {
Assert(!entry->rel->rd_isnailed);
Assert(entry->rel->entry == entry);
RelationClearRelation(entry->rel, false);
swapout_count_once++;
} else {
DLMoveToFront(&entry->cache_elem);
break;
}
} else {
LocalPartitionEntry *entry = (LocalPartitionEntry *)DLE_VAL(tmp);
if (PartitionHasReferenceCountZero(entry->part) &&
entry->part->pd_newRelfilenodeSubid == InvalidSubTransactionId &&
entry->part->pd_createSubid == InvalidSubTransactionId) {
Assert(entry->part->entry == entry);
PartitionClearPartition(entry->part, false);
swapout_count_once++;
} else {
DLMoveToFront(&entry->cache_elem);
break;
}
}
if (swapout_count_once == max_swapout_count_once) {
break;
}
}
if (!DLIsNIL(m_bucket_list.GetBucket(tail_index))) {
m_bucket_list.MoveBucketToHead(tail_index);
}
}
template void LocalBaseDefCache::RemoveTailDefElements<false>();
template void LocalBaseDefCache::RemoveTailDefElements<true>();