* only in the leader process.
*/
GinLeader *bs_leader;
- int bs_worker_id;
+
+ /* number of participating workers (including leader) */
+ int bs_num_workers;
/* used to pass information from workers to leader */
double bs_numtuples;
/*
* ginFlushBuildState
* Write all data from BuildAccumulator into the tuplesort.
+ *
+ * The number of TIDs written to the tuplesort at once is limited, to reduce
+ * the amount of memory needed when merging the intermediate results later.
+ * The leader will see up to two chunks per worker, so calculate the limit to
+ * not need more than MaxAllocSize overall.
+ *
+ * We don't need to worry about overflowing maintenance_work_mem. We can't
+ * build chunks larger than work_mem, and that limit was set so that workers
+ * produce sufficiently small chunks.
*/
static void
ginFlushBuildState(GinBuildState *buildstate, Relation index)
uint32 nlist;
OffsetNumber attnum;
TupleDesc tdesc = RelationGetDescr(index);
+ uint32 maxlen;
+
+ /* maximum number of TIDs per chunk (two chunks per worker) */
+ maxlen = MaxAllocSize / sizeof(ItemPointerData);
+ maxlen /= (2 * buildstate->bs_num_workers);
ginBeginBAScan(&buildstate->accum);
while ((list = ginGetBAEntry(&buildstate->accum,
/* information about the key */
CompactAttribute *attr = TupleDescCompactAttr(tdesc, (attnum - 1));
- /* GIN tuple and tuple length */
- GinTuple *tup;
- Size tuplen;
+ /* start of the chunk */
+ uint32 offset = 0;
- /* there could be many entries, so be willing to abort here */
- CHECK_FOR_INTERRUPTS();
+ /* split the entry into smaller chunk with up to maxlen items */
+ while (offset < nlist)
+ {
+ /* GIN tuple and tuple length */
+ GinTuple *tup;
+ Size tuplen;
+ uint32 len = Min(maxlen, nlist - offset);
- tup = _gin_build_tuple(attnum, category,
- key, attr->attlen, attr->attbyval,
- list, nlist, &tuplen);
+ /* there could be many entries, so be willing to abort here */
+ CHECK_FOR_INTERRUPTS();
+
+ tup = _gin_build_tuple(attnum, category,
+ key, attr->attlen, attr->attbyval,
+ &list[offset], len,
+ &tuplen);
- tuplesort_putgintuple(buildstate->bs_worker_sort, tup, tuplen);
+ offset += len;
- pfree(tup);
+ tuplesort_putgintuple(buildstate->bs_worker_sort, tup, tuplen);
+
+ pfree(tup);
+ }
}
MemoryContextReset(buildstate->tmpCtx);
/* remember how much space is allowed for the accumulated entries */
state->work_mem = (sortmem / 2);
+ /* remember how many workers participate in the build */
+ state->bs_num_workers = ginshared->scantuplesortstates;
+
/* Begin "partial" tuplesort */
state->bs_sortstate = tuplesort_begin_index_gin(heap, index,
state->work_mem,