0001-Avoid-redundant-tuple-copy-while-sending-tuples-to-G.patch
text/x-patch
Filename: 0001-Avoid-redundant-tuple-copy-while-sending-tuples-to-G.patch
Type: text/x-patch
Part: 1
Patch
Format: format-patch
Series: patch 0001
Subject: Avoid redundant tuple copy while sending tuples to Gather
| File | + | − |
|---|---|---|
| src/backend/executor/execTuples.c | 59 | 0 |
| src/backend/executor/tqueue.c | 10 | 7 |
| src/include/executor/tuptable.h | 2 | 0 |
From 286310e6a52af7883d20899163aaa349b479d614 Mon Sep 17 00:00:00 2001
From: Amit Khandekar <amitdkhan.pg@gmail.com>
Date: Wed, 9 Sep 2020 11:52:59 +0800
Subject: [PATCH 1/2] Avoid redundant tuple copy while sending tuples to Gather
If the tuple to be sent is a heap tuple, get the pointer to the minimal
tuple data from the heap tuple, and use this as the source data for
shm_mq_send(). This allows us to prevent a tuple copy when the slot
is a heap tuple slot.
Device a new function ExecFetchSlotMinimalTupleData() that tries to
send an in-place minimal tuple data or returns a copy only if the
slot is something other than a heap tuple or minimal tuple slot.
This shows between 4 to 10% speed up for simple non-aggregate parallel
queries.
---
src/backend/executor/execTuples.c | 59 +++++++++++++++++++++++++++++++
src/backend/executor/tqueue.c | 17 +++++----
src/include/executor/tuptable.h | 2 ++
3 files changed, 71 insertions(+), 7 deletions(-)
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 4c90ac5236..55a6652b4e 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -1682,6 +1682,65 @@ ExecFetchSlotMinimalTuple(TupleTableSlot *slot,
}
}
+/* --------------------------------
+ * ExecFetchSlotMinimalTupleData
+ * Return minimal tuple data, or the data belonging to minimal tuple
+ * section if it's a heap tuple slot.
+ *
+ * This function is similar to ExecFetchSlotMinimalTuple(), but it goes a
+ * step further in trying to avoid redundant tuple copy. It does this by
+ * returning the in-place minimal tuple data region if it's a heap tuple.
+ * If the slot is neither a minimal tuple nor heap tuple slot, a minimal
+ * tuple copy is returned, and should_free is set to true. Callers can use
+ * this if they only want the underlying minimal tuple data.
+ * One use is where minimal tuple data is sent through the gather queues.
+ * The receiver end can then treat the data as a MinimalTupleData, but
+ * they should update it's t_len field, because the data might have
+ * originally belonged to a heap tuple rather than minimal tuple.
+ */
+char *
+ExecFetchSlotMinimalTupleData(TupleTableSlot *slot, uint32 *len,
+ bool *shouldFree)
+{
+ /*
+ * sanity checks
+ */
+ Assert(slot != NULL);
+ Assert(!TTS_EMPTY(slot));
+
+ if (slot->tts_ops->get_heap_tuple)
+ {
+ HeapTuple htuple;
+
+ if (shouldFree)
+ *shouldFree = false;
+ htuple = slot->tts_ops->get_heap_tuple(slot);
+ *len = htuple->t_len - MINIMAL_TUPLE_OFFSET;
+
+ return (char*) htuple->t_data + MINIMAL_TUPLE_OFFSET;
+ }
+ else
+ {
+ MinimalTuple mtuple;
+
+ if (slot->tts_ops->get_minimal_tuple)
+ {
+ if (shouldFree)
+ *shouldFree = false;
+ mtuple = slot->tts_ops->get_minimal_tuple(slot);
+ }
+ else
+ {
+ if (shouldFree)
+ *shouldFree = true;
+ mtuple = slot->tts_ops->copy_minimal_tuple(slot);
+ }
+ *len = mtuple->t_len;
+
+ return (char *) mtuple;
+ }
+}
+
/* --------------------------------
* ExecFetchSlotHeapTupleDatum
* Fetch the slot's tuple as a composite-type Datum.
diff --git a/src/backend/executor/tqueue.c b/src/backend/executor/tqueue.c
index 30a264ebea..c70ee0f39a 100644
--- a/src/backend/executor/tqueue.c
+++ b/src/backend/executor/tqueue.c
@@ -54,16 +54,17 @@ static bool
tqueueReceiveSlot(TupleTableSlot *slot, DestReceiver *self)
{
TQueueDestReceiver *tqueue = (TQueueDestReceiver *) self;
- MinimalTuple tuple;
+ char *minimal_tuple_data;
+ uint32 len;
shm_mq_result result;
bool should_free;
- /* Send the tuple itself. */
- tuple = ExecFetchSlotMinimalTuple(slot, &should_free);
- result = shm_mq_send(tqueue->queue, tuple->t_len, tuple, false);
+ /* Send the minimal tuple data. */
+ minimal_tuple_data = ExecFetchSlotMinimalTupleData(slot, &len, &should_free);
+ result = shm_mq_send(tqueue->queue, len, minimal_tuple_data, false);
if (should_free)
- pfree(tuple);
+ pfree(minimal_tuple_data);
/* Check for failure. */
if (result == SHM_MQ_DETACHED)
@@ -201,10 +202,12 @@ TupleQueueReaderNext(TupleQueueReader *reader, bool nowait, bool *done)
/*
* Return a pointer to the queue memory directly (which had better be
- * sufficiently aligned).
+ * sufficiently aligned). Also, the sender might not have updated the t_len
+ * if the data belonged to a heap tuple rather than a minimal tuple. So
+ * update it now.
*/
tuple = (MinimalTuple) data;
- Assert(tuple->t_len == nbytes);
+ tuple->t_len = nbytes;
return tuple;
}
diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h
index f7df70b5ab..da78929035 100644
--- a/src/include/executor/tuptable.h
+++ b/src/include/executor/tuptable.h
@@ -325,6 +325,8 @@ extern void ExecStoreHeapTupleDatum(Datum data, TupleTableSlot *slot);
extern HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree);
extern MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot,
bool *shouldFree);
+extern char *ExecFetchSlotMinimalTupleData(TupleTableSlot *slot, uint32 *len,
+ bool *shouldFree);
extern Datum ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot);
extern void slot_getmissingattrs(TupleTableSlot *slot, int startAttNum,
int lastAttNum);
--
2.17.1