summaryrefslogtreecommitdiff
path: root/src/backend/utils/sort
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2006-06-27 02:51:40 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2006-06-27 02:51:40 +0000
commit3f50ba27cf417eb57fd310c2a88f76a6ea6b966e (patch)
treee9dec4aaac793ed8efab65488e62532057f91704 /src/backend/utils/sort
parentfe491fb9afd07f3cc9b8aabb17f43049b79258a9 (diff)
downloadpostgresql-3f50ba27cf417eb57fd310c2a88f76a6ea6b966e.tar.gz
Create infrastructure for 'MinimalTuple' representation of in-memory
tuples with less header overhead than a regular HeapTuple, per my recent proposal. Teach TupleTableSlot code how to deal with these. As proof of concept, change tuplestore.c to store MinimalTuples instead of HeapTuples. Future patches will expand the concept to other places where it is useful.
Diffstat (limited to 'src/backend/utils/sort')
-rw-r--r--src/backend/utils/sort/tuplestore.c130
1 files changed, 104 insertions, 26 deletions
diff --git a/src/backend/utils/sort/tuplestore.c b/src/backend/utils/sort/tuplestore.c
index 6ff6b72082..a2ed330ccc 100644
--- a/src/backend/utils/sort/tuplestore.c
+++ b/src/backend/utils/sort/tuplestore.c
@@ -36,7 +36,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.27 2006/03/05 15:58:49 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.28 2006/06/27 02:51:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -195,6 +195,7 @@ struct Tuplestorestate
static Tuplestorestate *tuplestore_begin_common(bool randomAccess,
bool interXact,
int maxKBytes);
+static void tuplestore_puttuple_common(Tuplestorestate *state, void *tuple);
static void dumptuples(Tuplestorestate *state);
static unsigned int getlen(Tuplestorestate *state, bool eofOK);
static void *copytup_heap(Tuplestorestate *state, void *tup);
@@ -304,15 +305,45 @@ tuplestore_ateof(Tuplestorestate *state)
* If the read status is currently "AT EOF" then it remains so (the read
* pointer advances along with the write pointer); otherwise the read
* pointer is unchanged. This is for the convenience of nodeMaterial.c.
+ *
+ * tuplestore_puttupleslot() is a convenience routine to collect data from
+ * a TupleTableSlot without an extra copy operation.
*/
void
-tuplestore_puttuple(Tuplestorestate *state, void *tuple)
+tuplestore_puttupleslot(Tuplestorestate *state,
+ TupleTableSlot *slot)
+{
+ MinimalTuple tuple;
+
+ /*
+ * Form a MinimalTuple in working memory
+ */
+ tuple = ExecCopySlotMinimalTuple(slot);
+ USEMEM(state, GetMemoryChunkSpace(tuple));
+
+ tuplestore_puttuple_common(state, (void *) tuple);
+}
+
+/*
+ * "Standard" case to copy from a HeapTuple. This is actually now somewhat
+ * deprecated, but not worth getting rid of in view of the number of callers.
+ * (Consider adding something that takes a tupdesc+values/nulls arrays so
+ * that we can use heap_form_minimal_tuple() and avoid a copy step.)
+ */
+void
+tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
{
/*
* Copy the tuple. (Must do this even in WRITEFILE case.)
*/
tuple = COPYTUP(state, tuple);
+ tuplestore_puttuple_common(state, (void *) tuple);
+}
+
+static void
+tuplestore_puttuple_common(Tuplestorestate *state, void *tuple)
+{
switch (state->status)
{
case TSS_INMEM:
@@ -389,7 +420,7 @@ tuplestore_puttuple(Tuplestorestate *state, void *tuple)
* Returns NULL if no more tuples. If should_free is set, the
* caller must pfree the returned tuple when done with it.
*/
-void *
+static void *
tuplestore_gettuple(Tuplestorestate *state, bool forward,
bool *should_free)
{
@@ -526,6 +557,59 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
}
/*
+ * tuplestore_gettupleslot - exported function to fetch a MinimalTuple
+ *
+ * If successful, put tuple in slot and return TRUE; else, clear the slot
+ * and return FALSE.
+ */
+bool
+tuplestore_gettupleslot(Tuplestorestate *state, bool forward,
+ TupleTableSlot *slot)
+{
+ MinimalTuple tuple;
+ bool should_free;
+
+ tuple = (MinimalTuple) tuplestore_gettuple(state, forward, &should_free);
+
+ if (tuple)
+ {
+ ExecStoreMinimalTuple(tuple, slot, should_free);
+ return true;
+ }
+ else
+ {
+ ExecClearTuple(slot);
+ return false;
+ }
+}
+
+/*
+ * tuplestore_advance - exported function to adjust position without fetching
+ *
+ * We could optimize this case to avoid palloc/pfree overhead, but for the
+ * moment it doesn't seem worthwhile.
+ */
+bool
+tuplestore_advance(Tuplestorestate *state, bool forward)
+{
+ void *tuple;
+ bool should_free;
+
+ tuple = tuplestore_gettuple(state, forward, &should_free);
+
+ if (tuple)
+ {
+ if (should_free)
+ pfree(tuple);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+/*
* dumptuples - remove tuples from memory and write to tape
*
* As a side effect, we must set readpos and markpos to the value
@@ -672,34 +756,31 @@ getlen(Tuplestorestate *state, bool eofOK)
/*
* Routines specialized for HeapTuple case
+ *
+ * The stored form is actually a MinimalTuple, but for largely historical
+ * reasons we allow COPYTUP to work from a HeapTuple.
+ *
+ * Since MinimalTuple already has length in its first word, we don't need
+ * to write that separately.
*/
static void *
copytup_heap(Tuplestorestate *state, void *tup)
{
- HeapTuple tuple = (HeapTuple) tup;
+ MinimalTuple tuple;
- tuple = heap_copytuple(tuple);
+ tuple = minimal_tuple_from_heap_tuple((HeapTuple) tup);
USEMEM(state, GetMemoryChunkSpace(tuple));
return (void *) tuple;
}
-/*
- * We don't bother to write the HeapTupleData part of the tuple.
- */
-
static void
writetup_heap(Tuplestorestate *state, void *tup)
{
- HeapTuple tuple = (HeapTuple) tup;
- unsigned int tuplen;
+ MinimalTuple tuple = (MinimalTuple) tup;
+ unsigned int tuplen = tuple->t_len;
- tuplen = tuple->t_len + sizeof(tuplen);
- if (BufFileWrite(state->myfile, (void *) &tuplen,
- sizeof(tuplen)) != sizeof(tuplen))
- elog(ERROR, "write failed");
- if (BufFileWrite(state->myfile, (void *) tuple->t_data,
- tuple->t_len) != (size_t) tuple->t_len)
+ if (BufFileWrite(state->myfile, (void *) tuple, tuplen) != (size_t) tuplen)
elog(ERROR, "write failed");
if (state->randomAccess) /* need trailing length word? */
if (BufFileWrite(state->myfile, (void *) &tuplen,
@@ -707,23 +788,20 @@ writetup_heap(Tuplestorestate *state, void *tup)
elog(ERROR, "write failed");
FREEMEM(state, GetMemoryChunkSpace(tuple));
- heap_freetuple(tuple);
+ heap_free_minimal_tuple(tuple);
}
static void *
readtup_heap(Tuplestorestate *state, unsigned int len)
{
- unsigned int tuplen = len - sizeof(unsigned int) + HEAPTUPLESIZE;
- HeapTuple tuple = (HeapTuple) palloc(tuplen);
+ MinimalTuple tuple = (MinimalTuple) palloc(len);
+ unsigned int tuplen;
USEMEM(state, GetMemoryChunkSpace(tuple));
- /* reconstruct the HeapTupleData portion */
- tuple->t_len = len - sizeof(unsigned int);
- ItemPointerSetInvalid(&(tuple->t_self));
- tuple->t_data = (HeapTupleHeader) (((char *) tuple) + HEAPTUPLESIZE);
/* read in the tuple proper */
- if (BufFileRead(state->myfile, (void *) tuple->t_data,
- tuple->t_len) != (size_t) tuple->t_len)
+ tuple->t_len = len;
+ if (BufFileRead(state->myfile, (void *) ((char *) tuple + sizeof(int)),
+ len - sizeof(int)) != (size_t) (len - sizeof(int)))
elog(ERROR, "unexpected end of data");
if (state->randomAccess) /* need trailing length word? */
if (BufFileRead(state->myfile, (void *) &tuplen,