diff --git a/gpMgmt/bin/gppylib/programs/clsInjectFault.py b/gpMgmt/bin/gppylib/programs/clsInjectFault.py index 18bd13f9fcc4aa031bde5bb64d02463ebc88d8f2..91c95c0b984e3545b286498d0eac55ff2b1a7709 100644 --- a/gpMgmt/bin/gppylib/programs/clsInjectFault.py +++ b/gpMgmt/bin/gppylib/programs/clsInjectFault.py @@ -409,6 +409,7 @@ class GpInjectFaultProgram: "vacuum_full_before_truncate (inject fault before truncate in vacuum full), " \ "vacuum_full_after_truncate (inject fault after truncate in vacuum full), " \ "vacuum_relation_end_of_first_round (inject fault at the end of first round of vacuumRelation loop), " \ + "vacuum_relation_open_relation_during_drop_phase (inject fault during open relation of drop phase of vacuumRelation loop), " \ "rebuild_pt_db (inject fault while rebuilding persistent tables (for each db)), " \ "procarray_add (inject fault while adding PGPROC to procarray), " \ "exec_hashjoin_new_batch (inject fault before switching to a new batch in Hash Join), " \ diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 5f9bc3e86bfb3bf427366cfd7e0eb5568a96ee21..01904ffd6edfc0ede91ebdce19961401d363c1da 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -956,7 +956,6 @@ vacuumStatement_Relation(VacuumStmt *vacstmt, Oid relid, Relation onerel; LockRelId onerelid; MemoryContext oldctx; - bool bTemp; VacuumStatsContext stats_context; vacstmt = copyObject(vacstmt); @@ -994,17 +993,29 @@ vacuumStatement_Relation(VacuumStmt *vacstmt, Oid relid, while (!getnextrelation) { - bTemp = false; getnextrelation = true; + /* + * The following block of code is relevant only for AO tables. The + * only phases relevant are prepare phase, compaction phase and the + * first phase of cleanup for VACUUM FULL (truncatePhase set to true + * refers to this phase). + */ if (Gp_role != GP_ROLE_EXECUTE && (!dropPhase || truncatePhase)) { - /* Reset the compaction segno if new relation or segment file is started */ + /* Reset the compaction segno if new relation or segment file is + * started + */ list_free(vacstmt->appendonly_compaction_segno); list_free(vacstmt->appendonly_compaction_insert_segno); vacstmt->appendonly_compaction_segno = NIL; vacstmt->appendonly_compaction_insert_segno = NIL; - vacstmt->appendonly_compaction_vacuum_cleanup = false; + /* + * We should not reset the cleanup flag for truncate phase because + * it is a sub part of the cleanup phase for VACUUM FULL case + */ + if (!truncatePhase) + vacstmt->appendonly_compaction_vacuum_cleanup = false; } /* Set up the distributed transaction context. */ @@ -1072,19 +1083,40 @@ vacuumStatement_Relation(VacuumStmt *vacstmt, Oid relid, */ onerel = open_relation_and_check_permission(vacstmt, relid, RELKIND_RELATION, dropPhase); + /* + * onerel can be NULL for the following cases: + * 1. If the user does not have the permissions to vacuum the table + * 2. For AO tables if the drop phase cannot be performed and should be skipped + */ if (onerel == NULL) { - if (Gp_role != GP_ROLE_EXECUTE) + if ((Gp_role != GP_ROLE_EXECUTE) && dropPhase) { + /* + * To ensure that vacuum decreases the age for appendonly + * tables even if drop phase is getting skipped, perform + * cleanup phase so that the relfrozenxid value is updated + * correctly in pg_class + */ + vacstmt->appendonly_compaction_vacuum_cleanup = true; + dropPhase = false; + /* + * Since the drop phase needs to be skipped, we need to + * deregister the segnos which were marked for drop in the + * compaction phase + */ DeregisterSegnoForCompactionDrop(relid, - vacstmt->appendonly_compaction_segno); + vacstmt->appendonly_compaction_segno); + onerel = open_relation_and_check_permission(vacstmt, relid, RELKIND_RELATION, false); + } + + if (!vacstmt->appendonly_compaction_vacuum_cleanup) + { CommitTransactionCommand(); + continue; } - continue; } - /* XXX not about temporary table, this is about meta data tracking. */ - bTemp = vacuumStatement_IsTemporary(onerel); vacuumStatement_AssignRelation(vacstmt, relid, relations); @@ -1113,89 +1145,98 @@ vacuumStatement_Relation(VacuumStmt *vacstmt, Oid relid, vacstmt->heap_truncate = true; } } - /* the rest is about AO tables */ - else if (vacstmt->appendonly_compaction_vacuum_prepare) - { - getnextrelation = false; - dropPhase = false; - } - else if (!dropPhase) + else { - if (!vacuumStatement_AssignAppendOnlyCompactionInfo(vacstmt, - onerel, compactedSegmentFileList, - insertedSegmentFileList, &getnextrelation)) + /* the rest is about AO tables */ + if (vacstmt->appendonly_compaction_vacuum_prepare) { - MemoryContextSwitchTo(oldctx); - /* Nothing left to do for this relation */ - relation_close(onerel, NoLock); - CommitTransactionCommand(); - /* don't dispatch this iteration */ - continue; + getnextrelation = false; + dropPhase = false; } - - compactedSegmentFileList = - list_union_int(compactedSegmentFileList, - vacstmt->appendonly_compaction_segno); - insertedSegmentFileList = - list_union_int(insertedSegmentFileList, - vacstmt->appendonly_compaction_insert_segno); - - dropPhase = !getnextrelation; - } - else - { - if (HasSerializableBackends(false)) + else if (dropPhase) { - /* - * Checking at this point is safe because - * any serializable transaction that could start afterwards - * will already see the state with AWAITING_DROP. We - * have only to deal with transactions that started before - * our transaction. - * - * We immediatelly get the next relation. There is no - * reason to stay in this relation. Actually, all - * other ao relation will skip the compaction step. - */ - elogif(Debug_appendonly_print_compaction, LOG, - "Skipping freeing compacted append-only segment file " - "because of concurrent serializable transaction"); + if (HasSerializableBackends(false)) + { + /* + * Checking at this point is safe because + * any serializable transaction that could start afterwards + * will already see the state with AWAITING_DROP. We + * have only to deal with transactions that started before + * our transaction. + * + * We immediatelly get the next relation. There is no + * reason to stay in this relation. Actually, all + * other ao relation will skip the compaction step. + */ + elogif(Debug_appendonly_print_compaction, LOG, + "Skipping freeing compacted append-only segment file " + "because of concurrent serializable transaction"); - DeregisterSegnoForCompactionDrop(relid, vacstmt->appendonly_compaction_segno); - MemoryContextSwitchTo(oldctx); - relation_close(onerel, NoLock); - CommitTransactionCommand(); - /* don't dispatch this iteration */ - continue; + DeregisterSegnoForCompactionDrop(relid, vacstmt->appendonly_compaction_segno); + vacstmt->appendonly_compaction_vacuum_cleanup = true; + dropPhase = false; + getnextrelation = false; + } + else + { + elogif(Debug_appendonly_print_compaction, LOG, + "Dispatch drop transaction on append-only relation %s", + RelationGetRelationName(onerel)); + + RegisterSegnoForCompactionDrop(relid, vacstmt->appendonly_compaction_segno); + list_free(vacstmt->appendonly_compaction_insert_segno); + vacstmt->appendonly_compaction_insert_segno = NIL; + dropPhase = false; + getnextrelation = false; + } } - elogif(Debug_appendonly_print_compaction, LOG, - "Dispatch drop transaction on append-only relation %s", - RelationGetRelationName(onerel)); + else + { + /* Either we are in cleanup or in compaction phase */ + if (!vacstmt->appendonly_compaction_vacuum_cleanup) + { + /* This block is only relevant for compaction */ + if (!vacuumStatement_AssignAppendOnlyCompactionInfo(vacstmt, + onerel, compactedSegmentFileList, + insertedSegmentFileList, &getnextrelation)) + { + MemoryContextSwitchTo(oldctx); + /* Nothing left to do for this relation */ + relation_close(onerel, NoLock); + CommitTransactionCommand(); + /* don't dispatch this iteration */ + continue; + } - RegisterSegnoForCompactionDrop(relid, vacstmt->appendonly_compaction_segno); - list_free(vacstmt->appendonly_compaction_insert_segno); - vacstmt->appendonly_compaction_insert_segno = NIL; - dropPhase = false; - getnextrelation = false; - } - MemoryContextSwitchTo(oldctx); + compactedSegmentFileList = + list_union_int(compactedSegmentFileList, + vacstmt->appendonly_compaction_segno); + insertedSegmentFileList = + list_union_int(insertedSegmentFileList, + vacstmt->appendonly_compaction_insert_segno); - /* - * For AO tables VACUUM FULL, we perform two-step for aux relations. - */ - if (!RelationIsHeap(onerel) && - vacstmt->full && - vacstmt->appendonly_compaction_vacuum_cleanup) - { - if (!truncatePhase) - { - truncatePhase = true; - getnextrelation = false; + dropPhase = !getnextrelation; + } } - else + MemoryContextSwitchTo(oldctx); + + /* + * If VACUUM FULL and in cleanup phase, perform two-step for + * aux relations. + */ + if (vacstmt->full && + vacstmt->appendonly_compaction_vacuum_cleanup) { - truncatePhase = false; - vacstmt->heap_truncate = true; + if (truncatePhase) + { + truncatePhase = false; + vacstmt->heap_truncate = true; + } + else + { + truncatePhase = true; + getnextrelation = false; + } } } } @@ -1311,6 +1352,34 @@ vacuumStatement_Relation(VacuumStmt *vacstmt, Oid relid, UpdateMasterAosegTotalsFromSegments(onerel, SnapshotNow, vacstmt->appendonly_compaction_segno, 0); } } + + /* + * We need some transaction to update the catalog. We could do + * it on the outer vacuumStatement, but it is useful to track + * relation by relation. + */ + if (relationRound == 0 && !vacuumStatement_IsTemporary(onerel)) + { + char *vsubtype = ""; /* NOFULL */ + + if (IsAutoVacuumWorkerProcess()) + vsubtype = "AUTO"; + else + { + if (vacstmt->full && + (0 == vacstmt->freeze_min_age)) + vsubtype = "FULL FREEZE"; + else if (vacstmt->full) + vsubtype = "FULL"; + else if (0 == vacstmt->freeze_min_age) + vsubtype = "FREEZE"; + } + MetaTrackUpdObject(RelationRelationId, + relid, + GetUserId(), + "VACUUM", + vsubtype); + } } /* @@ -1322,34 +1391,6 @@ vacuumStatement_Relation(VacuumStmt *vacstmt, Oid relid, */ relation_close(onerel, NoLock); - /* - * MPP-6929: metadata tracking - * We need some transaction to update the catalog. We could do - * it on the outer vacuumStatement, but it is useful to track - * relation by relation. - */ - if (relationRound == 0 && !bTemp && (Gp_role == GP_ROLE_DISPATCH)) - { - char *vsubtype = ""; /* NOFULL */ - - if (IsAutoVacuumWorkerProcess()) - vsubtype = "AUTO"; - else - { - if (vacstmt->full && - (0 == vacstmt->freeze_min_age)) - vsubtype = "FULL FREEZE"; - else if (vacstmt->full) - vsubtype = "FULL"; - else if (0 == vacstmt->freeze_min_age) - vsubtype = "FREEZE"; - } - MetaTrackUpdObject(RelationRelationId, - relid, - GetUserId(), - "VACUUM", - vsubtype); - } if (list_length(relations) > 1) { @@ -5397,6 +5438,7 @@ open_relation_and_check_permission(VacuumStmt *vacstmt, if (isDropTransaction && !vacstmt->full) { MyProc->inDropTransaction = true; + SIMPLE_FAULT_INJECTOR(VacuumRelationOpenRelationDuringDropPhase); if (HasDropTransaction(false)) { elogif(Debug_appendonly_print_compaction, LOG, diff --git a/src/backend/utils/misc/faultinjector.c b/src/backend/utils/misc/faultinjector.c index 9dbfda551e84c79ce4f732d45e207030329a39cf..16823cc3bd70e59d4c04e8dbf7de1a652df89d68 100644 --- a/src/backend/utils/misc/faultinjector.c +++ b/src/backend/utils/misc/faultinjector.c @@ -301,6 +301,8 @@ FaultInjectorIdentifierEnumToString[] = { /* inject fault after truncate in vacuum full */ _("vacuum_relation_end_of_first_round"), /* inject fault at the end of first round of vacuumRelation loop */ + _("vacuum_relation_open_relation_during_drop_phase"), + /* inject fault during the open relation of the drop phase of vacuumRelation loop */ _("rebuild_pt_db"), /* inject fault while rebuilding persistent tables (for each db) */ _("procarray_add"), diff --git a/src/include/utils/faultinjector.h b/src/include/utils/faultinjector.h index 35257021ba639864b30ee971cc2c0898bff21617..3523bad544eafa2bf1a68b3314f8fcbcba52a766 100644 --- a/src/include/utils/faultinjector.h +++ b/src/include/utils/faultinjector.h @@ -196,6 +196,7 @@ typedef enum FaultInjectorIdentifier_e { VacuumFullBeforeTruncate, VacuumFullAfterTruncate, VacuumRelationEndOfFirstRound, + VacuumRelationOpenRelationDuringDropPhase, RebuildPTDB, diff --git a/src/test/isolation2/expected/setup.out b/src/test/isolation2/expected/setup.out index a2eadf47b09f6532a3aad1bfb1cc16af60caf167..f64dce2dc83d81e426a23c53bf6e2e2c8d414ce1 100644 --- a/src/test/isolation2/expected/setup.out +++ b/src/test/isolation2/expected/setup.out @@ -21,3 +21,11 @@ CREATE create or replace view locktest_segments as SELECT coalesce( case when relname like 'pg_toast%index' then 'toast index' when relname like 'pg_toast%' then 'toast table' when relname like 'pg_aoseg%' then 'aoseg table' when relname like 'pg_aovisimap%index' then 'aovisimap index' when relname like 'pg_aovisimap%' then 'aovisimap table' else relname end, 'dropped table'), mode, locktype, case when count(*) = 1 then '1 segment' else 'n segments' end as node FROM gp_dist_random('locktest_segments_dist') group by relname, relation, mode, locktype; CREATE + +-- start_ignore +create language plpythonu; +CREATE +-- end_ignore + +CREATE OR REPLACE FUNCTION wait_for_trigger_fault(fault text, segno int) RETURNS bool as $$ import subprocess import time cmd = 'gpfaultinjector -f %s -y status -s %d | grep -i triggered | wc -l' % (fault, segno) for i in range(100): cmd_output = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True) if int(cmd_output.stdout.read()): return True time.sleep(0.5) return False $$ LANGUAGE plpythonu; +CREATE diff --git a/src/test/isolation2/input/uao/vacuum_cleanup.source b/src/test/isolation2/input/uao/vacuum_cleanup.source new file mode 100644 index 0000000000000000000000000000000000000000..0a9d782c530c027eaeb532ac3ee64ee6e27d3038 --- /dev/null +++ b/src/test/isolation2/input/uao/vacuum_cleanup.source @@ -0,0 +1,62 @@ +-- @Description Test that when there is a parallel vacuum going on in drop phase, the age of +-- the AO/AOCS table gets reduced correctly. + +1: create table ao_@orientation@_vacuum_cleanup1(a int, b int) with(appendonly=true, orientation=@orientation@); +1: insert into ao_@orientation@_vacuum_cleanup1 select 1, i from generate_series(1, 100) i; +1: update ao_@orientation@_vacuum_cleanup1 set b = b + 1; + +-- The age of the table is 1 after the following statement +2: create table ao_@orientation@_vacuum_cleanup2(a int, b int) with(appendonly=true, orientation=@orientation@); +-- The age of the table is 2 after the following statement +2: insert into ao_@orientation@_vacuum_cleanup2 select 1, i from generate_series(1, 100) i; +-- The age of the table is 3 after the following statement +2: update ao_@orientation@_vacuum_cleanup2 set b = b + 1; + + +1: !gpfaultinjector -f vacuum_relation_open_relation_during_drop_phase -y suspend -s 2; + +2&: vacuum ao_@orientation@_vacuum_cleanup1; + +1: select wait_for_trigger_fault('vacuum_relation_open_relation_during_drop_phase', 2); + +1: set vacuum_freeze_min_age = 0; +-- Check the age of the table just before vacuum +1: select age(relfrozenxid) from gp_dist_random('pg_class') where relname = 'ao_@orientation@_vacuum_cleanup2' and gp_segment_id = 0; +1: vacuum ao_@orientation@_vacuum_cleanup2; + +-- We expect the age to be 3. This is because all the xids before the first +-- vacuum will be frozen. The relfrozenxid will be the xid of the last +-- transaction before the vacuum (in this case it is the update statement) +1: select age(relfrozenxid) from gp_dist_random('pg_class') where relname = 'ao_@orientation@_vacuum_cleanup2' and gp_segment_id = 0; + +1: !gpfaultinjector -f vacuum_relation_open_relation_during_drop_phase -y reset -s 2; +2<: + +-- Check that drop phase is skipped, but still the cleanup phase is performed +-- when there are concurrent serializable transactions + +1: create table ao_@orientation@_vacuum_cleanup3(a int, b int) with(appendonly=true, orientation=@orientation@); +1: insert into ao_@orientation@_vacuum_cleanup3 select i, i from generate_series(1, 100) i; +1: delete from ao_@orientation@_vacuum_cleanup3; + +-- Check the age of the table before vacuum to make sure that clean phase gets +-- performed +1: select age(relfrozenxid) from gp_dist_random('pg_class') where relname = 'ao_@orientation@_vacuum_cleanup3' and gp_segment_id = 0; +1: !gpfaultinjector -f vacuum_relation_open_relation_during_drop_phase -y suspend -s 1; +1&: vacuum ao_@orientation@_vacuum_cleanup3; + +-- Wait till compaction phase is completed and only then start the serializable +-- transaction to ensure that only drop phase is skipped +2: select wait_for_trigger_fault('vacuum_relation_open_relation_during_drop_phase', 1); +2: begin isolation level serializable; +2: select 123; +2: !gpfaultinjector -f vacuum_relation_open_relation_during_drop_phase -y reset -s 1; + +1<: +1: select age(relfrozenxid) from gp_dist_random('pg_class') where relname = 'ao_@orientation@_vacuum_cleanup3' and gp_segment_id = 0; + +-- Validate that the drop phase was skipped. segfile 1 should be in state 2 +-- (AWAITING_DROP) +1: SELECT gp_ao_or_aocs_seg_name('ao_@orientation@_vacuum_cleanup3') from gp_dist_random('gp_id'); + +2: commit; diff --git a/src/test/isolation2/isolation2_schedule b/src/test/isolation2/isolation2_schedule index 46053919f68c6942f6d242b37e8849bca847c891..d284c20f0f59e183ef4debfa7823219097786dbb 100644 --- a/src/test/isolation2/isolation2_schedule +++ b/src/test/isolation2/isolation2_schedule @@ -49,6 +49,7 @@ test: uao/vacuum_self_serializable2_row test: uao/vacuum_self_serializable3_row test: uao/vacuum_while_insert_row test: uao/vacuum_while_vacuum_row +test: uao/vacuum_cleanup_row # Tests on Append-Optimized tables (column-oriented). test: uao/alter_while_vacuum_column @@ -95,5 +96,6 @@ test: uao/vacuum_self_serializable2_column test: uao/vacuum_self_serializable3_column test: uao/vacuum_while_insert_column test: uao/vacuum_while_vacuum_column +test: uao/vacuum_cleanup_column test: add_column_after_vacuum_skip_drop_column test: vacuum_after_vacuum_skip_drop_column diff --git a/src/test/isolation2/output/uao/vacuum_cleanup.source b/src/test/isolation2/output/uao/vacuum_cleanup.source new file mode 100644 index 0000000000000000000000000000000000000000..b89ce1d11b435e0cd66d9b8c63aec8fa62d84854 --- /dev/null +++ b/src/test/isolation2/output/uao/vacuum_cleanup.source @@ -0,0 +1,130 @@ +-- @Description Test that when there is a parallel vacuum going on in drop phase, the age of +-- the AO/AOCS table gets reduced correctly. + +1: create table ao_@orientation@_vacuum_cleanup1(a int, b int) with(appendonly=true, orientation=@orientation@); +CREATE +1: insert into ao_@orientation@_vacuum_cleanup1 select 1, i from generate_series(1, 100) i; +INSERT 100 +1: update ao_@orientation@_vacuum_cleanup1 set b = b + 1; +UPDATE 100 + +-- The age of the table is 1 after the following statement +2: create table ao_@orientation@_vacuum_cleanup2(a int, b int) with(appendonly=true, orientation=@orientation@); +CREATE +-- The age of the table is 2 after the following statement +2: insert into ao_@orientation@_vacuum_cleanup2 select 1, i from generate_series(1, 100) i; +INSERT 100 +-- The age of the table is 3 after the following statement +2: update ao_@orientation@_vacuum_cleanup2 set b = b + 1; +UPDATE 100 + + +1: !gpfaultinjector -f vacuum_relation_open_relation_during_drop_phase -y suspend -s 2; +20170505:11:00:18:092363 gpfaultinjector:subraa4-mac:abhijits-[INFO]:-Starting gpfaultinjector with args: -f vacuum_relation_open_relation_during_drop_phase -y suspend -s 2 +20170505:11:00:18:092363 gpfaultinjector:subraa4-mac:abhijits-[INFO]:-Injecting fault on content=0:dbid=2:mode=s:status=u +20170505:11:00:18:092363 gpfaultinjector:subraa4-mac:abhijits-[INFO]:-DONE + + +2&: vacuum ao_@orientation@_vacuum_cleanup1; + +1: select wait_for_trigger_fault('vacuum_relation_open_relation_during_drop_phase', 2); +wait_for_trigger_fault +---------------------- +t +(1 row) + +1: set vacuum_freeze_min_age = 0; +SET +-- Check the age of the table just before vacuum +1: select age(relfrozenxid) from gp_dist_random('pg_class') where relname = 'ao_@orientation@_vacuum_cleanup2' and gp_segment_id = 0; +age +--- +5 +(1 row) +1: vacuum ao_@orientation@_vacuum_cleanup2; +VACUUM + +-- We expect the age to be 3. This is because all the xids before the first +-- vacuum will be frozen. The relfrozenxid will be the xid of the last +-- transaction before the vacuum (in this case it is the update statement) +1: select age(relfrozenxid) from gp_dist_random('pg_class') where relname = 'ao_@orientation@_vacuum_cleanup2' and gp_segment_id = 0; +age +--- +3 +(1 row) + +1: !gpfaultinjector -f vacuum_relation_open_relation_during_drop_phase -y reset -s 2; +20170505:11:00:19:092390 gpfaultinjector:subraa4-mac:abhijits-[INFO]:-Starting gpfaultinjector with args: -f vacuum_relation_open_relation_during_drop_phase -y reset -s 2 +20170505:11:00:19:092390 gpfaultinjector:subraa4-mac:abhijits-[INFO]:-Injecting fault on content=0:dbid=2:mode=s:status=u +20170505:11:00:19:092390 gpfaultinjector:subraa4-mac:abhijits-[INFO]:-DONE + +2<: <... completed> +VACUUM + +-- Check that drop phase is skipped, but still the cleanup phase is performed +-- when there are concurrent serializable transactions + +1: create table ao_@orientation@_vacuum_cleanup3(a int, b int) with(appendonly=true, orientation=@orientation@); +CREATE +1: insert into ao_@orientation@_vacuum_cleanup3 select i, i from generate_series(1, 100) i; +INSERT 100 +1: delete from ao_@orientation@_vacuum_cleanup3; +DELETE 100 + +-- Check the age of the table before vacuum to make sure that clean phase gets +-- performed +1: select age(relfrozenxid) from gp_dist_random('pg_class') where relname = 'ao_@orientation@_vacuum_cleanup3' and gp_segment_id = 0; +age +--- +3 +(1 row) +1: !gpfaultinjector -f vacuum_relation_open_relation_during_drop_phase -y suspend -s 1; +20170509:15:52:16:071163 gpfaultinjector:subraa4-mac:abhijits-[INFO]:-Starting gpfaultinjector with args: -f vacuum_relation_open_relation_during_drop_phase -y suspend -s 1 +20170509:15:52:16:071163 gpfaultinjector:subraa4-mac:abhijits-[INFO]:-Injecting fault on content=-1:dbid=1:mode=s:status=u +20170509:15:52:16:071163 gpfaultinjector:subraa4-mac:abhijits-[INFO]:-DONE + +1&: vacuum ao_@orientation@_vacuum_cleanup3; + +-- Wait till compaction phase is completed and only then start the serializable +-- transaction to ensure that only drop phase is skipped +2: select wait_for_trigger_fault('vacuum_relation_open_relation_during_drop_phase', 1); +wait_for_trigger_fault +---------------------- +t +(1 row) +2: begin isolation level serializable; +BEGIN +2: select 123; +?column? +-------- +123 +(1 row) +2: !gpfaultinjector -f vacuum_relation_open_relation_during_drop_phase -y reset -s 1; +20170509:15:52:17:071190 gpfaultinjector:subraa4-mac:abhijits-[INFO]:-Starting gpfaultinjector with args: -f vacuum_relation_open_relation_during_drop_phase -y reset -s 1 +20170509:15:52:17:071190 gpfaultinjector:subraa4-mac:abhijits-[INFO]:-Injecting fault on content=-1:dbid=1:mode=s:status=u +20170509:15:52:17:071190 gpfaultinjector:subraa4-mac:abhijits-[INFO]:-DONE + + +1<: <... completed> +VACUUM +1: select age(relfrozenxid) from gp_dist_random('pg_class') where relname = 'ao_@orientation@_vacuum_cleanup3' and gp_segment_id = 0; +age +--- +1 +(1 row) + +-- Validate that the drop phase was skipped. segfile 1 should be in state 2 +-- (AWAITING_DROP) +1: SELECT gp_ao_or_aocs_seg_name('ao_@orientation@_vacuum_cleanup3') from gp_dist_random('gp_id'); +gp_ao_or_aocs_seg_name +---------------------- +(1,37,1,3,2) +(2,0,1,3,1) +(1,31,1,3,2) +(2,0,1,3,1) +(1,32,1,3,2) +(2,0,1,3,1) +(6 rows) + +2: commit; +COMMIT diff --git a/src/test/isolation2/sql/setup.sql b/src/test/isolation2/sql/setup.sql index 6f89e2e256af15fd64943800ed166e37ed51bbfa..8cd0d4b75b1512abe8943d348f808172451c083e 100644 --- a/src/test/isolation2/sql/setup.sql +++ b/src/test/isolation2/sql/setup.sql @@ -85,3 +85,20 @@ SELECT coalesce( else 'n segments' end as node FROM gp_dist_random('locktest_segments_dist') group by relname, relation, mode, locktype; + +-- start_ignore +create language plpythonu; +-- end_ignore + +CREATE OR REPLACE FUNCTION wait_for_trigger_fault(fault text, segno int) +RETURNS bool as $$ + import subprocess + import time + cmd = 'gpfaultinjector -f %s -y status -s %d | grep -i triggered | wc -l' % (fault, segno) + for i in range(100): + cmd_output = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True) + if int(cmd_output.stdout.read()): + return True + time.sleep(0.5) + return False +$$ LANGUAGE plpythonu;