/* Chunk written to disk. */ typedefstruct SharedTuplestoreChunk
{ int ntuples; /* Number of tuples in this chunk. */ int overflow; /* If overflow, how many including this one? */ char data[FLEXIBLE_ARRAY_MEMBER];
} SharedTuplestoreChunk;
/* Per-participant shared state. */ typedefstruct SharedTuplestoreParticipant
{
LWLock lock;
BlockNumber read_page; /* Page number for next read. */
BlockNumber npages; /* Number of pages written. */ bool writing; /* Used only for assertions. */
} SharedTuplestoreParticipant;
/* The control object that lives in shared memory. */ struct SharedTuplestore
{ int nparticipants; /* Number of participants that can write. */ int flags; /* Flag bits from SHARED_TUPLESTORE_XXX */
size_t meta_data_size; /* Size of per-tuple header. */ char name[NAMEDATALEN]; /* A name for this tuplestore. */
/* Followed by per-participant shared state. */
SharedTuplestoreParticipant participants[FLEXIBLE_ARRAY_MEMBER];
};
/* Per-participant state that lives in backend-local memory. */ struct SharedTuplestoreAccessor
{ int participant; /* My participant number. */
SharedTuplestore *sts; /* The shared state. */
SharedFileSet *fileset; /* The SharedFileSet holding files. */
MemoryContext context; /* Memory context for buffers. */
/* State for reading. */ int read_participant; /* The current participant to read from. */
BufFile *read_file; /* The current file to read from. */ int read_ntuples_available; /* The number of tuples in chunk. */ int read_ntuples; /* How many tuples have we read from chunk? */
size_t read_bytes; /* How many bytes have we read from chunk? */ char *read_buffer; /* A buffer for loading tuples. */
size_t read_buffer_size;
BlockNumber read_next_page; /* Lowest block we'll consider reading. */
/* State for writing. */
SharedTuplestoreChunk *write_chunk; /* Buffer for writing. */
BufFile *write_file; /* The current file to write to. */
BlockNumber write_page; /* The next page to write to. */ char *write_pointer; /* Current write pointer within chunk. */ char *write_end; /* One past the end of the current chunk. */
};
staticvoid sts_filename(char *name, SharedTuplestoreAccessor *accessor, int participant);
/* *Resetthesharedreadheadforallparticipants'files.Alsosetthe *initialchunksizetotheminimum(anyincreasesfromthatsizewillbe *recordedinchunk_expansion_log).
*/ for (i = 0; i < accessor->sts->nparticipants; ++i)
{
accessor->sts->participants[i].read_page = 0;
}
}
/* *Beginscanningthecontentsinparallel.
*/ void
sts_begin_parallel_scan(SharedTuplestoreAccessor *accessor)
{ int i PG_USED_FOR_ASSERTS_ONLY;
/* End any existing scan that was in progress. */
sts_end_parallel_scan(accessor);
/* *Anybackendthatmighthavewrittenintothissharedtuplestoremust *havecalledsts_end_write(),sothatallbuffersareflushedandthe *fileshavestoppedgrowing.
*/ for (i = 0; i < accessor->sts->nparticipants; ++i)
Assert(!accessor->sts->participants[i].writing);
/* Do we have our own file yet? */ if (accessor->write_file == NULL)
{
SharedTuplestoreParticipant *participant; char name[MAXPGPATH];
MemoryContext oldcxt;
/* Create one. Only this backend will write into it. */
sts_filename(name, accessor, accessor->participant);
/* Set up the shared state for this backend's file. */
participant = &accessor->sts->participants[accessor->participant];
participant->writing = true; /* for assertions only */
}
/* Do we have space? */
size = accessor->sts->meta_data_size + tuple->t_len; if (accessor->write_pointer == NULL ||
accessor->write_pointer + size > accessor->write_end)
{ if (accessor->write_chunk == NULL)
{ /* First time through. Allocate chunk. */
accessor->write_chunk = (SharedTuplestoreChunk *)
MemoryContextAllocZero(accessor->context,
STS_CHUNK_PAGES * BLCKSZ);
accessor->write_chunk->ntuples = 0;
accessor->write_pointer = &accessor->write_chunk->data[0];
accessor->write_end = (char *)
accessor->write_chunk + STS_CHUNK_PAGES * BLCKSZ;
} else
{ /* See if flushing helps. */
sts_flush_chunk(accessor);
}
/* It may still not be enough in the case of a gigantic tuple. */ if (accessor->write_pointer + size > accessor->write_end)
{
size_t written;
/* Write the meta-data as one chunk. */ if (accessor->sts->meta_data_size > 0)
memcpy(accessor->write_pointer, meta_data,
accessor->sts->meta_data_size);
/* *Writeasmuchofthetupleaswecanfit.Thisincludesthe *tuple'ssizeatthestart.
*/
written = accessor->write_end - accessor->write_pointer -
accessor->sts->meta_data_size;
memcpy(accessor->write_pointer + accessor->sts->meta_data_size,
tuple, written);
++accessor->write_chunk->ntuples;
size -= accessor->sts->meta_data_size;
size -= written; /* Now write as many overflow chunks as we need for the rest. */ while (size > 0)
{
size_t written_this_chunk;
/* Check if we need to read any overflow chunks. */ while (remaining_size > 0)
{ /* We are now positioned at the start of an overflow chunk. */
SharedTuplestoreChunk chunk_header;
for (;;)
{ /* Can we read more tuples from the current chunk? */ if (accessor->read_ntuples < accessor->read_ntuples_available) return sts_read_tuple(accessor, meta_data);
/* Find the location of a new chunk to read. */
p = &accessor->sts->participants[accessor->read_participant];
LWLockAcquire(&p->lock, LW_EXCLUSIVE); /* We can skip directly past overflow pages we know about. */ if (p->read_page < accessor->read_next_page)
p->read_page = accessor->read_next_page;
eof = p->read_page >= p->npages; if (!eof)
{ /* Claim the next chunk. */
read_page = p->read_page; /* Advance the read head for the next reader. */
p->read_page += STS_CHUNK_PAGES;
accessor->read_next_page = p->read_page;
}
LWLockRelease(&p->lock);
if (!eof)
{
SharedTuplestoreChunk chunk_header;
/* Make sure we have the file open. */ if (accessor->read_file == NULL)
{ char name[MAXPGPATH];
MemoryContext oldcxt;
/* Seek and load the chunk header. */ if (BufFileSeekBlock(accessor->read_file, read_page) != 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not seek to block %u in shared tuplestore temporary file",
read_page)));
BufFileReadExact(accessor->read_file, &chunk_header, STS_CHUNK_HEADER_SIZE);
/* Go around again, so we can get a tuple from this chunk. */
} else
{ if (accessor->read_file != NULL)
{
BufFileClose(accessor->read_file);
accessor->read_file = NULL;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.