mirror of
https://github.com/postgres/postgres.git
synced 2025-09-09 13:09:39 +03:00
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.
This commit is contained in:
@@ -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)
|
||||
{
|
||||
@@ -525,6 +556,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
|
||||
*
|
||||
@@ -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,
|
||||
|
Reference in New Issue
Block a user