Commit ad87bf35 authored by Tom Lane's avatar Tom Lane

Avoid some other O(N^2) hazards in list manipulation.

In the same spirit as 6301c3ada, fix some more places where we were
using list_delete_first() in a loop and thereby risking O(N^2)
behavior.  It's not clear that the lists manipulated in these spots
can get long enough to be really problematic ... but it's not clear
that they can't, either, and the fixes are simple enough.

As before, back-patch to v13.

Discussion: https://postgr.es/m/CD2F0E7F-9822-45EC-A411-AE56F14DEA9F@amazon.com
parent 494ec003
...@@ -905,6 +905,7 @@ transformGraph(TrgmNFA *trgmNFA) ...@@ -905,6 +905,7 @@ transformGraph(TrgmNFA *trgmNFA)
HASHCTL hashCtl; HASHCTL hashCtl;
TrgmStateKey initkey; TrgmStateKey initkey;
TrgmState *initstate; TrgmState *initstate;
ListCell *lc;
/* Initialize this stage's workspace in trgmNFA struct */ /* Initialize this stage's workspace in trgmNFA struct */
trgmNFA->queue = NIL; trgmNFA->queue = NIL;
...@@ -935,12 +936,13 @@ transformGraph(TrgmNFA *trgmNFA) ...@@ -935,12 +936,13 @@ transformGraph(TrgmNFA *trgmNFA)
/* /*
* Recursively build the expanded graph by processing queue of states * Recursively build the expanded graph by processing queue of states
* (breadth-first search). getState already put initstate in the queue. * (breadth-first search). getState already put initstate in the queue.
* Note that getState will append new states to the queue within the loop,
* too; this works as long as we don't do repeat fetches using the "lc"
* pointer.
*/ */
while (trgmNFA->queue != NIL) foreach(lc, trgmNFA->queue)
{ {
TrgmState *state = (TrgmState *) linitial(trgmNFA->queue); TrgmState *state = (TrgmState *) lfirst(lc);
trgmNFA->queue = list_delete_first(trgmNFA->queue);
/* /*
* If we overflowed then just mark state as final. Otherwise do * If we overflowed then just mark state as final. Otherwise do
...@@ -964,22 +966,29 @@ transformGraph(TrgmNFA *trgmNFA) ...@@ -964,22 +966,29 @@ transformGraph(TrgmNFA *trgmNFA)
static void static void
processState(TrgmNFA *trgmNFA, TrgmState *state) processState(TrgmNFA *trgmNFA, TrgmState *state)
{ {
ListCell *lc;
/* keysQueue should be NIL already, but make sure */ /* keysQueue should be NIL already, but make sure */
trgmNFA->keysQueue = NIL; trgmNFA->keysQueue = NIL;
/* /*
* Add state's own key, and then process all keys added to keysQueue until * Add state's own key, and then process all keys added to keysQueue until
* queue is empty. But we can quit if the state gets marked final. * queue is finished. But we can quit if the state gets marked final.
*/ */
addKey(trgmNFA, state, &state->stateKey); addKey(trgmNFA, state, &state->stateKey);
while (trgmNFA->keysQueue != NIL && !(state->flags & TSTATE_FIN)) foreach(lc, trgmNFA->keysQueue)
{ {
TrgmStateKey *key = (TrgmStateKey *) linitial(trgmNFA->keysQueue); TrgmStateKey *key = (TrgmStateKey *) lfirst(lc);
trgmNFA->keysQueue = list_delete_first(trgmNFA->keysQueue); if (state->flags & TSTATE_FIN)
break;
addKey(trgmNFA, state, key); addKey(trgmNFA, state, key);
} }
/* Release keysQueue to clean up for next cycle */
list_free(trgmNFA->keysQueue);
trgmNFA->keysQueue = NIL;
/* /*
* Add outgoing arcs only if state isn't final (we have no interest in * Add outgoing arcs only if state isn't final (we have no interest in
* outgoing arcs if we already match) * outgoing arcs if we already match)
......
...@@ -2602,8 +2602,9 @@ agg_refill_hash_table(AggState *aggstate) ...@@ -2602,8 +2602,9 @@ agg_refill_hash_table(AggState *aggstate)
if (aggstate->hash_batches == NIL) if (aggstate->hash_batches == NIL)
return false; return false;
batch = linitial(aggstate->hash_batches); /* hash_batches is a stack, with the top item at the end of the list */
aggstate->hash_batches = list_delete_first(aggstate->hash_batches); batch = llast(aggstate->hash_batches);
aggstate->hash_batches = list_delete_last(aggstate->hash_batches);
hash_agg_set_limits(aggstate->hashentrysize, batch->input_card, hash_agg_set_limits(aggstate->hashentrysize, batch->input_card,
batch->used_bits, &aggstate->hash_mem_limit, batch->used_bits, &aggstate->hash_mem_limit,
...@@ -3182,7 +3183,7 @@ hashagg_spill_finish(AggState *aggstate, HashAggSpill *spill, int setno) ...@@ -3182,7 +3183,7 @@ hashagg_spill_finish(AggState *aggstate, HashAggSpill *spill, int setno)
new_batch = hashagg_batch_new(tapeset, tapenum, setno, new_batch = hashagg_batch_new(tapeset, tapenum, setno,
spill->ntuples[i], cardinality, spill->ntuples[i], cardinality,
used_bits); used_bits);
aggstate->hash_batches = lcons(new_batch, aggstate->hash_batches); aggstate->hash_batches = lappend(aggstate->hash_batches, new_batch);
aggstate->hash_batches_used++; aggstate->hash_batches_used++;
} }
...@@ -3197,8 +3198,6 @@ hashagg_spill_finish(AggState *aggstate, HashAggSpill *spill, int setno) ...@@ -3197,8 +3198,6 @@ hashagg_spill_finish(AggState *aggstate, HashAggSpill *spill, int setno)
static void static void
hashagg_reset_spill_state(AggState *aggstate) hashagg_reset_spill_state(AggState *aggstate)
{ {
ListCell *lc;
/* free spills from initial pass */ /* free spills from initial pass */
if (aggstate->hash_spills != NULL) if (aggstate->hash_spills != NULL)
{ {
...@@ -3216,13 +3215,7 @@ hashagg_reset_spill_state(AggState *aggstate) ...@@ -3216,13 +3215,7 @@ hashagg_reset_spill_state(AggState *aggstate)
} }
/* free batches */ /* free batches */
foreach(lc, aggstate->hash_batches) list_free_deep(aggstate->hash_batches);
{
HashAggBatch *batch = (HashAggBatch *) lfirst(lc);
pfree(batch);
}
list_free(aggstate->hash_batches);
aggstate->hash_batches = NIL; aggstate->hash_batches = NIL;
/* close tape set */ /* close tape set */
......
...@@ -171,6 +171,7 @@ static void ...@@ -171,6 +171,7 @@ static void
llvm_release_context(JitContext *context) llvm_release_context(JitContext *context)
{ {
LLVMJitContext *llvm_context = (LLVMJitContext *) context; LLVMJitContext *llvm_context = (LLVMJitContext *) context;
ListCell *lc;
/* /*
* When this backend is exiting, don't clean up LLVM. As an error might * When this backend is exiting, don't clean up LLVM. As an error might
...@@ -188,12 +189,9 @@ llvm_release_context(JitContext *context) ...@@ -188,12 +189,9 @@ llvm_release_context(JitContext *context)
llvm_context->module = NULL; llvm_context->module = NULL;
} }
while (llvm_context->handles != NIL) foreach(lc, llvm_context->handles)
{ {
LLVMJitHandle *jit_handle; LLVMJitHandle *jit_handle = (LLVMJitHandle *) lfirst(lc);
jit_handle = (LLVMJitHandle *) linitial(llvm_context->handles);
llvm_context->handles = list_delete_first(llvm_context->handles);
#if LLVM_VERSION_MAJOR > 11 #if LLVM_VERSION_MAJOR > 11
{ {
...@@ -221,6 +219,8 @@ llvm_release_context(JitContext *context) ...@@ -221,6 +219,8 @@ llvm_release_context(JitContext *context)
pfree(jit_handle); pfree(jit_handle);
} }
list_free(llvm_context->handles);
llvm_context->handles = NIL;
} }
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment