On Sun, Mar 4, 2012 at 1:02 PM, Simon Riggs <si...@2ndquadrant.com> wrote: > On Sun, Mar 4, 2012 at 9:59 AM, Simon Riggs <si...@2ndquadrant.com> wrote: >> On Sun, Mar 4, 2012 at 2:28 AM, Marti Raudsepp <ma...@juffo.org> wrote: >>> On Sat, Mar 3, 2012 at 14:53, Simon Riggs <si...@2ndquadrant.com> wrote: >>>> Thanks Noah for drawing attention to this thread. I hadn't been >>>> watching. As you say, this work would allow me to freeze rows at load >>>> time and avoid the overhead of hint bit setting, which avoids >>>> performance issues from hint bit setting in checksum patch. >>>> >>>> I've reviewed this patch and it seems OK to me. Good work Marti. > > ... > >> v3 attached. > > More detailed thoughts show that the test in heap_beginscan_internal() > is not right enough, i.e. wrong. > > We need a specific XidInMVCCSnapshot test on the relvalidxid, so it > needs to be a specific xid, not an xmin because otherwise we can get > concurrent transactions failing, not just older transactions.
Marti, please review this latest version which has new isolation tests added. This does both TRUNCATE and CREATE TABLE. -- Simon Riggs http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index c910863..3d90125 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -73,7 +73,7 @@ /* GUC variable */ bool synchronize_seqscans = true; - +bool StrictMVCC = true; static HeapScanDesc heap_beginscan_internal(Relation relation, Snapshot snapshot, @@ -1175,6 +1175,24 @@ heap_beginscan_internal(Relation relation, Snapshot snapshot, HeapScanDesc scan; /* + * If the snapshot can't see relvalidxid then that means either the table + * is newly created or has recently been truncated. Either way, we aren't + * allowed to view the rows in StrictMVCC mode. + */ + if (IsMVCCSnapshot(snapshot) && + StrictMVCC && + XidInMVCCSnapshot(relation->rd_rel->relvalidxid, snapshot)) + { + /* Unless we created or truncated the table recently ourselves */ + if (relation->rd_createSubid == InvalidSubTransactionId && + relation->rd_newRelfilenodeSubid == InvalidSubTransactionId) + ereport(ERROR, + (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), + errmsg("cannot access recently added or recently removed data in %s", + NameStr(relation->rd_rel->relname)))); + } + + /* * increment relation ref count while scanning relation * * This is just to make really sure the relcache entry won't go away while diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index aef410a..eb93a7c 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -787,6 +787,7 @@ InsertPgClassTuple(Relation pg_class_desc, values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers); values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass); values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid); + values[Anum_pg_class_relvalidxid - 1] = TransactionIdGetDatum(rd_rel->relvalidxid); if (relacl != (Datum) 0) values[Anum_pg_class_relacl - 1] = relacl; else @@ -872,6 +873,7 @@ AddNewRelationTuple(Relation pg_class_desc, * that will do. */ new_rel_reltup->relfrozenxid = RecentXmin; + new_rel_reltup->relvalidxid = GetCurrentTransactionId(); } else { @@ -882,6 +884,7 @@ AddNewRelationTuple(Relation pg_class_desc, * commands/sequence.c.) */ new_rel_reltup->relfrozenxid = InvalidTransactionId; + new_rel_reltup->relvalidxid = InvalidTransactionId; } new_rel_reltup->relowner = relowner; diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index bfbe642..0d96a6a 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -2854,7 +2854,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks) } /* We'll build a new physical relation for the index */ - RelationSetNewRelfilenode(iRel, InvalidTransactionId); + RelationSetNewRelfilenode(iRel, InvalidTransactionId, InvalidTransactionId); /* Initialize the index and rebuild */ /* Note: we do not need to re-establish pkey setting */ diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index b40e57b..44b891c 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -538,6 +538,7 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, bool inh) totalrows, visibilitymap_count(onerel), hasindex, + InvalidTransactionId, InvalidTransactionId); /* @@ -558,6 +559,7 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, bool inh) totalindexrows, 0, false, + InvalidTransactionId, InvalidTransactionId); } } diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 1f95abc..ab4aec2 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -287,7 +287,7 @@ ResetSequence(Oid seq_relid) * Create a new storage file for the sequence. We want to keep the * sequence's relfrozenxid at 0, since it won't contain any unfrozen XIDs. */ - RelationSetNewRelfilenode(seq_rel, InvalidTransactionId); + RelationSetNewRelfilenode(seq_rel, InvalidTransactionId, InvalidTransactionId); /* * Insert the modified tuple into the new storage file. diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index cd4490a..aa9d2e9 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -19,6 +19,7 @@ #include "access/reloptions.h" #include "access/relscan.h" #include "access/sysattr.h" +#include "access/transam.h" #include "access/xact.h" #include "catalog/catalog.h" #include "catalog/dependency.h" @@ -1121,7 +1122,7 @@ ExecuteTruncate(TruncateStmt *stmt) * as the relfilenode value. The old storage file is scheduled for * deletion at commit. */ - RelationSetNewRelfilenode(rel, RecentXmin); + RelationSetNewRelfilenode(rel, RecentXmin, GetCurrentTransactionId()); heap_relid = RelationGetRelid(rel); toast_relid = rel->rd_rel->reltoastrelid; @@ -1132,7 +1133,12 @@ ExecuteTruncate(TruncateStmt *stmt) if (OidIsValid(toast_relid)) { rel = relation_open(toast_relid, AccessExclusiveLock); - RelationSetNewRelfilenode(rel, RecentXmin); + RelationSetNewRelfilenode(rel, RecentXmin, InvalidTransactionId); + + /* + * We don't need a cmin here because there can't be any open + * cursors in the same session as the TRUNCATE command. + */ heap_close(rel, NoLock); } diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 353af50..a0cfe54 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -573,7 +573,8 @@ void vac_update_relstats(Relation relation, BlockNumber num_pages, double num_tuples, BlockNumber num_all_visible_pages, - bool hasindex, TransactionId frozenxid) + bool hasindex, TransactionId frozenxid, + TransactionId oldestxmin) { Oid relid = RelationGetRelid(relation); Relation rd; @@ -647,6 +648,21 @@ vac_update_relstats(Relation relation, dirty = true; } + /* + * Reset relvalidxid if it's old enough. Resetting this value + * could cause MVCC failures on a standby that doesn't have + * hot_standby_feedback enabled, so only reset the value if we + * are certain that all prior snapshots have ended or been + * removed via conflict. Value should always be invalid for indexes. + */ + if (TransactionIdIsValid(oldestxmin) && + TransactionIdIsNormal(pgcform->relvalidxid) && + TransactionIdPrecedes(pgcform->relvalidxid, oldestxmin)) + { + pgcform->relvalidxid = InvalidTransactionId; + dirty = true; + } + /* If anything changed, write out the tuple. */ if (dirty) heap_inplace_update(rd, ctup); diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index 2fc749e..3b88652 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -255,7 +255,8 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, new_rel_tuples, new_rel_allvisible, vacrelstats->hasindex, - new_frozen_xid); + new_frozen_xid, + vacrelstats->latestRemovedXid); /* report results to the stats collector, too */ pgstat_report_vacuum(RelationGetRelid(onerel), @@ -1185,6 +1186,7 @@ lazy_cleanup_index(Relation indrel, stats->num_index_tuples, 0, false, + InvalidTransactionId, InvalidTransactionId); ereport(elevel, diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index a59950e..10ac6b8 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -2605,7 +2605,8 @@ RelationBuildLocalRelation(const char *relname, * the XIDs that will be put into the new relation contents. */ void -RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid) +RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid, + TransactionId validxid) { Oid newrelfilenode; RelFileNodeBackend newrnode; @@ -2673,6 +2674,7 @@ RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid) classform->relallvisible = 0; } classform->relfrozenxid = freezeXid; + classform->relvalidxid = validxid; simple_heap_update(pg_class, &tuple->t_self, tuple); CatalogUpdateIndexes(pg_class, tuple); diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 486bdcd..e4a19aa 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1430,6 +1430,19 @@ static struct config_bool ConfigureNamesBool[] = }, { + {"strict_mvcc", PGC_POSTMASTER, COMPAT_OPTIONS_PREVIOUS, + gettext_noop("Enables backward compatibility mode of strict MVCC " + "for TRUNCATE and CREATE TABLE."), + gettext_noop("When enabled viewing a truncated or newly created table " + "will throw a serialization error to prevent MVCC " + "discrepancies that were possible prior to 9.2.") + }, + &StrictMVCC, + true, + NULL, NULL, NULL + }, + + { {"quote_all_identifiers", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, gettext_noop("When generating SQL fragments, quote all identifiers."), NULL, diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 96da086..f56e374 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -548,6 +548,7 @@ #quote_all_identifiers = off #sql_inheritance = on #standard_conforming_strings = on +#strict_mvcc = on #synchronize_seqscans = on # - Other Platforms and Clients - diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c index 31791a7..4b2a119 100644 --- a/src/backend/utils/time/tqual.c +++ b/src/backend/utils/time/tqual.c @@ -72,9 +72,6 @@ SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf}; SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny}; SnapshotData SnapshotToastData = {HeapTupleSatisfiesToast}; -/* local functions */ -static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot); - /* * SetHintBits() @@ -1239,7 +1236,7 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin, * by this function. This is OK for current uses, because we actually only * apply this for known-committed XIDs. */ -static bool +bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) { uint32 i; diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 0335347..223f157 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201203021 +#define CATALOG_VERSION_NO 201203031 #endif diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index 1567206..4a78bdb 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -67,6 +67,7 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83) BKI_SCHEMA_MACRO bool relhastriggers; /* has (or has had) any TRIGGERs */ bool relhassubclass; /* has (or has had) derived classes */ TransactionId relfrozenxid; /* all Xids < this are frozen in this rel */ + TransactionId relvalidxid; /* data is only valid for snapshots > this Xid */ #ifdef CATALOG_VARLEN /* variable-length fields start here */ /* NOTE: These fields are not present in a relcache entry's rd_rel field. */ @@ -77,7 +78,7 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83) BKI_SCHEMA_MACRO /* Size of fixed part of pg_class tuples, not counting var-length fields */ #define CLASS_TUPLE_SIZE \ - (offsetof(FormData_pg_class,relfrozenxid) + sizeof(TransactionId)) + (offsetof(FormData_pg_class,relvalidxid) + sizeof(TransactionId)) /* ---------------- * Form_pg_class corresponds to a pointer to a tuple with @@ -91,7 +92,7 @@ typedef FormData_pg_class *Form_pg_class; * ---------------- */ -#define Natts_pg_class 27 +#define Natts_pg_class 28 #define Anum_pg_class_relname 1 #define Anum_pg_class_relnamespace 2 #define Anum_pg_class_reltype 3 @@ -117,8 +118,9 @@ typedef FormData_pg_class *Form_pg_class; #define Anum_pg_class_relhastriggers 23 #define Anum_pg_class_relhassubclass 24 #define Anum_pg_class_relfrozenxid 25 -#define Anum_pg_class_relacl 26 -#define Anum_pg_class_reloptions 27 +#define Anum_pg_class_relvalidxid 26 +#define Anum_pg_class_relacl 27 +#define Anum_pg_class_reloptions 28 /* ---------------- * initial contents of pg_class @@ -130,13 +132,13 @@ typedef FormData_pg_class *Form_pg_class; */ /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */ -DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 0 f f p r 30 0 t f f f f 3 _null_ _null_ )); +DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 0 f f p r 30 0 t f f f f 3 0 _null_ _null_ )); DESCR(""); -DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 0 f f p r 21 0 f f f f f 3 _null_ _null_ )); +DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 0 f f p r 21 0 f f f f f 3 0 _null_ _null_ )); DESCR(""); -DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 0 f f p r 27 0 t f f f f 3 _null_ _null_ )); +DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 0 f f p r 27 0 t f f f f 3 0 _null_ _null_ )); DESCR(""); -DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 0 f f p r 27 0 t f f f f 3 _null_ _null_ )); +DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 0 f f p r 28 0 t f f f f 3 0 _null_ _null_ )); DESCR(""); diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 4526648..fa79231 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -151,7 +151,8 @@ extern void vac_update_relstats(Relation relation, double num_tuples, BlockNumber num_all_visible_pages, bool hasindex, - TransactionId frozenxid); + TransactionId frozenxid, + TransactionId oldestxmin); extern void vacuum_set_xid_limits(int freeze_min_age, int freeze_table_age, bool sharedRel, TransactionId *oldestXmin, diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 610cb59..9d2be31 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -342,6 +342,8 @@ extern ProcessingMode Mode; #define GetProcessingMode() Mode +/* in access/heap/heapam.c */ +extern bool StrictMVCC; /***************************************************************************** * pinit.h -- * diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h index 2f39486..0fb2167 100644 --- a/src/include/utils/relcache.h +++ b/src/include/utils/relcache.h @@ -76,7 +76,8 @@ extern Relation RelationBuildLocalRelation(const char *relname, * Routine to manage assignment of new relfilenode to a relation */ extern void RelationSetNewRelfilenode(Relation relation, - TransactionId freezeXid); + TransactionId freezeXid, + TransactionId validxid); /* * Routines for flushing/rebuilding relcache entries in various scenarios diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h index 0f8a7f8..ffdcfd5 100644 --- a/src/include/utils/tqual.h +++ b/src/include/utils/tqual.h @@ -87,4 +87,6 @@ extern HTSV_Result HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, extern void HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid); +extern bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot); + #endif /* TQUAL_H */ diff --git a/src/test/isolation/expected/createtableandcopy.out b/src/test/isolation/expected/createtableandcopy.out new file mode 100644 index 0000000..241bda9 --- /dev/null +++ b/src/test/isolation/expected/createtableandcopy.out @@ -0,0 +1,81 @@ +Parsed test spec with 2 sessions + +starting permutation: begin select roll create +step begin: + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); + +foo + +1 +step select: SELECT * FROM foo; +ERROR: relation "foo" does not exist +step roll: ROLLBACK; +step create: + BEGIN; + CREATE TABLE foo (i int); + COPY foo FROM '/tmp/createtableandcopy.spec.data'; + COMMIT; + + +starting permutation: begin select create roll +step begin: + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); + +foo + +1 +step select: SELECT * FROM foo; +ERROR: relation "foo" does not exist +step create: + BEGIN; + CREATE TABLE foo (i int); + COPY foo FROM '/tmp/createtableandcopy.spec.data'; + COMMIT; + +step roll: ROLLBACK; + +starting permutation: begin create select roll +step begin: + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); + +foo + +1 +step create: + BEGIN; + CREATE TABLE foo (i int); + COPY foo FROM '/tmp/createtableandcopy.spec.data'; + COMMIT; + +step select: SELECT * FROM foo; +ERROR: cannot access recently added or recently removed data in foo +step roll: ROLLBACK; + +starting permutation: create begin select roll +step create: + BEGIN; + CREATE TABLE foo (i int); + COPY foo FROM '/tmp/createtableandcopy.spec.data'; + COMMIT; + +step begin: + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); + +foo + +1 +step select: SELECT * FROM foo; +i + +1 +2 +3 +step roll: ROLLBACK; diff --git a/src/test/isolation/expected/createtableandinsert.out b/src/test/isolation/expected/createtableandinsert.out new file mode 100644 index 0000000..b709dee --- /dev/null +++ b/src/test/isolation/expected/createtableandinsert.out @@ -0,0 +1,79 @@ +Parsed test spec with 2 sessions + +starting permutation: begin select roll create +step begin: + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); + +foo + +1 +step select: SELECT * FROM foo; +ERROR: relation "foo" does not exist +step roll: ROLLBACK; +step create: + BEGIN; + CREATE TABLE foo (i int); + INSERT INTO foo VALUES (1); + COMMIT; + + +starting permutation: begin select create roll +step begin: + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); + +foo + +1 +step select: SELECT * FROM foo; +ERROR: relation "foo" does not exist +step create: + BEGIN; + CREATE TABLE foo (i int); + INSERT INTO foo VALUES (1); + COMMIT; + +step roll: ROLLBACK; + +starting permutation: begin create select roll +step begin: + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); + +foo + +1 +step create: + BEGIN; + CREATE TABLE foo (i int); + INSERT INTO foo VALUES (1); + COMMIT; + +step select: SELECT * FROM foo; +ERROR: cannot access recently added or recently removed data in foo +step roll: ROLLBACK; + +starting permutation: create begin select roll +step create: + BEGIN; + CREATE TABLE foo (i int); + INSERT INTO foo VALUES (1); + COMMIT; + +step begin: + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); + +foo + +1 +step select: SELECT * FROM foo; +i + +1 +step roll: ROLLBACK; diff --git a/src/test/isolation/expected/truncate.out b/src/test/isolation/expected/truncate.out new file mode 100644 index 0000000..29c20db --- /dev/null +++ b/src/test/isolation/expected/truncate.out @@ -0,0 +1,63 @@ +Parsed test spec with 2 sessions + +starting permutation: begin select roll trunc +step begin: + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); + +foo + +1 +step select: SELECT * FROM foo; +i + +1 +step roll: ROLLBACK; +step trunc: TRUNCATE TABLE foo; + +starting permutation: begin select trunc roll +step begin: + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); + +foo + +1 +step select: SELECT * FROM foo; +i + +1 +step trunc: TRUNCATE TABLE foo; <waiting ...> +step roll: ROLLBACK; +step trunc: <... completed> + +starting permutation: begin trunc select roll +step begin: + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); + +foo + +1 +step trunc: TRUNCATE TABLE foo; +step select: SELECT * FROM foo; +ERROR: cannot access recently added or recently removed data in foo +step roll: ROLLBACK; + +starting permutation: trunc begin select roll +step trunc: TRUNCATE TABLE foo; +step begin: + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); + +foo + +1 +step select: SELECT * FROM foo; +i + +step roll: ROLLBACK; diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule index 669c0f2..6515824 100644 --- a/src/test/isolation/isolation_schedule +++ b/src/test/isolation/isolation_schedule @@ -1,3 +1,6 @@ +test: truncate +test: createtableandinsert +test: createtableandcopy test: simple-write-skew test: receipt-report test: temporal-range-integrity diff --git a/src/test/isolation/specs/createtableandcopy.spec b/src/test/isolation/specs/createtableandcopy.spec new file mode 100644 index 0000000..84e3629 --- /dev/null +++ b/src/test/isolation/specs/createtableandcopy.spec @@ -0,0 +1,28 @@ +setup +{ + CREATE TABLE copydata AS SELECT generate_series(1,3)::integer AS a; + COPY copydata TO '/tmp/createtableandcopy.spec.data'; +} + +session "s1" +step "begin" +{ + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); +} +step "select" { SELECT * FROM foo; } +step "roll" { ROLLBACK; } + +session "s2" +step "create" { + BEGIN; + CREATE TABLE foo (i int); + COPY foo FROM '/tmp/createtableandcopy.spec.data'; + COMMIT; +} + +teardown +{ + DROP TABLE foo, copydata; +} diff --git a/src/test/isolation/specs/createtableandinsert.spec b/src/test/isolation/specs/createtableandinsert.spec new file mode 100644 index 0000000..9a152ab --- /dev/null +++ b/src/test/isolation/specs/createtableandinsert.spec @@ -0,0 +1,22 @@ +session "s1" +step "begin" +{ + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); +} +step "select" { SELECT * FROM foo; } +step "roll" { ROLLBACK; } + +session "s2" +step "create" { + BEGIN; + CREATE TABLE foo (i int); + INSERT INTO foo VALUES (1); + COMMIT; +} + +teardown +{ + DROP TABLE foo; +} diff --git a/src/test/isolation/specs/truncate.spec b/src/test/isolation/specs/truncate.spec new file mode 100644 index 0000000..2c7b707 --- /dev/null +++ b/src/test/isolation/specs/truncate.spec @@ -0,0 +1,23 @@ +setup +{ + CREATE TABLE foo (i int); + INSERT INTO foo VALUES (1); +} + +teardown +{ + DROP TABLE foo; +} + +session "s1" +step "begin" +{ + BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; + -- Force snapshot open + SELECT 1 AS foo FROM txid_current(); +} +step "select" { SELECT * FROM foo; } +step "roll" { ROLLBACK; } + +session "s2" +step "trunc" { TRUNCATE TABLE foo; }
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers