summaryrefslogtreecommitdiff
path: root/src/dict.c
diff options
context:
space:
mode:
authororanagra <oran@redislabs.com>2016-05-09 18:01:09 +0300
committerantirez <antirez@gmail.com>2016-09-14 12:18:59 +0200
commitafcbcc0e58749ebbebcd595c120d17a0e3dbb82e (patch)
tree9f4ba46910e78486ee1f23a0578aafdd6b4a701e /src/dict.c
parent8c84c962cfb6359401c2df92f79d7e848a34802f (diff)
downloadredis-afcbcc0e58749ebbebcd595c120d17a0e3dbb82e.tar.gz
dict.c: introduce dictUnlink().
Notes by @antirez: This patch was picked from a larger commit by Oran and adapted to change the API a bit. The basic idea is to avoid double lookups when there is to use the value of the deleted entry. BEFORE: entry = dictFind( ... ); /* 1st lookup. */ /* Do somethjing with the entry. */ dictDelete(...); /* 2nd lookup. */ AFTER: entry = dictUnlink( ... ); /* 1st lookup. */ /* Do somethjing with the entry. */ dictFreeUnlinkedEntry(entry); /* No lookups!. */
Diffstat (limited to 'src/dict.c')
-rw-r--r--src/dict.c50
1 files changed, 41 insertions, 9 deletions
diff --git a/src/dict.c b/src/dict.c
index 2d9ac35a2..322490283 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -407,14 +407,15 @@ dictEntry *dictReplaceRaw(dict *d, void *key) {
return entry ? entry : existing;
}
-/* Search and remove an element */
-static int dictGenericDelete(dict *d, const void *key, int nofree)
-{
+/* Search and remove an element. This is an helper function for
+ * dictDelete() and dictUnlink(), please check the top comment
+ * of those functions. */
+static dictEntry *dictGenericDelete(dict *d, const void *key, int nofree) {
unsigned int h, idx;
dictEntry *he, *prevHe;
int table;
- if (d->ht[0].size == 0) return DICT_ERR; /* d->ht[0].table is NULL */
+ if (d->ht[0].used == 0) return NULL;
if (dictIsRehashing(d)) _dictRehashStep(d);
h = dictHashKey(d, key);
@@ -432,27 +433,58 @@ static int dictGenericDelete(dict *d, const void *key, int nofree)
if (!nofree) {
dictFreeKey(d, he);
dictFreeVal(d, he);
+ zfree(he);
}
- zfree(he);
d->ht[table].used--;
- return DICT_OK;
+ return he;
}
prevHe = he;
he = he->next;
}
if (!dictIsRehashing(d)) break;
}
- return DICT_ERR; /* not found */
+ return NULL; /* not found */
}
+/* Remove an element, returning DICT_OK on success or DICT_ERR if the
+ * element was not found. */
int dictDelete(dict *ht, const void *key) {
- return dictGenericDelete(ht,key,0);
+ return dictGenericDelete(ht,key,0) ? DICT_OK : DICT_ERR;
}
-int dictDeleteNoFree(dict *ht, const void *key) {
+/* Remove an element from the table, but without actually releasing
+ * the key, value and dictionary entry. The dictionary entry is returned
+ * if the element was found (and unlinked from the table), and the user
+ * should later call `dictFreeUnlinkedEntry()` with it in order to release it.
+ * Otherwise if the key is not found, NULL is returned.
+ *
+ * This function is useful when we want to remove something from the hash
+ * table but want to use its value before actually deleting the entry.
+ * Without this function the pattern would require two lookups:
+ *
+ * entry = dictFind(...);
+ * // Do something with entry
+ * dictDelete(dictionary,entry);
+ *
+ * Thanks to this function it is possible to avoid this, and use
+ * instead:
+ *
+ * entry = dictUnlink(dictionary,entry);
+ * // Do something with entry
+ * dictFreeUnlinkedEntry(entry); // <- This does not need to lookup again.
+ */
+dictEntry *dictUnlink(dict *ht, const void *key) {
return dictGenericDelete(ht,key,1);
}
+/* You need to call this function to really free the entry after a call
+ * to dictUnlink(). */
+void dictFreeUnlinkedEntry(dict *d, dictEntry *he) {
+ dictFreeKey(d, he);
+ dictFreeVal(d, he);
+ zfree(he);
+}
+
/* Destroy an entire dictionary */
int _dictClear(dict *d, dictht *ht, void(callback)(void *)) {
unsigned long i;