]> git.saurik.com Git - redis.git/blobdiff - dict.c
use the right object when cleaning up after zunion/zinter (fixes issue 216)
[redis.git] / dict.c
diff --git a/dict.c b/dict.c
index 2d186c1d021ac87c2d738b509f78f5ab79f11b37..23f7933bfa43ad1a08e3f7bc373e789c793dbbe3 100644 (file)
--- a/dict.c
+++ b/dict.c
@@ -5,7 +5,7 @@
  * tables of power of two in size are used, collisions are handled by
  * chaining. See the source code for more information... :)
  *
  * tables of power of two in size are used, collisions are handled by
  * chaining. See the source code for more information... :)
  *
- * Copyright (c) 2006-2009, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "fmacros.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #include <assert.h>
+#include <limits.h>
 
 #include "dict.h"
 #include "zmalloc.h"
 
 #include "dict.h"
 #include "zmalloc.h"
@@ -57,7 +60,7 @@ static void _dictPanic(const char *fmt, ...)
 
 /* ------------------------- Heap Management Wrappers------------------------ */
 
 
 /* ------------------------- Heap Management Wrappers------------------------ */
 
-static void *_dictAlloc(int size)
+static void *_dictAlloc(size_t size)
 {
     void *p = zmalloc(size);
     if (p == NULL)
 {
     void *p = zmalloc(size);
     if (p == NULL)
@@ -72,7 +75,7 @@ static void _dictFree(void *ptr) {
 /* -------------------------- private prototypes ---------------------------- */
 
 static int _dictExpandIfNeeded(dict *ht);
 /* -------------------------- private prototypes ---------------------------- */
 
 static int _dictExpandIfNeeded(dict *ht);
-static unsigned int _dictNextPower(unsigned int size);
+static unsigned long _dictNextPower(unsigned long size);
 static int _dictKeyIndex(dict *ht, const void *key);
 static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
 
 static int _dictKeyIndex(dict *ht, const void *key);
 static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
 
@@ -150,10 +153,10 @@ int dictResize(dict *ht)
 }
 
 /* Expand or create the hashtable */
 }
 
 /* Expand or create the hashtable */
-int dictExpand(dict *ht, unsigned int size)
+int dictExpand(dict *ht, unsigned long size)
 {
     dict n; /* the new hashtable */
 {
     dict n; /* the new hashtable */
-    unsigned int realsize = _dictNextPower(size), i;
+    unsigned long realsize = _dictNextPower(size), i;
 
     /* the size is invalid if it is smaller than the number of
      * elements already inside the hashtable */
 
     /* the size is invalid if it is smaller than the number of
      * elements already inside the hashtable */
@@ -223,21 +226,30 @@ int dictAdd(dict *ht, void *key, void *val)
     return DICT_OK;
 }
 
     return DICT_OK;
 }
 
-/* Add an element, discarding the old if the key already exists */
+/* Add an element, discarding the old if the key already exists.
+ * Return 1 if the key was added from scratch, 0 if there was already an
+ * element with such key and dictReplace() just performed a value update
+ * operation. */
 int dictReplace(dict *ht, void *key, void *val)
 {
 int dictReplace(dict *ht, void *key, void *val)
 {
-    dictEntry *entry;
+    dictEntry *entry, auxentry;
 
     /* Try to add the element. If the key
      * does not exists dictAdd will suceed. */
     if (dictAdd(ht, key, val) == DICT_OK)
 
     /* Try to add the element. If the key
      * does not exists dictAdd will suceed. */
     if (dictAdd(ht, key, val) == DICT_OK)
-        return DICT_OK;
+        return 1;
     /* It already exists, get the entry */
     entry = dictFind(ht, key);
     /* Free the old value and set the new one */
     /* It already exists, get the entry */
     entry = dictFind(ht, key);
     /* Free the old value and set the new one */
-    dictFreeEntryVal(ht, entry);
+    /* Set the new value and free the old one. Note that it is important
+     * to do that in this order, as the value may just be exactly the same
+     * as the previous one. In this context, think to reference counting,
+     * you want to increment (set), and then decrement (free), and not the
+     * reverse. */
+    auxentry = *entry;
     dictSetHashVal(ht, entry, val);
     dictSetHashVal(ht, entry, val);
-    return DICT_OK;
+    dictFreeEntryVal(ht, &auxentry);
+    return 0;
 }
 
 /* Search and remove an element */
 }
 
 /* Search and remove an element */
@@ -284,7 +296,7 @@ int dictDeleteNoFree(dict *ht, const void *key) {
 /* Destroy an entire hash table */
 int _dictClear(dict *ht)
 {
 /* Destroy an entire hash table */
 int _dictClear(dict *ht)
 {
-    unsigned int i;
+    unsigned long i;
 
     /* Free all the elements */
     for (i = 0; i < ht->size && ht->used > 0; i++) {
 
     /* Free all the elements */
     for (i = 0; i < ht->size && ht->used > 0; i++) {
@@ -375,7 +387,7 @@ dictEntry *dictGetRandomKey(dict *ht)
     unsigned int h;
     int listlen, listele;
 
     unsigned int h;
     int listlen, listele;
 
-    if (ht->size == 0) return NULL;
+    if (ht->used == 0) return NULL;
     do {
         h = random() & ht->sizemask;
         he = ht->table[h];
     do {
         h = random() & ht->sizemask;
         he = ht->table[h];
@@ -411,12 +423,11 @@ static int _dictExpandIfNeeded(dict *ht)
 }
 
 /* Our hash table capability is a power of two */
 }
 
 /* Our hash table capability is a power of two */
-static unsigned int _dictNextPower(unsigned int size)
+static unsigned long _dictNextPower(unsigned long size)
 {
 {
-    unsigned int i = DICT_HT_INITIAL_SIZE;
+    unsigned long i = DICT_HT_INITIAL_SIZE;
 
 
-    if (size >= 2147483648U)
-        return 2147483648U;
+    if (size >= LONG_MAX) return LONG_MAX;
     while(1) {
         if (i >= size)
             return i;
     while(1) {
         if (i >= size)
             return i;
@@ -453,9 +464,9 @@ void dictEmpty(dict *ht) {
 
 #define DICT_STATS_VECTLEN 50
 void dictPrintStats(dict *ht) {
 
 #define DICT_STATS_VECTLEN 50
 void dictPrintStats(dict *ht) {
-    unsigned int i, slots = 0, chainlen, maxchainlen = 0;
-    unsigned int totchainlen = 0;
-    unsigned int clvector[DICT_STATS_VECTLEN];
+    unsigned long i, slots = 0, chainlen, maxchainlen = 0;
+    unsigned long totchainlen = 0;
+    unsigned long clvector[DICT_STATS_VECTLEN];
 
     if (ht->used == 0) {
         printf("No stats available for empty dictionaries\n");
 
     if (ht->used == 0) {
         printf("No stats available for empty dictionaries\n");
@@ -483,16 +494,16 @@ void dictPrintStats(dict *ht) {
         totchainlen += chainlen;
     }
     printf("Hash table stats:\n");
         totchainlen += chainlen;
     }
     printf("Hash table stats:\n");
-    printf(" table size: %d\n", ht->size);
-    printf(" number of elements: %d\n", ht->used);
-    printf(" different slots: %d\n", slots);
-    printf(" max chain length: %d\n", maxchainlen);
+    printf(" table size: %ld\n", ht->size);
+    printf(" number of elements: %ld\n", ht->used);
+    printf(" different slots: %ld\n", slots);
+    printf(" max chain length: %ld\n", maxchainlen);
     printf(" avg chain length (counted): %.02f\n", (float)totchainlen/slots);
     printf(" avg chain length (computed): %.02f\n", (float)ht->used/slots);
     printf(" Chain length distribution:\n");
     for (i = 0; i < DICT_STATS_VECTLEN-1; i++) {
         if (clvector[i] == 0) continue;
     printf(" avg chain length (counted): %.02f\n", (float)totchainlen/slots);
     printf(" avg chain length (computed): %.02f\n", (float)ht->used/slots);
     printf(" Chain length distribution:\n");
     for (i = 0; i < DICT_STATS_VECTLEN-1; i++) {
         if (clvector[i] == 0) continue;
-        printf("   %s%d: %d (%.02f%%)\n",(i == DICT_STATS_VECTLEN-1)?">= ":"", i, clvector[i], ((float)clvector[i]/ht->size)*100);
+        printf("   %s%ld: %ld (%.02f%%)\n",(i == DICT_STATS_VECTLEN-1)?">= ":"", i, clvector[i], ((float)clvector[i]/ht->size)*100);
     }
 }
 
     }
 }