1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-02-09 13:46:51 +02:00

Improve hex encode performance with bytewise lookup.

Previously, hex encode looked up each nibble of the input separately. Instead use a larger lookup table containing the two-byte encoding of every possible input byte, resulting in a 1/3 reduction in encoding time.

Inspired by and mostly cribbed from PostgreSQL commit e24d7708.
This commit is contained in:
David Steele 2025-01-20 14:09:54 -05:00
parent 713f6657d3
commit 23bd392bdc
4 changed files with 42 additions and 8 deletions

View File

@ -50,6 +50,15 @@
<p>Full/incremental backup method.</p>
</release-item>
<release-item>
<release-item-contributor-list>
<release-item-ideator id="john.naylor"/>
<release-item-contributor id="david.steele"/>
</release-item-contributor-list>
<p>Improve hex encode performance with bytewise lookup.</p>
</release-item>
</release-development-list>
</release-core-list>
</release>

View File

@ -560,6 +560,11 @@
<contributor-id type="github">precision-software</contributor-id>
</contributor>
<contributor id="john.naylor">
<contributor-name-display>John Naylor</contributor-name-display>
<contributor-id type="github">j-naylor</contributor-id>
</contributor>
<contributor id="jordan.english">
<contributor-name-display>Jordan English</contributor-name-display>
<contributor-id type="github">jordanenglish</contributor-id>

View File

@ -291,10 +291,18 @@ encodeToStrSizeBase64Url(const size_t sourceSize)
/***********************************************************************************************************************************
Hex encoding/decoding
***********************************************************************************************************************************/
static const char encodeHexLookup[] = "0123456789abcdef";
static const char encodeHexLookup[512] =
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
"202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
"404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"
"a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
"e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
static void
encodeToStrHex(const unsigned char *const source, const size_t sourceSize, char *const destination)
encodeToStrHex(const unsigned char *const source, const size_t sourceSize, char *destination)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM_P(UCHARDATA, source);
@ -305,17 +313,15 @@ encodeToStrHex(const unsigned char *const source, const size_t sourceSize, char
ASSERT(source != NULL);
ASSERT(destination != NULL);
unsigned int destinationIdx = 0;
// Encode the string from one bytes to two characters
for (unsigned int sourceIdx = 0; sourceIdx < sourceSize; sourceIdx += 1)
{
destination[destinationIdx++] = encodeHexLookup[source[sourceIdx] >> 4];
destination[destinationIdx++] = encodeHexLookup[source[sourceIdx] & 0xF];
memcpy(destination, &encodeHexLookup[source[sourceIdx] * 2], 2);
destination += 2;
}
// Zero-terminate the string
destination[destinationIdx] = 0;
*destination = 0;
FUNCTION_TEST_RETURN_VOID();
}

View File

@ -153,7 +153,7 @@ testRun(void)
TEST_TITLE("encode");
const unsigned char *encode = (const unsigned char *)"string_to_encode\r\n";
char destinationEncode[256];
char destinationEncode[513];
encodeToStr(encodingHex, encode, 1, destinationEncode);
TEST_RESULT_Z(destinationEncode, "73", "1 character encode");
@ -189,6 +189,20 @@ testRun(void)
encodeToStr(encodingHex, destinationDecode, decodeToBinSize(encodingHex, decodeMixed), destinationEncode), "encode");
TEST_RESULT_Z(destinationEncode, "0123456789aabbccddeeff", "check encoded hex");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("decode/encode all values");
unsigned char decodedAll[256];
for (unsigned int decodeIdx = 0; decodeIdx < sizeof(decodedAll); decodeIdx++)
decodedAll[decodeIdx] = (unsigned char)decodeIdx;
encodeToStr(encodingHex, decodedAll, sizeof(decodedAll), destinationEncode);
TEST_RESULT_UINT(strlen(destinationEncode), 512, "all values encoded size");
TEST_RESULT_INT(memcmp(destinationEncode, encodeHexLookup, 512), 0, "all values encoded");
decodeToBin(encodingHex, destinationEncode, destinationDecode);
TEST_RESULT_INT(memcmp(decodedAll, destinationDecode, sizeof(decodedAll)), 0, "all values decoded");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("decode errors");