const char *statfile = PGSTAT_STAT_PERMANENT_FILENAME;
dshash_seq_status hstat;
PgStatShared_HashEntry *ps;
+ PgStat_StatsFileOp status = STATS_WRITE;
pgstat_assert_is_up();
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);
+ if (kind_info->to_serialized_data &&
+ !kind_info->to_serialized_data(&ps->key, shstats, fpout))
+ {
+ status = STATS_DISCARD;
+ break;
+ }
}
dshash_seq_term(&hstat);
*/
fputc(PGSTAT_FILE_ENTRY_END, fpout);
- if (ferror(fpout))
+ if (status == STATS_DISCARD)
+ {
+ /*
+ * A to_serialized_data callback failed. DEBUG2 because the callback
+ * already logged the reason.
+ */
+ elog(DEBUG2, "discarding temporary statistics file \"%s\"", tmpfile);
+ FreeFile(fpout);
+ unlink(tmpfile);
+ }
+ else if (ferror(fpout))
{
ereport(LOG,
(errcode_for_file_access(),
tmpfile)));
FreeFile(fpout);
unlink(tmpfile);
+ status = STATS_DISCARD;
}
else if (FreeFile(fpout) < 0)
{
errmsg("could not close temporary statistics file \"%s\": %m",
tmpfile)));
unlink(tmpfile);
+ status = STATS_DISCARD;
}
else if (durable_rename(tmpfile, statfile, LOG) < 0)
{
/* durable_rename already emitted log message */
unlink(tmpfile);
+ status = STATS_DISCARD;
}
/* Finish callbacks, if required */
const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
if (kind_info && kind_info->finish)
- kind_info->finish(STATS_WRITE);
+ kind_info->finish(status);
}
}
FILE *fpin;
int32 format_id;
bool found;
+ PgStat_StatsFileOp status = STATS_READ;
const char *statfile = PGSTAT_STAT_PERMANENT_FILENAME;
PgStat_ShmemControl *shmem = pgStatLocal.shmem;
errmsg("could not open statistics file \"%s\": %m",
statfile)));
pgstat_reset_after_failure();
- return;
+ status = STATS_DISCARD;
+ goto finish;
}
/*
elog(DEBUG2, "removing permanent stats file \"%s\"", statfile);
unlink(statfile);
+finish:
/* 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);
+ kind_info->finish(status);
}
return;
(errmsg("corrupted statistics file \"%s\"", statfile)));
pgstat_reset_after_failure();
+ status = STATS_DISCARD;
goto done;
}
* an entry, in the stats file or optionally in a different file.
* Optional.
*
- * to_serialized_data: write auxiliary data for an entry.
+ * to_serialized_data: write auxiliary data for an entry. Returns true on
+ * success, false on write error.
*
* from_serialized_data: read auxiliary data for an entry. Returns true
* on success, false on read error.
* just written or read. "header" is a pointer to the stats data; it may
* be modified only in from_serialized_data to reconstruct an entry.
*/
- void (*to_serialized_data) (const PgStat_HashKey *key,
+ bool (*to_serialized_data) (const PgStat_HashKey *key,
const PgStatShared_Common *header,
FILE *statfile);
bool (*from_serialized_data) (const PgStat_HashKey *key,
);
/* Local helpers for stats file I/O */
-#define write_chunk(fpout, ptr, len) ((void) fwrite(ptr, len, 1, fpout))
+#define write_chunk(fpout, ptr, len) (fwrite(ptr, len, 1, fpout) == 1)
#define write_chunk_s(fpout, ptr) write_chunk(fpout, ptr, sizeof(*ptr))
#define read_chunk(fpin, ptr, len) (fread(ptr, 1, len, fpin) == (len))
#define read_chunk_s(fpin, ptr) read_chunk(fpin, ptr, sizeof(*ptr))
bool nowait);
/* Serialization callback: write auxiliary entry data */
-static void test_custom_stats_var_to_serialized_data(const PgStat_HashKey *key,
+static bool test_custom_stats_var_to_serialized_data(const PgStat_HashKey *key,
const PgStatShared_Common *header,
FILE *statfile);
* - The length of the description.
* - The description data itself.
*/
-static void
+static bool
test_custom_stats_var_to_serialized_data(const PgStat_HashKey *key,
const PgStatShared_Common *header,
FILE *statfile)
* First mark the main file with a magic number, keeping a trace that some
* auxiliary data will exist in the secondary statistics file.
*/
- write_chunk_s(statfile, &magic_number);
+ if (!write_chunk_s(statfile, &magic_number))
+ return false;
/* Open statistics file for writing. */
if (!fd_description)
(errcode_for_file_access(),
errmsg("could not open statistics file \"%s\" for writing: %m",
TEST_CUSTOM_AUX_DATA_DESC)));
- return;
+ return false;
}
/* Initialize offset for secondary statistics file. */
}
/* Write offset to the main data file */
- write_chunk_s(statfile, &fd_description_offset);
+ if (!write_chunk_s(statfile, &fd_description_offset))
+ return false;
/*
* First write the entry key to the secondary statistics file. This will
* be cross-checked with the key read from main stats file at loading
* time.
*/
- write_chunk_s(fd_description, (PgStat_HashKey *) key);
+ if (!write_chunk_s(fd_description, (PgStat_HashKey *) key))
+ return false;
fd_description_offset += sizeof(PgStat_HashKey);
if (!custom_stats_description_dsa)
{
/* length to description file */
len = 0;
- write_chunk_s(fd_description, &len);
+ if (!write_chunk_s(fd_description, &len))
+ return false;
fd_description_offset += sizeof(size_t);
- return;
+ return true;
}
/*
description = dsa_get_address(custom_stats_description_dsa,
entry->description);
len = strlen(description) + 1;
- write_chunk_s(fd_description, &len);
- write_chunk(fd_description, description, len);
+ if (!write_chunk_s(fd_description, &len))
+ return false;
+ if (!write_chunk(fd_description, description, len))
+ return false;
/*
* Update offset for next entry, counting for the length (size_t) of the
* description and the description contents.
*/
fd_description_offset += len + sizeof(size_t);
+ return true;
}
/*