]> granicus.if.org Git - postgresql/commitdiff
Add function pg_xlog_location_diff to help comparisons
authorMagnus Hagander <magnus@hagander.net>
Sun, 4 Mar 2012 11:15:24 +0000 (12:15 +0100)
committerMagnus Hagander <magnus@hagander.net>
Sun, 4 Mar 2012 11:22:38 +0000 (12:22 +0100)
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

doc/src/sgml/func.sgml
src/backend/access/transam/xlogfuncs.c
src/include/access/xlog_internal.h
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h

index 5c1cff3618d529ead6138c64a54c45f288718225..34fea16eeeeb58d2c76d1e028eadd3f46e834c3f 100644 (file)
@@ -14475,11 +14475,15 @@ SELECT set_config('log_statement_stats', 'off', false);
    <indexterm>
     <primary>pg_xlogfile_name_offset</primary>
    </indexterm>
+   <indexterm>
+    <primary>pg_xlog_location_diff</primary>
+   </indexterm>
 
    <para>
     The functions shown in <xref
     linkend="functions-admin-backup-table"> assist in making on-line backups.
-    These functions cannot be executed during recovery.
+    These functions cannot be executed during recovery (except
+    <function>pg_xlog_location_diff</function>).
    </para>
 
    <table id="functions-admin-backup-table">
@@ -14547,6 +14551,13 @@ SELECT set_config('log_statement_stats', 'off', false);
        <entry><type>text</>, <type>integer</></entry>
        <entry>Convert transaction log location string to file name and decimal byte offset within file</entry>
       </row>
+      <row>
+       <entry>
+        <literal><function>pg_xlog_location_diff(<parameter>location</> <type>text</>, <parameter>location</> <type>text</>)</function></literal>
+       </entry>
+       <entry><type>numeric</></entry>
+       <entry>Calculate the difference between two transaction log locations</entry>
+      </row>
      </tbody>
     </tgroup>
    </table>
@@ -14639,6 +14650,13 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
     needs to be archived.
    </para>
 
+   <para>
+    <function>pg_xlog_location_diff</> calculates the difference in bytes
+    between two transaction log locations. It can be used with
+    <structname>pg_stat_replication</structname> or some functions shown in
+    <xref linkend="functions-admin-backup-table"> to get the replication lag.
+   </para>
+
    <para>
     For details about proper usage of these functions, see
     <xref linkend="continuous-archiving">.
index 2e10d4d15f742cfa82ff1899cb364a659ba4143e..08b5724b97e7b47617b30c2af8691cf2ef554287 100644 (file)
@@ -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);
+}
index b81c15688182baa1fe23e9be429bb981d0da129e..c079a9aa8f555c87c10efaa484d77c331d3edebd 100644 (file)
@@ -281,5 +281,6 @@ extern Datum pg_is_in_recovery(PG_FUNCTION_ARGS);
 extern Datum pg_xlog_replay_pause(PG_FUNCTION_ARGS);
 extern Datum pg_xlog_replay_resume(PG_FUNCTION_ARGS);
 extern Datum pg_is_xlog_replay_paused(PG_FUNCTION_ARGS);
+extern Datum pg_xlog_location_diff(PG_FUNCTION_ARGS);
 
 #endif   /* XLOG_INTERNAL_H */
index 223f157310b6da6cacfce57bc61b15640477bd7e..993e3872c7b76fd753a848ab805a40074dab5b72 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201203031
+#define CATALOG_VERSION_NO     201203041
 
 #endif
index 074051bdcc6a939bc6266e0dfa74f0c3d56c996a..2db848903c4a2de8de76d30c556dd962d2fce5b3 100644 (file)
@@ -2936,6 +2936,9 @@ DESCR("xlog filename and byte offset, given an xlog location");
 DATA(insert OID = 2851 ( pg_xlogfile_name                      PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "25" _null_ _null_ _null_ _null_ pg_xlogfile_name _null_ _null_ _null_ ));
 DESCR("xlog filename, given an xlog location");
 
+DATA(insert OID = 3165 ( pg_xlog_location_diff         PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1700 "25 25" _null_ _null_ _null_ _null_ pg_xlog_location_diff _null_ _null_ _null_ ));
+DESCR("difference in bytes, given two xlog locations");
+
 DATA(insert OID = 3809 ( pg_export_snapshot            PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ pg_export_snapshot _null_ _null_ _null_ ));
 DESCR("export a snapshot");