0001-Improve-lazy-tuple-slot-v2.patch
application/octet-stream
Filename: 0001-Improve-lazy-tuple-slot-v2.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v2-0001
Subject: Improve lazy tuple slot
| File | + | − |
|---|---|---|
| src/backend/access/heap/heapam_handler.c | 2 | 2 |
| src/backend/executor/nodeModifyTable.c | 2 | 2 |
| src/include/executor/tuptable.h | 41 | 16 |
From 185a6c8ee89aecb49b61b35da3c3c5562a558bd8 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Mon, 27 Mar 2023 15:05:25 +0300
Subject: [PATCH 1/2] Improve lazy tuple slot
This commit implements two improvements to lazy tuple slot implementation.
* Replace macros with inline function to prevent multiple evaluation of the
argument.
* Introdue a new lazy tuple slot constructor on the base of existing normal
slot, not a callback.
Reported-by: Andres Freund
Discussion: https://postgr.es/m/20230323003003.plgaxjqahjgkuxrk%40awork3.anarazel.de
---
src/backend/access/heap/heapam_handler.c | 4 +-
src/backend/executor/nodeModifyTable.c | 4 +-
src/include/executor/tuptable.h | 57 +++++++++++++++++-------
3 files changed, 45 insertions(+), 20 deletions(-)
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 9e690074e94..2bddf562c2f 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -330,7 +330,7 @@ heapam_tuple_delete(Relation relation, ItemPointer tid, CommandId cid,
Assert(wait);
- evalSlot = LAZY_TTS_EVAL(lockedSlot);
+ evalSlot = LazyTupleTableSlotEval(lockedSlot);
result = heapam_tuple_lock_internal(relation, tid, snapshot,
evalSlot, cid, LockTupleExclusive,
LockWaitBlock,
@@ -403,7 +403,7 @@ heapam_tuple_update(Relation relation, ItemPointer otid, TupleTableSlot *slot,
Assert(wait);
- evalSlot = LAZY_TTS_EVAL(lockedSlot);
+ evalSlot = LazyTupleTableSlotEval(lockedSlot);
result = heapam_tuple_lock_internal(relation, otid, snapshot,
evalSlot, cid, *lockmode,
LockWaitBlock,
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index e3503756818..2f6c97a8404 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1365,7 +1365,7 @@ ExecDeleteAct(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
if (lockUpdated)
{
- MAKE_LAZY_TTS(&lazyEPQSlot, GetEPQSlot, &slotArg);
+ MakeLazyTupleTableSlotWithCallback(&lazyEPQSlot, GetEPQSlot, &slotArg);
lazyEPQSlotPtr = &lazyEPQSlot;
}
else
@@ -2101,7 +2101,7 @@ lreplace:
*/
if (lockUpdated)
{
- MAKE_LAZY_TTS(&lazyEPQSlot, GetEPQSlot, &slotArg);
+ MakeLazyTupleTableSlotWithCallback(&lazyEPQSlot, GetEPQSlot, &slotArg);
lazyEPQSlotPtr = &lazyEPQSlot;
}
else
diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h
index c61734a15d4..30729f7a076 100644
--- a/src/include/executor/tuptable.h
+++ b/src/include/executor/tuptable.h
@@ -307,9 +307,11 @@ typedef struct MinimalTupleTableSlot
* likely will reain undemanded. Preallocating such slot would be a waste of
* resources in the majority of cases. Lazy slot is aimed to resolve this
* problem. It is basically a promise to allocate the slot once it's needed.
- * Once callee needs the slot, it could get it using LAZY_TTS_EVAL(lazySlot)
- * macro.
+ * Once callee needs the slot, it could get it using
+ * LazyTupleTableSlotEval(lazySlot) function.
*/
+typedef TupleTableSlot *(*LazyTupleTableSlotCallback) (void *arg);
+
typedef struct
{
TupleTableSlot *slot; /* cached slot or NULL if not yet allocated */
@@ -318,25 +320,48 @@ typedef struct
} LazyTupleTableSlot;
/*
- * A constructor for the lazy slot.
+ * Initialize LazyTupleTableSlot with callback and argument.
+ */
+static inline void
+MakeLazyTupleTableSlotWithCallback(LazyTupleTableSlot *lazySlot,
+ LazyTupleTableSlotCallback callback,
+ void *arg)
+{
+ lazySlot->slot = NULL;
+ lazySlot->getSlot = callback;
+ lazySlot->getSlotArg = arg;
+}
+
+/*
+ * Initialize LazyTupleTableSlot with existing slot.
*/
-#define MAKE_LAZY_TTS(lazySlot, callback, arg) \
- do { \
- (lazySlot)->slot = NULL; \
- (lazySlot)->getSlot = callback; \
- (lazySlot)->getSlotArg = arg; \
- } while (false)
+static inline void
+MakeLazyTupleTableSlotWithSlot(LazyTupleTableSlot *lazySlot,
+ TupleTableSlot *slot)
+{
+ lazySlot->slot = slot;
+ lazySlot->getSlot = NULL;
+ lazySlot->getSlotArg = NULL;
+}
/*
- * Macro for lazy slot evaluation. NULL lazy slot evaluates to NULL slot.
+ * Function for lazy slot evaluation. NULL lazy slot evaluates to NULL slot.
* Cached version is used if present. Use the callback otherwise.
*/
-#define LAZY_TTS_EVAL(lazySlot) \
- ((lazySlot) ? \
- ((lazySlot)->slot ? \
- (lazySlot)->slot : \
- ((lazySlot)->slot = (lazySlot)->getSlot((lazySlot)->getSlotArg))) : \
- NULL)
+static inline TupleTableSlot *
+LazyTupleTableSlotEval(LazyTupleTableSlot *lazySlot)
+{
+ if (!lazySlot)
+ return NULL;
+
+ if (!lazySlot->slot)
+ {
+ Assert(lazySlot->getSlot);
+ lazySlot->slot = lazySlot->getSlot(lazySlot->getSlotArg);
+ }
+ Assert(lazySlot->slot);
+ return lazySlot->slot;
+}
/* in executor/execTuples.c */
extern TupleTableSlot *MakeTupleTableSlot(TupleDesc tupleDesc,
--
2.37.1 (Apple Git-137.1)