Perform cleanup phase even if open relation failed during drop phase of vacuum.

Vacuum of AO tables happens in four phases: prepare, compact, drop and cleanup.
When there are concurrent transactions executing vacuum on AO tables, if one of
the vacuum transaction is executing a drop phase, the other transaction will
not be able to open the relation if it is also executing the drop phase. When
the relation open fails, vacuum simply exits without performing the cleanup
phase. The relfrozenxid in pg_class is updated during the cleanup phase and
hence the age of the table does not get reduced. This becomes a problem because
the age of the database does not reduce and eventually the xid wraparound issue
will be encountered.

This problem is fixed by performing the cleanup phase even if the open relation
fails during drop phase.
上级 b1a1d190
......@@ -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), " \
......
......@@ -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,
......
......@@ -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"),
......
......@@ -196,6 +196,7 @@ typedef enum FaultInjectorIdentifier_e {
VacuumFullBeforeTruncate,
VacuumFullAfterTruncate,
VacuumRelationEndOfFirstRound,
VacuumRelationOpenRelationDuringDropPhase,
RebuildPTDB,
......
......@@ -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
-- @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;
......@@ -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
-- @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; <waiting ...>
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; <waiting ...>
-- 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
......@@ -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;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册