mirror of
https://github.com/postgres/postgres.git
synced 2025-07-27 12:41:57 +03:00
Add contrib/pg_logicalinspect.
This module provides SQL functions that allow to inspect logical decoding components. It currently allows to inspect the contents of serialized logical snapshots of a running database cluster, which is useful for debugging or educational purposes. Author: Bertrand Drouvot Reviewed-by: Amit Kapila, Shveta Malik, Peter Smith, Peter Eisentraut Reviewed-by: David G. Johnston Discussion: https://postgr.es/m/ZscuZ92uGh3wm4tW%40ip-10-97-1-34.eu-west-3.compute.internal
This commit is contained in:
@ -1684,34 +1684,31 @@ out:
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore a snapshot into 'builder' if previously one has been stored at the
|
||||
* location indicated by 'lsn'. Returns true if successful, false otherwise.
|
||||
* Restore the logical snapshot file contents to 'ondisk'.
|
||||
*
|
||||
* 'context' is the memory context where the catalog modifying/committed xid
|
||||
* will live.
|
||||
* If 'missing_ok' is true, will not throw an error if the file is not found.
|
||||
*/
|
||||
static bool
|
||||
SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
|
||||
bool
|
||||
SnapBuildRestoreSnapshot(SnapBuildOnDisk *ondisk, const char *path,
|
||||
MemoryContext context, bool missing_ok)
|
||||
{
|
||||
SnapBuildOnDisk ondisk;
|
||||
int fd;
|
||||
char path[MAXPGPATH];
|
||||
Size sz;
|
||||
pg_crc32c checksum;
|
||||
|
||||
/* no point in loading a snapshot if we're already there */
|
||||
if (builder->state == SNAPBUILD_CONSISTENT)
|
||||
return false;
|
||||
|
||||
sprintf(path, "%s/%X-%X.snap",
|
||||
PG_LOGICAL_SNAPSHOTS_DIR,
|
||||
LSN_FORMAT_ARGS(lsn));
|
||||
Size sz;
|
||||
|
||||
fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
|
||||
|
||||
if (fd < 0 && errno == ENOENT)
|
||||
return false;
|
||||
else if (fd < 0)
|
||||
if (fd < 0)
|
||||
{
|
||||
if (missing_ok && errno == ENOENT)
|
||||
return false;
|
||||
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not open file \"%s\": %m", path)));
|
||||
}
|
||||
|
||||
/* ----
|
||||
* Make sure the snapshot had been stored safely to disk, that's normally
|
||||
@ -1724,47 +1721,46 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
|
||||
fsync_fname(path, false);
|
||||
fsync_fname(PG_LOGICAL_SNAPSHOTS_DIR, true);
|
||||
|
||||
|
||||
/* read statically sized portion of snapshot */
|
||||
SnapBuildRestoreContents(fd, (char *) &ondisk, SnapBuildOnDiskConstantSize, path);
|
||||
SnapBuildRestoreContents(fd, (char *) ondisk, SnapBuildOnDiskConstantSize, path);
|
||||
|
||||
if (ondisk.magic != SNAPBUILD_MAGIC)
|
||||
if (ondisk->magic != SNAPBUILD_MAGIC)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATA_CORRUPTED),
|
||||
errmsg("snapbuild state file \"%s\" has wrong magic number: %u instead of %u",
|
||||
path, ondisk.magic, SNAPBUILD_MAGIC)));
|
||||
path, ondisk->magic, SNAPBUILD_MAGIC)));
|
||||
|
||||
if (ondisk.version != SNAPBUILD_VERSION)
|
||||
if (ondisk->version != SNAPBUILD_VERSION)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATA_CORRUPTED),
|
||||
errmsg("snapbuild state file \"%s\" has unsupported version: %u instead of %u",
|
||||
path, ondisk.version, SNAPBUILD_VERSION)));
|
||||
path, ondisk->version, SNAPBUILD_VERSION)));
|
||||
|
||||
INIT_CRC32C(checksum);
|
||||
COMP_CRC32C(checksum,
|
||||
((char *) &ondisk) + SnapBuildOnDiskNotChecksummedSize,
|
||||
((char *) ondisk) + SnapBuildOnDiskNotChecksummedSize,
|
||||
SnapBuildOnDiskConstantSize - SnapBuildOnDiskNotChecksummedSize);
|
||||
|
||||
/* read SnapBuild */
|
||||
SnapBuildRestoreContents(fd, (char *) &ondisk.builder, sizeof(SnapBuild), path);
|
||||
COMP_CRC32C(checksum, &ondisk.builder, sizeof(SnapBuild));
|
||||
SnapBuildRestoreContents(fd, (char *) &ondisk->builder, sizeof(SnapBuild), path);
|
||||
COMP_CRC32C(checksum, &ondisk->builder, sizeof(SnapBuild));
|
||||
|
||||
/* restore committed xacts information */
|
||||
if (ondisk.builder.committed.xcnt > 0)
|
||||
if (ondisk->builder.committed.xcnt > 0)
|
||||
{
|
||||
sz = sizeof(TransactionId) * ondisk.builder.committed.xcnt;
|
||||
ondisk.builder.committed.xip = MemoryContextAllocZero(builder->context, sz);
|
||||
SnapBuildRestoreContents(fd, (char *) ondisk.builder.committed.xip, sz, path);
|
||||
COMP_CRC32C(checksum, ondisk.builder.committed.xip, sz);
|
||||
sz = sizeof(TransactionId) * ondisk->builder.committed.xcnt;
|
||||
ondisk->builder.committed.xip = MemoryContextAllocZero(context, sz);
|
||||
SnapBuildRestoreContents(fd, (char *) ondisk->builder.committed.xip, sz, path);
|
||||
COMP_CRC32C(checksum, ondisk->builder.committed.xip, sz);
|
||||
}
|
||||
|
||||
/* restore catalog modifying xacts information */
|
||||
if (ondisk.builder.catchange.xcnt > 0)
|
||||
if (ondisk->builder.catchange.xcnt > 0)
|
||||
{
|
||||
sz = sizeof(TransactionId) * ondisk.builder.catchange.xcnt;
|
||||
ondisk.builder.catchange.xip = MemoryContextAllocZero(builder->context, sz);
|
||||
SnapBuildRestoreContents(fd, (char *) ondisk.builder.catchange.xip, sz, path);
|
||||
COMP_CRC32C(checksum, ondisk.builder.catchange.xip, sz);
|
||||
sz = sizeof(TransactionId) * ondisk->builder.catchange.xcnt;
|
||||
ondisk->builder.catchange.xip = MemoryContextAllocZero(context, sz);
|
||||
SnapBuildRestoreContents(fd, (char *) ondisk->builder.catchange.xip, sz, path);
|
||||
COMP_CRC32C(checksum, ondisk->builder.catchange.xip, sz);
|
||||
}
|
||||
|
||||
if (CloseTransientFile(fd) != 0)
|
||||
@ -1775,11 +1771,36 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
|
||||
FIN_CRC32C(checksum);
|
||||
|
||||
/* verify checksum of what we've read */
|
||||
if (!EQ_CRC32C(checksum, ondisk.checksum))
|
||||
if (!EQ_CRC32C(checksum, ondisk->checksum))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATA_CORRUPTED),
|
||||
errmsg("checksum mismatch for snapbuild state file \"%s\": is %u, should be %u",
|
||||
path, checksum, ondisk.checksum)));
|
||||
path, checksum, ondisk->checksum)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore a snapshot into 'builder' if previously one has been stored at the
|
||||
* location indicated by 'lsn'. Returns true if successful, false otherwise.
|
||||
*/
|
||||
static bool
|
||||
SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
|
||||
{
|
||||
SnapBuildOnDisk ondisk;
|
||||
char path[MAXPGPATH];
|
||||
|
||||
/* no point in loading a snapshot if we're already there */
|
||||
if (builder->state == SNAPBUILD_CONSISTENT)
|
||||
return false;
|
||||
|
||||
sprintf(path, "%s/%X-%X.snap",
|
||||
PG_LOGICAL_SNAPSHOTS_DIR,
|
||||
LSN_FORMAT_ARGS(lsn));
|
||||
|
||||
/* validate and restore the snapshot to 'ondisk' */
|
||||
if (!SnapBuildRestoreSnapshot(&ondisk, path, builder->context, true))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* ok, we now have a sensible snapshot here, figure out if it has more
|
||||
|
Reference in New Issue
Block a user