diff options
author | Lars Wirzenius <liw@liw.fi> | 2011-01-09 11:35:54 +0000 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2011-01-09 11:35:54 +0000 |
commit | 860c0bcab5ab9994bd2bff62798e88c2ffd42c4f (patch) | |
tree | f171860db899434e88b2f37e93163250043d051d | |
parent | d503cf266afa8c01f50b54065d5461c19857dac8 (diff) | |
download | larch-860c0bcab5ab9994bd2bff62798e88c2ffd42c4f.tar.gz |
Make maximum size of values be explicit.
-rw-r--r-- | btree/__init__.py | 2 | ||||
-rw-r--r-- | btree/nodestore.py | 7 | ||||
-rw-r--r-- | btree/tree.py | 20 | ||||
-rw-r--r-- | btree/tree_tests.py | 17 | ||||
-rwxr-xr-x | insert-remove-test | 2 |
5 files changed, 44 insertions, 4 deletions
diff --git a/btree/__init__.py b/btree/__init__.py index 60f8c46..44f5cd7 100644 --- a/btree/__init__.py +++ b/btree/__init__.py @@ -19,7 +19,7 @@ version = '0.16' from nodes import LeafNode, IndexNode from codec import NodeCodec, CodecError -from tree import BTree, KeySizeMismatch +from tree import BTree, KeySizeMismatch, ValueTooLarge from forest import Forest from nodestore import (NodeStore, NodeStoreTests, NodeMissing, NodeTooBig, NodeExists) diff --git a/btree/nodestore.py b/btree/nodestore.py index c356f98..ad67ccf 100644 --- a/btree/nodestore.py +++ b/btree/nodestore.py @@ -95,7 +95,8 @@ class NodeStore(object): # pragma: no cover def __init__(self, node_size, codec): self.node_size = node_size self.codec = codec - + self.max_value_size = (node_size / 2) - codec.leaf_header.size + def max_index_pairs(self): return self.codec.max_index_pairs(self.node_size) @@ -191,6 +192,10 @@ class NodeStoreTests(object): # pragma: no cover def test_sets_node_size(self): self.assertEqual(self.ns.node_size, self.node_size) + + def test_sets_max_value_size(self): + self.assert_(self.ns.max_value_size > 1) + self.assert_(self.ns.max_value_size < self.node_size / 2) def test_has_no_metadata_initially(self): self.assertEqual(self.ns.get_metadata_keys(), []) diff --git a/btree/tree.py b/btree/tree.py index 7138414..e4f8bab 100644 --- a/btree/tree.py +++ b/btree/tree.py @@ -32,6 +32,17 @@ class KeySizeMismatch(Exception): def __str__(self): return 'Key %s is of wrong length (%d, should be %d)' % \ (repr(self.key), len(self.key), self.wanted_size) + + +class ValueTooLarge(Exception): + + def __init__(self, value, max_size): + self.value = value + self.max_size = max_size + + def __str__(self): + return 'Value %s is too long (%d, max %d)' % \ + (repr(self.value), len(self.value), self.max_size) class BTree(object): @@ -39,7 +50,9 @@ class BTree(object): '''B-tree. The nodes are stored in an external node store; see the NodeStore - class. Key sizes are fixed, and given in bytes. + class. Key sizes are fixed, and given in bytes. Values may be of + any size up to slightly less than half the maximum size of a node. + See NodeStore.max_value_size for the exact value. ''' @@ -59,6 +72,10 @@ class BTree(object): if len(key) != self.node_store.codec.key_bytes: raise KeySizeMismatch(key, self.node_store.codec.key_bytes) + def check_value_size(self, value): + if len(value) > self.node_store.max_value_size: + raise ValueTooLarge(value, self.node_store.max_value_size) + def new_id(self): '''Generate a new node identifier.''' return self.forest.new_id() @@ -201,6 +218,7 @@ class BTree(object): ''' self.check_key_size(key) + self.check_value_size(value) # Is the tree empty? This needs special casing to keep # _insert_into_index simpler. diff --git a/btree/tree_tests.py b/btree/tree_tests.py index 24efad8..86b5684 100644 --- a/btree/tree_tests.py +++ b/btree/tree_tests.py @@ -35,6 +35,7 @@ class DummyNodeStore(object): def __init__(self, node_size, codec): self.node_size = node_size + self.max_value_size = node_size / 2 - 1 self.codec = codec self.nodes = dict() self.metadata = dict() @@ -87,6 +88,18 @@ class KeySizeMismatchTests(unittest.TestCase): self.assert_('4' in str(self.err)) +class ValueTooLargeTests(unittest.TestCase): + + def setUp(self): + self.err = btree.ValueTooLarge('foobar', 3) + + def test_error_message_contains_value(self): + self.assert_('foobar' in str(self.err)) + + def test_error_message_contains_max_size(self): + self.assert_('3' in str(self.err)) + + class BTreeTests(unittest.TestCase): def setUp(self): @@ -190,6 +203,10 @@ class BTreeTests(unittest.TestCase): def test_insert_with_wrong_size_key_raises_error(self): self.assertRaises(btree.KeySizeMismatch, self.tree.insert, '', '') + def test_insert_with_too_large_value_raises_error(self): + self.assertRaises(btree.ValueTooLarge, self.tree.insert, 'xxx', + 'x' * (self.ns.max_value_size + 1)) + def test_remove_from_empty_tree_raises_keyerror(self): self.assertRaises(KeyError, self.tree.remove, 'foo') diff --git a/insert-remove-test b/insert-remove-test index 83ef0c7..c59e9b9 100755 --- a/insert-remove-test +++ b/insert-remove-test @@ -83,7 +83,7 @@ def main(): key_size = 19 value_size = 128 - node_size = 256 + node_size = 300 codec = btree.NodeCodec(key_size) |