summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2011-01-09 11:35:54 +0000
committerLars Wirzenius <liw@liw.fi>2011-01-09 11:35:54 +0000
commit860c0bcab5ab9994bd2bff62798e88c2ffd42c4f (patch)
treef171860db899434e88b2f37e93163250043d051d
parentd503cf266afa8c01f50b54065d5461c19857dac8 (diff)
downloadlarch-860c0bcab5ab9994bd2bff62798e88c2ffd42c4f.tar.gz
Make maximum size of values be explicit.
-rw-r--r--btree/__init__.py2
-rw-r--r--btree/nodestore.py7
-rw-r--r--btree/tree.py20
-rw-r--r--btree/tree_tests.py17
-rwxr-xr-xinsert-remove-test2
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)