#include "postgres.h"#include "access/htup_details.h"#include "commands/tablespace.h"#include "executor/executor.h"#include "storage/buffile.h"#include "utils/memutils.h"#include "utils/resowner.h"
Go to the source code of this file.
Definition at line 179 of file tuplestore.c.
Referenced by tuplestore_puttuple().
Definition at line 184 of file tuplestore.c.
Referenced by grow_memtuples(), tuplestore_clear(), tuplestore_trim(), and writetup_heap().
Definition at line 182 of file tuplestore.c.
Referenced by grow_memtuples(), and tuplestore_puttuple_common().
Definition at line 181 of file tuplestore.c.
Referenced by tuplestore_gettuple().
Definition at line 183 of file tuplestore.c.
Referenced by copytup_heap(), grow_memtuples(), readtup_heap(), tuplestore_begin_common(), tuplestore_puttupleslot(), and tuplestore_putvalues().
Definition at line 180 of file tuplestore.c.
Referenced by dumptuples(), and tuplestore_puttuple_common().
| enum TupStoreStatus |
Definition at line 69 of file tuplestore.c.
{
TSS_INMEM, /* Tuples still fit in memory */
TSS_WRITEFILE, /* Writing to temp file */
TSS_READFILE /* Reading from temp file */
} TupStoreStatus;
| static void * copytup_heap | ( | Tuplestorestate * | state, | |
| void * | tup | |||
| ) | [static] |
Definition at line 1371 of file tuplestore.c.
References GetMemoryChunkSpace(), minimal_tuple_from_heap_tuple(), and USEMEM.
{
MinimalTuple tuple;
tuple = minimal_tuple_from_heap_tuple((HeapTuple) tup);
USEMEM(state, GetMemoryChunkSpace(tuple));
return (void *) tuple;
}
| static void dumptuples | ( | Tuplestorestate * | state | ) | [static] |
Definition at line 1090 of file tuplestore.c.
References BufFileTell(), TSReadPointer::current, TSReadPointer::eof_reached, TSReadPointer::file, i, Tuplestorestate::memtupcount, Tuplestorestate::memtupdeleted, Tuplestorestate::memtuples, Tuplestorestate::myfile, TSReadPointer::offset, Tuplestorestate::readptrcount, Tuplestorestate::readptrs, and WRITETUP.
Referenced by tuplestore_puttuple_common().
{
int i;
for (i = state->memtupdeleted;; i++)
{
TSReadPointer *readptr = state->readptrs;
int j;
for (j = 0; j < state->readptrcount; readptr++, j++)
{
if (i == readptr->current && !readptr->eof_reached)
BufFileTell(state->myfile,
&readptr->file, &readptr->offset);
}
if (i >= state->memtupcount)
break;
WRITETUP(state, state->memtuples[i]);
}
state->memtupdeleted = 0;
state->memtupcount = 0;
}
| static unsigned int getlen | ( | Tuplestorestate * | state, | |
| bool | eofOK | |||
| ) | [static] |
Definition at line 1344 of file tuplestore.c.
References BufFileRead(), elog, ERROR, and Tuplestorestate::myfile.
Referenced by tuplestore_gettuple().
| static bool grow_memtuples | ( | Tuplestorestate * | state | ) | [static] |
Definition at line 548 of file tuplestore.c.
References Tuplestorestate::allowedMem, Tuplestorestate::availMem, elog, ERROR, FREEMEM, GetMemoryChunkSpace(), Tuplestorestate::growmemtuples, LACKMEM, MaxAllocSize, Tuplestorestate::memtuples, Tuplestorestate::memtupsize, repalloc(), and USEMEM.
Referenced by tuplestore_puttuple_common().
{
int newmemtupsize;
int memtupsize = state->memtupsize;
long memNowUsed = state->allowedMem - state->availMem;
/* Forget it if we've already maxed out memtuples, per comment above */
if (!state->growmemtuples)
return false;
/* Select new value of memtupsize */
if (memNowUsed <= state->availMem)
{
/*
* It is surely safe to double memtupsize if we've used no more than
* half of allowedMem.
*
* Note: it might seem that we need to worry about memtupsize * 2
* overflowing an int, but the MaxAllocSize clamp applied below
* ensures the existing memtupsize can't be large enough for that.
*/
newmemtupsize = memtupsize * 2;
}
else
{
/*
* This will be the last increment of memtupsize. Abandon doubling
* strategy and instead increase as much as we safely can.
*
* To stay within allowedMem, we can't increase memtupsize by more
* than availMem / sizeof(void *) elements. In practice, we want
* to increase it by considerably less, because we need to leave some
* space for the tuples to which the new array slots will refer. We
* assume the new tuples will be about the same size as the tuples
* we've already seen, and thus we can extrapolate from the space
* consumption so far to estimate an appropriate new size for the
* memtuples array. The optimal value might be higher or lower than
* this estimate, but it's hard to know that in advance.
*
* This calculation is safe against enlarging the array so much that
* LACKMEM becomes true, because the memory currently used includes
* the present array; thus, there would be enough allowedMem for the
* new array elements even if no other memory were currently used.
*
* We do the arithmetic in float8, because otherwise the product of
* memtupsize and allowedMem could overflow. (A little algebra shows
* that grow_ratio must be less than 2 here, so we are not risking
* integer overflow this way.) Any inaccuracy in the result should be
* insignificant; but even if we computed a completely insane result,
* the checks below will prevent anything really bad from happening.
*/
double grow_ratio;
grow_ratio = (double) state->allowedMem / (double) memNowUsed;
newmemtupsize = (int) (memtupsize * grow_ratio);
/* We won't make any further enlargement attempts */
state->growmemtuples = false;
}
/* Must enlarge array by at least one element, else report failure */
if (newmemtupsize <= memtupsize)
goto noalloc;
/*
* On a 64-bit machine, allowedMem could be more than MaxAllocSize. Clamp
* to ensure our request won't be rejected by palloc.
*/
if ((Size) newmemtupsize >= MaxAllocSize / sizeof(void *))
{
newmemtupsize = (int) (MaxAllocSize / sizeof(void *));
state->growmemtuples = false; /* can't grow any more */
}
/*
* We need to be sure that we do not cause LACKMEM to become true, else
* the space management algorithm will go nuts. The code above should
* never generate a dangerous request, but to be safe, check explicitly
* that the array growth fits within availMem. (We could still cause
* LACKMEM if the memory chunk overhead associated with the memtuples
* array were to increase. That shouldn't happen with any sane value of
* allowedMem, because at any array size large enough to risk LACKMEM,
* palloc would be treating both old and new arrays as separate chunks.
* But we'll check LACKMEM explicitly below just in case.)
*/
if (state->availMem < (long) ((newmemtupsize - memtupsize) * sizeof(void *)))
goto noalloc;
/* OK, do it */
FREEMEM(state, GetMemoryChunkSpace(state->memtuples));
state->memtupsize = newmemtupsize;
state->memtuples = (void **)
repalloc(state->memtuples,
state->memtupsize * sizeof(void *));
USEMEM(state, GetMemoryChunkSpace(state->memtuples));
if (LACKMEM(state))
elog(ERROR, "unexpected out-of-memory situation during sort");
return true;
noalloc:
/* If for any reason we didn't realloc, shut off future attempts */
state->growmemtuples = false;
return false;
}
| static void * readtup_heap | ( | Tuplestorestate * | state, | |
| unsigned int | len | |||
| ) | [static] |
Definition at line 1408 of file tuplestore.c.
References Tuplestorestate::backward, BufFileRead(), elog, ERROR, GetMemoryChunkSpace(), Tuplestorestate::myfile, palloc(), MinimalTupleData::t_len, and USEMEM.
{
unsigned int tupbodylen = len - sizeof(int);
unsigned int tuplen = tupbodylen + MINIMAL_TUPLE_DATA_OFFSET;
MinimalTuple tuple = (MinimalTuple) palloc(tuplen);
char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
USEMEM(state, GetMemoryChunkSpace(tuple));
/* read in the tuple proper */
tuple->t_len = tuplen;
if (BufFileRead(state->myfile, (void *) tupbody,
tupbodylen) != (size_t) tupbodylen)
elog(ERROR, "unexpected end of data");
if (state->backward) /* need trailing length word? */
if (BufFileRead(state->myfile, (void *) &tuplen,
sizeof(tuplen)) != sizeof(tuplen))
elog(ERROR, "unexpected end of data");
return (void *) tuple;
}
| bool tuplestore_advance | ( | Tuplestorestate * | state, | |
| bool | forward | |||
| ) |
Definition at line 1063 of file tuplestore.c.
References pfree(), and tuplestore_gettuple().
Referenced by CteScanNext(), ExecMaterial(), PersistHoldablePortal(), window_gettupleslot(), and WinSetMarkPosition().
{
void *tuple;
bool should_free;
tuple = tuplestore_gettuple(state, forward, &should_free);
if (tuple)
{
if (should_free)
pfree(tuple);
return true;
}
else
{
return false;
}
}
| int tuplestore_alloc_read_pointer | ( | Tuplestorestate * | state, | |
| int | eflags | |||
| ) |
Definition at line 371 of file tuplestore.c.
References TSReadPointer::eflags, Tuplestorestate::eflags, elog, ERROR, Tuplestorestate::memtupcount, Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::readptrsize, repalloc(), Tuplestorestate::status, and TSS_INMEM.
Referenced by begin_partition(), ExecInitCteScan(), and ExecMaterial().
{
/* Check for possible increase of requirements */
if (state->status != TSS_INMEM || state->memtupcount != 0)
{
if ((state->eflags | eflags) != state->eflags)
elog(ERROR, "too late to require new tuplestore eflags");
}
/* Make room for another read pointer if needed */
if (state->readptrcount >= state->readptrsize)
{
int newcnt = state->readptrsize * 2;
state->readptrs = (TSReadPointer *)
repalloc(state->readptrs, newcnt * sizeof(TSReadPointer));
state->readptrsize = newcnt;
}
/* And set it up */
state->readptrs[state->readptrcount] = state->readptrs[0];
state->readptrs[state->readptrcount].eflags = eflags;
state->eflags |= eflags;
return state->readptrcount++;
}
| bool tuplestore_ateof | ( | Tuplestorestate * | state | ) |
Definition at line 528 of file tuplestore.c.
References Tuplestorestate::activeptr, TSReadPointer::eof_reached, and Tuplestorestate::readptrs.
Referenced by CteScanNext(), and ExecMaterial().
{
return state->readptrs[state->activeptr].eof_reached;
}
| static Tuplestorestate * tuplestore_begin_common | ( | int | eflags, | |
| bool | interXact, | |||
| int | maxKBytes | |||
| ) | [static] |
Definition at line 249 of file tuplestore.c.
References Tuplestorestate::activeptr, Tuplestorestate::allowedMem, Tuplestorestate::availMem, Tuplestorestate::context, TSReadPointer::current, CurrentMemoryContext, CurrentResourceOwner, TSReadPointer::eflags, Tuplestorestate::eflags, TSReadPointer::eof_reached, GetMemoryChunkSpace(), Tuplestorestate::growmemtuples, Tuplestorestate::interXact, Tuplestorestate::memtupcount, Tuplestorestate::memtupdeleted, Tuplestorestate::memtuples, Tuplestorestate::memtupsize, Tuplestorestate::myfile, palloc(), palloc0(), Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::readptrsize, Tuplestorestate::resowner, Tuplestorestate::status, Tuplestorestate::truncated, and USEMEM.
Referenced by tuplestore_begin_heap().
{
Tuplestorestate *state;
state = (Tuplestorestate *) palloc0(sizeof(Tuplestorestate));
state->status = TSS_INMEM;
state->eflags = eflags;
state->interXact = interXact;
state->truncated = false;
state->allowedMem = maxKBytes * 1024L;
state->availMem = state->allowedMem;
state->myfile = NULL;
state->context = CurrentMemoryContext;
state->resowner = CurrentResourceOwner;
state->memtupdeleted = 0;
state->memtupcount = 0;
state->memtupsize = 1024; /* initial guess */
state->growmemtuples = true;
state->memtuples = (void **) palloc(state->memtupsize * sizeof(void *));
USEMEM(state, GetMemoryChunkSpace(state->memtuples));
state->activeptr = 0;
state->readptrcount = 1;
state->readptrsize = 8; /* arbitrary */
state->readptrs = (TSReadPointer *)
palloc(state->readptrsize * sizeof(TSReadPointer));
state->readptrs[0].eflags = eflags;
state->readptrs[0].eof_reached = false;
state->readptrs[0].current = 0;
return state;
}
| Tuplestorestate* tuplestore_begin_heap | ( | bool | randomAccess, | |
| bool | interXact, | |||
| int | maxKBytes | |||
| ) |
Definition at line 306 of file tuplestore.c.
References Tuplestorestate::copytup, EXEC_FLAG_BACKWARD, EXEC_FLAG_REWIND, Tuplestorestate::readtup, tuplestore_begin_common(), and Tuplestorestate::writetup.
Referenced by begin_partition(), connectby(), crosstab(), dblink_get_notify(), deflist_to_tuplestore(), each_worker(), exec_init_tuple_store(), ExecInitCteScan(), ExecInitRecursiveUnion(), ExecMakeTableFunctionResult(), ExecMaterial(), ExecRecursiveUnion(), fmgr_sql(), get_crosstab_tuplestore(), json_array_elements(), json_populate_recordset(), materializeQueryResult(), materializeResult(), pg_available_extension_versions(), pg_available_extensions(), pg_cursor(), pg_event_trigger_dropped_objects(), pg_extension_update_paths(), pg_prepared_statement(), pg_stat_get_wal_senders(), pg_stat_statements(), plperl_return_next(), PortalCreateHoldStore(), storeRow(), and xpath_table().
{
Tuplestorestate *state;
int eflags;
/*
* This interpretation of the meaning of randomAccess is compatible with
* the pre-8.3 behavior of tuplestores.
*/
eflags = randomAccess ?
(EXEC_FLAG_BACKWARD | EXEC_FLAG_REWIND) :
(EXEC_FLAG_REWIND);
state = tuplestore_begin_common(eflags, interXact, maxKBytes);
state->copytup = copytup_heap;
state->writetup = writetup_heap;
state->readtup = readtup_heap;
return state;
}
| void tuplestore_clear | ( | Tuplestorestate * | state | ) |
Definition at line 406 of file tuplestore.c.
References BufFileClose(), TSReadPointer::current, TSReadPointer::eof_reached, FREEMEM, GetMemoryChunkSpace(), i, Tuplestorestate::memtupcount, Tuplestorestate::memtupdeleted, Tuplestorestate::memtuples, Tuplestorestate::myfile, pfree(), Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::status, and Tuplestorestate::truncated.
Referenced by ExecReScanCteScan(), ExecReScanRecursiveUnion(), and fmgr_sql().
{
int i;
TSReadPointer *readptr;
if (state->myfile)
BufFileClose(state->myfile);
state->myfile = NULL;
if (state->memtuples)
{
for (i = state->memtupdeleted; i < state->memtupcount; i++)
{
FREEMEM(state, GetMemoryChunkSpace(state->memtuples[i]));
pfree(state->memtuples[i]);
}
}
state->status = TSS_INMEM;
state->truncated = false;
state->memtupdeleted = 0;
state->memtupcount = 0;
readptr = state->readptrs;
for (i = 0; i < state->readptrcount; readptr++, i++)
{
readptr->eof_reached = false;
readptr->current = 0;
}
}
| void tuplestore_copy_read_pointer | ( | Tuplestorestate * | state, | |
| int | srcptr, | |||
| int | destptr | |||
| ) |
Definition at line 1150 of file tuplestore.c.
References Tuplestorestate::activeptr, Assert, BufFileSeek(), BufFileTell(), Tuplestorestate::eflags, TSReadPointer::eflags, elog, TSReadPointer::eof_reached, ERROR, TSReadPointer::file, i, Tuplestorestate::myfile, TSReadPointer::offset, Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::status, TSS_INMEM, TSS_READFILE, TSS_WRITEFILE, Tuplestorestate::writepos_file, and Tuplestorestate::writepos_offset.
Referenced by ExecMaterialMarkPos(), and ExecMaterialRestrPos().
{
TSReadPointer *sptr = &state->readptrs[srcptr];
TSReadPointer *dptr = &state->readptrs[destptr];
Assert(srcptr >= 0 && srcptr < state->readptrcount);
Assert(destptr >= 0 && destptr < state->readptrcount);
/* Assigning to self is a no-op */
if (srcptr == destptr)
return;
if (dptr->eflags != sptr->eflags)
{
/* Possible change of overall eflags, so copy and then recompute */
int eflags;
int i;
*dptr = *sptr;
eflags = state->readptrs[0].eflags;
for (i = 1; i < state->readptrcount; i++)
eflags |= state->readptrs[i].eflags;
state->eflags = eflags;
}
else
*dptr = *sptr;
switch (state->status)
{
case TSS_INMEM:
case TSS_WRITEFILE:
/* no work */
break;
case TSS_READFILE:
/*
* This case is a bit tricky since the active read pointer's
* position corresponds to the seek point, not what is in its
* variables. Assigning to the active requires a seek, and
* assigning from the active requires a tell, except when
* eof_reached.
*/
if (destptr == state->activeptr)
{
if (dptr->eof_reached)
{
if (BufFileSeek(state->myfile,
state->writepos_file,
state->writepos_offset,
SEEK_SET) != 0)
elog(ERROR, "tuplestore seek failed");
}
else
{
if (BufFileSeek(state->myfile,
dptr->file, dptr->offset,
SEEK_SET) != 0)
elog(ERROR, "tuplestore seek failed");
}
}
else if (srcptr == state->activeptr)
{
if (!dptr->eof_reached)
BufFileTell(state->myfile,
&dptr->file,
&dptr->offset);
}
break;
default:
elog(ERROR, "invalid tuplestore state");
break;
}
}
| void tuplestore_end | ( | Tuplestorestate * | state | ) |
Definition at line 440 of file tuplestore.c.
References BufFileClose(), i, Tuplestorestate::memtupdeleted, Tuplestorestate::memtuples, Tuplestorestate::myfile, pfree(), and Tuplestorestate::readptrs.
Referenced by ExecEndCteScan(), ExecEndFunctionScan(), ExecEndMaterial(), ExecEndRecursiveUnion(), ExecMakeFunctionResult(), ExecRecursiveUnion(), ExecReScanFunctionScan(), ExecReScanMaterial(), PortalDrop(), release_partition(), ShutdownFuncExpr(), ShutdownSQLFunction(), and storeRow().
| static void* tuplestore_gettuple | ( | Tuplestorestate * | state, | |
| bool | forward, | |||
| bool * | should_free | |||
| ) | [static] |
Definition at line 861 of file tuplestore.c.
References Tuplestorestate::activeptr, Assert, BufFileSeek(), BufFileTell(), TSReadPointer::current, TSReadPointer::eflags, elog, TSReadPointer::eof_reached, ERROR, EXEC_FLAG_BACKWARD, TSReadPointer::file, getlen(), Tuplestorestate::memtupcount, Tuplestorestate::memtupdeleted, Tuplestorestate::memtuples, Tuplestorestate::myfile, TSReadPointer::offset, Tuplestorestate::readptrs, READTUP, Tuplestorestate::status, Tuplestorestate::truncated, TSS_INMEM, TSS_READFILE, TSS_WRITEFILE, Tuplestorestate::writepos_file, and Tuplestorestate::writepos_offset.
Referenced by tuplestore_advance(), and tuplestore_gettupleslot().
{
TSReadPointer *readptr = &state->readptrs[state->activeptr];
unsigned int tuplen;
void *tup;
Assert(forward || (readptr->eflags & EXEC_FLAG_BACKWARD));
switch (state->status)
{
case TSS_INMEM:
*should_free = false;
if (forward)
{
if (readptr->eof_reached)
return NULL;
if (readptr->current < state->memtupcount)
{
/* We have another tuple, so return it */
return state->memtuples[readptr->current++];
}
readptr->eof_reached = true;
return NULL;
}
else
{
/*
* if all tuples are fetched already then we return last
* tuple, else tuple before last returned.
*/
if (readptr->eof_reached)
{
readptr->current = state->memtupcount;
readptr->eof_reached = false;
}
else
{
if (readptr->current <= state->memtupdeleted)
{
Assert(!state->truncated);
return NULL;
}
readptr->current--; /* last returned tuple */
}
if (readptr->current <= state->memtupdeleted)
{
Assert(!state->truncated);
return NULL;
}
return state->memtuples[readptr->current - 1];
}
break;
case TSS_WRITEFILE:
/* Skip state change if we'll just return NULL */
if (readptr->eof_reached && forward)
return NULL;
/*
* Switch from writing to reading.
*/
BufFileTell(state->myfile,
&state->writepos_file, &state->writepos_offset);
if (!readptr->eof_reached)
if (BufFileSeek(state->myfile,
readptr->file, readptr->offset,
SEEK_SET) != 0)
elog(ERROR, "tuplestore seek failed");
state->status = TSS_READFILE;
/* FALL THRU into READFILE case */
case TSS_READFILE:
*should_free = true;
if (forward)
{
if ((tuplen = getlen(state, true)) != 0)
{
tup = READTUP(state, tuplen);
return tup;
}
else
{
readptr->eof_reached = true;
return NULL;
}
}
/*
* Backward.
*
* if all tuples are fetched already then we return last tuple,
* else tuple before last returned.
*
* Back up to fetch previously-returned tuple's ending length
* word. If seek fails, assume we are at start of file.
*/
if (BufFileSeek(state->myfile, 0, -(long) sizeof(unsigned int),
SEEK_CUR) != 0)
{
/* even a failed backwards fetch gets you out of eof state */
readptr->eof_reached = false;
Assert(!state->truncated);
return NULL;
}
tuplen = getlen(state, false);
if (readptr->eof_reached)
{
readptr->eof_reached = false;
/* We will return the tuple returned before returning NULL */
}
else
{
/*
* Back up to get ending length word of tuple before it.
*/
if (BufFileSeek(state->myfile, 0,
-(long) (tuplen + 2 * sizeof(unsigned int)),
SEEK_CUR) != 0)
{
/*
* If that fails, presumably the prev tuple is the first
* in the file. Back up so that it becomes next to read
* in forward direction (not obviously right, but that is
* what in-memory case does).
*/
if (BufFileSeek(state->myfile, 0,
-(long) (tuplen + sizeof(unsigned int)),
SEEK_CUR) != 0)
elog(ERROR, "bogus tuple length in backward scan");
Assert(!state->truncated);
return NULL;
}
tuplen = getlen(state, false);
}
/*
* Now we have the length of the prior tuple, back up and read it.
* Note: READTUP expects we are positioned after the initial
* length word of the tuple, so back up to that point.
*/
if (BufFileSeek(state->myfile, 0,
-(long) tuplen,
SEEK_CUR) != 0)
elog(ERROR, "bogus tuple length in backward scan");
tup = READTUP(state, tuplen);
return tup;
default:
elog(ERROR, "invalid tuplestore state");
return NULL; /* keep compiler quiet */
}
}
| bool tuplestore_gettupleslot | ( | Tuplestorestate * | state, | |
| bool | forward, | |||
| bool | copy, | |||
| TupleTableSlot * | slot | |||
| ) |
Definition at line 1030 of file tuplestore.c.
References ExecClearTuple(), ExecStoreMinimalTuple(), heap_copy_minimal_tuple(), and tuplestore_gettuple().
Referenced by CteScanNext(), ExecMakeFunctionResult(), ExecMaterial(), ExecWindowAgg(), fmgr_sql(), FunctionNext(), RunFromStore(), window_gettupleslot(), and WorkTableScanNext().
{
MinimalTuple tuple;
bool should_free;
tuple = (MinimalTuple) tuplestore_gettuple(state, forward, &should_free);
if (tuple)
{
if (copy && !should_free)
{
tuple = heap_copy_minimal_tuple(tuple);
should_free = true;
}
ExecStoreMinimalTuple(tuple, slot, should_free);
return true;
}
else
{
ExecClearTuple(slot);
return false;
}
}
| bool tuplestore_in_memory | ( | Tuplestorestate * | state | ) |
Definition at line 1333 of file tuplestore.c.
References Tuplestorestate::status, and TSS_INMEM.
Referenced by spool_tuples().
| void tuplestore_puttuple | ( | Tuplestorestate * | state, | |
| HeapTuple | tuple | |||
| ) |
Definition at line 692 of file tuplestore.c.
References Tuplestorestate::context, COPYTUP, MemoryContextSwitchTo(), and tuplestore_puttuple_common().
Referenced by build_tuplestore_recursively(), crosstab(), each_object_field_end(), elements_array_element_end(), exec_stmt_return_next(), exec_stmt_return_query(), ExecMakeTableFunctionResult(), get_crosstab_tuplestore(), materializeQueryResult(), materializeResult(), plperl_return_next(), populate_recordset_object_end(), storeRow(), and xpath_table().
{
MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
/*
* Copy the tuple. (Must do this even in WRITEFILE case. Note that
* COPYTUP includes USEMEM, so we needn't do that here.)
*/
tuple = COPYTUP(state, tuple);
tuplestore_puttuple_common(state, (void *) tuple);
MemoryContextSwitchTo(oldcxt);
}
| static void tuplestore_puttuple_common | ( | Tuplestorestate * | state, | |
| void * | tuple | |||
| ) | [static] |
Definition at line 727 of file tuplestore.c.
References Tuplestorestate::activeptr, Assert, Tuplestorestate::backward, BufFileCreateTemp(), BufFileSeek(), BufFileTell(), TSReadPointer::current, CurrentResourceOwner, dumptuples(), Tuplestorestate::eflags, elog, TSReadPointer::eof_reached, ERROR, TSReadPointer::file, grow_memtuples(), i, Tuplestorestate::interXact, LACKMEM, Tuplestorestate::memtupcount, Tuplestorestate::memtuples, Tuplestorestate::memtupsize, Tuplestorestate::myfile, TSReadPointer::offset, PrepareTempTablespaces(), Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::resowner, Tuplestorestate::status, TSS_INMEM, TSS_READFILE, TSS_WRITEFILE, Tuplestorestate::writepos_file, Tuplestorestate::writepos_offset, and WRITETUP.
Referenced by tuplestore_puttuple(), tuplestore_puttupleslot(), and tuplestore_putvalues().
{
TSReadPointer *readptr;
int i;
ResourceOwner oldowner;
switch (state->status)
{
case TSS_INMEM:
/*
* Update read pointers as needed; see API spec above.
*/
readptr = state->readptrs;
for (i = 0; i < state->readptrcount; readptr++, i++)
{
if (readptr->eof_reached && i != state->activeptr)
{
readptr->eof_reached = false;
readptr->current = state->memtupcount;
}
}
/*
* Grow the array as needed. Note that we try to grow the array
* when there is still one free slot remaining --- if we fail,
* there'll still be room to store the incoming tuple, and then
* we'll switch to tape-based operation.
*/
if (state->memtupcount >= state->memtupsize - 1)
{
(void) grow_memtuples(state);
Assert(state->memtupcount < state->memtupsize);
}
/* Stash the tuple in the in-memory array */
state->memtuples[state->memtupcount++] = tuple;
/*
* Done if we still fit in available memory and have array slots.
*/
if (state->memtupcount < state->memtupsize && !LACKMEM(state))
return;
/*
* Nope; time to switch to tape-based operation. Make sure that
* the temp file(s) are created in suitable temp tablespaces.
*/
PrepareTempTablespaces();
/* associate the file with the store's resource owner */
oldowner = CurrentResourceOwner;
CurrentResourceOwner = state->resowner;
state->myfile = BufFileCreateTemp(state->interXact);
CurrentResourceOwner = oldowner;
/*
* Freeze the decision about whether trailing length words will be
* used. We can't change this choice once data is on tape, even
* though callers might drop the requirement.
*/
state->backward = (state->eflags & EXEC_FLAG_BACKWARD) != 0;
state->status = TSS_WRITEFILE;
dumptuples(state);
break;
case TSS_WRITEFILE:
/*
* Update read pointers as needed; see API spec above. Note:
* BufFileTell is quite cheap, so not worth trying to avoid
* multiple calls.
*/
readptr = state->readptrs;
for (i = 0; i < state->readptrcount; readptr++, i++)
{
if (readptr->eof_reached && i != state->activeptr)
{
readptr->eof_reached = false;
BufFileTell(state->myfile,
&readptr->file,
&readptr->offset);
}
}
WRITETUP(state, tuple);
break;
case TSS_READFILE:
/*
* Switch from reading to writing.
*/
if (!state->readptrs[state->activeptr].eof_reached)
BufFileTell(state->myfile,
&state->readptrs[state->activeptr].file,
&state->readptrs[state->activeptr].offset);
if (BufFileSeek(state->myfile,
state->writepos_file, state->writepos_offset,
SEEK_SET) != 0)
elog(ERROR, "tuplestore seek to EOF failed");
state->status = TSS_WRITEFILE;
/*
* Update read pointers as needed; see API spec above.
*/
readptr = state->readptrs;
for (i = 0; i < state->readptrcount; readptr++, i++)
{
if (readptr->eof_reached && i != state->activeptr)
{
readptr->eof_reached = false;
readptr->file = state->writepos_file;
readptr->offset = state->writepos_offset;
}
}
WRITETUP(state, tuple);
break;
default:
elog(ERROR, "invalid tuplestore state");
break;
}
}
| void tuplestore_puttupleslot | ( | Tuplestorestate * | state, | |
| TupleTableSlot * | slot | |||
| ) |
Definition at line 670 of file tuplestore.c.
References Tuplestorestate::context, ExecCopySlotMinimalTuple(), GetMemoryChunkSpace(), MemoryContextSwitchTo(), tuplestore_puttuple_common(), and USEMEM.
Referenced by begin_partition(), CteScanNext(), ExecMaterial(), ExecRecursiveUnion(), spool_tuples(), sqlfunction_receive(), and tstoreReceiveSlot_notoast().
{
MinimalTuple tuple;
MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
/*
* Form a MinimalTuple in working memory
*/
tuple = ExecCopySlotMinimalTuple(slot);
USEMEM(state, GetMemoryChunkSpace(tuple));
tuplestore_puttuple_common(state, (void *) tuple);
MemoryContextSwitchTo(oldcxt);
}
| void tuplestore_putvalues | ( | Tuplestorestate * | state, | |
| TupleDesc | tdesc, | |||
| Datum * | values, | |||
| bool * | isnull | |||
| ) |
Definition at line 712 of file tuplestore.c.
References Tuplestorestate::context, GetMemoryChunkSpace(), heap_form_minimal_tuple(), MemoryContextSwitchTo(), tuplestore_puttuple_common(), and USEMEM.
Referenced by dblink_get_notify(), deflist_to_tuplestore(), exec_stmt_return_next(), ExecMakeTableFunctionResult(), get_available_versions_for_extension(), pg_available_extensions(), pg_cursor(), pg_event_trigger_dropped_objects(), pg_extension_update_paths(), pg_prepared_statement(), pg_stat_get_wal_senders(), pg_stat_statements(), plperl_return_next(), and tstoreReceiveSlot_detoast().
{
MinimalTuple tuple;
MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
tuple = heap_form_minimal_tuple(tdesc, values, isnull);
USEMEM(state, GetMemoryChunkSpace(tuple));
tuplestore_puttuple_common(state, (void *) tuple);
MemoryContextSwitchTo(oldcxt);
}
| void tuplestore_rescan | ( | Tuplestorestate * | state | ) |
Definition at line 1117 of file tuplestore.c.
References Tuplestorestate::activeptr, Assert, BufFileSeek(), TSReadPointer::current, TSReadPointer::eflags, elog, TSReadPointer::eof_reached, ERROR, EXEC_FLAG_REWIND, TSReadPointer::file, Tuplestorestate::myfile, TSReadPointer::offset, Tuplestorestate::readptrs, Tuplestorestate::status, Tuplestorestate::truncated, TSS_INMEM, TSS_READFILE, and TSS_WRITEFILE.
Referenced by DoPortalRewind(), ExecReScanCteScan(), ExecReScanFunctionScan(), ExecReScanMaterial(), ExecReScanWorkTableScan(), and PersistHoldablePortal().
{
TSReadPointer *readptr = &state->readptrs[state->activeptr];
Assert(readptr->eflags & EXEC_FLAG_REWIND);
Assert(!state->truncated);
switch (state->status)
{
case TSS_INMEM:
readptr->eof_reached = false;
readptr->current = 0;
break;
case TSS_WRITEFILE:
readptr->eof_reached = false;
readptr->file = 0;
readptr->offset = 0L;
break;
case TSS_READFILE:
readptr->eof_reached = false;
if (BufFileSeek(state->myfile, 0, 0L, SEEK_SET) != 0)
elog(ERROR, "tuplestore seek to start failed");
break;
default:
elog(ERROR, "invalid tuplestore state");
break;
}
}
| void tuplestore_select_read_pointer | ( | Tuplestorestate * | state, | |
| int | ptr | |||
| ) |
Definition at line 460 of file tuplestore.c.
References Tuplestorestate::activeptr, Assert, BufFileSeek(), BufFileTell(), elog, TSReadPointer::eof_reached, ERROR, TSReadPointer::file, Tuplestorestate::myfile, TSReadPointer::offset, Tuplestorestate::readptrs, Tuplestorestate::status, TSS_INMEM, TSS_READFILE, TSS_WRITEFILE, Tuplestorestate::writepos_file, and Tuplestorestate::writepos_offset.
Referenced by CteScanNext(), ExecReScanCteScan(), ExecWindowAgg(), window_gettupleslot(), and WinSetMarkPosition().
{
TSReadPointer *readptr;
TSReadPointer *oldptr;
Assert(ptr >= 0 && ptr < state->readptrcount);
/* No work if already active */
if (ptr == state->activeptr)
return;
readptr = &state->readptrs[ptr];
oldptr = &state->readptrs[state->activeptr];
switch (state->status)
{
case TSS_INMEM:
case TSS_WRITEFILE:
/* no work */
break;
case TSS_READFILE:
/*
* First, save the current read position in the pointer about to
* become inactive.
*/
if (!oldptr->eof_reached)
BufFileTell(state->myfile,
&oldptr->file,
&oldptr->offset);
/*
* We have to make the temp file's seek position equal to the
* logical position of the new read pointer. In eof_reached
* state, that's the EOF, which we have available from the saved
* write position.
*/
if (readptr->eof_reached)
{
if (BufFileSeek(state->myfile,
state->writepos_file,
state->writepos_offset,
SEEK_SET) != 0)
elog(ERROR, "tuplestore seek failed");
}
else
{
if (BufFileSeek(state->myfile,
readptr->file,
readptr->offset,
SEEK_SET) != 0)
elog(ERROR, "tuplestore seek failed");
}
break;
default:
elog(ERROR, "invalid tuplestore state");
break;
}
state->activeptr = ptr;
}
| void tuplestore_set_eflags | ( | Tuplestorestate * | state, | |
| int | eflags | |||
| ) |
Definition at line 347 of file tuplestore.c.
References Tuplestorestate::eflags, TSReadPointer::eflags, elog, ERROR, i, Tuplestorestate::memtupcount, Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::status, and TSS_INMEM.
Referenced by begin_partition(), ExecInitCteScan(), and ExecMaterial().
| void tuplestore_trim | ( | Tuplestorestate * | state | ) |
Definition at line 1238 of file tuplestore.c.
References Assert, TSReadPointer::current, Tuplestorestate::eflags, TSReadPointer::eof_reached, EXEC_FLAG_REWIND, FREEMEM, GetMemoryChunkSpace(), i, memmove, Tuplestorestate::memtupcount, Tuplestorestate::memtupdeleted, Tuplestorestate::memtuples, Min, pfree(), Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::status, Tuplestorestate::truncated, and TSS_INMEM.
Referenced by ExecMaterialMarkPos(), and ExecWindowAgg().
{
int oldest;
int nremove;
int i;
/*
* Truncation is disallowed if any read pointer requires rewind
* capability.
*/
if (state->eflags & EXEC_FLAG_REWIND)
return;
/*
* We don't bother trimming temp files since it usually would mean more
* work than just letting them sit in kernel buffers until they age out.
*/
if (state->status != TSS_INMEM)
return;
/* Find the oldest read pointer */
oldest = state->memtupcount;
for (i = 0; i < state->readptrcount; i++)
{
if (!state->readptrs[i].eof_reached)
oldest = Min(oldest, state->readptrs[i].current);
}
/*
* Note: you might think we could remove all the tuples before the oldest
* "current", since that one is the next to be returned. However, since
* tuplestore_gettuple returns a direct pointer to our internal copy of
* the tuple, it's likely that the caller has still got the tuple just
* before "current" referenced in a slot. So we keep one extra tuple
* before the oldest "current". (Strictly speaking, we could require such
* callers to use the "copy" flag to tuplestore_gettupleslot, but for
* efficiency we allow this one case to not use "copy".)
*/
nremove = oldest - 1;
if (nremove <= 0)
return; /* nothing to do */
Assert(nremove >= state->memtupdeleted);
Assert(nremove <= state->memtupcount);
/* Release no-longer-needed tuples */
for (i = state->memtupdeleted; i < nremove; i++)
{
FREEMEM(state, GetMemoryChunkSpace(state->memtuples[i]));
pfree(state->memtuples[i]);
state->memtuples[i] = NULL;
}
state->memtupdeleted = nremove;
/* mark tuplestore as truncated (used for Assert crosschecks only) */
state->truncated = true;
/*
* If nremove is less than 1/8th memtupcount, just stop here, leaving the
* "deleted" slots as NULL. This prevents us from expending O(N^2) time
* repeatedly memmove-ing a large pointer array. The worst case space
* wastage is pretty small, since it's just pointers and not whole tuples.
*/
if (nremove < state->memtupcount / 8)
return;
/*
* Slide the array down and readjust pointers.
*
* In mergejoin's current usage, it's demonstrable that there will always
* be exactly one non-removed tuple; so optimize that case.
*/
if (nremove + 1 == state->memtupcount)
state->memtuples[0] = state->memtuples[nremove];
else
memmove(state->memtuples, state->memtuples + nremove,
(state->memtupcount - nremove) * sizeof(void *));
state->memtupdeleted = 0;
state->memtupcount -= nremove;
for (i = 0; i < state->readptrcount; i++)
{
if (!state->readptrs[i].eof_reached)
state->readptrs[i].current -= nremove;
}
}
| static void writetup_heap | ( | Tuplestorestate * | state, | |
| void * | tup | |||
| ) | [static] |
Definition at line 1381 of file tuplestore.c.
References Tuplestorestate::backward, BufFileWrite(), elog, ERROR, FREEMEM, GetMemoryChunkSpace(), heap_free_minimal_tuple(), MINIMAL_TUPLE_DATA_OFFSET, Tuplestorestate::myfile, and MinimalTupleData::t_len.
{
MinimalTuple tuple = (MinimalTuple) tup;
/* the part of the MinimalTuple we'll write: */
char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
unsigned int tupbodylen = tuple->t_len - MINIMAL_TUPLE_DATA_OFFSET;
/* total on-disk footprint: */
unsigned int tuplen = tupbodylen + sizeof(int);
if (BufFileWrite(state->myfile, (void *) &tuplen,
sizeof(tuplen)) != sizeof(tuplen))
elog(ERROR, "write failed");
if (BufFileWrite(state->myfile, (void *) tupbody,
tupbodylen) != (size_t) tupbodylen)
elog(ERROR, "write failed");
if (state->backward) /* need trailing length word? */
if (BufFileWrite(state->myfile, (void *) &tuplen,
sizeof(tuplen)) != sizeof(tuplen))
elog(ERROR, "write failed");
FREEMEM(state, GetMemoryChunkSpace(tuple));
heap_free_minimal_tuple(tuple);
}
1.7.1