#include "utils/builtins.h"
#include "utils/timestamp.h"
+PG_FUNCTION_INFO_V1(pg_clear_collected_local_advice);
+PG_FUNCTION_INFO_V1(pg_clear_collected_shared_advice);
PG_FUNCTION_INFO_V1(pg_get_collected_local_advice);
PG_FUNCTION_INFO_V1(pg_get_collected_shared_advice);
dsa_area *area,
dsa_pointer *result);
static void pgpa_store_local_advice(pgpa_collected_advice *ca);
-static void pgpa_trim_local_advice(void);
+static void pgpa_trim_local_advice(int limit);
static void pgpa_store_shared_advice(dsa_pointer ca_pointer);
-static void pgpa_trim_shared_advice(void);
+static void pgpa_trim_shared_advice(int limit);
/* Helper function to extract the query string from pgpa_collected_advice */
static inline const char *
++la->next_id;
/* If we've exceeded the storage limit, discard old data. */
- pgpa_trim_local_advice();
-}
-
-/*
- * Remove local advice in excess of pg_plan_advice.local_collection_limit.
- */
-static void
-pgpa_trim_local_advice(void)
-{
- pgpa_local_advice *la = local_collector;
- uint64 current_count;
- uint64 trim_count;
- uint64 total_chunk_count;
- uint64 trim_chunk_count;
- uint64 remaining_chunk_count;
-
- /* If we haven't yet reached the limit, there's nothing to do. */
- current_count = la->next_id - la->oldest_id;
- if (current_count < pg_plan_advice_local_collection_limit)
- return;
-
- /* Free enough entries to get us back down to the limit. */
- trim_count = current_count - pg_plan_advice_local_collection_limit;
- while (trim_count > 0)
- {
- uint64 chunk_number;
- uint64 chunk_offset;
-
- chunk_number = (la->oldest_id - la->base_id) / ADVICE_CHUNK_SIZE;
- chunk_offset = (la->oldest_id - la->base_id) % ADVICE_CHUNK_SIZE;
-
- Assert(la->chunks[chunk_number]->entries[chunk_offset] != NULL);
- pfree(la->chunks[chunk_number]->entries[chunk_offset]);
- la->chunks[chunk_number]->entries[chunk_offset] = NULL;
- ++la->oldest_id;
- --trim_count;
- }
-
- /* Free any chunks that are now entirely unused. */
- trim_chunk_count = (la->oldest_id - la->base_id) / ADVICE_CHUNK_SIZE;
- for (uint64 n = 0; n < trim_chunk_count; ++n)
- pfree(la->chunks[n]);
-
- /* Slide remaining chunk pointers back toward the base of the array. */
- total_chunk_count = (la->next_id - la->base_id +
- ADVICE_CHUNK_SIZE - 1) / ADVICE_CHUNK_SIZE;
- remaining_chunk_count = total_chunk_count - trim_chunk_count;
- if (remaining_chunk_count > 0)
- memmove(&la->chunks[0], &la->chunks[trim_chunk_count],
- sizeof(pgpa_local_advice_chunk *) * remaining_chunk_count);
-
- /* Adjust base ID value accordingly. */
- la->base_id += trim_chunk_count * ADVICE_CHUNK_SIZE;
+ pgpa_trim_local_advice(pg_plan_advice_local_collection_limit);
}
/*
++sa->next_id;
/* If we've exceeded the storage limit, discard old data. */
- pgpa_trim_shared_advice();
+ pgpa_trim_shared_advice(pg_plan_advice_shared_collection_limit);
/* Release lock on shared state. */
LWLockRelease(&state->lock);
}
/*
- * Remove shared advice in excess of pg_plan_advice.shared_collection_limit.
+ * Discard collected advice stored in backend-local memory in excess of the
+ * specified limit.
+ */
+static void
+pgpa_trim_local_advice(int limit)
+{
+ pgpa_local_advice *la = local_collector;
+ uint64 current_count;
+ uint64 trim_count;
+ uint64 total_chunk_count;
+ uint64 trim_chunk_count;
+ uint64 remaining_chunk_count;
+
+ /* If we haven't yet reached the limit, there's nothing to do. */
+ current_count = la->next_id - la->oldest_id;
+ if (current_count <= limit)
+ return;
+
+ /* Free enough entries to get us back down to the limit. */
+ trim_count = current_count - limit;
+ while (trim_count > 0)
+ {
+ uint64 chunk_number;
+ uint64 chunk_offset;
+
+ chunk_number = (la->oldest_id - la->base_id) / ADVICE_CHUNK_SIZE;
+ chunk_offset = (la->oldest_id - la->base_id) % ADVICE_CHUNK_SIZE;
+
+ Assert(la->chunks[chunk_number]->entries[chunk_offset] != NULL);
+ pfree(la->chunks[chunk_number]->entries[chunk_offset]);
+ la->chunks[chunk_number]->entries[chunk_offset] = NULL;
+ ++la->oldest_id;
+ --trim_count;
+ }
+
+ /* Free any chunks that are now entirely unused. */
+ trim_chunk_count = (la->oldest_id - la->base_id) / ADVICE_CHUNK_SIZE;
+ for (uint64 n = 0; n < trim_chunk_count; ++n)
+ pfree(la->chunks[n]);
+
+ /* Slide remaining chunk pointers back toward the base of the array. */
+ total_chunk_count = (la->next_id - la->base_id +
+ ADVICE_CHUNK_SIZE - 1) / ADVICE_CHUNK_SIZE;
+ remaining_chunk_count = total_chunk_count - trim_chunk_count;
+ if (remaining_chunk_count > 0)
+ memmove(&la->chunks[0], &la->chunks[trim_chunk_count],
+ sizeof(pgpa_local_advice_chunk *) * remaining_chunk_count);
+
+ /* Adjust base ID value accordingly. */
+ la->base_id += trim_chunk_count * ADVICE_CHUNK_SIZE;
+}
+
+/*
+ * Discard collected advice stored in shared memory in excess of the
+ * specified limit.
*/
static void
-pgpa_trim_shared_advice(void)
+pgpa_trim_shared_advice(int limit)
{
dsa_area *area = pg_plan_advice_dsa_area();
pgpa_shared_advice *sa = shared_collector;
/* 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)
+ if (current_count <= 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;
+ trim_count = current_count - limit;
while (trim_count > 0)
{
uint64 chunk_number;
}
/*
- * SQL-callable SRF to return locally collected advice
+ * SQL-callable function to discard advice collected in backend-local memory
+ */
+Datum
+pg_clear_collected_local_advice(PG_FUNCTION_ARGS)
+{
+ pgpa_trim_local_advice(0);
+
+ PG_RETURN_VOID();
+}
+
+/*
+ * SQL-callable function to discard advice collected in backend-local memory
+ */
+Datum
+pg_clear_collected_shared_advice(PG_FUNCTION_ARGS)
+{
+ pgpa_shared_state *state = pg_plan_advice_attach();
+
+ LWLockAcquire(&state->lock, LW_EXCLUSIVE);
+ pgpa_trim_shared_advice(0);
+ LWLockRelease(&state->lock);
+
+ PG_RETURN_VOID();
+}
+
+/*
+ * SQL-callable SRF to return advice collected in backend-local memory
*/
Datum
pg_get_collected_local_advice(PG_FUNCTION_ARGS)
}
/*
- * SQL-callable SRF to return locally collected advice
+ * SQL-callable SRF to return advice collected in shared memory
*/
Datum
pg_get_collected_shared_advice(PG_FUNCTION_ARGS)