Browse Source

Fix hashindex resize issue

closes #6
Jonas Borgström 11 years ago
parent
commit
baaeb7e060
3 changed files with 39 additions and 5 deletions
  1. 19 4
      attic/_hashindex.c
  2. 2 1
      attic/testsuite/__init__.py
  3. 18 0
      attic/testsuite/hashindex.py

+ 19 - 4
attic/_hashindex.c

@@ -110,6 +110,7 @@ static int
 hashindex_resize(HashIndex *index, int capacity)
 hashindex_resize(HashIndex *index, int capacity)
 {
 {
     char *new_path = malloc(strlen(index->path) + 5);
     char *new_path = malloc(strlen(index->path) + 5);
+    int ret = 0;
     strcpy(new_path, index->path);
     strcpy(new_path, index->path);
     strcat(new_path, ".tmp");
     strcat(new_path, ".tmp");
     HashIndex *new;
     HashIndex *new;
@@ -129,12 +130,20 @@ hashindex_resize(HashIndex *index, int capacity)
     index->lower_limit = new->lower_limit;
     index->lower_limit = new->lower_limit;
     index->upper_limit = new->upper_limit;
     index->upper_limit = new->upper_limit;
     index->buckets = new->buckets;
     index->buckets = new->buckets;
-    unlink(index->path);
-    rename(new_path, index->path);
+    if(unlink(index->path) < 0) {
+        EPRINTF("unlink failed");
+        goto out;
+    }
+    if(rename(new_path, index->path) < 0) {
+        EPRINTF_PATH(new_path, "rename failed");
+        goto out;
+    }
+    ret = 1;
+out:
     free(new_path);
     free(new_path);
     free(new->path);
     free(new->path);
     free(new);
     free(new);
-    return 1;
+    return ret;
 }
 }
 
 
 /* Public API */
 /* Public API */
@@ -237,10 +246,16 @@ hashindex_create(const char *path, int capacity, int key_size, int value_size)
     }
     }
     if(fclose(fd) < 0) {
     if(fclose(fd) < 0) {
         EPRINTF_PATH(path, "fclose failed");
         EPRINTF_PATH(path, "fclose failed");
+        if(unlink(path) < 0) {
+            EPRINTF_PATH(path, "unlink failed");
+    }
         return NULL;
         return NULL;
     }
     }
     return hashindex_open(path, 0);
     return hashindex_open(path, 0);
 error:
 error:
+    if(unlink(path) < 0) {
+        EPRINTF_PATH(path, "unlink failed");
+    }
     EPRINTF_PATH(path, "fwrite failed");
     EPRINTF_PATH(path, "fwrite failed");
     if(fclose(fd) < 0) {
     if(fclose(fd) < 0) {
         EPRINTF_PATH(path, "fclose failed");
         EPRINTF_PATH(path, "fclose failed");
@@ -338,7 +353,7 @@ hashindex_delete(HashIndex *index, const void *key)
     BUCKET_MARK_DELETED(index, idx);
     BUCKET_MARK_DELETED(index, idx);
     index->num_entries -= 1;
     index->num_entries -= 1;
     if(index->num_entries < index->lower_limit) {
     if(index->num_entries < index->lower_limit) {
-        if(!hashindex_resize(index, index->num_buckets * 2)) {
+        if(!hashindex_resize(index, index->num_buckets / 2)) {
             return 0;
             return 0;
         }
         }
     }
     }

+ 2 - 1
attic/testsuite/__init__.py

@@ -37,6 +37,7 @@ class AtticTestCase(unittest.TestCase):
     assert_equal = unittest.TestCase.assertEqual
     assert_equal = unittest.TestCase.assertEqual
     assert_not_equal = unittest.TestCase.assertNotEqual
     assert_not_equal = unittest.TestCase.assertNotEqual
     assert_raises = unittest.TestCase.assertRaises
     assert_raises = unittest.TestCase.assertRaises
+    assert_true = unittest.TestCase.assertTrue
 
 
     def assert_dirs_equal(self, dir1, dir2):
     def assert_dirs_equal(self, dir1, dir2):
         diff = filecmp.dircmp(dir1, dir2)
         diff = filecmp.dircmp(dir1, dir2)
@@ -89,7 +90,7 @@ def get_tests(suite):
     """
     """
     for item in suite:
     for item in suite:
         try:
         try:
-            # TODO: This could be "yield from..." with Python 3.3+ 
+            # TODO: This could be "yield from..." with Python 3.3+
             for i in get_tests(item):
             for i in get_tests(item):
                 yield i
                 yield i
         except TypeError:
         except TypeError:

+ 18 - 0
attic/testsuite/hashindex.py

@@ -1,4 +1,5 @@
 import hashlib
 import hashlib
+import os
 import tempfile
 import tempfile
 from attic.hashindex import NSIndex, ChunkIndex
 from attic.hashindex import NSIndex, ChunkIndex
 from attic.testsuite import AtticTestCase
 from attic.testsuite import AtticTestCase
@@ -46,3 +47,20 @@ class HashIndexTestCase(AtticTestCase):
     def test_chunkindex(self):
     def test_chunkindex(self):
         self._generic_test(ChunkIndex, lambda x: (x, x, x), 'ed22e8a883400453c0ee79a06c54df72c994a54eeefdc6c0989efdc5ee6d07b7')
         self._generic_test(ChunkIndex, lambda x: (x, x, x), 'ed22e8a883400453c0ee79a06c54df72c994a54eeefdc6c0989efdc5ee6d07b7')
 
 
+    def test_resize(self):
+        n = 2000  # Must be >= MIN_BUCKETS
+        idx_name = tempfile.NamedTemporaryFile()
+        idx = NSIndex.create(idx_name.name)
+        initial_size = os.path.getsize(idx_name.name)
+        self.assert_equal(len(idx), 0)
+        for x in range(n):
+            idx[bytes('%-32d' % x, 'ascii')] = x, x
+        idx.flush()
+        self.assert_true(initial_size < os.path.getsize(idx_name.name))
+        for x in range(n):
+            del idx[bytes('%-32d' % x, 'ascii')]
+        self.assert_equal(len(idx), 0)
+        idx.flush()
+        self.assert_equal(initial_size, os.path.getsize(idx_name.name))
+
+