diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2006-06-27 02:51:40 +0000 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2006-06-27 02:51:40 +0000 |
| commit | 3f50ba27cf417eb57fd310c2a88f76a6ea6b966e (patch) | |
| tree | e9dec4aaac793ed8efab65488e62532057f91704 /src/backend/utils/sort | |
| parent | fe491fb9afd07f3cc9b8aabb17f43049b79258a9 (diff) | |
| download | postgresql-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.c | 130 |
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, |
