/* NB: this needs to be done even in single user mode */
+ /* First, cleanup the main pgstats file */
ret = unlink(PGSTAT_STAT_PERMANENT_FILENAME);
if (ret != 0)
{
PGSTAT_STAT_PERMANENT_FILENAME)));
}
+ /* Finish callbacks, if required */
+ for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
+ {
+ const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
+
+ if (kind_info && kind_info->finish)
+ kind_info->finish(STATS_DISCARD);
+ }
+
/*
* Reset stats contents. This will set reset timestamps of fixed-numbered
* stats to the current time (no variable stats exist).
pgstat_write_chunk(fpout,
pgstat_get_entry_data(ps->key.kind, shstats),
pgstat_get_entry_len(ps->key.kind));
+
+ /* Write more data for the entry, if required */
+ if (kind_info->to_serialized_data)
+ kind_info->to_serialized_data(&ps->key, shstats, fpout);
}
dshash_seq_term(&hstat);
/* durable_rename already emitted log message */
unlink(tmpfile);
}
+
+ /* Finish callbacks, if required */
+ for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
+ {
+ const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
+
+ if (kind_info && kind_info->finish)
+ kind_info->finish(STATS_WRITE);
+ }
}
/* helper for pgstat_read_statsfile() */
PgStat_HashKey key;
PgStatShared_HashEntry *p;
PgStatShared_Common *header;
+ const PgStat_KindInfo *kind_info = NULL;
CHECK_FOR_INTERRUPTS();
goto error;
}
- if (!pgstat_get_kind_info(key.kind))
+ kind_info = pgstat_get_kind_info(key.kind);
+ if (!kind_info)
{
elog(WARNING, "could not find information of kind for entry %u/%u/%" PRIu64 " of type %c",
key.kind, key.dboid,
else
{
/* stats entry identified by name on disk (e.g. slots) */
- const PgStat_KindInfo *kind_info = NULL;
PgStat_Kind kind;
NameData name;
goto error;
}
+ /* read more data for the entry, if required */
+ if (kind_info->from_serialized_data)
+ {
+ if (!kind_info->from_serialized_data(&key, header, fpin))
+ {
+ elog(WARNING, "could not read auxiliary data for entry %u/%u/%" PRIu64 " of type %c",
+ key.kind, key.dboid,
+ key.objid, t);
+ goto error;
+ }
+ }
+
break;
}
case PGSTAT_FILE_ENTRY_END:
}
done:
+ /* First, cleanup the main stats file */
FreeFile(fpin);
elog(DEBUG2, "removing permanent stats file \"%s\"", statfile);
unlink(statfile);
+ /* Finish callbacks, if required */
+ for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
+ {
+ const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
+
+ if (kind_info && kind_info->finish)
+ kind_info->finish(STATS_READ);
+ }
+
return;
error:
* identifier. */
} PgStat_HashKey;
+/*
+ * Tracks if the stats file is being read, written or discarded, used in
+ * combination with the finish callback.
+ *
+ * These states allow plugins that create auxiliary data files to determine
+ * the current operation and perform any necessary file cleanup.
+ */
+typedef enum PgStat_StatsFileOp
+{
+ STATS_WRITE,
+ STATS_READ,
+ STATS_DISCARD,
+} PgStat_StatsFileOp;
+
/*
* PgStat_HashKey should not have any padding. Checking that the structure
* size matches with the sum of each field is a check simple enough to
const PgStatShared_Common *header, NameData *name);
bool (*from_serialized_name) (const NameData *name, PgStat_HashKey *key);
+ /*
+ * For variable-numbered stats: read or write additional data related to
+ * an entry, in the stats file or optionally in a different file.
+ * Optional.
+ *
+ * to_serialized_data: write auxiliary data for an entry.
+ *
+ * from_serialized_data: read auxiliary data for an entry. Returns true
+ * on success, false on read error.
+ *
+ * "statfile" is a pointer to the on-disk stats file, named
+ * PGSTAT_STAT_PERMANENT_FILENAME. "key" is the hash key of the entry
+ * just written or read. "header" is a pointer to the stats data.
+ */
+ void (*to_serialized_data) (const PgStat_HashKey *key,
+ const PgStatShared_Common *header,
+ FILE *statfile);
+ bool (*from_serialized_data) (const PgStat_HashKey *key,
+ const PgStatShared_Common *header,
+ FILE *statfile);
+
+ /*
+ * For fixed-numbered or variable-numbered statistics.
+ *
+ * Perform custom actions when done processing the on-disk stats file
+ * after all the stats entries have been processed. Optional.
+ *
+ * "status" tracks the operation done for the on-disk stats file (read,
+ * write, discard).
+ */
+ void (*finish) (PgStat_StatsFileOp status);
+
/*
* For fixed-numbered statistics: Initialize shared memory state.
*