]> granicus.if.org Git - postgresql/commitdiff
Make abbreviated key comparisons for text a bit cheaper.
authorRobert Haas <rhaas@postgresql.org>
Fri, 9 Oct 2015 19:06:06 +0000 (15:06 -0400)
committerRobert Haas <rhaas@postgresql.org>
Fri, 9 Oct 2015 19:06:06 +0000 (15:06 -0400)
If we do some byte-swapping while abbreviating, we can do comparisons
using integer arithmetic rather than memcmp.

Peter Geoghegan, reviewed and slightly revised by me.

src/backend/utils/adt/varlena.c
src/include/port/pg_bswap.h

index 2fbbf5475ece78fe38086faded6fed64781a4950..49a4898987e9b5cad78f470bc47c67af236eb4cc 100644 (file)
@@ -26,6 +26,7 @@
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "parser/scansup.h"
+#include "port/pg_bswap.h"
 #include "regex/regex.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
@@ -1967,25 +1968,25 @@ done:
 static int
 bttextcmp_abbrev(Datum x, Datum y, SortSupport ssup)
 {
-       char       *a = (char *) &x;
-       char       *b = (char *) &y;
-       int                     result;
-
-       result = memcmp(a, b, sizeof(Datum));
-
        /*
-        * When result = 0, the core system will call bttextfastcmp_c() or
+        * When 0 is returned, the core system will call bttextfastcmp_c() or
         * bttextfastcmp_locale().  Even a strcmp() on two non-truncated strxfrm()
         * blobs cannot indicate *equality* authoritatively, for the same reason
         * that there is a strcoll() tie-breaker call to strcmp() in varstr_cmp().
         */
-       return result;
+       if (x > y)
+               return 1;
+       else if (x == y)
+               return 0;
+       else
+               return -1;
 }
 
 /*
  * Conversion routine for sortsupport.  Converts original text to abbreviated
  * key representation.  Our encoding strategy is simple -- pack the first 8
- * bytes of a strxfrm() blob into a Datum.
+ * bytes of a strxfrm() blob into a Datum (on little-endian machines, the 8
+ * bytes are stored in reverse order), and treat it as an unsigned integer.
  */
 static Datum
 bttext_abbrev_convert(Datum original, SortSupport ssup)
@@ -2104,6 +2105,16 @@ bttext_abbrev_convert(Datum original, SortSupport ssup)
 
        addHyperLogLog(&tss->abbr_card, hash);
 
+       /*
+        * Byteswap on little-endian machines.
+        *
+        * This is needed so that bttextcmp_abbrev() (an unsigned integer 3-way
+        * comparator) works correctly on all platforms.  If we didn't do this,
+        * the comparator would have to call memcmp() with a pair of pointers to
+        * the first byte of each abbreviated key, which is slower.
+        */
+       res = DatumBigEndianToNative(res);
+
        /* Don't leak memory here */
        if (PointerGetDatum(authoritative) != original)
                pfree(authoritative);
index 6555942c9214901615200e88ce2ca84489d3f590..e9cf93233fae65a34684cdcd19d34d028940af67 100644 (file)
@@ -28,7 +28,7 @@
                                        ((x << 8) & 0x00ff0000) | \
                                        ((x >> 8) & 0x0000ff00) | \
                                        ((x >> 24) & 0x000000ff))
-#endif /* HAVE__BUILTIN_BSWAP32 */
+#endif   /* HAVE__BUILTIN_BSWAP32 */
 
 #ifdef HAVE__BUILTIN_BSWAP64
 #define BSWAP64(x) __builtin_bswap64(x)
                                        ((x >> 24) & 0x0000000000ff0000UL) | \
                                        ((x >> 40) & 0x000000000000ff00UL) | \
                                        ((x >> 56) & 0x00000000000000ffUL))
-#endif /* HAVE__BUILTIN_BSWAP64 */
+#endif   /* HAVE__BUILTIN_BSWAP64 */
+
+/*
+ * Rearrange the bytes of a Datum from big-endian order into the native byte
+ * order.  On big-endian machines, this does nothing at all.  Note that the C
+ * type Datum is an unsigned integer type on all platforms.
+ *
+ * One possible application of the DatumBigEndianToNative() macro is to make
+ * bitwise comparisons cheaper.  A simple 3-way comparison of Datums
+ * transformed by the macro (based on native, unsigned comparisons) will return
+ * the same result as a memcmp() of the corresponding original Datums, but can
+ * be much cheaper.  It's generally safe to do this on big-endian systems
+ * without any special transformation occurring first.
+ */
+#ifdef WORDS_BIGENDIAN
+#define                DatumBigEndianToNative(x)       (x)
+#else                                                  /* !WORDS_BIGENDIAN */
+#if SIZEOF_DATUM == 8
+#define                DatumBigEndianToNative(x)       BSWAP64(x)
+#else                                                  /* SIZEOF_DATUM != 8 */
+#define                DatumBigEndianToNative(x)       BSWAP32(x)
+#endif   /* SIZEOF_DATUM == 8 */
+#endif   /* WORDS_BIGENDIAN */
 
 #endif   /* PG_BSWAP_H */