Allow users of simplehash.h to perform direct deletions

Previously simplehash.h only exposed a method to perform a hash table
delete using the hash table key. This meant that the delete function had
to perform a hash lookup in order to find the entry to delete.  Here we
add a new function so that users of simplehash.h can perform a hash delete
directly using the entry pointer, thus saving the hash lookup.

An upcoming patch that uses simplehash.h already has performed the hash
lookup so already has the entry pointer.  This change will allow the
code in that patch to perform the hash delete without the code in
simplehash.h having to perform an additional hash lookup.

Author: David Rowley
Reviewed-by: Andres Freund
Discussion: https://postgr.es/m/CAApHDvqFLXXge153WmPsjke5VGOSt7Ez0yD0c7eBXLfmWxs3Kw@mail.gmail.com
This commit is contained in:
David Rowley 2021-03-30 19:56:50 +13:00
parent bc9f1afdeb
commit ff53d7b159

View File

@ -110,6 +110,7 @@
#define SH_RESET SH_MAKE_NAME(reset)
#define SH_INSERT SH_MAKE_NAME(insert)
#define SH_INSERT_HASH SH_MAKE_NAME(insert_hash)
#define SH_DELETE_ITEM SH_MAKE_NAME(delete_item)
#define SH_DELETE SH_MAKE_NAME(delete)
#define SH_LOOKUP SH_MAKE_NAME(lookup)
#define SH_LOOKUP_HASH SH_MAKE_NAME(lookup_hash)
@ -217,6 +218,9 @@ SH_SCOPE SH_ELEMENT_TYPE *SH_LOOKUP(SH_TYPE * tb, SH_KEY_TYPE key);
SH_SCOPE SH_ELEMENT_TYPE *SH_LOOKUP_HASH(SH_TYPE * tb, SH_KEY_TYPE key,
uint32 hash);
/* void <prefix>_delete_item(<prefix>_hash *tb, <element> *entry) */
SH_SCOPE void SH_DELETE_ITEM(SH_TYPE * tb, SH_ELEMENT_TYPE * entry);
/* bool <prefix>_delete(<prefix>_hash *tb, <key> key) */
SH_SCOPE bool SH_DELETE(SH_TYPE * tb, SH_KEY_TYPE key);
@ -829,7 +833,7 @@ SH_LOOKUP_HASH(SH_TYPE * tb, SH_KEY_TYPE key, uint32 hash)
}
/*
* Delete entry from hash table. Returns whether to-be-deleted key was
* Delete entry from hash table by key. Returns whether to-be-deleted key was
* present.
*/
SH_SCOPE bool
@ -900,6 +904,61 @@ SH_DELETE(SH_TYPE * tb, SH_KEY_TYPE key)
}
}
/*
* Delete entry from hash table by entry pointer
*/
SH_SCOPE void
SH_DELETE_ITEM(SH_TYPE * tb, SH_ELEMENT_TYPE * entry)
{
SH_ELEMENT_TYPE *lastentry = entry;
uint32 hash = SH_ENTRY_HASH(tb, entry);
uint32 startelem = SH_INITIAL_BUCKET(tb, hash);
uint32 curelem;
/* Calculate the index of 'entry' */
curelem = entry - &tb->data[0];
tb->members--;
/*
* Backward shift following elements till either an empty element or an
* element at its optimal position is encountered.
*
* While that sounds expensive, the average chain length is short, and
* deletions would otherwise require tombstones.
*/
while (true)
{
SH_ELEMENT_TYPE *curentry;
uint32 curhash;
uint32 curoptimal;
curelem = SH_NEXT(tb, curelem, startelem);
curentry = &tb->data[curelem];
if (curentry->status != SH_STATUS_IN_USE)
{
lastentry->status = SH_STATUS_EMPTY;
break;
}
curhash = SH_ENTRY_HASH(tb, curentry);
curoptimal = SH_INITIAL_BUCKET(tb, curhash);
/* current is at optimal position, done */
if (curoptimal == curelem)
{
lastentry->status = SH_STATUS_EMPTY;
break;
}
/* shift */
memcpy(lastentry, curentry, sizeof(SH_ELEMENT_TYPE));
lastentry = curentry;
}
}
/*
* Initialize iterator.
*/
@ -1102,6 +1161,7 @@ SH_STAT(SH_TYPE * tb)
#undef SH_RESET
#undef SH_INSERT
#undef SH_INSERT_HASH
#undef SH_DELETE_ITEM
#undef SH_DELETE
#undef SH_LOOKUP
#undef SH_LOOKUP_HASH