Fix a couple of snapshot management bugs in the new ResourceOwner world:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 4 Dec 2008 14:51:02 +0000 (14:51 +0000)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 4 Dec 2008 14:51:02 +0000 (14:51 +0000)
non-writable large objects need to have their snapshots registered on the
transaction resowner, not the current portal's, because it must persist until
the large object is closed (which the portal does not).  Also, ensure that the
serializable snapshot is recorded by the transaction resource owner too, even
when a subtransaction has changed the current resource owner before
serializable is taken.

Per bug reports from Pavan Deolasee.

src/backend/access/transam/xact.c
src/backend/storage/large_object/inv_api.c
src/backend/utils/time/snapmgr.c
src/include/utils/snapmgr.h
src/test/regress/input/largeobject.source
src/test/regress/output/largeobject.source
src/test/regress/output/largeobject_1.source

index b61fe41083fb523f032b55ba5344c66ad686f20c..c5a1b33a9e9796571d2c7e70ea6d128ef3b200da 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.269 2008/11/19 10:34:50 heikki Exp $
+ *   $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.270 2008/12/04 14:51:02 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1667,6 +1667,9 @@ CommitTransaction(void)
    /* Clean up the relation cache */
    AtEOXact_RelationCache(true);
 
+   /* Clean up the snapshot manager */
+   AtEarlyCommit_Snapshot();
+
    /*
     * Make catalog changes visible to all backends.  This has to happen after
     * relcache references are dropped (see comments for
@@ -1906,6 +1909,9 @@ PrepareTransaction(void)
    /* Clean up the relation cache */
    AtEOXact_RelationCache(true);
 
+   /* Clean up the snapshot manager */
+   AtEarlyCommit_Snapshot();
+
    /* notify and flatfiles don't need a postprepare call */
 
    PostPrepare_PgStat();
index 3936260e6cfb0a90e56cb0d013cec8d3fd6ac943..14f101adb34d19a4e4685473d78130e33606258f 100644 (file)
@@ -24,7 +24,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.135 2008/11/02 01:45:28 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.136 2008/12/04 14:51:02 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -247,7 +247,13 @@ inv_open(Oid lobjId, int flags, MemoryContext mcxt)
    }
    else if (flags & INV_READ)
    {
-       retval->snapshot = RegisterSnapshot(GetActiveSnapshot());
+       /*
+        * We must register the snapshot in TopTransaction's resowner,
+        * because it must stay alive until the LO is closed rather than until
+        * the current portal shuts down.
+        */
+       retval->snapshot = RegisterSnapshotOnOwner(GetActiveSnapshot(),
+                                                  TopTransactionResourceOwner);
        retval->flags = IFS_RDLOCK;
    }
    else
@@ -270,8 +276,11 @@ void
 inv_close(LargeObjectDesc *obj_desc)
 {
    Assert(PointerIsValid(obj_desc));
+
    if (obj_desc->snapshot != SnapshotNow)
-       UnregisterSnapshot(obj_desc->snapshot);
+       UnregisterSnapshotFromOwner(obj_desc->snapshot,
+                                   TopTransactionResourceOwner);
+
    pfree(obj_desc);
 }
 
index 1107abdf27ac826a01a18ed8a7e8bc5db64f7c6d..d37dc5df84cce48a2cf0a6d596118b44b6b72163 100644 (file)
@@ -19,7 +19,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.7 2008/11/25 20:28:29 alvherre Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.8 2008/12/04 14:51:02 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -136,7 +136,8 @@ GetTransactionSnapshot(void)
         */
        if (IsXactIsoLevelSerializable)
        {
-           CurrentSnapshot = RegisterSnapshot(CurrentSnapshot);
+           CurrentSnapshot = RegisterSnapshotOnOwner(CurrentSnapshot,
+                                                     TopTransactionResourceOwner);
            registered_serializable = true;
        }
 
@@ -345,14 +346,27 @@ ActiveSnapshotSet(void)
 
 /*
  * RegisterSnapshot
- *         Register a snapshot as being in use
+ *         Register a snapshot as being in use by the current resource owner
  *
  * If InvalidSnapshot is passed, it is not registered.
  */
 Snapshot
 RegisterSnapshot(Snapshot snapshot)
 {
-   Snapshot    snap;
+   if (snapshot == InvalidSnapshot)
+       return InvalidSnapshot;
+
+   return RegisterSnapshotOnOwner(snapshot, CurrentResourceOwner);
+}
+
+/*
+ * RegisterSnapshotOnOwner
+ *         As above, but use the specified resource owner
+ */
+Snapshot
+RegisterSnapshotOnOwner(Snapshot snapshot, ResourceOwner owner)
+{
+   Snapshot        snap;
 
    if (snapshot == InvalidSnapshot)
        return InvalidSnapshot;
@@ -361,9 +375,9 @@ RegisterSnapshot(Snapshot snapshot)
    snap = snapshot->copied ? snapshot : CopySnapshot(snapshot);
 
    /* and tell resowner.c about it */
-   ResourceOwnerEnlargeSnapshots(CurrentResourceOwner);
+   ResourceOwnerEnlargeSnapshots(owner);
    snap->regd_count++;
-   ResourceOwnerRememberSnapshot(CurrentResourceOwner, snap);
+   ResourceOwnerRememberSnapshot(owner, snap);
 
    RegisteredSnapshots++;
 
@@ -379,6 +393,19 @@ RegisterSnapshot(Snapshot snapshot)
  */
 void
 UnregisterSnapshot(Snapshot snapshot)
+{
+   if (snapshot == NULL)
+       return;
+
+   UnregisterSnapshotFromOwner(snapshot, CurrentResourceOwner);
+}
+
+/*
+ * UnregisterSnapshotFromOwner
+ *         As above, but use the specified resource owner
+ */
+void
+UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
 {
    if (snapshot == NULL)
        return;
@@ -386,7 +413,7 @@ UnregisterSnapshot(Snapshot snapshot)
    Assert(snapshot->regd_count > 0);
    Assert(RegisteredSnapshots > 0);
 
-   ResourceOwnerForgetSnapshot(CurrentResourceOwner, snapshot);
+   ResourceOwnerForgetSnapshot(owner, snapshot);
    RegisteredSnapshots--;
    if (--snapshot->regd_count == 0 && snapshot->active_count == 0)
    {
@@ -463,6 +490,26 @@ AtSubAbort_Snapshot(int level)
    SnapshotResetXmin();
 }
 
+/*
+ * AtEarlyCommit_Snapshot
+ *
+ * Snapshot manager's cleanup function, to be called on commit, before
+ * doing resowner.c resource release.
+ */
+void
+AtEarlyCommit_Snapshot(void)
+{
+   /*
+    * On a serializable transaction we must unregister our private refcount to
+    * the serializable snapshot.
+    */
+   if (registered_serializable)
+       UnregisterSnapshotFromOwner(CurrentSnapshot,
+                                   TopTransactionResourceOwner);
+   registered_serializable = false;
+
+}
+
 /*
  * AtEOXact_Snapshot
  *         Snapshot manager's cleanup function for end of transaction
@@ -475,13 +522,6 @@ AtEOXact_Snapshot(bool isCommit)
    {
        ActiveSnapshotElt   *active;
 
-       /*
-        * On a serializable snapshot we must first unregister our private
-        * refcount to the serializable snapshot.
-        */
-       if (registered_serializable)
-           UnregisterSnapshot(CurrentSnapshot);
-
        if (RegisteredSnapshots != 0)
            elog(WARNING, "%d registered snapshots seem to remain after cleanup",
                 RegisteredSnapshots);
index 8f3cc44c57b24c5541377c48d847df6a35294415..f4e55c9930f5c0a4318e8577c69d32cbb6f9da0b 100644 (file)
@@ -6,13 +6,14 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/snapmgr.h,v 1.2 2008/05/12 20:02:02 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/utils/snapmgr.h,v 1.3 2008/12/04 14:51:02 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef SNAPMGR_H
 #define SNAPMGR_H
 
+#include "utils/resowner.h"
 #include "utils/snapshot.h"
 
 
@@ -34,9 +35,12 @@ extern bool ActiveSnapshotSet(void);
 
 extern Snapshot RegisterSnapshot(Snapshot snapshot);
 extern void UnregisterSnapshot(Snapshot snapshot);
+extern Snapshot RegisterSnapshotOnOwner(Snapshot snapshot, ResourceOwner owner);
+extern void UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner);
 
 extern void AtSubCommit_Snapshot(int level);
 extern void AtSubAbort_Snapshot(int level);
+extern void AtEarlyCommit_Snapshot(void);
 extern void AtEOXact_Snapshot(bool isCommit);
 
 #endif /* SNAPMGR_H */
index 1d62caa3eaf0488028021a3cf5715ffa6f126d10..46ba9261ac5fe9426217da76d2b769103976e23b 100644 (file)
@@ -83,6 +83,11 @@ SELECT lo_close(fd) FROM lotest_stash_values;
 
 END;
 
+-- Test resource management
+BEGIN;
+SELECT lo_open(loid, x'40000'::int) from lotest_stash_values;
+ABORT;
+
 -- Test truncation.
 BEGIN;
 UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer));
index 36b51fdccddf548437a580591995d5a193236329..9d69f6c913e2ebd7bfade32b9546450280594eae 100644 (file)
@@ -116,6 +116,15 @@ SELECT lo_close(fd) FROM lotest_stash_values;
 (1 row)
 
 END;
+-- Test resource management
+BEGIN;
+SELECT lo_open(loid, x'40000'::int) from lotest_stash_values;
+ lo_open 
+---------
+       0
+(1 row)
+
+ABORT;
 -- Test truncation.
 BEGIN;
 UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer));
index f1157e45718890582013a5da5e44e52cfc00a70c..1fbc29c25171d6e2bc02b4d49012e990f1190a09 100644 (file)
@@ -116,6 +116,15 @@ SELECT lo_close(fd) FROM lotest_stash_values;
 (1 row)
 
 END;
+-- Test resource management
+BEGIN;
+SELECT lo_open(loid, x'40000'::int) from lotest_stash_values;
+ lo_open 
+---------
+       0
+(1 row)
+
+ABORT;
 -- Test truncation.
 BEGIN;
 UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer));