1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-03-03 14:52:21 +02:00

Add strLstMergeAnti() for merge anti-joins.

We deal with some pretty big lists in archive-push so a nested-loop anti-join looked like it would not be efficient enough.

This merge anti-join should do the trick even though both lists must be sorted first.
This commit is contained in:
David Steele 2019-03-25 20:35:20 +04:00
parent 538e2c7474
commit abba2bd132
5 changed files with 112 additions and 1 deletions

View File

@ -93,6 +93,10 @@
<p>Make <code>strLstDup()</code> null-tolerant.</p>
</release-item>
<release-item>
<p>Add <code>strLstMergeAnti()</code> for merge anti-joins.</p>
</release-item>
<release-item>
<p>Add <code>cvtSSizeToZ()</code> and debug macros.</p>
</release-item>

View File

@ -472,6 +472,69 @@ strLstJoinQuote(const StringList *this, const char *separator, const char *quote
FUNCTION_TEST_RETURN(join);
}
/***********************************************************************************************************************************
Return all items in this list which are not in the anti list
The input lists must *both* be sorted or the results will be unpredictable.
***********************************************************************************************************************************/
StringList *
strLstMergeAnti(const StringList *this, const StringList *anti)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING_LIST, this);
FUNCTION_TEST_PARAM(STRING_LIST, anti);
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(anti != NULL);
StringList *result = NULL;
MEM_CONTEXT_TEMP_BEGIN()
{
result = strLstNew();
unsigned int antiIdx = 0;
// Check every item in this
for (unsigned int thisIdx = 0; thisIdx < strLstSize(this); thisIdx++)
{
bool add = true;
const String *listItem = strLstGet(this, thisIdx);
// If anything left in anti look for matches
while (antiIdx < strLstSize(anti))
{
int compare = strCmp(listItem, strLstGet(anti, antiIdx));
// If the current item in this is less than the current item in anti then it will be added
if (compare < 0)
{
break;
}
// If they are equal it will not be added
else if (compare == 0)
{
add = false;
antiIdx++;
break;
}
// Otherwise keep searching anti for a match
else
antiIdx++;
}
// Add to the result list if no match found
if (add)
strLstAdd(result, listItem);
}
strLstMove(result, MEM_CONTEXT_OLD());
}
MEM_CONTEXT_TEMP_END();
FUNCTION_TEST_RETURN(result);
}
/***********************************************************************************************************************************
Move the string list
***********************************************************************************************************************************/

View File

@ -42,6 +42,7 @@ StringList *strLstInsertZ(StringList *this, unsigned int listIdx, const char *st
String *strLstGet(const StringList *this, unsigned int listIdx);
String *strLstJoin(const StringList *this, const char *separator);
String *strLstJoinQuote(const StringList *this, const char *separator, const char *quote);
StringList *strLstMergeAnti(const StringList *this, const StringList *anti);
StringList * strLstMove(StringList *this, MemContext *parentNew);
const char **strLstPtr(const StringList *this);
unsigned int strLstSize(const StringList *this);

View File

@ -155,7 +155,7 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: type-string
total: 25
total: 26
coverage:
common/type/string: full

View File

@ -396,6 +396,49 @@ testRun(void)
strLstFree(list);
}
// *****************************************************************************************************************************
if (testBegin("strLstMergeAnti()"))
{
StringList *list = strLstNew();
StringList *anti = strLstNew();
TEST_RESULT_STR(strPtr(strLstJoin(strLstMergeAnti(list, anti), ", ")), "", "list and anti empty");
strLstAddZ(anti, "item2");
strLstAddZ(anti, "item3");
TEST_RESULT_STR(strPtr(strLstJoin(strLstMergeAnti(list, anti), ", ")), "", "list empty");
strLstAddZ(list, "item1");
strLstAddZ(list, "item3");
strLstAddZ(list, "item4");
strLstAddZ(list, "item5");
TEST_RESULT_STR(strPtr(strLstJoin(strLstMergeAnti(list, anti), ", ")), "item1, item4, item5", "list results");
list = strLstNew();
strLstAddZ(list, "item2");
strLstAddZ(list, "item4");
strLstAddZ(list, "item6");
anti = strLstNew();
strLstAddZ(anti, "item1");
strLstAddZ(anti, "item4");
strLstAddZ(anti, "item7");
TEST_RESULT_STR(strPtr(strLstJoin(strLstMergeAnti(list, anti), ", ")), "item2, item6", "list results");
list = strLstNew();
strLstAddZ(list, "item7");
anti = strLstNew();
strLstAddZ(anti, "item1");
strLstAddZ(anti, "item4");
strLstAddZ(anti, "item6");
TEST_RESULT_STR(strPtr(strLstJoin(strLstMergeAnti(list, anti), ", ")), "item7", "list results");
}
// *****************************************************************************************************************************
if (testBegin("strLstSort()"))
{