🌐 AI搜索 & 代理 主页
Skip to content

Commit 4ba012a

Browse files
committed
Allow cumulative statistics to read/write auxiliary data from/to disk
Cumulative stats kinds gain the capability to write additional per-entry data when flushing the stats at shutdown, and read this data when loading back the stats at startup. This can be fit for example in the case of variable-length data (like normalized query strings), so as it becomes possible to link the shared memory stats entries to data that is stored in a different area, like a DSA segment. Three new optional callbacks are added to PgStat_KindInfo, available to variable-numbered stats kinds: * to_serialized_data: writes auxiliary data for an entry. * from_serialized_data: reads auxiliary data for an entry. * finish: performs actions after read/write/discard operations. This is invoked after processing all the entries of a kind, allowing extensions to close file handles and clean up resources. Stats kinds have the option to store this data in the existing pgstats file, but can as well store it in one or more additional files whose names can be built upon the entry keys. The new serialized callbacks are called once an entry key is read or written from the main stats file. A file descriptor to the main pgstats file is available in the arguments of the callbacks. Author: Sami Imseih <samimseih@gmail.com> Co-authored-by: Michael Paquier <michael@paquier.xyz> Reviewed-by: Chao Li <li.evan.chao@gmail.com> Discussion: https://postgr.es/m/CAA5RZ0s9SDOu+Z6veoJCHWk+kDeTktAtC-KY9fQ9Z6BJdDUirQ@mail.gmail.com
1 parent 58dad7f commit 4ba012a

File tree

3 files changed

+95
-2
lines changed

3 files changed

+95
-2
lines changed

src/backend/utils/activity/pgstat.c

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ pgstat_discard_stats(void)
523523

524524
/* NB: this needs to be done even in single user mode */
525525

526+
/* First, cleanup the main pgstats file */
526527
ret = unlink(PGSTAT_STAT_PERMANENT_FILENAME);
527528
if (ret != 0)
528529
{
@@ -544,6 +545,15 @@ pgstat_discard_stats(void)
544545
PGSTAT_STAT_PERMANENT_FILENAME)));
545546
}
546547

548+
/* Finish callbacks, if required */
549+
for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
550+
{
551+
const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
552+
553+
if (kind_info && kind_info->finish)
554+
kind_info->finish(STATS_DISCARD);
555+
}
556+
547557
/*
548558
* Reset stats contents. This will set reset timestamps of fixed-numbered
549559
* stats to the current time (no variable stats exist).
@@ -1702,6 +1712,10 @@ pgstat_write_statsfile(void)
17021712
pgstat_write_chunk(fpout,
17031713
pgstat_get_entry_data(ps->key.kind, shstats),
17041714
pgstat_get_entry_len(ps->key.kind));
1715+
1716+
/* Write more data for the entry, if required */
1717+
if (kind_info->to_serialized_data)
1718+
kind_info->to_serialized_data(&ps->key, shstats, fpout);
17051719
}
17061720
dshash_seq_term(&hstat);
17071721

@@ -1734,6 +1748,15 @@ pgstat_write_statsfile(void)
17341748
/* durable_rename already emitted log message */
17351749
unlink(tmpfile);
17361750
}
1751+
1752+
/* Finish callbacks, if required */
1753+
for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
1754+
{
1755+
const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
1756+
1757+
if (kind_info && kind_info->finish)
1758+
kind_info->finish(STATS_WRITE);
1759+
}
17371760
}
17381761

17391762
/* helper for pgstat_read_statsfile() */
@@ -1871,6 +1894,7 @@ pgstat_read_statsfile(void)
18711894
PgStat_HashKey key;
18721895
PgStatShared_HashEntry *p;
18731896
PgStatShared_Common *header;
1897+
const PgStat_KindInfo *kind_info = NULL;
18741898

18751899
CHECK_FOR_INTERRUPTS();
18761900

@@ -1891,7 +1915,8 @@ pgstat_read_statsfile(void)
18911915
goto error;
18921916
}
18931917

1894-
if (!pgstat_get_kind_info(key.kind))
1918+
kind_info = pgstat_get_kind_info(key.kind);
1919+
if (!kind_info)
18951920
{
18961921
elog(WARNING, "could not find information of kind for entry %u/%u/%" PRIu64 " of type %c",
18971922
key.kind, key.dboid,
@@ -1902,7 +1927,6 @@ pgstat_read_statsfile(void)
19021927
else
19031928
{
19041929
/* stats entry identified by name on disk (e.g. slots) */
1905-
const PgStat_KindInfo *kind_info = NULL;
19061930
PgStat_Kind kind;
19071931
NameData name;
19081932

@@ -1996,6 +2020,18 @@ pgstat_read_statsfile(void)
19962020
goto error;
19972021
}
19982022

2023+
/* read more data for the entry, if required */
2024+
if (kind_info->from_serialized_data)
2025+
{
2026+
if (!kind_info->from_serialized_data(&key, header, fpin))
2027+
{
2028+
elog(WARNING, "could not read auxiliary data for entry %u/%u/%" PRIu64 " of type %c",
2029+
key.kind, key.dboid,
2030+
key.objid, t);
2031+
goto error;
2032+
}
2033+
}
2034+
19992035
break;
20002036
}
20012037
case PGSTAT_FILE_ENTRY_END:
@@ -2019,11 +2055,21 @@ pgstat_read_statsfile(void)
20192055
}
20202056

20212057
done:
2058+
/* First, cleanup the main stats file */
20222059
FreeFile(fpin);
20232060

20242061
elog(DEBUG2, "removing permanent stats file \"%s\"", statfile);
20252062
unlink(statfile);
20262063

2064+
/* Finish callbacks, if required */
2065+
for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
2066+
{
2067+
const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
2068+
2069+
if (kind_info && kind_info->finish)
2070+
kind_info->finish(STATS_READ);
2071+
}
2072+
20272073
return;
20282074

20292075
error:

src/include/utils/pgstat_internal.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,20 @@ typedef struct PgStat_HashKey
6363
* identifier. */
6464
} PgStat_HashKey;
6565

66+
/*
67+
* Tracks if the stats file is being read, written or discarded, used in
68+
* combination with the finish callback.
69+
*
70+
* These states allow plugins that create auxiliary data files to determine
71+
* the current operation and perform any necessary file cleanup.
72+
*/
73+
typedef enum PgStat_StatsFileOp
74+
{
75+
STATS_WRITE,
76+
STATS_READ,
77+
STATS_DISCARD,
78+
} PgStat_StatsFileOp;
79+
6680
/*
6781
* PgStat_HashKey should not have any padding. Checking that the structure
6882
* size matches with the sum of each field is a check simple enough to
@@ -303,6 +317,38 @@ typedef struct PgStat_KindInfo
303317
const PgStatShared_Common *header, NameData *name);
304318
bool (*from_serialized_name) (const NameData *name, PgStat_HashKey *key);
305319

320+
/*
321+
* For variable-numbered stats: read or write additional data related to
322+
* an entry, in the stats file or optionally in a different file.
323+
* Optional.
324+
*
325+
* to_serialized_data: write auxiliary data for an entry.
326+
*
327+
* from_serialized_data: read auxiliary data for an entry. Returns true
328+
* on success, false on read error.
329+
*
330+
* "statfile" is a pointer to the on-disk stats file, named
331+
* PGSTAT_STAT_PERMANENT_FILENAME. "key" is the hash key of the entry
332+
* just written or read. "header" is a pointer to the stats data.
333+
*/
334+
void (*to_serialized_data) (const PgStat_HashKey *key,
335+
const PgStatShared_Common *header,
336+
FILE *statfile);
337+
bool (*from_serialized_data) (const PgStat_HashKey *key,
338+
const PgStatShared_Common *header,
339+
FILE *statfile);
340+
341+
/*
342+
* For fixed-numbered or variable-numbered statistics.
343+
*
344+
* Perform custom actions when done processing the on-disk stats file
345+
* after all the stats entries have been processed. Optional.
346+
*
347+
* "status" tracks the operation done for the on-disk stats file (read,
348+
* write, discard).
349+
*/
350+
void (*finish) (PgStat_StatsFileOp status);
351+
306352
/*
307353
* For fixed-numbered statistics: Initialize shared memory state.
308354
*

src/tools/pgindent/typedefs.list

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2279,6 +2279,7 @@ PgStat_StatFuncEntry
22792279
PgStat_StatReplSlotEntry
22802280
PgStat_StatSubEntry
22812281
PgStat_StatTabEntry
2282+
PgStat_StatsFileOp
22822283
PgStat_SubXactStatus
22832284
PgStat_TableCounts
22842285
PgStat_TableStatus

0 commit comments

Comments
 (0)