diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index b61fe41083fb523f032b55ba5344c66ad686f20c..c5a1b33a9e9796571d2c7e70ea6d128ef3b200da 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -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();
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index 3936260e6cfb0a90e56cb0d013cec8d3fd6ac943..14f101adb34d19a4e4685473d78130e33606258f 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -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);
 }
 
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 1107abdf27ac826a01a18ed8a7e8bc5db64f7c6d..d37dc5df84cce48a2cf0a6d596118b44b6b72163 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -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);
diff --git a/src/include/utils/snapmgr.h b/src/include/utils/snapmgr.h
index 8f3cc44c57b24c5541377c48d847df6a35294415..f4e55c9930f5c0a4318e8577c69d32cbb6f9da0b 100644
--- a/src/include/utils/snapmgr.h
+++ b/src/include/utils/snapmgr.h
@@ -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 */
diff --git a/src/test/regress/input/largeobject.source b/src/test/regress/input/largeobject.source
index 1d62caa3eaf0488028021a3cf5715ffa6f126d10..46ba9261ac5fe9426217da76d2b769103976e23b 100644
--- a/src/test/regress/input/largeobject.source
+++ b/src/test/regress/input/largeobject.source
@@ -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));
diff --git a/src/test/regress/output/largeobject.source b/src/test/regress/output/largeobject.source
index 36b51fdccddf548437a580591995d5a193236329..9d69f6c913e2ebd7bfade32b9546450280594eae 100644
--- a/src/test/regress/output/largeobject.source
+++ b/src/test/regress/output/largeobject.source
@@ -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));
diff --git a/src/test/regress/output/largeobject_1.source b/src/test/regress/output/largeobject_1.source
index f1157e45718890582013a5da5e44e52cfc00a70c..1fbc29c25171d6e2bc02b4d49012e990f1190a09 100644
--- a/src/test/regress/output/largeobject_1.source
+++ b/src/test/regress/output/largeobject_1.source
@@ -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));