forked from huawei/openGauss-server
Global SysCache
Offering: openGaussDev More detail: 修复闪回功能未适配GSC导致DDL数据无法丢弃问题 # Conflicts: # src/gausskernel/storage/tcap/tcap_truncate.cpp Match-id-e09ce9c267ac9ae227186b0e7cbc9377b1cfb06a
This commit is contained in:
parent
66b05d1215
commit
0c08e764e0
|
|
@ -211,7 +211,7 @@ void LocalPartDefCache::Init()
|
|||
}
|
||||
m_global_partdefcache = t_thrd.lsc_cxt.lsc->GetGlobalPartDefCache();
|
||||
m_db_id = t_thrd.lsc_cxt.lsc->my_database_id;
|
||||
part_cache_need_eoxact_work = false;
|
||||
PartCacheNeedEOXActWork = false;
|
||||
m_is_inited = true;
|
||||
}
|
||||
|
||||
|
|
@ -298,7 +298,7 @@ void LocalPartDefCache::AtEOXact_PartitionCache(bool isCommit)
|
|||
* transaction, even though we could clear it at subtransaction end in
|
||||
* some cases.
|
||||
*/
|
||||
if (!part_cache_need_eoxact_work
|
||||
if (!GetPartCacheNeedEOXActWork()
|
||||
#ifdef USE_ASSERT_CHECKING
|
||||
&& !assert_enabled
|
||||
#endif
|
||||
|
|
@ -356,7 +356,7 @@ void LocalPartDefCache::AtEOXact_PartitionCache(bool isCommit)
|
|||
}
|
||||
|
||||
/* Once done with the transaction, we can reset need_eoxact_work */
|
||||
part_cache_need_eoxact_work = false;
|
||||
SetPartCacheNeedEOXActWork(false);
|
||||
}
|
||||
|
||||
void LocalPartDefCache::AtEOSubXact_PartitionCache(bool isCommit, SubTransactionId mySubid,
|
||||
|
|
@ -366,7 +366,7 @@ void LocalPartDefCache::AtEOSubXact_PartitionCache(bool isCommit, SubTransaction
|
|||
* Skip the relcache scan if nothing to do --- see notes for
|
||||
* AtEOXact_PartitionCache.
|
||||
*/
|
||||
if (!part_cache_need_eoxact_work)
|
||||
if (!GetPartCacheNeedEOXActWork())
|
||||
return;
|
||||
|
||||
Dlelem *bucket_elt;
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ void LocalTabDefCache::Init()
|
|||
|
||||
relcacheInvalsReceived = 0;
|
||||
initFileRelationIds = NIL;
|
||||
need_eoxact_work = false;
|
||||
RelCacheNeedEOXActWork = false;
|
||||
|
||||
g_bucketmap_cache = NIL;
|
||||
max_bucket_map_size = BUCKET_MAP_SIZE;
|
||||
|
|
@ -874,7 +874,7 @@ void LocalTabDefCache::AtEOXact_RelationCache(bool isCommit)
|
|||
* transaction, even though we could clear it at subtransaction end in
|
||||
* some cases.
|
||||
*/
|
||||
if (!LocalRelCacheNeedEOXactWork()
|
||||
if (!GetRelCacheNeedEOXActWork()
|
||||
#ifdef USE_ASSERT_CHECKING
|
||||
&& !assert_enabled
|
||||
#endif
|
||||
|
|
@ -963,7 +963,7 @@ void LocalTabDefCache::AtEOXact_RelationCache(bool isCommit)
|
|||
}
|
||||
}
|
||||
/* Once done with the transaction, we can reset u_sess->relcache_cxt.need_eoxact_work */
|
||||
SetLocalRelCacheNeedEOXactWork(false);
|
||||
SetRelCacheNeedEOXActWork(false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -980,7 +980,7 @@ void LocalTabDefCache::AtEOSubXact_RelationCache(bool isCommit, SubTransactionId
|
|||
* Skip the relcache scan if nothing to do --- see notes for
|
||||
* AtEOXact_RelationCache.
|
||||
*/
|
||||
if (!LocalRelCacheNeedEOXactWork())
|
||||
if (!GetRelCacheNeedEOXActWork())
|
||||
return;
|
||||
|
||||
Dlelem *bucket_elt;
|
||||
|
|
@ -1118,7 +1118,7 @@ void LocalTabDefCache::ResetInitFlag()
|
|||
|
||||
relcacheInvalsReceived = 0;
|
||||
initFileRelationIds = NIL;
|
||||
need_eoxact_work = false;
|
||||
RelCacheNeedEOXActWork = false;
|
||||
|
||||
g_bucketmap_cache = NIL;
|
||||
max_bucket_map_size = 0;
|
||||
|
|
|
|||
|
|
@ -473,7 +473,7 @@ Partition PartitionBuildLocalPartition(const char *relname, Oid partid, Oid part
|
|||
part->pd_newRelfilenodeSubid = InvalidSubTransactionId;
|
||||
|
||||
/* must flag that we have rels created in this transaction */
|
||||
SetPartCacheNeedEoxactWork(true);
|
||||
SetPartCacheNeedEOXActWork(true);
|
||||
|
||||
/*
|
||||
* initialize partition tuple form (caller may add/override data later)
|
||||
|
|
@ -986,7 +986,7 @@ void AtEOXact_PartitionCache(bool isCommit)
|
|||
* transaction, even though we could clear it at subtransaction end in
|
||||
* some cases.
|
||||
*/
|
||||
if (!u_sess->cache_cxt.part_cache_need_eoxact_work
|
||||
if (!GetPartCacheNeedEOXActWork()
|
||||
#ifdef USE_ASSERT_CHECKING
|
||||
&& !assert_enabled
|
||||
#endif
|
||||
|
|
@ -1040,7 +1040,7 @@ void AtEOXact_PartitionCache(bool isCommit)
|
|||
}
|
||||
|
||||
/* Once done with the transaction, we can reset need_eoxact_work */
|
||||
u_sess->cache_cxt.part_cache_need_eoxact_work = false;
|
||||
SetPartCacheNeedEOXActWork(false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1063,7 +1063,7 @@ void AtEOSubXact_PartitionCache(bool isCommit, SubTransactionId mySubid, SubTran
|
|||
* Skip the relcache scan if nothing to do --- see notes for
|
||||
* AtEOXact_PartitionCache.
|
||||
*/
|
||||
if (!u_sess->cache_cxt.part_cache_need_eoxact_work)
|
||||
if (!GetPartCacheNeedEOXActWork())
|
||||
return;
|
||||
|
||||
hash_seq_init(&status, u_sess->cache_cxt.PartitionIdCache);
|
||||
|
|
@ -1705,7 +1705,7 @@ void PartitionSetNewRelfilenode(Relation parent, Partition part, TransactionId f
|
|||
part->pd_newRelfilenodeSubid = GetCurrentSubTransactionId();
|
||||
|
||||
/* ... and now we have eoxact cleanup work to do */
|
||||
SetPartCacheNeedEoxactWork(true);
|
||||
SetPartCacheNeedEOXActWork(true);
|
||||
}
|
||||
|
||||
static void PartitionParseRelOptions(Partition partition, HeapTuple tuple)
|
||||
|
|
|
|||
|
|
@ -4161,7 +4161,7 @@ void AtEOXact_RelationCache(bool isCommit)
|
|||
* transaction, even though we could clear it at subtransaction end in
|
||||
* some cases.
|
||||
*/
|
||||
if (!u_sess->relcache_cxt.need_eoxact_work
|
||||
if (!GetRelCacheNeedEOXActWork()
|
||||
#ifdef USE_ASSERT_CHECKING
|
||||
&& !assert_enabled
|
||||
#endif
|
||||
|
|
@ -4253,7 +4253,7 @@ void AtEOXact_RelationCache(bool isCommit)
|
|||
}
|
||||
|
||||
/* Once done with the transaction, we can reset u_sess->relcache_cxt.need_eoxact_work */
|
||||
u_sess->relcache_cxt.need_eoxact_work = false;
|
||||
SetRelCacheNeedEOXActWork(false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -4276,7 +4276,7 @@ void AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid, SubTrans
|
|||
* Skip the relcache scan if nothing to do --- see notes for
|
||||
* AtEOXact_RelationCache.
|
||||
*/
|
||||
if (!u_sess->relcache_cxt.need_eoxact_work)
|
||||
if (!GetRelCacheNeedEOXActWork())
|
||||
return;
|
||||
|
||||
hash_seq_init(&status, u_sess->relcache_cxt.RelationIdCache);
|
||||
|
|
@ -4416,7 +4416,7 @@ Relation RelationBuildLocalRelation(const char* relname, Oid relnamespace, Tuple
|
|||
rel->rd_newRelfilenodeSubid = InvalidSubTransactionId;
|
||||
|
||||
/* must flag that we have rels created in this transaction */
|
||||
SetLocalRelCacheNeedEOXactWork(true);
|
||||
SetRelCacheNeedEOXActWork(true);
|
||||
|
||||
/*
|
||||
* create a new tuple descriptor from the one passed in. We do this
|
||||
|
|
@ -4784,7 +4784,7 @@ void RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid, Multi
|
|||
*/
|
||||
relation->rd_newRelfilenodeSubid = GetCurrentSubTransactionId();
|
||||
/* ... and now we have eoxact cleanup work to do */
|
||||
SetLocalRelCacheNeedEOXactWork(true);
|
||||
SetRelCacheNeedEOXActWork(true);
|
||||
}
|
||||
|
||||
RelFileNodeBackend CreateNewRelfilenode(Relation relation, TransactionId freezeXid)
|
||||
|
|
@ -6064,7 +6064,7 @@ void RelationSetIndexList(Relation relation, List* indexIds, Oid oidIndex)
|
|||
relation->rd_pkindex = InvalidOid;
|
||||
relation->rd_indexvalid = 2; /* mark list as forced */
|
||||
/* must flag that we have a forced index list */
|
||||
SetLocalRelCacheNeedEOXactWork(true);
|
||||
SetRelCacheNeedEOXActWork(true);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -936,7 +936,7 @@ void RebuildPartitonMap(PartitionMap* oldMap, PartitionMap* newMap)
|
|||
}
|
||||
} else {
|
||||
oldMap->isDirty = true;
|
||||
SetLocalRelCacheNeedEOXactWork(true);
|
||||
SetRelCacheNeedEOXActWork(true);
|
||||
elog(LOG, "map refcount is not zero when RebuildPartitonMap ");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -985,7 +985,7 @@ static void knl_u_relcache_init(knl_u_relcache_context* relcache_cxt)
|
|||
relcache_cxt->criticalSharedRelcachesBuilt = false;
|
||||
relcache_cxt->relcacheInvalsReceived = 0L;
|
||||
relcache_cxt->initFileRelationIds = NIL;
|
||||
relcache_cxt->need_eoxact_work = false;
|
||||
relcache_cxt->RelCacheNeedEOXActWork = false;
|
||||
relcache_cxt->OpClassCache = NULL;
|
||||
relcache_cxt->pgclassdesc = NULL;
|
||||
relcache_cxt->pgindexdesc = NULL;
|
||||
|
|
@ -1174,7 +1174,7 @@ static void knl_u_cache_init(knl_u_cache_context* cache_cxt)
|
|||
|
||||
cache_cxt->PartitionIdCache = NULL;
|
||||
cache_cxt->BucketIdCache = NULL;
|
||||
cache_cxt->part_cache_need_eoxact_work = false;
|
||||
cache_cxt->PartCacheNeedEOXActWork = false;
|
||||
cache_cxt->bucket_cache_need_eoxact_work = false;
|
||||
cache_cxt->dn_hash_table = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,491 +1,493 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
*
|
||||
* 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.
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* tcap_truncate.cpp
|
||||
* Routines to support Timecapsule `Recyclebin-based query, restore`.
|
||||
* We use Tr prefix to indicate it in following coding.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/gausskernel/storage/tcap/tcap_truncate.cpp
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "pgstat.h"
|
||||
#include "access/reloptions.h"
|
||||
#include "access/sysattr.h"
|
||||
#include "access/xlog.h"
|
||||
#include "catalog/dependency.h"
|
||||
#include "catalog/heap.h"
|
||||
#include "catalog/index.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/objectaccess.h"
|
||||
#include "catalog/pg_collation_fn.h"
|
||||
#include "catalog/pg_collation.h"
|
||||
#include "catalog/pg_constraint.h"
|
||||
#include "catalog/pg_conversion_fn.h"
|
||||
#include "catalog/pg_conversion.h"
|
||||
#include "catalog/pg_depend.h"
|
||||
#include "catalog/pg_extension_data_source.h"
|
||||
#include "catalog/pg_extension.h"
|
||||
#include "catalog/pg_foreign_data_wrapper.h"
|
||||
#include "catalog/pg_foreign_server.h"
|
||||
#include "catalog/pg_job.h"
|
||||
#include "catalog/pg_language.h"
|
||||
#include "catalog/pg_largeobject.h"
|
||||
#include "catalog/pg_object.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_opfamily.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_recyclebin.h"
|
||||
#include "catalog/pg_rewrite.h"
|
||||
#include "catalog/pg_rlspolicy.h"
|
||||
#include "catalog/pg_synonym.h"
|
||||
#include "catalog/pg_tablespace.h"
|
||||
#include "catalog/pg_trigger.h"
|
||||
#include "catalog/pg_ts_config.h"
|
||||
#include "catalog/pg_ts_dict.h"
|
||||
#include "catalog/pg_ts_parser.h"
|
||||
#include "catalog/pg_ts_template.h"
|
||||
#include "catalog/pgxc_class.h"
|
||||
#include "catalog/storage.h"
|
||||
#include "catalog/pg_partition_fn.h"
|
||||
#include "commands/comment.h"
|
||||
#include "commands/dbcommands.h"
|
||||
#include "commands/directory.h"
|
||||
#include "commands/extension.h"
|
||||
#include "commands/matview.h"
|
||||
#include "commands/proclang.h"
|
||||
#include "commands/schemacmds.h"
|
||||
#include "commands/seclabel.h"
|
||||
#include "commands/sec_rls_cmds.h"
|
||||
#include "commands/tablecmds.h"
|
||||
#include "commands/tablespace.h"
|
||||
#include "commands/trigger.h"
|
||||
#include "commands/typecmds.h"
|
||||
#include "executor/node/nodeModifyTable.h"
|
||||
#include "rewrite/rewriteRemove.h"
|
||||
#include "storage/lmgr.h"
|
||||
#include "storage/predicate.h"
|
||||
#include "storage/smgr/relfilenode.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/inval.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/relcache.h"
|
||||
#include "utils/snapmgr.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
#include "storage/tcap.h"
|
||||
#include "storage/tcap_impl.h"
|
||||
|
||||
void TrRelationSetNewRelfilenode(Relation relation, TransactionId freezeXid, void *baseDesc)
|
||||
{
|
||||
TrObjDesc desc;
|
||||
TrObjDesc *trBaseDesc = (TrObjDesc *)baseDesc;
|
||||
RelFileNodeBackend newrnode;
|
||||
|
||||
/* Indexes, sequences must have Invalid frozenxid; other rels must not. */
|
||||
Assert((((relation->rd_rel->relkind == RELKIND_INDEX) || (relation->rd_rel->relkind == RELKIND_GLOBAL_INDEX) ||
|
||||
(RELKIND_IS_SEQUENCE(relation->rd_rel->relkind))) ?
|
||||
(freezeXid == InvalidTransactionId) :
|
||||
TransactionIdIsNormal(freezeXid)) ||
|
||||
relation->rd_rel->relkind == RELKIND_RELATION);
|
||||
|
||||
/* Record the old relfilenode to recyclebin. */
|
||||
desc = *trBaseDesc;
|
||||
if (!TR_IS_BASE_OBJ_EX(trBaseDesc, RelationGetRelid(relation))) {
|
||||
TrDescInit(relation, &desc, RB_OPER_TRUNCATE,
|
||||
TrGetObjType(RelationGetNamespace(relation), RelationGetRelkind(relation)), false);
|
||||
TrDescWrite(&desc);
|
||||
}
|
||||
|
||||
/* Allocate a new relfilenode, create storage for the main fork. */
|
||||
newrnode = CreateNewRelfilenode(relation, freezeXid);
|
||||
|
||||
/*
|
||||
* NOTE: if the relation was created in this transaction, it will now be
|
||||
* present in the pending-delete list twice, once with atCommit true and
|
||||
* once with atCommit false. Hence, it will be physically deleted at end
|
||||
* of xact in either case (and the other entry will be ignored by
|
||||
* smgrDoPendingDeletes, so no error will occur). We could instead remove
|
||||
* the existing list entry and delete the physical file immediately, but
|
||||
* for now I'll keep the logic simple.
|
||||
*/
|
||||
RelationCloseSmgr(relation);
|
||||
|
||||
/*
|
||||
* Update pg_class entry for new relfilenode.
|
||||
*/
|
||||
UpdatePgclass(relation, freezeXid, &newrnode);
|
||||
|
||||
/*
|
||||
* Make the pg_class row change visible, as well as the relation map
|
||||
* change if any. This will cause the relcache entry to get updated, too.
|
||||
*/
|
||||
CommandCounterIncrement();
|
||||
|
||||
/*
|
||||
* Mark the rel as having been given a new relfilenode in the current
|
||||
* (sub) transaction. This is a hint that can be used to optimize later
|
||||
* operations on the rel in the same transaction.
|
||||
*/
|
||||
relation->rd_newRelfilenodeSubid = GetCurrentSubTransactionId();
|
||||
|
||||
/* ... and now we have eoxact cleanup work to do */
|
||||
u_sess->relcache_cxt.need_eoxact_work = true;
|
||||
}
|
||||
|
||||
void TrPartitionSetNewRelfilenode(Relation parent, Partition part, TransactionId freezeXid, void *baseDesc)
|
||||
{
|
||||
RelFileNodeBackend newrnode;
|
||||
TrObjDesc desc;
|
||||
TrObjDesc *trBaseDesc = (TrObjDesc *)baseDesc;
|
||||
|
||||
Assert((parent->rd_rel->relkind == RELKIND_INDEX || RELKIND_IS_SEQUENCE(parent->rd_rel->relkind))
|
||||
? freezeXid == InvalidTransactionId
|
||||
: TransactionIdIsNormal(freezeXid));
|
||||
|
||||
/* Record the old relfilenode to recyclebin. */
|
||||
desc = *trBaseDesc;
|
||||
if (!TR_IS_BASE_OBJ_EX(trBaseDesc, part->pd_id)) {
|
||||
TrPartDescInit(parent, part, &desc, RB_OPER_TRUNCATE,
|
||||
TrGetObjType(RelationGetNamespace(parent), RelationGetRelkind(parent)), false);
|
||||
TrDescWrite(&desc);
|
||||
}
|
||||
|
||||
/* Allocate a new relfilenode */
|
||||
newrnode = CreateNewRelfilenodePart(parent, part);
|
||||
|
||||
UpdatePartition(parent, part, freezeXid, &newrnode);
|
||||
|
||||
CommandCounterIncrement();
|
||||
|
||||
/*
|
||||
* Mark the part as having been given a new relfilenode in the current
|
||||
* (sub) transaction. This is a hint that can be used to optimize later
|
||||
* operations on the rel in the same transaction.
|
||||
*/
|
||||
part->pd_newRelfilenodeSubid = GetCurrentSubTransactionId();
|
||||
|
||||
/* ... and now we have eoxact cleanup work to do */
|
||||
u_sess->cache_cxt.part_cache_need_eoxact_work = true;
|
||||
}
|
||||
|
||||
bool TrCheckRecyclebinTruncate(const TruncateStmt *stmt)
|
||||
{
|
||||
RangeVar *rel = NULL;
|
||||
Oid relid;
|
||||
|
||||
if (/*
|
||||
* Disable Recyclebin-based-Truncate when with purge option, or
|
||||
*/
|
||||
/* recyblebin disabled, or */
|
||||
!u_sess->attr.attr_storage.enable_recyclebin ||
|
||||
/* with purge option, or */
|
||||
stmt->purge ||
|
||||
/* with restart_seqs option, or */
|
||||
stmt->restart_seqs ||
|
||||
/* multi objects truncate. */
|
||||
list_length(stmt->relations) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rel = (RangeVar *)linitial(stmt->relations);
|
||||
relid = RangeVarGetRelid(rel, NoLock, false);
|
||||
|
||||
return NeedTrComm(relid);
|
||||
}
|
||||
|
||||
void TrTruncateOnePart(Relation rel, HeapTuple tup, Oid insertBaseid)
|
||||
{
|
||||
Oid toastOid = ((Form_pg_partition)GETSTRUCT(tup))->reltoastrelid;
|
||||
Relation toastRel = NULL;
|
||||
Oid partOid = HeapTupleGetOid(tup);
|
||||
Partition p = partitionOpen(rel, partOid, AccessExclusiveLock);
|
||||
TrObjDesc baseDesc;
|
||||
TrPartDescInit(rel, p, &baseDesc, RB_OPER_TRUNCATE, RB_OBJ_PARTITION, false);
|
||||
baseDesc.id = baseDesc.baseid = insertBaseid;
|
||||
(void)TrDescWrite(&baseDesc);
|
||||
TrUpdateBaseid(&baseDesc);
|
||||
|
||||
TrPartitionSetNewRelfilenode(rel, p, u_sess->utils_cxt.RecentXmin, &baseDesc);
|
||||
|
||||
/* process the toast table */
|
||||
if (OidIsValid(toastOid)) {
|
||||
Assert(rel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED);
|
||||
toastRel = heap_open(toastOid, AccessExclusiveLock);
|
||||
TrRelationSetNewRelfilenode(toastRel, u_sess->utils_cxt.RecentXmin, &baseDesc);
|
||||
heap_close(toastRel, AccessExclusiveLock);
|
||||
}
|
||||
partitionClose(rel, p, AccessExclusiveLock);
|
||||
|
||||
/* report truncate partition to PgStatCollector */
|
||||
pgstat_report_truncate(partOid, rel->rd_id, rel->rd_rel->relisshared);
|
||||
}
|
||||
|
||||
void TrPartitionTableProcess(Relation rel, Oid insertBaseid)
|
||||
{
|
||||
/* truncate partitioned table */
|
||||
List* partTupleList = NIL;
|
||||
ListCell* partCell = NULL;
|
||||
Oid heap_relid;
|
||||
bool is_shared = rel->rd_rel->relisshared;
|
||||
|
||||
heap_relid = RelationGetRelid(rel);
|
||||
/* partitioned table unspport the unlogged table */
|
||||
Assert(rel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED);
|
||||
|
||||
/* process all partition */
|
||||
partTupleList = searchPgPartitionByParentId(PART_OBJ_TYPE_TABLE_PARTITION, rel->rd_id);
|
||||
foreach (partCell, partTupleList) {
|
||||
if (RelationIsSubPartitioned(rel)) {
|
||||
/* the "tup" just for get partOid, UHeapTup has no HEAP_HASOID flag, so here use HeapTuple */
|
||||
HeapTuple tup = (HeapTuple)lfirst(partCell);
|
||||
Oid partOid = HeapTupleGetOid(tup);
|
||||
Partition p = partitionOpen(rel, partOid, AccessExclusiveLock);
|
||||
Relation partRel = partitionGetRelation(rel, p);
|
||||
List* subPartTupleList = searchPgPartitionByParentId(PART_OBJ_TYPE_TABLE_SUB_PARTITION, partOid);
|
||||
ListCell* subPartCell = NULL;
|
||||
foreach (subPartCell, subPartTupleList) {
|
||||
HeapTuple tup = (HeapTuple)lfirst(subPartCell);
|
||||
TrTruncateOnePart(partRel, tup, insertBaseid);
|
||||
}
|
||||
freePartList(subPartTupleList);
|
||||
|
||||
releaseDummyRelation(&partRel);
|
||||
partitionClose(rel, p, AccessExclusiveLock);
|
||||
} else {
|
||||
HeapTuple tup = (HeapTuple)lfirst(partCell);
|
||||
TrTruncateOnePart(rel, tup, insertBaseid);
|
||||
}
|
||||
}
|
||||
|
||||
freePartList(partTupleList);
|
||||
/* report truncate partitioned table to PgStatCollector */
|
||||
pgstat_report_truncate(heap_relid, InvalidOid, is_shared);
|
||||
}
|
||||
|
||||
void TrTruncate(const TruncateStmt *stmt)
|
||||
{
|
||||
RangeVar *rv = (RangeVar*)linitial(stmt->relations);
|
||||
Relation rel;
|
||||
Oid relid;
|
||||
Oid toastRelid;
|
||||
TrObjDesc baseDesc;
|
||||
|
||||
/*
|
||||
* 1. Open relation in AccessExclusiveLock, and check permission, etc.
|
||||
*/
|
||||
|
||||
rel = heap_openrv(rv, AccessExclusiveLock);
|
||||
relid = RelationGetRelid(rel);
|
||||
|
||||
/* find matview exists or not. */
|
||||
Oid mlogid = find_matview_mlog_table(relid);
|
||||
if (OidIsValid(mlogid)) {
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("Not support truncate table under materialized view.")));
|
||||
}
|
||||
|
||||
TrForbidAccessRbObject(RelationRelationId, relid, rv->relname);
|
||||
|
||||
truncate_check_rel(rel);
|
||||
|
||||
/*
|
||||
* This effectively deletes all rows in the table, and may be done
|
||||
* in a serializable transaction. In that case we must record a
|
||||
* rw-conflict in to this transaction from each transaction
|
||||
* holding a predicate lock on the table.
|
||||
*/
|
||||
CheckTableForSerializableConflictIn(rel);
|
||||
|
||||
/*
|
||||
* 2. Create a new empty storage file for the relation, and assign it
|
||||
* as the relfilenode value, and record the old relfilenode to recyclebin.
|
||||
*/
|
||||
|
||||
TrDescInit(rel, &baseDesc, RB_OPER_TRUNCATE, RB_OBJ_TABLE, true, true);
|
||||
baseDesc.id = baseDesc.baseid = TrDescWrite(&baseDesc);
|
||||
TrUpdateBaseid(&baseDesc);
|
||||
|
||||
/*
|
||||
* step 2.1. If rel is partition table, find all partitions, and Create some new empty
|
||||
* storage file for the all partitions of the relation, and assign them as the
|
||||
* relfilenodes value, and record the old relfilenodes to recyclebin.
|
||||
*/
|
||||
if (RELATION_IS_PARTITIONED(rel)) {
|
||||
TrPartitionTableProcess(rel, baseDesc.baseid);
|
||||
}
|
||||
|
||||
TrRelationSetNewRelfilenode(rel, u_sess->utils_cxt.RecentXmin, &baseDesc);
|
||||
|
||||
/*
|
||||
* 3. The same for the toast table, if any.
|
||||
*/
|
||||
|
||||
toastRelid = rel->rd_rel->reltoastrelid;
|
||||
if (OidIsValid(toastRelid) && !RELATION_IS_PARTITIONED(rel)) {
|
||||
Relation relToast = relation_open(toastRelid, AccessExclusiveLock);
|
||||
TrRelationSetNewRelfilenode(relToast, u_sess->utils_cxt.RecentXmin, &baseDesc);
|
||||
heap_close(relToast, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* 4. Reconstruct the indexes to match, and we're done.
|
||||
*/
|
||||
|
||||
(void)ReindexRelation(relid, REINDEX_REL_PROCESS_TOAST, REINDEX_ALL_INDEX, &baseDesc);
|
||||
|
||||
/*
|
||||
* 5. Report stat, and clean.
|
||||
*/
|
||||
|
||||
/* report truncate to PgStatCollector */
|
||||
pgstat_report_truncate(relid, InvalidOid, false);
|
||||
|
||||
/* Record time of truancate relation. */
|
||||
recordRelationMTime(relid, rel->rd_rel->relkind);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* RelationDropStorage
|
||||
* Schedule unlinking of physical storage at transaction commit.
|
||||
*/
|
||||
void TrDoPurgeObjectTruncate(TrObjDesc *desc)
|
||||
{
|
||||
Relation rbRel;
|
||||
SysScanDesc sd;
|
||||
ScanKeyData skey[1];
|
||||
HeapTuple tup;
|
||||
|
||||
Assert (((desc->type == RB_OBJ_TABLE) && desc->canpurge) || ((desc->type == RB_OBJ_PARTITION) && !desc->canpurge));
|
||||
|
||||
rbRel = heap_open(RecyclebinRelationId, RowExclusiveLock);
|
||||
|
||||
ScanKeyInit(&skey[0], Anum_pg_recyclebin_rcybaseid, BTEqualStrategyNumber,
|
||||
F_INT8EQ, Int64GetDatum(desc->baseid));
|
||||
|
||||
sd = systable_beginscan(rbRel, RecyclebinBaseidIndexId, true, NULL, 1, skey);
|
||||
while (HeapTupleIsValid(tup = systable_getnext(sd))) {
|
||||
Form_pg_recyclebin rbForm = (Form_pg_recyclebin)GETSTRUCT(tup);
|
||||
RelFileNode rnode;
|
||||
|
||||
rnode.spcNode = ConvertToRelfilenodeTblspcOid(rbForm->rcytablespace);
|
||||
rnode.dbNode = (rnode.spcNode == GLOBALTABLESPACE_OID) ? InvalidOid :
|
||||
u_sess->proc_cxt.MyDatabaseId;
|
||||
rnode.relNode = rbForm->rcyrelfilenode;
|
||||
rnode.bucketNode = InvalidBktId;
|
||||
|
||||
/*
|
||||
* Schedule unlinking of the old storage at transaction commit.
|
||||
*/
|
||||
InsertStorageIntoPendingList(
|
||||
&rnode, InvalidAttrNumber, InvalidBackendId, rbForm->rcyowner, true, false);
|
||||
|
||||
simple_heap_delete(rbRel, &tup->t_self);
|
||||
|
||||
ereport(LOG, (errmsg("Delete truncated object %u/%u/%u", rnode.spcNode,
|
||||
rnode.dbNode, rnode.relNode)));
|
||||
}
|
||||
|
||||
systable_endscan(sd);
|
||||
heap_close(rbRel, RowExclusiveLock);
|
||||
|
||||
/* ... and now we have eoxact cleanup work to do */
|
||||
u_sess->relcache_cxt.need_eoxact_work = true;
|
||||
|
||||
/*
|
||||
* CommandCounterIncrement here to ensure that preceding changes are all
|
||||
* visible to the next deletion step.
|
||||
*/
|
||||
CommandCounterIncrement();
|
||||
}
|
||||
|
||||
/* flashback table to before truncate */
|
||||
void TrRestoreTruncate(const TimeCapsuleStmt *stmt)
|
||||
{
|
||||
TrObjDesc baseDesc;
|
||||
Relation rbRel;
|
||||
SysScanDesc sd;
|
||||
ScanKeyData skey[1];
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
Oid relid;
|
||||
bool found = false;
|
||||
TrObjDesc desc;
|
||||
|
||||
/* process restore truncate fail: TIMECAPSULE TABLE "BIN$3C534EBE021$4930808==$0" TO BEFORE TRUNCATE; */
|
||||
found = TrFetchName(stmt->relation->relname, RB_OBJ_TABLE, &desc, RB_OPER_RESTORE_TRUNCATE);
|
||||
if (found) {
|
||||
stmt->relation->relname = desc.originname;
|
||||
}
|
||||
|
||||
rel = heap_openrv(stmt->relation, AccessExclusiveLock);
|
||||
relid = RelationGetRelid(rel);
|
||||
if (rel->rd_tam_type == TAM_HEAP) {
|
||||
heap_close(rel, NoLock);
|
||||
elog(ERROR, "timecapsule does not support astore yet");
|
||||
return;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
stmt->relation->relname = desc.name;
|
||||
}
|
||||
|
||||
/* 1. Fetch the latest available recycle object. */
|
||||
TrOperFetch(stmt->relation, RB_OBJ_TABLE, &baseDesc, RB_OPER_RESTORE_TRUNCATE);
|
||||
|
||||
/* 2. Lock recycle object and base relation. */
|
||||
baseDesc.authid = GetUserId();
|
||||
TrOperPrep(&baseDesc, RB_OPER_RESTORE_TRUNCATE);
|
||||
|
||||
/* 3. Check base relation whether normal and matched. */
|
||||
TrBaseRelMatched(&baseDesc);
|
||||
|
||||
/* 4. Do restore. */
|
||||
rbRel = heap_open(RecyclebinRelationId, RowExclusiveLock);
|
||||
|
||||
ScanKeyInit(&skey[0], Anum_pg_recyclebin_rcybaseid, BTEqualStrategyNumber,
|
||||
F_INT8EQ, Int64GetDatum(baseDesc.id));
|
||||
|
||||
sd = systable_beginscan(rbRel, RecyclebinBaseidIndexId, true, NULL, 1, skey);
|
||||
while (HeapTupleIsValid(tup = systable_getnext(sd))) {
|
||||
if (!RELATION_IS_PARTITIONED(rel)) {
|
||||
TrSwapRelfilenode(rbRel, tup, false);
|
||||
} else {
|
||||
TrSwapRelfilenode(rbRel, tup, true);
|
||||
}
|
||||
}
|
||||
|
||||
systable_endscan(sd);
|
||||
heap_close(rbRel, RowExclusiveLock);
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
/*
|
||||
* CommandCounterIncrement here to ensure that preceding changes are all
|
||||
* visible to the next deletion step.
|
||||
*/
|
||||
CommandCounterIncrement();
|
||||
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
*
|
||||
* 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.
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* tcap_truncate.cpp
|
||||
* Routines to support Timecapsule `Recyclebin-based query, restore`.
|
||||
* We use Tr prefix to indicate it in following coding.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/gausskernel/storage/tcap/tcap_truncate.cpp
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "pgstat.h"
|
||||
#include "access/reloptions.h"
|
||||
#include "access/sysattr.h"
|
||||
#include "access/xlog.h"
|
||||
#include "catalog/dependency.h"
|
||||
#include "catalog/heap.h"
|
||||
#include "catalog/index.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/objectaccess.h"
|
||||
#include "catalog/pg_collation_fn.h"
|
||||
#include "catalog/pg_collation.h"
|
||||
#include "catalog/pg_constraint.h"
|
||||
#include "catalog/pg_conversion_fn.h"
|
||||
#include "catalog/pg_conversion.h"
|
||||
#include "catalog/pg_depend.h"
|
||||
#include "catalog/pg_extension_data_source.h"
|
||||
#include "catalog/pg_extension.h"
|
||||
#include "catalog/pg_foreign_data_wrapper.h"
|
||||
#include "catalog/pg_foreign_server.h"
|
||||
#include "catalog/pg_job.h"
|
||||
#include "catalog/pg_language.h"
|
||||
#include "catalog/pg_largeobject.h"
|
||||
#include "catalog/pg_object.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_opfamily.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_recyclebin.h"
|
||||
#include "catalog/pg_rewrite.h"
|
||||
#include "catalog/pg_rlspolicy.h"
|
||||
#include "catalog/pg_synonym.h"
|
||||
#include "catalog/pg_tablespace.h"
|
||||
#include "catalog/pg_trigger.h"
|
||||
#include "catalog/pg_ts_config.h"
|
||||
#include "catalog/pg_ts_dict.h"
|
||||
#include "catalog/pg_ts_parser.h"
|
||||
#include "catalog/pg_ts_template.h"
|
||||
#include "catalog/pgxc_class.h"
|
||||
#include "catalog/storage.h"
|
||||
#include "catalog/pg_partition_fn.h"
|
||||
#include "commands/comment.h"
|
||||
#include "commands/dbcommands.h"
|
||||
#include "commands/directory.h"
|
||||
#include "commands/extension.h"
|
||||
#include "commands/matview.h"
|
||||
#include "commands/proclang.h"
|
||||
#include "commands/schemacmds.h"
|
||||
#include "commands/seclabel.h"
|
||||
#include "commands/sec_rls_cmds.h"
|
||||
#include "commands/tablecmds.h"
|
||||
#include "commands/tablespace.h"
|
||||
#include "commands/trigger.h"
|
||||
#include "commands/typecmds.h"
|
||||
#include "executor/node/nodeModifyTable.h"
|
||||
#include "rewrite/rewriteRemove.h"
|
||||
#include "storage/lmgr.h"
|
||||
#include "storage/predicate.h"
|
||||
#include "storage/smgr/relfilenode.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/inval.h"
|
||||
#include "utils/knl_partcache.h"
|
||||
#include "utils/knl_relcache.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/relcache.h"
|
||||
#include "utils/snapmgr.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
#include "storage/tcap.h"
|
||||
#include "storage/tcap_impl.h"
|
||||
|
||||
void TrRelationSetNewRelfilenode(Relation relation, TransactionId freezeXid, void *baseDesc)
|
||||
{
|
||||
TrObjDesc desc;
|
||||
TrObjDesc *trBaseDesc = (TrObjDesc *)baseDesc;
|
||||
RelFileNodeBackend newrnode;
|
||||
|
||||
/* Indexes, sequences must have Invalid frozenxid; other rels must not. */
|
||||
Assert((((relation->rd_rel->relkind == RELKIND_INDEX) || (relation->rd_rel->relkind == RELKIND_GLOBAL_INDEX) ||
|
||||
(RELKIND_IS_SEQUENCE(relation->rd_rel->relkind))) ?
|
||||
(freezeXid == InvalidTransactionId) :
|
||||
TransactionIdIsNormal(freezeXid)) ||
|
||||
relation->rd_rel->relkind == RELKIND_RELATION);
|
||||
|
||||
/* Record the old relfilenode to recyclebin. */
|
||||
desc = *trBaseDesc;
|
||||
if (!TR_IS_BASE_OBJ_EX(trBaseDesc, RelationGetRelid(relation))) {
|
||||
TrDescInit(relation, &desc, RB_OPER_TRUNCATE,
|
||||
TrGetObjType(RelationGetNamespace(relation), RelationGetRelkind(relation)), false);
|
||||
TrDescWrite(&desc);
|
||||
}
|
||||
|
||||
/* Allocate a new relfilenode, create storage for the main fork. */
|
||||
newrnode = CreateNewRelfilenode(relation, freezeXid);
|
||||
|
||||
/*
|
||||
* NOTE: if the relation was created in this transaction, it will now be
|
||||
* present in the pending-delete list twice, once with atCommit true and
|
||||
* once with atCommit false. Hence, it will be physically deleted at end
|
||||
* of xact in either case (and the other entry will be ignored by
|
||||
* smgrDoPendingDeletes, so no error will occur). We could instead remove
|
||||
* the existing list entry and delete the physical file immediately, but
|
||||
* for now I'll keep the logic simple.
|
||||
*/
|
||||
RelationCloseSmgr(relation);
|
||||
|
||||
/*
|
||||
* Update pg_class entry for new relfilenode.
|
||||
*/
|
||||
UpdatePgclass(relation, freezeXid, &newrnode);
|
||||
|
||||
/*
|
||||
* Make the pg_class row change visible, as well as the relation map
|
||||
* change if any. This will cause the relcache entry to get updated, too.
|
||||
*/
|
||||
CommandCounterIncrement();
|
||||
|
||||
/*
|
||||
* Mark the rel as having been given a new relfilenode in the current
|
||||
* (sub) transaction. This is a hint that can be used to optimize later
|
||||
* operations on the rel in the same transaction.
|
||||
*/
|
||||
relation->rd_newRelfilenodeSubid = GetCurrentSubTransactionId();
|
||||
|
||||
/* ... and now we have eoxact cleanup work to do */
|
||||
SetRelCacheNeedEOXActWork(true);
|
||||
}
|
||||
|
||||
void TrPartitionSetNewRelfilenode(Relation parent, Partition part, TransactionId freezeXid, void *baseDesc)
|
||||
{
|
||||
RelFileNodeBackend newrnode;
|
||||
TrObjDesc desc;
|
||||
TrObjDesc *trBaseDesc = (TrObjDesc *)baseDesc;
|
||||
|
||||
Assert((parent->rd_rel->relkind == RELKIND_INDEX || RELKIND_IS_SEQUENCE(parent->rd_rel->relkind))
|
||||
? freezeXid == InvalidTransactionId
|
||||
: TransactionIdIsNormal(freezeXid));
|
||||
|
||||
/* Record the old relfilenode to recyclebin. */
|
||||
desc = *trBaseDesc;
|
||||
if (!TR_IS_BASE_OBJ_EX(trBaseDesc, part->pd_id)) {
|
||||
TrPartDescInit(parent, part, &desc, RB_OPER_TRUNCATE,
|
||||
TrGetObjType(RelationGetNamespace(parent), RelationGetRelkind(parent)), false);
|
||||
TrDescWrite(&desc);
|
||||
}
|
||||
|
||||
/* Allocate a new relfilenode */
|
||||
newrnode = CreateNewRelfilenodePart(parent, part);
|
||||
|
||||
UpdatePartition(parent, part, freezeXid, &newrnode);
|
||||
|
||||
CommandCounterIncrement();
|
||||
|
||||
/*
|
||||
* Mark the part as having been given a new relfilenode in the current
|
||||
* (sub) transaction. This is a hint that can be used to optimize later
|
||||
* operations on the rel in the same transaction.
|
||||
*/
|
||||
part->pd_newRelfilenodeSubid = GetCurrentSubTransactionId();
|
||||
|
||||
/* ... and now we have eoxact cleanup work to do */
|
||||
SetPartCacheNeedEOXActWork(true);
|
||||
}
|
||||
|
||||
bool TrCheckRecyclebinTruncate(const TruncateStmt *stmt)
|
||||
{
|
||||
RangeVar *rel = NULL;
|
||||
Oid relid;
|
||||
|
||||
if (/*
|
||||
* Disable Recyclebin-based-Truncate when with purge option, or
|
||||
*/
|
||||
/* recyblebin disabled, or */
|
||||
!u_sess->attr.attr_storage.enable_recyclebin ||
|
||||
/* with purge option, or */
|
||||
stmt->purge ||
|
||||
/* with restart_seqs option, or */
|
||||
stmt->restart_seqs ||
|
||||
/* multi objects truncate. */
|
||||
list_length(stmt->relations) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rel = (RangeVar *)linitial(stmt->relations);
|
||||
relid = RangeVarGetRelid(rel, NoLock, false);
|
||||
|
||||
return NeedTrComm(relid);
|
||||
}
|
||||
|
||||
void TrTruncateOnePart(Relation rel, HeapTuple tup, Oid insertBaseid)
|
||||
{
|
||||
Oid toastOid = ((Form_pg_partition)GETSTRUCT(tup))->reltoastrelid;
|
||||
Relation toastRel = NULL;
|
||||
Oid partOid = HeapTupleGetOid(tup);
|
||||
Partition p = partitionOpen(rel, partOid, AccessExclusiveLock);
|
||||
TrObjDesc baseDesc;
|
||||
TrPartDescInit(rel, p, &baseDesc, RB_OPER_TRUNCATE, RB_OBJ_PARTITION, false);
|
||||
baseDesc.id = baseDesc.baseid = insertBaseid;
|
||||
(void)TrDescWrite(&baseDesc);
|
||||
TrUpdateBaseid(&baseDesc);
|
||||
|
||||
TrPartitionSetNewRelfilenode(rel, p, u_sess->utils_cxt.RecentXmin, &baseDesc);
|
||||
|
||||
/* process the toast table */
|
||||
if (OidIsValid(toastOid)) {
|
||||
Assert(rel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED);
|
||||
toastRel = heap_open(toastOid, AccessExclusiveLock);
|
||||
TrRelationSetNewRelfilenode(toastRel, u_sess->utils_cxt.RecentXmin, &baseDesc);
|
||||
heap_close(toastRel, AccessExclusiveLock);
|
||||
}
|
||||
partitionClose(rel, p, AccessExclusiveLock);
|
||||
|
||||
/* report truncate partition to PgStatCollector */
|
||||
pgstat_report_truncate(partOid, rel->rd_id, rel->rd_rel->relisshared);
|
||||
}
|
||||
|
||||
void TrPartitionTableProcess(Relation rel, Oid insertBaseid)
|
||||
{
|
||||
/* truncate partitioned table */
|
||||
List* partTupleList = NIL;
|
||||
ListCell* partCell = NULL;
|
||||
Oid heap_relid;
|
||||
bool is_shared = rel->rd_rel->relisshared;
|
||||
|
||||
heap_relid = RelationGetRelid(rel);
|
||||
/* partitioned table unspport the unlogged table */
|
||||
Assert(rel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED);
|
||||
|
||||
/* process all partition */
|
||||
partTupleList = searchPgPartitionByParentId(PART_OBJ_TYPE_TABLE_PARTITION, rel->rd_id);
|
||||
foreach (partCell, partTupleList) {
|
||||
if (RelationIsSubPartitioned(rel)) {
|
||||
/* the "tup" just for get partOid, UHeapTup has no HEAP_HASOID flag, so here use HeapTuple */
|
||||
HeapTuple tup = (HeapTuple)lfirst(partCell);
|
||||
Oid partOid = HeapTupleGetOid(tup);
|
||||
Partition p = partitionOpen(rel, partOid, AccessExclusiveLock);
|
||||
Relation partRel = partitionGetRelation(rel, p);
|
||||
List* subPartTupleList = searchPgPartitionByParentId(PART_OBJ_TYPE_TABLE_SUB_PARTITION, partOid);
|
||||
ListCell* subPartCell = NULL;
|
||||
foreach (subPartCell, subPartTupleList) {
|
||||
HeapTuple tup = (HeapTuple)lfirst(subPartCell);
|
||||
TrTruncateOnePart(partRel, tup, insertBaseid);
|
||||
}
|
||||
freePartList(subPartTupleList);
|
||||
|
||||
releaseDummyRelation(&partRel);
|
||||
partitionClose(rel, p, AccessExclusiveLock);
|
||||
} else {
|
||||
HeapTuple tup = (HeapTuple)lfirst(partCell);
|
||||
TrTruncateOnePart(rel, tup, insertBaseid);
|
||||
}
|
||||
}
|
||||
|
||||
freePartList(partTupleList);
|
||||
/* report truncate partitioned table to PgStatCollector */
|
||||
pgstat_report_truncate(heap_relid, InvalidOid, is_shared);
|
||||
}
|
||||
|
||||
void TrTruncate(const TruncateStmt *stmt)
|
||||
{
|
||||
RangeVar *rv = (RangeVar*)linitial(stmt->relations);
|
||||
Relation rel;
|
||||
Oid relid;
|
||||
Oid toastRelid;
|
||||
TrObjDesc baseDesc;
|
||||
|
||||
/*
|
||||
* 1. Open relation in AccessExclusiveLock, and check permission, etc.
|
||||
*/
|
||||
|
||||
rel = heap_openrv(rv, AccessExclusiveLock);
|
||||
relid = RelationGetRelid(rel);
|
||||
|
||||
/* find matview exists or not. */
|
||||
Oid mlogid = find_matview_mlog_table(relid);
|
||||
if (OidIsValid(mlogid)) {
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("Not support truncate table under materialized view.")));
|
||||
}
|
||||
|
||||
TrForbidAccessRbObject(RelationRelationId, relid, rv->relname);
|
||||
|
||||
truncate_check_rel(rel);
|
||||
|
||||
/*
|
||||
* This effectively deletes all rows in the table, and may be done
|
||||
* in a serializable transaction. In that case we must record a
|
||||
* rw-conflict in to this transaction from each transaction
|
||||
* holding a predicate lock on the table.
|
||||
*/
|
||||
CheckTableForSerializableConflictIn(rel);
|
||||
|
||||
/*
|
||||
* 2. Create a new empty storage file for the relation, and assign it
|
||||
* as the relfilenode value, and record the old relfilenode to recyclebin.
|
||||
*/
|
||||
|
||||
TrDescInit(rel, &baseDesc, RB_OPER_TRUNCATE, RB_OBJ_TABLE, true, true);
|
||||
baseDesc.id = baseDesc.baseid = TrDescWrite(&baseDesc);
|
||||
TrUpdateBaseid(&baseDesc);
|
||||
|
||||
/*
|
||||
* step 2.1. If rel is partition table, find all partitions, and Create some new empty
|
||||
* storage file for the all partitions of the relation, and assign them as the
|
||||
* relfilenodes value, and record the old relfilenodes to recyclebin.
|
||||
*/
|
||||
if (RELATION_IS_PARTITIONED(rel)) {
|
||||
TrPartitionTableProcess(rel, baseDesc.baseid);
|
||||
}
|
||||
|
||||
TrRelationSetNewRelfilenode(rel, u_sess->utils_cxt.RecentXmin, &baseDesc);
|
||||
|
||||
/*
|
||||
* 3. The same for the toast table, if any.
|
||||
*/
|
||||
|
||||
toastRelid = rel->rd_rel->reltoastrelid;
|
||||
if (OidIsValid(toastRelid) && !RELATION_IS_PARTITIONED(rel)) {
|
||||
Relation relToast = relation_open(toastRelid, AccessExclusiveLock);
|
||||
TrRelationSetNewRelfilenode(relToast, u_sess->utils_cxt.RecentXmin, &baseDesc);
|
||||
heap_close(relToast, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* 4. Reconstruct the indexes to match, and we're done.
|
||||
*/
|
||||
|
||||
(void)ReindexRelation(relid, REINDEX_REL_PROCESS_TOAST, REINDEX_ALL_INDEX, &baseDesc);
|
||||
|
||||
/*
|
||||
* 5. Report stat, and clean.
|
||||
*/
|
||||
|
||||
/* report truncate to PgStatCollector */
|
||||
pgstat_report_truncate(relid, InvalidOid, false);
|
||||
|
||||
/* Record time of truancate relation. */
|
||||
recordRelationMTime(relid, rel->rd_rel->relkind);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* RelationDropStorage
|
||||
* Schedule unlinking of physical storage at transaction commit.
|
||||
*/
|
||||
void TrDoPurgeObjectTruncate(TrObjDesc *desc)
|
||||
{
|
||||
Relation rbRel;
|
||||
SysScanDesc sd;
|
||||
ScanKeyData skey[1];
|
||||
HeapTuple tup;
|
||||
|
||||
Assert (((desc->type == RB_OBJ_TABLE) && desc->canpurge) || ((desc->type == RB_OBJ_PARTITION) && !desc->canpurge));
|
||||
|
||||
rbRel = heap_open(RecyclebinRelationId, RowExclusiveLock);
|
||||
|
||||
ScanKeyInit(&skey[0], Anum_pg_recyclebin_rcybaseid, BTEqualStrategyNumber,
|
||||
F_INT8EQ, Int64GetDatum(desc->baseid));
|
||||
|
||||
sd = systable_beginscan(rbRel, RecyclebinBaseidIndexId, true, NULL, 1, skey);
|
||||
while (HeapTupleIsValid(tup = systable_getnext(sd))) {
|
||||
Form_pg_recyclebin rbForm = (Form_pg_recyclebin)GETSTRUCT(tup);
|
||||
RelFileNode rnode;
|
||||
|
||||
rnode.spcNode = ConvertToRelfilenodeTblspcOid(rbForm->rcytablespace);
|
||||
rnode.dbNode = (rnode.spcNode == GLOBALTABLESPACE_OID) ? InvalidOid :
|
||||
u_sess->proc_cxt.MyDatabaseId;
|
||||
rnode.relNode = rbForm->rcyrelfilenode;
|
||||
rnode.bucketNode = InvalidBktId;
|
||||
|
||||
/*
|
||||
* Schedule unlinking of the old storage at transaction commit.
|
||||
*/
|
||||
InsertStorageIntoPendingList(
|
||||
&rnode, InvalidAttrNumber, InvalidBackendId, rbForm->rcyowner, true, false);
|
||||
|
||||
simple_heap_delete(rbRel, &tup->t_self);
|
||||
|
||||
ereport(LOG, (errmsg("Delete truncated object %u/%u/%u", rnode.spcNode,
|
||||
rnode.dbNode, rnode.relNode)));
|
||||
}
|
||||
|
||||
systable_endscan(sd);
|
||||
heap_close(rbRel, RowExclusiveLock);
|
||||
|
||||
/* ... and now we have eoxact cleanup work to do */
|
||||
SetRelCacheNeedEOXActWork(true);
|
||||
|
||||
/*
|
||||
* CommandCounterIncrement here to ensure that preceding changes are all
|
||||
* visible to the next deletion step.
|
||||
*/
|
||||
CommandCounterIncrement();
|
||||
}
|
||||
|
||||
/* flashback table to before truncate */
|
||||
void TrRestoreTruncate(const TimeCapsuleStmt *stmt)
|
||||
{
|
||||
TrObjDesc baseDesc;
|
||||
Relation rbRel;
|
||||
SysScanDesc sd;
|
||||
ScanKeyData skey[1];
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
Oid relid;
|
||||
bool found = false;
|
||||
TrObjDesc desc;
|
||||
|
||||
/* process restore truncate fail: TIMECAPSULE TABLE "BIN$3C534EBE021$4930808==$0" TO BEFORE TRUNCATE; */
|
||||
found = TrFetchName(stmt->relation->relname, RB_OBJ_TABLE, &desc, RB_OPER_RESTORE_TRUNCATE);
|
||||
if (found) {
|
||||
stmt->relation->relname = desc.originname;
|
||||
}
|
||||
|
||||
rel = heap_openrv(stmt->relation, AccessExclusiveLock);
|
||||
relid = RelationGetRelid(rel);
|
||||
if (rel->rd_tam_type == TAM_HEAP) {
|
||||
heap_close(rel, NoLock);
|
||||
elog(ERROR, "timecapsule does not support astore yet");
|
||||
return;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
stmt->relation->relname = desc.name;
|
||||
}
|
||||
|
||||
/* 1. Fetch the latest available recycle object. */
|
||||
TrOperFetch(stmt->relation, RB_OBJ_TABLE, &baseDesc, RB_OPER_RESTORE_TRUNCATE);
|
||||
|
||||
/* 2. Lock recycle object and base relation. */
|
||||
baseDesc.authid = GetUserId();
|
||||
TrOperPrep(&baseDesc, RB_OPER_RESTORE_TRUNCATE);
|
||||
|
||||
/* 3. Check base relation whether normal and matched. */
|
||||
TrBaseRelMatched(&baseDesc);
|
||||
|
||||
/* 4. Do restore. */
|
||||
rbRel = heap_open(RecyclebinRelationId, RowExclusiveLock);
|
||||
|
||||
ScanKeyInit(&skey[0], Anum_pg_recyclebin_rcybaseid, BTEqualStrategyNumber,
|
||||
F_INT8EQ, Int64GetDatum(baseDesc.id));
|
||||
|
||||
sd = systable_beginscan(rbRel, RecyclebinBaseidIndexId, true, NULL, 1, skey);
|
||||
while (HeapTupleIsValid(tup = systable_getnext(sd))) {
|
||||
if (!RELATION_IS_PARTITIONED(rel)) {
|
||||
TrSwapRelfilenode(rbRel, tup, false);
|
||||
} else {
|
||||
TrSwapRelfilenode(rbRel, tup, true);
|
||||
}
|
||||
}
|
||||
|
||||
systable_endscan(sd);
|
||||
heap_close(rbRel, RowExclusiveLock);
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
/*
|
||||
* CommandCounterIncrement here to ensure that preceding changes are all
|
||||
* visible to the next deletion step.
|
||||
*/
|
||||
CommandCounterIncrement();
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1879,7 +1879,7 @@ typedef struct knl_u_relcache_context {
|
|||
/*
|
||||
* This flag lets us optimize away work in AtEO(Sub)Xact_RelationCache().
|
||||
*/
|
||||
bool need_eoxact_work;
|
||||
bool RelCacheNeedEOXActWork;
|
||||
|
||||
HTAB* OpClassCache;
|
||||
|
||||
|
|
@ -2309,7 +2309,7 @@ typedef struct knl_u_cache_context {
|
|||
|
||||
struct HTAB* dn_hash_table;
|
||||
|
||||
bool part_cache_need_eoxact_work;
|
||||
bool PartCacheNeedEOXActWork;
|
||||
|
||||
bool bucket_cache_need_eoxact_work;
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public:
|
|||
m_bucket_list.ResetContent();
|
||||
invalid_entries.ResetInitFlag();
|
||||
m_global_partdefcache = NULL;
|
||||
part_cache_need_eoxact_work = false;
|
||||
PartCacheNeedEOXActWork = false;
|
||||
m_is_inited = false;
|
||||
m_db_id = InvalidOid;
|
||||
}
|
||||
|
|
@ -64,7 +64,7 @@ public:
|
|||
Partition PartitionIdGetPartition(Oid part_oid, StorageType storage_type);
|
||||
|
||||
public:
|
||||
bool part_cache_need_eoxact_work;
|
||||
bool PartCacheNeedEOXActWork;
|
||||
|
||||
private:
|
||||
void InsertPartitionIntoGlobal(Partition part, uint32 hash_value);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public:
|
|||
{
|
||||
m_is_inited = false;
|
||||
local_systupcaches = NULL;
|
||||
need_eoxact_work = false;
|
||||
CatCacheNeedEOXActWork = false;
|
||||
}
|
||||
|
||||
void ResetInitFlag(bool include_shared)
|
||||
|
|
@ -54,13 +54,13 @@ public:
|
|||
|
||||
void AtEOXact_CatCache(bool isCommit)
|
||||
{
|
||||
if (!need_eoxact_work) {
|
||||
if (!CatCacheNeedEOXActWork) {
|
||||
return;
|
||||
}
|
||||
for (int cache_id = 0; cache_id < SysCacheSize; cache_id++) {
|
||||
local_systupcaches[cache_id]->AtEOXact_CatCache(isCommit);
|
||||
}
|
||||
need_eoxact_work = false;
|
||||
CatCacheNeedEOXActWork = false;
|
||||
}
|
||||
|
||||
/* systup may be shared table cache. not cleaned when cleardb */
|
||||
|
|
@ -166,7 +166,7 @@ public:
|
|||
}
|
||||
local_systupcaches[cache_id]->PrepareToInvalidateCacheTuple(tuple, newtuple, function);
|
||||
}
|
||||
need_eoxact_work = true;
|
||||
CatCacheNeedEOXActWork = true;
|
||||
}
|
||||
|
||||
void CreateObject();
|
||||
|
|
@ -270,6 +270,6 @@ private:
|
|||
}
|
||||
|
||||
bool m_is_inited;
|
||||
bool need_eoxact_work;
|
||||
bool CatCacheNeedEOXActWork;
|
||||
};
|
||||
#endif
|
||||
|
|
@ -124,7 +124,7 @@ public:
|
|||
*/
|
||||
List *initFileRelationIds;
|
||||
|
||||
bool need_eoxact_work;
|
||||
bool RelCacheNeedEOXActWork;
|
||||
|
||||
struct tupleDesc *m_pgclassdesc;
|
||||
struct tupleDesc *m_pgindexdesc;
|
||||
|
|
|
|||
|
|
@ -105,21 +105,21 @@ extern Partition PartitionBuildDesc(Oid targetPartId, StorageType storage_type,
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
inline bool PartCacheNeedEoxactWork()
|
||||
inline bool GetPartCacheNeedEOXActWork()
|
||||
{
|
||||
if (EnableLocalSysCache()) {
|
||||
return t_thrd.lsc_cxt.lsc->partdefcache.part_cache_need_eoxact_work;
|
||||
return t_thrd.lsc_cxt.lsc->partdefcache.PartCacheNeedEOXActWork;
|
||||
} else {
|
||||
return u_sess->cache_cxt.part_cache_need_eoxact_work;
|
||||
return u_sess->cache_cxt.PartCacheNeedEOXActWork;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetPartCacheNeedEoxactWork(bool value)
|
||||
inline void SetPartCacheNeedEOXActWork(bool value)
|
||||
{
|
||||
if (EnableLocalSysCache()) {
|
||||
t_thrd.lsc_cxt.lsc->partdefcache.part_cache_need_eoxact_work = value;
|
||||
t_thrd.lsc_cxt.lsc->partdefcache.PartCacheNeedEOXActWork = value;
|
||||
} else {
|
||||
u_sess->cache_cxt.part_cache_need_eoxact_work = value;
|
||||
u_sess->cache_cxt.PartCacheNeedEOXActWork = value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -194,21 +194,21 @@ inline void AddLocalRelCacheInvalsReceived(int value)
|
|||
}
|
||||
}
|
||||
|
||||
inline bool LocalRelCacheNeedEOXactWork()
|
||||
inline bool GetRelCacheNeedEOXActWork()
|
||||
{
|
||||
if (EnableLocalSysCache()) {
|
||||
return t_thrd.lsc_cxt.lsc->tabdefcache.need_eoxact_work;
|
||||
return t_thrd.lsc_cxt.lsc->tabdefcache.RelCacheNeedEOXActWork;
|
||||
} else {
|
||||
return u_sess->relcache_cxt.need_eoxact_work;
|
||||
return u_sess->relcache_cxt.RelCacheNeedEOXActWork;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetLocalRelCacheNeedEOXactWork(bool value)
|
||||
inline void SetRelCacheNeedEOXActWork(bool value)
|
||||
{
|
||||
if (EnableLocalSysCache()) {
|
||||
t_thrd.lsc_cxt.lsc->tabdefcache.need_eoxact_work = value;
|
||||
t_thrd.lsc_cxt.lsc->tabdefcache.RelCacheNeedEOXActWork = value;
|
||||
} else {
|
||||
u_sess->relcache_cxt.need_eoxact_work = value;
|
||||
u_sess->relcache_cxt.RelCacheNeedEOXActWork = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue