fix GTT alter table toast issue

This commit is contained in:
wangzhijun2018 2020-08-05 10:30:29 +08:00
parent 937bc72dec
commit e734c01acc
8 changed files with 88 additions and 127 deletions

View File

@ -1370,3 +1370,27 @@ static gtt_local_hash_entry* gtt_search_by_relid(Oid relid, bool missingOk)
return entry;
}
void gtt_create_storage_files(Oid relid)
{
if (gtt_storage_attached(relid)) {
return;
}
MemoryContext ctxAlterGtt =
AllocSetContextCreate(CurrentMemoryContext, "gtt alter table", ALLOCSET_DEFAULT_SIZES);
MemoryContext oldcontext = MemoryContextSwitchTo(ctxAlterGtt);
ResultRelInfo* resultRelInfo = makeNode(ResultRelInfo);
Relation rel = relation_open(relid, NoLock);
InitResultRelInfo(resultRelInfo, rel, 1, 0);
if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
resultRelInfo->ri_IndexRelationDescs == NULL) {
ExecOpenIndices(resultRelInfo);
}
init_gtt_storage(CMD_UTILITY, resultRelInfo);
relation_close(rel, NoLock);
ExecCloseIndices(resultRelInfo);
(void)MemoryContextSwitchTo(oldcontext);
MemoryContextDelete(ctxAlterGtt);
}

View File

@ -1922,16 +1922,20 @@ char get_rel_persistence(Oid relid)
{
HeapTuple tp;
Form_pg_class reltup;
char result;
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for relation %u", relid);
reltup = (Form_pg_class) GETSTRUCT(tp);
result = reltup->relpersistence;
ReleaseSysCache(tp);
return result;
if (HeapTupleIsValid(tp)) {
reltup = (Form_pg_class) GETSTRUCT(tp);
char result = reltup->relpersistence;
ReleaseSysCache(tp);
return result;
} else {
/*
* for partition table.
* global temp table does not support partitioning.
*/
return '\0';
}
}
/*

View File

@ -142,8 +142,7 @@ static Datum pgxc_parallel_execution(const char* query, ExecNodes* exec_nodes);
static int switch_relfilenode_execnode(Oid relOid1, Oid relOid2, bool isbucket, RedisSwitchNode* rsn);
#endif
static void swapRelationIndicesRelfileNode(Relation rel1, Relation rel2, bool swapBucket);
static void GttSwapRelationFiles(Oid r1, Oid r2, bool targetIsPgClass, bool swapToastByContent,
TransactionId frozenXid, Oid *mappedTables);
static void GttSwapRelationFiles(Oid r1, Oid r2);
/* ---------------------------------------------------------------------------
* This cluster code allows for clustering multiple tables at once. Because
@ -698,7 +697,6 @@ static void rebuild_relation(
Oid tableOid = RelationGetRelid(OldHeap);
Oid tableSpace = OldHeap->rd_rel->reltablespace;
Oid OIDNewHeap;
char relpersistence;
bool is_system_catalog = false;
bool swap_toast_by_content = false;
TransactionId frozenXid;
@ -710,7 +708,6 @@ static void rebuild_relation(
mark_index_clustered(OldHeap, indexOid);
/* Remember if it's a system catalog */
relpersistence = OldHeap->rd_rel->relpersistence;
is_system_catalog = IsSystemRelation(OldHeap);
/* Close relcache entry, but keep lock until transaction commit */
@ -744,8 +741,7 @@ static void rebuild_relation(
* Swap the physical files of the target and transient tables, then
* rebuild the target's indexes and throw away the transient table.
*/
finish_heap_swap(
tableOid, OIDNewHeap, is_system_catalog, swap_toast_by_content, false, frozenXid, memUsage, relpersistence);
finish_heap_swap(tableOid, OIDNewHeap, is_system_catalog, swap_toast_by_content, false, frozenXid, memUsage);
/* report vacuum full stat to PgStatCollector */
pgstat_report_vacuum(tableOid, InvalidOid, is_shared, deleteTupleNum);
@ -2790,7 +2786,7 @@ static void SwapCStoreTables(Oid relId1, Oid relId2, Oid parentOid, Oid tempTabl
* cleaning up (including rebuilding all indexes on the old heap).
*/
void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bool swap_toast_by_content,
bool checkConstraints, TransactionId frozenXid, AdaptMem* memInfo, char newrelpersistence)
bool checkConstraints, TransactionId frozenXid, AdaptMem* memInfo)
{
ObjectAddress object;
Oid mapped_tables[4];
@ -2806,10 +2802,9 @@ void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bo
* Swap the contents of the heap relations (including any toast tables).
* Also set old heap's relfrozenxid to frozenXid.
*/
if (newrelpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
if (get_rel_persistence(OIDOldHeap) == RELPERSISTENCE_GLOBAL_TEMP) {
Assert(!is_system_catalog);
GttSwapRelationFiles(OIDOldHeap, OIDNewHeap, (OIDOldHeap == RelationRelationId),
swap_toast_by_content, frozenXid, mapped_tables);
GttSwapRelationFiles(OIDOldHeap, OIDNewHeap);
} else {
swap_relation_files(OIDOldHeap, OIDNewHeap, (OIDOldHeap == RelationRelationId),
swap_toast_by_content, frozenXid, mapped_tables);
@ -2997,17 +2992,13 @@ static List* get_tables_to_cluster(MemoryContext cluster_context)
return rvs;
}
static void GttSwapRelationFiles(Oid r1, Oid r2, bool targetIsPgClass, bool swapToastByContent,
TransactionId frozenXid, Oid *mappedTables)
static void GttSwapRelationFiles(Oid r1, Oid r2)
{
Relation relRelation;
Oid relfilenode1,
relfilenode2;
Oid relfilenode1;
Oid relfilenode2;
Relation rel1;
Relation rel2;
relRelation = relation_open(RelationRelationId, RowExclusiveLock);
rel1 = relation_open(r1, AccessExclusiveLock);
rel2 = relation_open(r2, AccessExclusiveLock);
@ -3020,82 +3011,17 @@ static void GttSwapRelationFiles(Oid r1, Oid r2, bool targetIsPgClass, bool swap
CacheInvalidateRelcache(rel1);
CacheInvalidateRelcache(rel2);
if (rel1->rd_rel->reltoastrelid || rel2->rd_rel->reltoastrelid) {
if (swapToastByContent) {
if (rel1->rd_rel->reltoastrelid && rel2->rd_rel->reltoastrelid) {
GttSwapRelationFiles(rel1->rd_rel->reltoastrelid,
rel2->rd_rel->reltoastrelid,
targetIsPgClass,
swapToastByContent,
frozenXid,
mappedTables);
} else {
elog(ERROR, "cannot swap toast files by content when there's only one");
}
} else {
ObjectAddress baseobject,
toastobject;
long count;
if (IsSystemRelation(rel1)) {
elog(ERROR, "cannot swap toast files by links for system catalogs");
}
if (rel1->rd_rel->reltoastrelid) {
count = deleteDependencyRecordsFor(RelationRelationId,
rel1->rd_rel->reltoastrelid,
false);
if (count != 1) {
elog(ERROR, "expected one dependency record for TOAST table, found %ld",
count);
}
}
if (rel2->rd_rel->reltoastrelid) {
count = deleteDependencyRecordsFor(RelationRelationId,
rel2->rd_rel->reltoastrelid,
false);
if (count != 1) {
elog(ERROR, "expected one dependency record for TOAST table, found %ld",
count);
}
}
/* Register new dependencies */
baseobject.classId = RelationRelationId;
baseobject.objectSubId = 0;
toastobject.classId = RelationRelationId;
toastobject.objectSubId = 0;
if (rel1->rd_rel->reltoastrelid) {
baseobject.objectId = r1;
toastobject.objectId = rel1->rd_rel->reltoastrelid;
recordDependencyOn(&toastobject, &baseobject,
DEPENDENCY_INTERNAL);
}
if (rel2->rd_rel->reltoastrelid) {
baseobject.objectId = r2;
toastobject.objectId = rel2->rd_rel->reltoastrelid;
recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL);
}
}
if (rel1->rd_rel->reltoastrelid && rel2->rd_rel->reltoastrelid) {
GttSwapRelationFiles(rel1->rd_rel->reltoastrelid, rel2->rd_rel->reltoastrelid);
}
if (swapToastByContent && rel1->rd_rel->relkind == RELKIND_TOASTVALUE &&
rel2->rd_rel->relkind == RELKIND_TOASTVALUE) {
GttSwapRelationFiles(rel1->rd_rel->reltoastidxid,
rel2->rd_rel->reltoastidxid,
targetIsPgClass,
swapToastByContent,
InvalidTransactionId,
mappedTables);
if (rel1->rd_rel->relkind == RELKIND_TOASTVALUE && rel2->rd_rel->relkind == RELKIND_TOASTVALUE) {
GttSwapRelationFiles(rel1->rd_rel->reltoastidxid, rel2->rd_rel->reltoastidxid);
}
relation_close(rel1, NoLock);
relation_close(rel2, NoLock);
relation_close(relRelation, RowExclusiveLock);
RelationCloseSmgrByOid(r1);
RelationCloseSmgrByOid(r2);

View File

@ -6272,7 +6272,9 @@ static void ATRewriteCatalogs(List** wqueue, LOCKMODE lockmode)
/* Check to see if a toast table must be added. */
foreach (ltab, *wqueue) {
AlteredTableInfo* tab = (AlteredTableInfo*)lfirst(ltab);
if (get_rel_persistence(tab->relid) == RELPERSISTENCE_GLOBAL_TEMP) {
gtt_create_storage_files(tab->relid);
}
if (tab->relkind == RELKIND_RELATION)
AlterTableCreateToastTable(tab->relid, (Datum)0);
}
@ -6674,28 +6676,6 @@ static void ATRewriteTables(List** wqueue, LOCKMODE lockmode)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot rewrite temporary tables of other sessions")));
if (RELATION_IS_GLOBAL_TEMP(OldHeap)) {
/* gtt may not attached, create it */
if (!gtt_storage_attached(tab->relid)) {
ResultRelInfo *resultRelInfo;
MemoryContext oldcontext;
MemoryContext ctx_alter_gtt;
ctx_alter_gtt =
AllocSetContextCreate(CurrentMemoryContext, "gtt alter table", ALLOCSET_DEFAULT_SIZES);
oldcontext = MemoryContextSwitchTo(ctx_alter_gtt);
resultRelInfo = makeNode(ResultRelInfo);
InitResultRelInfo(resultRelInfo, OldHeap, 1, 0);
if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
resultRelInfo->ri_IndexRelationDescs == NULL)
ExecOpenIndices(resultRelInfo);
init_gtt_storage(CMD_UTILITY, resultRelInfo);
ExecCloseIndices(resultRelInfo);
(void)MemoryContextSwitchTo(oldcontext);
MemoryContextDelete(ctx_alter_gtt);
}
}
/*
* Select destination tablespace (same as original unless user
* requested a change)
@ -20247,7 +20227,10 @@ static void ExecRewriteRowTable(AlteredTableInfo* tab, Oid NewTableSpace, LOCKMO
ATRewriteTable(tab, oldRel, newRel);
heap_close(oldRel, NoLock);
heap_close(newRel, NoLock);
bool swapToastByContent = false;
if (RELATION_IS_GLOBAL_TEMP(oldRel)) {
swapToastByContent = true;
}
/*
* Swap the physical files of the old and new heaps, then rebuild
* indexes and discard the old heap. We can use RecentXmin for
@ -20256,7 +20239,7 @@ static void ExecRewriteRowTable(AlteredTableInfo* tab, Oid NewTableSpace, LOCKMO
* we never try to swap toast tables by content, since we have no
* interest in letting this code work on system catalogs.
*/
finish_heap_swap(tab->relid, OIDNewHeap, false, false, true, u_sess->utils_cxt.RecentXmin);
finish_heap_swap(tab->relid, OIDNewHeap, false, swapToastByContent, true, u_sess->utils_cxt.RecentXmin);
/* clear all attrinitdefval */
clearAttrInitDefVal(tab->relid);

View File

@ -43,5 +43,5 @@ extern void gtt_fix_index_state(Relation index);
extern void init_gtt_storage(CmdType operation, ResultRelInfo *resultRelInfo);
extern Oid gtt_fetch_current_relfilenode(Oid relid);
extern void gtt_switch_rel_relfilenode(Oid rel1, Oid relfilenode1, Oid rel2, Oid relfilenode2, bool footprint);
extern void gtt_create_storage_files(Oid relid);
#endif /* STORAGE_GTT_H */

View File

@ -36,8 +36,7 @@ extern void finishPartitionHeapSwap(Oid partitionOid, Oid tempTableOid, bool swa
TransactionId frozenXid, bool tempTableIsPartition = false);
extern void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bool swap_toast_by_content,
bool check_constraints, TransactionId frozenXid, AdaptMem* memInfo = NULL,
char newrelpersistence = RELPERSISTENCE_PERMANENT);
bool check_constraints, TransactionId frozenXid, AdaptMem* memInfo = NULL);
extern void vacuumFullPart(Oid partOid, VacuumStmt* vacstmt, int freeze_min_age, int freeze_table_age);
extern void updateRelationName(Oid relOid, bool isPartition, const char* relNewName);

View File

@ -73,8 +73,8 @@ PARTITION BY RANGE (cre_time) (
PARTITION P2 VALUES LESS THAN('2019-01-01 00:00:00')
);
NOTICE: CREATE TABLE will create implicit sequence "p_table01_id_seq" for serial column "p_table01.id"
ERROR: ON COMMIT option is not supported for partitioned table
ERROR: ON COMMIT option is not supported for partitioned table
--CREATE global temp TABLE p_table01_2018
--PARTITION OF p_table01
--FOR VALUES FROM ('2018-01-01 00:00:00') TO ('2019-01-01 00:00:00') on commit delete rows;
@ -160,8 +160,21 @@ create global temp table gtt_test_rename(a int primary key, b text);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "gtt_test_rename_pkey" for table "gtt_test_rename"
--ok
alter table gtt_test_rename rename to gtt_test_new;
--ok
ALTER TABLE gtt_test_new ADD COLUMN address integer;
--ok
insert into gtt_test_new values(1, 'hello postgres', 128);
-- ok
ALTER TABLE gtt_test_new ADD COLUMN address varchar(30);
ALTER TABLE gtt_test_new MODIFY (address varchar(1024));
--ok
select * from gtt_test_new;
a | b | address
---+----------------+---------
1 | hello postgres | 128
(1 row)
--ok
ALTER TABLE gtt_test_new DROP address;
CREATE global temp TABLE products (
product_no integer PRIMARY KEY,
name text,

View File

@ -141,7 +141,7 @@ create global temp table gtt4(a int primary key, b text) with(on_commit_delete_r
create global temp table gtt5(a int primary key, b text) with(on_commit_delete_rows=true);
-- ok
create table tb1 (like gtt2 including reloptions);
create table tb1 (like gtt2 including reloptions);
-- ERROR
create global temp table gtt7 (like gtt2 including reloptions) on commit preserve rows;
@ -160,8 +160,20 @@ create global temp table gtt_test_rename(a int primary key, b text);
--ok
alter table gtt_test_rename rename to gtt_test_new;
--ok
ALTER TABLE gtt_test_new ADD COLUMN address integer;
--ok
insert into gtt_test_new values(1, 'hello postgres', 128);
-- ok
ALTER TABLE gtt_test_new ADD COLUMN address varchar(30);
ALTER TABLE gtt_test_new MODIFY (address varchar(1024));
--ok
select * from gtt_test_new;
--ok
ALTER TABLE gtt_test_new DROP address;
CREATE global temp TABLE products (
product_no integer PRIMARY KEY,