#define STICKY_DECREASE_FACTOR (0.50) /* factor for sticky entries */
#define USAGE_DEALLOC_PERCENT 5 /* free this % of entries at once */
-/* In PostgreSQL 11, queryid becomes a uint64 internally.
- */
+/* In PostgreSQL 11, queryid becomes a uint64 internally. */
#if PG_VERSION_NUM >= 110000
typedef uint64 queryid_t;
#define PGSP_NO_QUERYID UINT64CONST(0)
} Counters;
/*
+ * Global statistics for pg_store_plans
+ */
+typedef struct pgspGlobalStats
+{
+ int64 dealloc; /* # of times entries were deallocated */
+ TimestampTz stats_reset; /* timestamp with all stats reset */
+} pgspGlobalStats;
+
+/*
* Statistics per plan
*
* NB: see the file read/write code before changing field order here.
Size extent; /* current extent of plan file */
int n_writers; /* number of active writers to query file */
int gc_count; /* plan file garbage collection cycle count */
+ pgspGlobalStats stats; /* global statistics for pgsp */
} pgspSharedState;
/*---- Local variables ----*/
Datum pg_store_plans_yamlplan(PG_FUNCTION_ARGS);
Datum pg_store_plans_xmlplan(PG_FUNCTION_ARGS);
Datum pg_store_plans_textplan(PG_FUNCTION_ARGS);
+Datum pg_store_plans_info(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(pg_store_plans_reset);
PG_FUNCTION_INFO_V1(pg_store_plans_hash_query);
PG_FUNCTION_INFO_V1(pg_store_plans_shorten);
PG_FUNCTION_INFO_V1(pg_store_plans_normalize);
PG_FUNCTION_INFO_V1(pg_store_plans_jsonplan);
-PG_FUNCTION_INFO_V1(pg_store_plans_textplan);
PG_FUNCTION_INFO_V1(pg_store_plans_yamlplan);
PG_FUNCTION_INFO_V1(pg_store_plans_xmlplan);
+PG_FUNCTION_INFO_V1(pg_store_plans_textplan);
+PG_FUNCTION_INFO_V1(pg_store_plans_info);
#if PG_VERSION_NUM < 130000
#define COMPTAG_TYPE char
&plan_storage,
PLAN_STORAGE_FILE,
plan_storage_options,
- PGC_USERSET,
+ PGC_POSTMASTER,
0,
NULL,
NULL,
{
bool found;
HASHCTL info;
- FILE *file;
+ FILE *file = NULL;
FILE *pfile = NULL;
uint32 header;
int32 num;
shared_state->extent = 0;
shared_state->n_writers = 0;
shared_state->gc_count = 0;
+ shared_state->stats.dealloc = 0;
+ shared_state->stats.stats_reset = GetCurrentTimestamp();
}
/* Be sure everyone agrees on the hash table entry size */
{
values[i++] = Int64GetDatumFast(queryid);
values[i++] = Int64GetDatumFast(planid);
+
+ /* fill queryid_stat_statements with the same value with queryid */
if (api_version == PGSP_V1_5)
- values[i++] = ObjectIdGetDatum(queryid);
+ values[i++] = Int64GetDatumFast(queryid);
}
else
{
- values[i++] = Int64GetDatumFast(0);
- values[i++] = Int64GetDatumFast(0);
+ nulls[i++] = true; /* queryid */
+ nulls[i++] = true; /* planid */
+
+ /* queryid_stat_statemetns*/
if (api_version == PGSP_V1_5)
- values[i++] = Int64GetDatumFast(0);
+ nulls[i++] = true;
}
if (is_allowed_role || entry->key.userid == userid)
mstr = pgsp_json_xmlize(pstr);
break;
default:
+ mstr = pstr;
break;
}
tuplestore_donestoring(tupstore);
}
+/* Number of output arguments (columns) for pg_stat_statements_info */
+#define PG_STORE_PLANS_INFO_COLS 2
+
+/*
+ * Return statistics of pg_stat_statements.
+ */
+Datum
+pg_store_plans_info(PG_FUNCTION_ARGS)
+{
+ pgspGlobalStats stats;
+ TupleDesc tupdesc;
+ Datum values[PG_STORE_PLANS_INFO_COLS];
+ bool nulls[PG_STORE_PLANS_INFO_COLS];
+
+ if (!shared_state || !hash_table)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("pg_store_plans must be loaded via shared_preload_libraries")));
+
+ /* Build a tuple descriptor for our result type */
+ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+ elog(ERROR, "return type must be a row type");
+
+ MemSet(values, 0, sizeof(values));
+ MemSet(nulls, 0, sizeof(nulls));
+
+ /* Read global statistics for pg_stat_statements */
+ {
+ volatile pgspSharedState *s = (volatile pgspSharedState *) shared_state;
+
+ SpinLockAcquire(&s->mutex);
+ stats = s->stats;
+ SpinLockRelease(&s->mutex);
+ }
+
+ values[0] = Int64GetDatum(stats.dealloc);
+ values[1] = TimestampTzGetDatum(stats.stats_reset);
+
+ PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+}
+
/*
* Estimate shared memory space needed.
*/
entries = palloc(hash_get_num_entries(hash_table) * sizeof(pgspEntry *));
i = 0;
+ tottextlen = 0;
+ nvalidtexts = 0;
+
hash_seq_init(&hash_seq, hash_table);
while ((entry = hash_seq_search(&hash_seq)) != NULL)
{
}
pfree(entries);
+
+ /* Increment the number of times entries are deallocated */
+ {
+ volatile pgspSharedState *s = (volatile pgspSharedState *) shared_state;
+
+ SpinLockAcquire(&s->mutex);
+ s->stats.dealloc += 1;
+ SpinLockRelease(&s->mutex);
+ }
}
/*
}
/*
+ * Reset global statistics for pg_store_plans.
+ */
+ {
+ volatile pgspSharedState *s = (volatile pgspSharedState *) shared_state;
+ TimestampTz stats_reset = GetCurrentTimestamp();
+
+ SpinLockAcquire(&s->mutex);
+ s->stats.dealloc = 0;
+ s->stats.stats_reset = stats_reset;
+ SpinLockRelease(&s->mutex);
+ }
+
+ /*
* Write new empty plan file, perhaps even creating a new one to recover
* if the file was missing.
*/