From baaeb7e06019b71ef48aeee7577390e4f51c1717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Borgstr=C3=B6m?= Date: Wed, 2 Oct 2013 20:42:26 +0200 Subject: [PATCH] Fix hashindex resize issue closes #6 --- attic/_hashindex.c | 23 +++++++++++++++++++---- attic/testsuite/__init__.py | 3 ++- attic/testsuite/hashindex.py | 18 ++++++++++++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/attic/_hashindex.c b/attic/_hashindex.c index 52212fd7e..18c0482c4 100644 --- a/attic/_hashindex.c +++ b/attic/_hashindex.c @@ -110,6 +110,7 @@ static int hashindex_resize(HashIndex *index, int capacity) { char *new_path = malloc(strlen(index->path) + 5); + int ret = 0; strcpy(new_path, index->path); strcat(new_path, ".tmp"); HashIndex *new; @@ -129,12 +130,20 @@ hashindex_resize(HashIndex *index, int capacity) index->lower_limit = new->lower_limit; index->upper_limit = new->upper_limit; 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); - return 1; + return ret; } /* Public API */ @@ -237,10 +246,16 @@ hashindex_create(const char *path, int capacity, int key_size, int value_size) } if(fclose(fd) < 0) { EPRINTF_PATH(path, "fclose failed"); + if(unlink(path) < 0) { + EPRINTF_PATH(path, "unlink failed"); + } return NULL; } return hashindex_open(path, 0); error: + if(unlink(path) < 0) { + EPRINTF_PATH(path, "unlink failed"); + } EPRINTF_PATH(path, "fwrite failed"); if(fclose(fd) < 0) { EPRINTF_PATH(path, "fclose failed"); @@ -338,7 +353,7 @@ hashindex_delete(HashIndex *index, const void *key) BUCKET_MARK_DELETED(index, idx); index->num_entries -= 1; 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; } } diff --git a/attic/testsuite/__init__.py b/attic/testsuite/__init__.py index 5286d56df..b26e5ffd1 100644 --- a/attic/testsuite/__init__.py +++ b/attic/testsuite/__init__.py @@ -37,6 +37,7 @@ class AtticTestCase(unittest.TestCase): assert_equal = unittest.TestCase.assertEqual assert_not_equal = unittest.TestCase.assertNotEqual assert_raises = unittest.TestCase.assertRaises + assert_true = unittest.TestCase.assertTrue def assert_dirs_equal(self, dir1, dir2): diff = filecmp.dircmp(dir1, dir2) @@ -89,7 +90,7 @@ def get_tests(suite): """ for item in suite: 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): yield i except TypeError: diff --git a/attic/testsuite/hashindex.py b/attic/testsuite/hashindex.py index d8cd19a37..d323390f1 100644 --- a/attic/testsuite/hashindex.py +++ b/attic/testsuite/hashindex.py @@ -1,4 +1,5 @@ import hashlib +import os import tempfile from attic.hashindex import NSIndex, ChunkIndex from attic.testsuite import AtticTestCase @@ -46,3 +47,20 @@ def test_nsindex(self): def test_chunkindex(self): 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)) + +