aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/xlogfuncs.c
diff options
context:
space:
mode:
authorMagnus Hagander <magnus@hagander.net>2012-03-04 12:15:24 +0100
committerMagnus Hagander <magnus@hagander.net>2012-03-04 12:22:38 +0100
commitbc5ac3686580079bd4ea26bf027178786d77a9ee (patch)
treee8ba991d3227149fb636a1f0f00d6c8597035ac9 /src/backend/access/transam/xlogfuncs.c
parent0e5e167aaea4ceb355a6e20eec96c4f7d05527ab (diff)
downloadpostgresql-bc5ac3686580079bd4ea26bf027178786d77a9ee.tar.gz
postgresql-bc5ac3686580079bd4ea26bf027178786d77a9ee.zip
Add function pg_xlog_location_diff to help comparisons
Comparing two xlog locations are useful for example when calculating replication lag. Euler Taveira de Oliveira, reviewed by Fujii Masao, and some cleanups from me
Diffstat (limited to 'src/backend/access/transam/xlogfuncs.c')
-rw-r--r--src/backend/access/transam/xlogfuncs.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 2e10d4d15f7..08b5724b97e 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -26,6 +26,7 @@
#include "replication/walreceiver.h"
#include "storage/smgr.h"
#include "utils/builtins.h"
+#include "utils/numeric.h"
#include "utils/guc.h"
#include "utils/timestamp.h"
@@ -465,3 +466,92 @@ pg_is_in_recovery(PG_FUNCTION_ARGS)
{
PG_RETURN_BOOL(RecoveryInProgress());
}
+
+/*
+ * Validate the text form of a transaction log location.
+ * (Just using sscanf() input allows incorrect values such as
+ * negatives, so we have to be a bit more careful about that).
+ */
+static void
+validate_xlog_location(char *str)
+{
+#define MAXLSNCOMPONENT 8
+
+ int len1,
+ len2;
+
+ len1 = strspn(str, "0123456789abcdefABCDEF");
+ if (len1 < 1 || len1 > MAXLSNCOMPONENT || str[len1] != '/')
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for transaction log location: \"%s\"", str)));
+
+ len2 = strspn(str + len1 + 1, "0123456789abcdefABCDEF");
+ if (len2 < 1 || len2 > MAXLSNCOMPONENT || str[len1 + 1 + len2] != '\0')
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for transaction log location: \"%s\"", str)));
+}
+
+/*
+ * Compute the difference in bytes between two WAL locations.
+ */
+Datum
+pg_xlog_location_diff(PG_FUNCTION_ARGS)
+{
+ text *location1 = PG_GETARG_TEXT_P(0);
+ text *location2 = PG_GETARG_TEXT_P(1);
+ char *str1,
+ *str2;
+ XLogRecPtr loc1,
+ loc2;
+ Numeric result;
+
+ /*
+ * Read and parse input
+ */
+ str1 = text_to_cstring(location1);
+ str2 = text_to_cstring(location2);
+
+ validate_xlog_location(str1);
+ validate_xlog_location(str2);
+
+ if (sscanf(str1, "%X/%X", &loc1.xlogid, &loc1.xrecoff) != 2)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not parse transaction log location \"%s\"", str1)));
+ if (sscanf(str2, "%X/%X", &loc2.xlogid, &loc2.xrecoff) != 2)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not parse transaction log location \"%s\"", str2)));
+
+ /*
+ * Sanity check
+ */
+ if (loc1.xrecoff > XLogFileSize)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("xrecoff \"%X\" is out of valid range, 0..%X", loc1.xrecoff, XLogFileSize)));
+ if (loc2.xrecoff > XLogFileSize)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("xrecoff \"%X\" is out of valid range, 0..%X", loc2.xrecoff, XLogFileSize)));
+
+ /*
+ * result = XLogFileSize * (xlogid1 - xlogid2) + xrecoff1 - xrecoff2
+ */
+ result = DatumGetNumeric(DirectFunctionCall2(numeric_sub,
+ DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) loc1.xlogid)),
+ DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) loc2.xlogid))));
+ result = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
+ DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) XLogFileSize)),
+ NumericGetDatum(result)));
+ result = DatumGetNumeric(DirectFunctionCall2(numeric_add,
+ NumericGetDatum(result),
+ DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) loc1.xrecoff))));
+ result = DatumGetNumeric(DirectFunctionCall2(numeric_sub,
+ NumericGetDatum(result),
+ DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) loc2.xrecoff))));
+
+ PG_RETURN_NUMERIC(result);
+}