/* * Set up the data structures that we'll need for Gather Merge. * * We allocate these once on the basis of gm->num_workers, which is an * upper bound for the number of workers we'll actually have. During * a rescan, we reset the structures to empty. This approach simplifies * not leaking memory across rescans. * * In the gm_slots[] array, index 0 is for the leader, and indexes 1 to n * are for workers. The values placed into gm_heap correspond to indexes * in gm_slots[]. The gm_tuple_buffers[] array, however, is indexed from * 0 to n-1; it has no entry for the leader. */ static void gather_merge_setup(GatherMergeState *gm_state) { GatherMerge *gm = castNode(GatherMerge, gm_state->ps.plan); int nreaders = gm->num_workers; int i; /* * Allocate gm_slots for the number of workers + one more slot for leader. * Slot 0 is always for the leader. Leader always calls ExecProcNode() to * read the tuple, and then stores it directly into its gm_slots entry. * For other slots, code below will call ExecInitExtraTupleSlot() to * create a slot for the worker's results. Note that during any single * scan, we might have fewer than num_workers available workers, in which * case the extra array entries go unused. */ gm_state->gm_slots = (TupleTableSlot **) palloc0((nreaders + 1) * sizeof(TupleTableSlot *)); /* Allocate the tuple slot and tuple array for each worker */ gm_state->gm_tuple_buffers = (GMReaderTupleBuffer *) palloc0(nreaders * sizeof(GMReaderTupleBuffer)); for (i = 0; i < nreaders; i++) { /* Allocate the tuple array with length MAX_TUPLE_STORE */ gm_state->gm_tuple_buffers[i].tuple = (HeapTuple *) palloc0(sizeof(HeapTuple) * MAX_TUPLE_STORE); /* Initialize tuple slot for worker */ gm_state->gm_slots[i + 1] = ExecInitExtraTupleSlot(gm_state->ps.state, gm_state->tupDesc, &TTSOpsHeapTuple); } /* Allocate the resources for the merge */ gm_state->gm_heap = binaryheap_allocate(nreaders + 1, heap_compare_slots, gm_state); }
/* * Initialize the Gather merge tuple read. * * Pull at least a single tuple from each worker + leader and set up the heap. */ static void gather_merge_init(GatherMergeState *gm_state) { int nreaders = gm_state->nreaders; bool initialize = true; int i; /* * Allocate gm_slots for the number of worker + one more slot for leader. * Last slot is always for leader. Leader always calls ExecProcNode() to * read the tuple which will return the TupleTableSlot. Later it will * directly get assigned to gm_slot. So just initialize leader gm_slot * with NULL. For other slots below code will call * ExecInitExtraTupleSlot() which will do the initialization of worker * slots. */ gm_state->gm_slots = palloc((gm_state->nreaders + 1) * sizeof(TupleTableSlot *)); gm_state->gm_slots[gm_state->nreaders] = NULL; /* Initialize the tuple slot and tuple array for each worker */ gm_state->gm_tuple_buffers = (GMReaderTupleBuffer *) palloc0(sizeof(GMReaderTupleBuffer) * (gm_state->nreaders + 1)); for (i = 0; i < gm_state->nreaders; i++) { /* Allocate the tuple array with MAX_TUPLE_STORE size */ gm_state->gm_tuple_buffers[i].tuple = (HeapTuple *) palloc0(sizeof(HeapTuple) * MAX_TUPLE_STORE); /* Initialize slot for worker */ gm_state->gm_slots[i] = ExecInitExtraTupleSlot(gm_state->ps.state); ExecSetSlotDescriptor(gm_state->gm_slots[i], gm_state->tupDesc); } /* Allocate the resources for the merge */ gm_state->gm_heap = binaryheap_allocate(gm_state->nreaders + 1, heap_compare_slots, gm_state); /* * First, try to read a tuple from each worker (including leader) in * nowait mode, so that we initialize read from each worker as well as * leader. After this, if all active workers are unable to produce a * tuple, then re-read and this time use wait mode. For workers that were * able to produce a tuple in the earlier loop and are still active, just * try to fill the tuple array if more tuples are avaiable. */ reread: for (i = 0; i < nreaders + 1; i++) { CHECK_FOR_INTERRUPTS(); if (!gm_state->gm_tuple_buffers[i].done && (TupIsNull(gm_state->gm_slots[i]) || gm_state->gm_slots[i]->tts_isempty)) { if (gather_merge_readnext(gm_state, i, initialize)) { binaryheap_add_unordered(gm_state->gm_heap, Int32GetDatum(i)); } } else form_tuple_array(gm_state, i); } initialize = false; for (i = 0; i < nreaders; i++) if (!gm_state->gm_tuple_buffers[i].done && (TupIsNull(gm_state->gm_slots[i]) || gm_state->gm_slots[i]->tts_isempty)) goto reread; binaryheap_build(gm_state->gm_heap); gm_state->gm_initialized = true; }