}
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
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);
}
*/
if (IsXactIsoLevelSerializable)
{
- CurrentSnapshot = RegisterSnapshot(CurrentSnapshot);
+ CurrentSnapshot = RegisterSnapshotOnOwner(CurrentSnapshot,
+ TopTransactionResourceOwner);
registered_serializable = true;
}
/*
* 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;
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++;
*/
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;
Assert(snapshot->regd_count > 0);
Assert(RegisteredSnapshots > 0);
- ResourceOwnerForgetSnapshot(CurrentResourceOwner, snapshot);
+ ResourceOwnerForgetSnapshot(owner, snapshot);
RegisteredSnapshots--;
if (--snapshot->regd_count == 0 && snapshot->active_count == 0)
{
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
{
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);
#ifndef SNAPMGR_H
#define SNAPMGR_H
+#include "utils/resowner.h"
#include "utils/snapshot.h"
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 */