Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1bf3d61

Browse files
committed
Fix subtransaction behavior for large objects, temp namespace, files,
password/group files. Also allow read-only subtransactions of a read-write parent, but not vice versa. These are the reasonably noncontroversial parts of Alvaro's recent mop-up patch, plus further work on large objects to minimize use of the TopTransactionResourceOwner.
1 parent cc813fc commit 1bf3d61

File tree

17 files changed

+572
-205
lines changed

17 files changed

+572
-205
lines changed

src/backend/access/transam/xact.c

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.172 2004/07/27 05:10:49 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.173 2004/07/28 14:23:27 tgl Exp $
1212
*
1313
* NOTES
1414
* Transaction aborts can now occur two ways:
@@ -224,6 +224,7 @@ typedef struct TransactionStateData
224224
ResourceOwner curTransactionOwner; /* my query resources */
225225
List *childXids; /* subcommitted child XIDs */
226226
AclId currentUser; /* subxact start current_user */
227+
bool prevXactReadOnly; /* entry-time xact r/o state */
227228
struct TransactionStateData *parent; /* back link to parent */
228229
} TransactionStateData;
229230

@@ -284,6 +285,7 @@ static TransactionStateData TopTransactionStateData = {
284285
NULL, /* cur transaction resource owner */
285286
NIL, /* subcommitted child Xids */
286287
0, /* entry-time current userid */
288+
false, /* entry-time xact r/o state */
287289
NULL /* link to parent state block */
288290
};
289291

@@ -1242,7 +1244,8 @@ StartTransaction(void)
12421244
* check the current transaction state
12431245
*/
12441246
if (s->state != TRANS_DEFAULT)
1245-
elog(WARNING, "StartTransaction and not in default state");
1247+
elog(WARNING, "StartTransaction while in %s state",
1248+
TransStateAsString(s->state));
12461249

12471250
/*
12481251
* set the current transaction state information appropriately during
@@ -1287,6 +1290,8 @@ StartTransaction(void)
12871290
* you won't because it doesn't work during startup; the userid isn't
12881291
* set yet during a backend's first transaction start. We only use
12891292
* the currentUser field in sub-transaction state structs.
1293+
*
1294+
* prevXactReadOnly is also valid only in sub-transactions.
12901295
*/
12911296

12921297
/*
@@ -1319,7 +1324,8 @@ CommitTransaction(void)
13191324
* check the current transaction state
13201325
*/
13211326
if (s->state != TRANS_INPROGRESS)
1322-
elog(WARNING, "CommitTransaction and not in in-progress state");
1327+
elog(WARNING, "CommitTransaction while in %s state",
1328+
TransStateAsString(s->state));
13231329
Assert(s->parent == NULL);
13241330

13251331
/*
@@ -1351,14 +1357,14 @@ CommitTransaction(void)
13511357

13521358
AtCommit_Portals();
13531359

1354-
/* handle commit for large objects [ PA, 7/17/98 ] */
1355-
/* XXX probably this does not belong here */
1356-
lo_commit(true);
1360+
/* close large objects before lower-level cleanup */
1361+
AtEOXact_LargeObject(true);
13571362

13581363
/* NOTIFY commit must come before lower-level cleanup */
13591364
AtCommit_Notify();
13601365

13611366
/* Update the flat password file if we changed pg_shadow or pg_group */
1367+
/* This should be the last step before commit */
13621368
AtEOXact_UpdatePasswordFile(true);
13631369

13641370
/*
@@ -1486,7 +1492,8 @@ AbortTransaction(void)
14861492
* check the current transaction state
14871493
*/
14881494
if (s->state != TRANS_INPROGRESS)
1489-
elog(WARNING, "AbortTransaction and not in in-progress state");
1495+
elog(WARNING, "AbortTransaction while in %s state",
1496+
TransStateAsString(s->state));
14901497
Assert(s->parent == NULL);
14911498

14921499
/*
@@ -1515,7 +1522,7 @@ AbortTransaction(void)
15151522
*/
15161523
DeferredTriggerAbortXact();
15171524
AtAbort_Portals();
1518-
lo_commit(false); /* 'false' means it's abort */
1525+
AtEOXact_LargeObject(false); /* 'false' means it's abort */
15191526
AtAbort_Notify();
15201527
AtEOXact_UpdatePasswordFile(false);
15211528

@@ -1870,6 +1877,9 @@ CleanupAbortedSubTransactions(bool returnName)
18701877
s = CurrentTransactionState;
18711878
}
18721879

1880+
AssertState(s->blockState == TBLOCK_SUBINPROGRESS ||
1881+
s->blockState == TBLOCK_INPROGRESS);
1882+
18731883
return name;
18741884
}
18751885

@@ -2866,7 +2876,8 @@ StartSubTransaction(void)
28662876
TransactionState s = CurrentTransactionState;
28672877

28682878
if (s->state != TRANS_DEFAULT)
2869-
elog(WARNING, "StartSubTransaction and not in default state");
2879+
elog(WARNING, "StartSubTransaction while in %s state",
2880+
TransStateAsString(s->state));
28702881

28712882
s->state = TRANS_START;
28722883

@@ -2889,6 +2900,7 @@ StartSubTransaction(void)
28892900
* Finish setup of other transaction state fields.
28902901
*/
28912902
s->currentUser = GetUserId();
2903+
s->prevXactReadOnly = XactReadOnly;
28922904

28932905
/*
28942906
* Initialize other subsystems for new subtransaction
@@ -2913,7 +2925,8 @@ CommitSubTransaction(void)
29132925
ShowTransactionState("CommitSubTransaction");
29142926

29152927
if (s->state != TRANS_INPROGRESS)
2916-
elog(WARNING, "CommitSubTransaction and not in in-progress state");
2928+
elog(WARNING, "CommitSubTransaction while in %s state",
2929+
TransStateAsString(s->state));
29172930

29182931
/* Pre-commit processing */
29192932
AtSubCommit_Portals(s->parent->transactionIdData,
@@ -2930,9 +2943,18 @@ CommitSubTransaction(void)
29302943
/* Post-commit cleanup */
29312944
AtSubCommit_smgr();
29322945

2933-
AtSubEOXact_Inval(true);
2946+
AtEOSubXact_Inval(true);
29342947
AtEOSubXact_SPI(true, s->transactionIdData);
29352948

2949+
AtEOSubXact_LargeObject(true, s->transactionIdData,
2950+
s->parent->transactionIdData);
2951+
AtEOSubXact_UpdatePasswordFile(true, s->transactionIdData,
2952+
s->parent->transactionIdData);
2953+
AtEOSubXact_Files(true, s->transactionIdData,
2954+
s->parent->transactionIdData);
2955+
AtEOSubXact_Namespace(true, s->transactionIdData,
2956+
s->parent->transactionIdData);
2957+
29362958
/*
29372959
* Note that we just release the resource owner's resources and don't
29382960
* delete it. This is because locks are not actually released here.
@@ -2953,6 +2975,13 @@ CommitSubTransaction(void)
29532975
AtEOSubXact_on_commit_actions(true, s->transactionIdData,
29542976
s->parent->transactionIdData);
29552977

2978+
/*
2979+
* We need to restore the upper transaction's read-only state,
2980+
* in case the upper is read-write while the child is read-only;
2981+
* GUC will incorrectly think it should leave the child state in place.
2982+
*/
2983+
XactReadOnly = s->prevXactReadOnly;
2984+
29562985
CurrentResourceOwner = s->parent->curTransactionOwner;
29572986
CurTransactionResourceOwner = s->parent->curTransactionOwner;
29582987
s->curTransactionOwner = NULL;
@@ -2973,7 +3002,8 @@ AbortSubTransaction(void)
29733002
ShowTransactionState("AbortSubTransaction");
29743003

29753004
if (s->state != TRANS_INPROGRESS)
2976-
elog(WARNING, "AbortSubTransaction and not in in-progress state");
3005+
elog(WARNING, "AbortSubTransaction while in %s state",
3006+
TransStateAsString(s->state));
29773007

29783008
HOLD_INTERRUPTS();
29793009

@@ -3010,7 +3040,16 @@ AbortSubTransaction(void)
30103040
AtEOSubXact_SPI(false, s->transactionIdData);
30113041
AtSubAbort_Portals(s->parent->transactionIdData,
30123042
s->parent->curTransactionOwner);
3013-
AtSubEOXact_Inval(false);
3043+
AtEOSubXact_Inval(false);
3044+
3045+
AtEOSubXact_LargeObject(false, s->transactionIdData,
3046+
s->parent->transactionIdData);
3047+
AtEOSubXact_UpdatePasswordFile(false, s->transactionIdData,
3048+
s->parent->transactionIdData);
3049+
AtEOSubXact_Files(false, s->transactionIdData,
3050+
s->parent->transactionIdData);
3051+
AtEOSubXact_Namespace(false, s->transactionIdData,
3052+
s->parent->transactionIdData);
30143053

30153054
ResourceOwnerRelease(s->curTransactionOwner,
30163055
RESOURCE_RELEASE_BEFORE_LOCKS,
@@ -3041,6 +3080,13 @@ AbortSubTransaction(void)
30413080
*/
30423081
SetUserId(s->currentUser);
30433082

3083+
/*
3084+
* Restore the upper transaction's read-only state, too. This should
3085+
* be redundant with GUC's cleanup but we may as well do it for
3086+
* consistency with the commit case.
3087+
*/
3088+
XactReadOnly = s->prevXactReadOnly;
3089+
30443090
CommandCounterIncrement();
30453091

30463092
RESUME_INTERRUPTS();
@@ -3057,7 +3103,8 @@ CleanupSubTransaction(void)
30573103
ShowTransactionState("CleanupSubTransaction");
30583104

30593105
if (s->state != TRANS_ABORT)
3060-
elog(WARNING, "CleanupSubTransaction and not in aborted state");
3106+
elog(WARNING, "CleanupSubTransaction while in %s state",
3107+
TransStateAsString(s->state));
30613108

30623109
AtSubCleanup_Portals();
30633110

@@ -3088,7 +3135,8 @@ StartAbortedSubTransaction(void)
30883135
TransactionState s = CurrentTransactionState;
30893136

30903137
if (s->state != TRANS_DEFAULT)
3091-
elog(WARNING, "StartAbortedSubTransaction and not in default state");
3138+
elog(WARNING, "StartAbortedSubTransaction while in %s state",
3139+
TransStateAsString(s->state));
30923140

30933141
s->state = TRANS_START;
30943142

@@ -3168,7 +3216,8 @@ PopTransaction(void)
31683216
TransactionState s = CurrentTransactionState;
31693217

31703218
if (s->state != TRANS_DEFAULT)
3171-
elog(WARNING, "PopTransaction and not in default state");
3219+
elog(WARNING, "PopTransaction while in %s state",
3220+
TransStateAsString(s->state));
31723221

31733222
if (s->parent == NULL)
31743223
elog(FATAL, "PopTransaction with no parent");

src/backend/catalog/namespace.c

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* Portions Copyright (c) 1994, Regents of the University of California
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.67 2004/06/18 06:13:19 tgl Exp $
16+
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.68 2004/07/28 14:23:27 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -107,12 +107,17 @@ static bool namespaceSearchPathValid = true;
107107
* myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
108108
* in a particular backend session (this happens when a CREATE TEMP TABLE
109109
* command is first executed). Thereafter it's the OID of the temp namespace.
110-
* firstTempTransaction flags whether we've committed creation of the TEMP
111-
* namespace or not.
110+
*
111+
* myTempNamespaceXID shows whether we've created the TEMP namespace in the
112+
* current transaction. The TransactionId propagates up the transaction tree,
113+
* so the main transaction will correctly recognize the flag if all
114+
* intermediate subtransactions commit. When it is InvalidTransactionId,
115+
* we either haven't made the TEMP namespace yet, or have successfully
116+
* committed its creation, depending on whether myTempNamespace is valid.
112117
*/
113118
static Oid myTempNamespace = InvalidOid;
114119

115-
static bool firstTempTransaction = false;
120+
static TransactionId myTempNamespaceXID = InvalidTransactionId;
116121

117122
/*
118123
* "Special" namespace for CREATE SCHEMA. If set, it's the first search
@@ -1688,7 +1693,9 @@ InitTempTableNamespace(void)
16881693
*/
16891694
myTempNamespace = namespaceId;
16901695

1691-
firstTempTransaction = true;
1696+
/* It should not be done already. */
1697+
AssertState(myTempNamespaceXID == InvalidTransactionId);
1698+
myTempNamespaceXID = GetCurrentTransactionId();
16921699

16931700
namespaceSearchPathValid = false; /* need to rebuild list */
16941701
}
@@ -1707,7 +1714,7 @@ AtEOXact_Namespace(bool isCommit)
17071714
* temp tables at backend shutdown. (We only want to register the
17081715
* callback once per session, so this is a good place to do it.)
17091716
*/
1710-
if (firstTempTransaction)
1717+
if (myTempNamespaceXID == GetCurrentTransactionId())
17111718
{
17121719
if (isCommit)
17131720
on_shmem_exit(RemoveTempRelationsCallback, 0);
@@ -1716,7 +1723,7 @@ AtEOXact_Namespace(bool isCommit)
17161723
myTempNamespace = InvalidOid;
17171724
namespaceSearchPathValid = false; /* need to rebuild list */
17181725
}
1719-
firstTempTransaction = false;
1726+
myTempNamespaceXID = InvalidTransactionId;
17201727
}
17211728

17221729
/*
@@ -1729,6 +1736,32 @@ AtEOXact_Namespace(bool isCommit)
17291736
}
17301737
}
17311738

1739+
/*
1740+
* AtEOSubXact_Namespace
1741+
*
1742+
* At subtransaction commit, propagate the temp-namespace-creation
1743+
* flag to the parent transaction.
1744+
*
1745+
* At subtransaction abort, forget the flag if we set it up.
1746+
*/
1747+
void
1748+
AtEOSubXact_Namespace(bool isCommit, TransactionId myXid,
1749+
TransactionId parentXid)
1750+
{
1751+
if (myTempNamespaceXID == myXid)
1752+
{
1753+
if (isCommit)
1754+
myTempNamespaceXID = parentXid;
1755+
else
1756+
{
1757+
myTempNamespaceXID = InvalidTransactionId;
1758+
/* TEMP namespace creation failed, so reset state */
1759+
myTempNamespace = InvalidOid;
1760+
namespaceSearchPathValid = false; /* need to rebuild list */
1761+
}
1762+
}
1763+
}
1764+
17321765
/*
17331766
* Remove all relations in the specified temp namespace.
17341767
*

0 commit comments

Comments
 (0)