/* * Read tuple(s) for given reader in nowait mode, and load into its tuple * array, until we have MAX_TUPLE_STORE of them or would have to block. */ static void load_tuple_array(GatherMergeState *gm_state, int reader) { GMReaderTupleBuffer *tuple_buffer; int i; /* Don't do anything if this is the leader. */ if (reader == 0) return; tuple_buffer = &gm_state->gm_tuple_buffers[reader - 1]; /* If there's nothing in the array, reset the counters to zero. */ if (tuple_buffer->nTuples == tuple_buffer->readCounter) tuple_buffer->nTuples = tuple_buffer->readCounter = 0; /* Try to fill additional slots in the array. */ for (i = tuple_buffer->nTuples; i < MAX_TUPLE_STORE; i++) { HeapTuple tuple; tuple = gm_readnext_tuple(gm_state, reader, true, &tuple_buffer->done); if (!HeapTupleIsValid(tuple)) break; tuple_buffer->tuple[i] = tuple; tuple_buffer->nTuples++; } }
/* * Read the tuple for given reader in nowait mode, and form the tuple array. */ static void form_tuple_array(GatherMergeState *gm_state, int reader) { GMReaderTupleBuffer *tuple_buffer = &gm_state->gm_tuple_buffers[reader]; int i; /* Last slot is for leader and we don't build tuple array for leader */ if (reader == gm_state->nreaders) return; /* * We here because we already read all the tuples from the tuple array, so * initialize the counter to zero. */ if (tuple_buffer->nTuples == tuple_buffer->readCounter) tuple_buffer->nTuples = tuple_buffer->readCounter = 0; /* Tuple array is already full? */ if (tuple_buffer->nTuples == MAX_TUPLE_STORE) return; for (i = tuple_buffer->nTuples; i < MAX_TUPLE_STORE; i++) { tuple_buffer->tuple[i] = heap_copytuple(gm_readnext_tuple(gm_state, reader, false, &tuple_buffer->done)); if (!HeapTupleIsValid(tuple_buffer->tuple[i])) break; tuple_buffer->nTuples++; } }
/* * Store the next tuple for a given reader into the appropriate slot. * * Returns true if successful, false if not (either reader is exhausted, * or we didn't want to wait for a tuple). Sets done flag if reader * is found to be exhausted. */ static bool gather_merge_readnext(GatherMergeState *gm_state, int reader, bool nowait) { GMReaderTupleBuffer *tuple_buffer; HeapTuple tup; /* * If we're being asked to generate a tuple from the leader, then we just * call ExecProcNode as normal to produce one. */ if (reader == 0) { if (gm_state->need_to_scan_locally) { PlanState *outerPlan = outerPlanState(gm_state); TupleTableSlot *outerTupleSlot; EState *estate = gm_state->ps.state; /* Install our DSA area while executing the plan. */ estate->es_query_dsa = gm_state->pei ? gm_state->pei->area : NULL; outerTupleSlot = ExecProcNode(outerPlan); estate->es_query_dsa = NULL; if (!TupIsNull(outerTupleSlot)) { gm_state->gm_slots[0] = outerTupleSlot; return true; } /* need_to_scan_locally serves as "done" flag for leader */ gm_state->need_to_scan_locally = false; } return false; } /* Otherwise, check the state of the relevant tuple buffer. */ tuple_buffer = &gm_state->gm_tuple_buffers[reader - 1]; if (tuple_buffer->nTuples > tuple_buffer->readCounter) { /* Return any tuple previously read that is still buffered. */ tup = tuple_buffer->tuple[tuple_buffer->readCounter++]; } else if (tuple_buffer->done) { /* Reader is known to be exhausted. */ return false; } else { /* Read and buffer next tuple. */ tup = gm_readnext_tuple(gm_state, reader, nowait, &tuple_buffer->done); if (!HeapTupleIsValid(tup)) return false; /* * Attempt to read more tuples in nowait mode and store them in the * pending-tuple array for the reader. */ load_tuple_array(gm_state, reader); } Assert(HeapTupleIsValid(tup)); /* Build the TupleTableSlot for the given tuple */ ExecStoreHeapTuple(tup, /* tuple to store */ gm_state->gm_slots[reader], /* slot in which to store * the tuple */ true); /* pfree tuple when done with it */ return true; }
/* * Store the next tuple for a given reader into the appropriate slot. * * Returns false if the reader is exhausted, and true otherwise. */ static bool gather_merge_readnext(GatherMergeState *gm_state, int reader, bool nowait) { GMReaderTupleBuffer *tuple_buffer; HeapTuple tup = NULL; /* * If we're being asked to generate a tuple from the leader, then we just * call ExecProcNode as normal to produce one. */ if (gm_state->nreaders == reader) { if (gm_state->need_to_scan_locally) { PlanState *outerPlan = outerPlanState(gm_state); TupleTableSlot *outerTupleSlot; outerTupleSlot = ExecProcNode(outerPlan); if (!TupIsNull(outerTupleSlot)) { gm_state->gm_slots[reader] = outerTupleSlot; return true; } gm_state->gm_tuple_buffers[reader].done = true; gm_state->need_to_scan_locally = false; } return false; } /* Otherwise, check the state of the relevant tuple buffer. */ tuple_buffer = &gm_state->gm_tuple_buffers[reader]; if (tuple_buffer->nTuples > tuple_buffer->readCounter) { /* Return any tuple previously read that is still buffered. */ tuple_buffer = &gm_state->gm_tuple_buffers[reader]; tup = tuple_buffer->tuple[tuple_buffer->readCounter++]; } else if (tuple_buffer->done) { /* Reader is known to be exhausted. */ DestroyTupleQueueReader(gm_state->reader[reader]); gm_state->reader[reader] = NULL; return false; } else { /* Read and buffer next tuple. */ tup = heap_copytuple(gm_readnext_tuple(gm_state, reader, nowait, &tuple_buffer->done)); /* * Attempt to read more tuples in nowait mode and store them in the * tuple array. */ if (HeapTupleIsValid(tup)) form_tuple_array(gm_state, reader); else return false; } Assert(HeapTupleIsValid(tup)); /* Build the TupleTableSlot for the given tuple */ ExecStoreTuple(tup, /* tuple to store */ gm_state->gm_slots[reader], /* slot in which to store the * tuple */ InvalidBuffer, /* buffer associated with this tuple */ true); /* pfree this pointer if not from heap */ return true; }