From: Robert Haas Date: Thu, 3 Jul 2025 19:00:08 +0000 (-0400) Subject: trim shared advice X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=c00a8f2deb6186ec8585820e9d2cd63739ab18f9;p=users%2Frhaas%2Fpostgres.git trim shared advice --- diff --git a/contrib/pg_plan_advice/pgpa_collector.c b/contrib/pg_plan_advice/pgpa_collector.c index 89e14f5603..0bfb0fb85b 100644 --- a/contrib/pg_plan_advice/pgpa_collector.c +++ b/contrib/pg_plan_advice/pgpa_collector.c @@ -108,6 +108,7 @@ static pgpa_collected_advice *pgpa_make_collected_advice(Oid userid, static void pgpa_store_local_advice(pgpa_collected_advice *ca); static void pgpa_trim_local_advice(void); static void pgpa_store_shared_advice(dsa_pointer ca_pointer); +static void pgpa_trim_shared_advice(void); /* Helper function to extract the query string from pgpa_collected_advice */ static inline const char * @@ -145,7 +146,6 @@ pgpa_collect_advice(uint64 queryId, const char *query_string, query_string, advice_string, NULL, NULL); pgpa_store_local_advice(ca); - pgpa_trim_local_advice(); MemoryContextSwitchTo(oldcontext); } @@ -255,6 +255,9 @@ pgpa_store_local_advice(pgpa_collected_advice *ca) Assert(la->chunks[chunk_number]->entries[chunk_offset] == NULL); la->chunks[chunk_number]->entries[chunk_offset] = ca; ++la->next_id; + + /* If we've exceeded the storage limit, discard old data. */ + pgpa_trim_local_advice(); } /* @@ -392,9 +395,70 @@ pgpa_store_shared_advice(dsa_pointer ca_pointer) chunk->entries[chunk_offset] = ca_pointer; ++sa->next_id; + /* If we've exceeded the storage limit, discard old data. */ + pgpa_trim_shared_advice(); + /* Release lock on shared state. */ LWLockRelease(&state->lock); +} + +/* + * Remove shared advice in excess of pg_plan_advice.shared_collection_limit. + */ +static void +pgpa_trim_shared_advice(void) +{ + dsa_area *area = pg_plan_advice_dsa_area(); + pgpa_shared_advice *sa = shared_collector; + uint64 current_count; + uint64 trim_count; + uint64 total_chunk_count; + uint64 trim_chunk_count; + uint64 remaining_chunk_count; + dsa_pointer *chunk_array; + + /* If we haven't yet reached the limit, there's nothing to do. */ + current_count = sa->next_id - sa->oldest_id; + if (current_count < pg_plan_advice_shared_collection_limit) + return; + + /* Get a pointer to the chunk array. */ + chunk_array = dsa_get_address(area, sa->chunks); + + /* Free enough entries to get us back down to the limit. */ + trim_count = current_count - pg_plan_advice_shared_collection_limit; + while (trim_count > 0) + { + uint64 chunk_number; + uint64 chunk_offset; + pgpa_shared_advice_chunk *chunk; + + chunk_number = (sa->oldest_id - sa->base_id) / ADVICE_CHUNK_SIZE; + chunk_offset = (sa->oldest_id - sa->base_id) % ADVICE_CHUNK_SIZE; + + chunk = dsa_get_address(area, chunk_array[chunk_number]); + Assert(chunk->entries[chunk_offset] != InvalidDsaPointer); + dsa_free(area, chunk->entries[chunk_offset]); + chunk->entries[chunk_offset] = InvalidDsaPointer; + ++sa->oldest_id; + --trim_count; + } + + /* Free any chunks that are now entirely unused. */ + trim_chunk_count = (sa->oldest_id - sa->base_id) / ADVICE_CHUNK_SIZE; + for (uint64 n = 0; n < trim_chunk_count; ++n) + dsa_free(area, chunk_array[n]); + /* Slide remaining chunk pointers back toward the base of the array. */ + total_chunk_count = (sa->next_id - sa->base_id + + ADVICE_CHUNK_SIZE - 1) / ADVICE_CHUNK_SIZE; + remaining_chunk_count = total_chunk_count - trim_chunk_count; + if (remaining_chunk_count > 0) + memmove(&chunk_array[0], &chunk_array[trim_chunk_count], + sizeof(dsa_pointer) * remaining_chunk_count); + + /* Adjust base ID value accordingly. */ + sa->base_id += trim_chunk_count * ADVICE_CHUNK_SIZE; } /* @@ -420,6 +484,7 @@ pg_get_collected_local_advice(PG_FUNCTION_ARGS) if (la == NULL) return (Datum) 0; + /* Loop over all entries. */ for (uint64 id = la->oldest_id; id < la->next_id; ++id) { uint64 chunk_number; @@ -457,6 +522,7 @@ pg_get_collected_shared_advice(PG_FUNCTION_ARGS) ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; pgpa_shared_state *state = pg_plan_advice_attach(); dsa_area *area = pg_plan_advice_dsa_area(); + dsa_pointer *chunk_array; pgpa_shared_advice *sa = shared_collector; InitMaterializedSRF(fcinfo, 0); @@ -479,11 +545,14 @@ pg_get_collected_shared_advice(PG_FUNCTION_ARGS) shared_collector = sa = dsa_get_address(area, state->shared_collector); } + /* Get a pointer to the chunk array. */ + chunk_array = dsa_get_address(area, sa->chunks); + + /* Loop over all entries. */ for (uint64 id = sa->oldest_id; id < sa->next_id; ++id) { uint64 chunk_number; uint64 chunk_offset; - dsa_pointer *chunk_array; pgpa_shared_advice_chunk *chunk; pgpa_collected_advice *ca; Datum values[PG_GET_ADVICE_COLUMNS]; @@ -492,7 +561,6 @@ pg_get_collected_shared_advice(PG_FUNCTION_ARGS) chunk_number = (id - sa->base_id) / ADVICE_CHUNK_SIZE; chunk_offset = (id - sa->base_id) % ADVICE_CHUNK_SIZE; - chunk_array = dsa_get_address(area, sa->chunks); chunk = dsa_get_address(area, chunk_array[chunk_number]); ca = dsa_get_address(area, chunk->entries[chunk_offset]);