Rev 4728: Start using StaticTuple as part of the chk_map api. in http://bazaar.launchpad.net/~jameinel/bzr/2.1-static-tuple

John Arbash Meinel john at arbash-meinel.com
Wed Sep 30 22:54:07 BST 2009


At http://bazaar.launchpad.net/~jameinel/bzr/2.1-static-tuple

------------------------------------------------------------
revno: 4728
revision-id: john at arbash-meinel.com-20090930215359-8gvb6appgkc7j8wz
parent: john at arbash-meinel.com-20090930212526-imvbkyikd9d3r4o6
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 2.1-static-tuple
timestamp: Wed 2009-09-30 16:53:59 -0500
message:
  Start using StaticTuple as part of the chk_map api.
  
  All tests now pass, because I changed the apis to not use the direct functions.
  I'm not 100% sure about the performance impact, that needs to be profiled.
  However, at least everything works, and potentially this will help
  memory overhead. I'm not 100% sure about speed just yet.
-------------- next part --------------
=== modified file 'bzrlib/_btree_serializer_pyx.pyx'
--- a/bzrlib/_btree_serializer_pyx.pyx	2009-09-30 21:25:26 +0000
+++ b/bzrlib/_btree_serializer_pyx.pyx	2009-09-30 21:53:59 +0000
@@ -38,6 +38,8 @@
     Py_ssize_t PyString_Size(object p)
     Py_ssize_t PyString_GET_SIZE_ptr "PyString_GET_SIZE" (PyObject *)
     char * PyString_AS_STRING_ptr "PyString_AS_STRING" (PyObject *)
+    char * PyString_AS_STRING(object)
+    Py_ssize_t PyString_GET_SIZE(object)
     int PyString_AsStringAndSize_ptr(PyObject *, char **buf, Py_ssize_t *len)
     void PyString_InternInPlace(PyObject **)
     int PyTuple_CheckExact(object t)
@@ -66,6 +68,7 @@
     # Steals a reference and Val must be a PyStringObject, no checking is done
     void StaticTuple_SET_ITEM(object key, Py_ssize_t offset, object val)
     object StaticTuple_GET_ITEM(object key, Py_ssize_t offset)
+    int StaticTuple_CheckExact(object)
 
 
 # TODO: Find some way to import this from _dirstate_helpers
@@ -322,7 +325,6 @@
     cdef Py_ssize_t flat_len
     cdef Py_ssize_t key_len
     cdef Py_ssize_t node_len
-    cdef PyObject * val
     cdef char * value
     cdef Py_ssize_t value_len
     cdef char * out
@@ -331,13 +333,12 @@
     cdef int first_ref_list
     cdef int first_reference
     cdef int i
-    cdef PyObject *ref_bit
     cdef Py_ssize_t ref_bit_len
 
-    if not PyTuple_CheckExact(node):
-        raise TypeError('We expected a tuple() for node not: %s'
+    if not PyTuple_CheckExact(node) and not StaticTuple_CheckExact(node):
+        raise TypeError('We expected a tuple() or StaticTuple() for node not: %s'
             % type(node))
-    node_len = PyTuple_GET_SIZE(node)
+    node_len = len(node)
     have_reference_lists = reference_lists
     if have_reference_lists:
         if node_len != 4:
@@ -347,7 +348,7 @@
         raise ValueError('Without ref_lists, we need at least 3 entries not: %s'
             % len(node))
     # I don't expect that we can do faster than string.join()
-    string_key = '\0'.join(<object>PyTuple_GET_ITEM_ptr_object(node, 1))
+    string_key = '\0'.join(node[1])# <object>PyTuple_GET_ITEM_ptr_object(node, 1))
 
     # TODO: instead of using string joins, precompute the final string length,
     #       and then malloc a single string and copy everything in.
@@ -364,7 +365,7 @@
     refs_len = 0
     if have_reference_lists:
         # Figure out how many bytes it will take to store the references
-        ref_lists = <object>PyTuple_GET_ITEM_ptr_object(node, 3)
+        ref_lists = node[3]# <object>PyTuple_GET_ITEM_ptr_object(node, 3)
         next_len = len(ref_lists) # TODO: use a Py function
         if next_len > 0:
             # If there are no nodes, we don't need to do any work
@@ -378,31 +379,32 @@
                     # references
                     refs_len = refs_len + (next_len - 1)
                     for reference in ref_list:
-                        if not PyTuple_CheckExact(reference):
+                        if (not PyTuple_CheckExact(reference)
+                            and not StaticTuple_CheckExact(reference)):
                             raise TypeError(
                                 'We expect references to be tuples not: %s'
                                 % type(reference))
-                        next_len = PyTuple_GET_SIZE(reference)
+                        next_len = len(reference)
                         if next_len > 0:
                             # We will need (len - 1) '\x00' characters to
                             # separate the reference key
                             refs_len = refs_len + (next_len - 1)
                             for i from 0 <= i < next_len:
-                                ref_bit = PyTuple_GET_ITEM_ptr_object(reference, i)
-                                if not PyString_CheckExact_ptr(ref_bit):
+                                ref_bit = reference[i]
+                                if not PyString_CheckExact(ref_bit):
                                     raise TypeError('We expect reference bits'
                                         ' to be strings not: %s'
                                         % type(<object>ref_bit))
-                                refs_len = refs_len + PyString_GET_SIZE_ptr(ref_bit)
+                                refs_len = refs_len + PyString_GET_SIZE(ref_bit)
 
     # So we have the (key NULL refs NULL value LF)
     key_len = PyString_Size(string_key)
-    val = PyTuple_GET_ITEM_ptr_object(node, 2)
-    if not PyString_CheckExact_ptr(val):
+    val = node[2] # PyTuple_GET_ITEM_ptr_object(node, 2)
+    if not PyString_CheckExact(val):
         raise TypeError('Expected a plain str for value not: %s'
-                        % type(<object>val))
-    value = PyString_AS_STRING_ptr(val)
-    value_len = PyString_GET_SIZE_ptr(val)
+                        % type(val))
+    value = PyString_AS_STRING(val)
+    value_len = PyString_GET_SIZE(val)
     flat_len = (key_len + 1 + refs_len + 1 + value_len + 1)
     line = PyString_FromStringAndSize(NULL, flat_len)
     # Get a pointer to the new buffer
@@ -424,14 +426,14 @@
                     out[0] = c'\r'
                     out = out + 1
                 first_reference = 0
-                next_len = PyTuple_GET_SIZE(reference)
+                next_len = len(reference)
                 for i from 0 <= i < next_len:
                     if i != 0:
                         out[0] = c'\x00'
                         out = out + 1
-                    ref_bit = PyTuple_GET_ITEM_ptr_object(reference, i)
-                    ref_bit_len = PyString_GET_SIZE_ptr(ref_bit)
-                    memcpy(out, PyString_AS_STRING_ptr(ref_bit), ref_bit_len)
+                    ref_bit = reference[i] #PyTuple_GET_ITEM_ptr_object(reference, i)
+                    ref_bit_len = PyString_GET_SIZE(ref_bit)
+                    memcpy(out, PyString_AS_STRING(ref_bit), ref_bit_len)
                     out = out + ref_bit_len
     out[0] = c'\0'
     out = out  + 1

=== modified file 'bzrlib/_chk_map_py.py'
--- a/bzrlib/_chk_map_py.py	2009-04-09 20:23:07 +0000
+++ b/bzrlib/_chk_map_py.py	2009-09-30 21:53:59 +0000
@@ -156,3 +156,5 @@
     result._search_prefix = common_prefix
     return result
 
+
+_key_type = tuple

=== modified file 'bzrlib/_chk_map_pyx.pyx'
--- a/bzrlib/_chk_map_pyx.pyx	2009-06-22 12:52:39 +0000
+++ b/bzrlib/_chk_map_pyx.pyx	2009-09-30 21:53:59 +0000
@@ -59,9 +59,31 @@
 
     uLong crc32(uLong crc, Bytef *buf, uInt len)
 
-
+cdef extern from "_static_tuple_c.h":
+    void **StaticTuple_API
+    int import_static_tuple()
+
+    object StaticTuple_New(Py_ssize_t)
+    object StaticTuple_intern(object)
+    # Steals a reference and val must be a String or StaticTuple, no checking
+    # is done
+    void StaticTuple_SET_ITEM(object key, Py_ssize_t offset, object val)
+    object StaticTuple_GET_ITEM(object key, Py_ssize_t offset)
+    int StaticTuple_CheckExact(object)
+
+
+from bzrlib import _static_tuple_c
+# This sets up the StaticTuple C_API functionality
+if import_static_tuple() == -1 or StaticTuple_API == NULL:
+    raise ImportError('failed to import_static_tuple()')
+cdef object StaticTuple
+StaticTuple = _static_tuple_c.StaticTuple
+
+cdef object _LeafNode
 _LeafNode = None
+cdef object _InternalNode
 _InternalNode = None
+cdef object _unknown
 _unknown = None
 
 # We shouldn't just copy this from _dirstate_helpers_pyx
@@ -89,11 +111,11 @@
     cdef uInt crc_val
     cdef Py_ssize_t out_off
     cdef char *c_out
-    cdef PyObject *bit
+    # cdef PyObject *bit
 
-    if not PyTuple_CheckExact(key):
+    if not PyTuple_CheckExact(key) and not StaticTuple_CheckExact(key):
         raise TypeError('key %r is not a tuple' % (key,))
-    num_bits = PyTuple_GET_SIZE(key)
+    num_bits = len(key)
     # 4 bytes per crc32, and another 1 byte between bits
     num_out_bytes = (9 * num_bits) - 1
     out = PyString_FromStringAndSize(NULL, num_out_bytes)
@@ -105,11 +127,13 @@
         # We use the _ptr variant, because GET_ITEM returns a borrowed
         # reference, and Pyrex assumes that returned 'object' are a new
         # reference
-        bit = PyTuple_GET_ITEM_ptr(key, i)
-        if not PyString_CheckExact_ptr(bit):
+        # XXX: This needs to be updated for PySequence_GetItem since both
+        #      PyTuple and StaticTuple support that api
+        bit = key[i]# PyTuple_GET_ITEM_ptr(key, i)
+        if not PyString_CheckExact(bit):
             raise TypeError('Bit %d of %r is not a string' % (i, key))
-        c_bit = <Bytef *>PyString_AS_STRING_ptr(bit)
-        c_len = PyString_GET_SIZE_ptr(bit)
+        c_bit = <Bytef *>PyString_AS_STRING(bit)
+        c_len = PyString_GET_SIZE(bit)
         crc_val = crc32(0, c_bit, c_len)
         # Hex(val) order
         sprintf(c_out, '%08X', crc_val)
@@ -127,11 +151,11 @@
     cdef uInt crc_val
     cdef Py_ssize_t out_off
     cdef char *c_out
-    cdef PyObject *bit
+    # cdef PyObject *bit
 
-    if not PyTuple_CheckExact(key):
+    if not PyTuple_CheckExact(key) and not StaticTuple_CheckExact(key):
         raise TypeError('key %r is not a tuple' % (key,))
-    num_bits = PyTuple_GET_SIZE(key)
+    num_bits = len(key)
     # 4 bytes per crc32, and another 1 byte between bits
     num_out_bytes = (5 * num_bits) - 1
     out = PyString_FromStringAndSize(NULL, num_out_bytes)
@@ -140,12 +164,12 @@
         if i > 0:
             c_out[0] = c'\x00'
             c_out = c_out + 1
-        bit = PyTuple_GET_ITEM_ptr(key, i)
-        if not PyString_CheckExact_ptr(bit):
+        bit = key[i] # PyTuple_GET_ITEM_ptr(key, i)
+        if not PyString_CheckExact(bit):
             raise TypeError('Bit %d of %r is not a string: %r' % (i, key,
-            <object>bit))
-        c_bit = <Bytef *>PyString_AS_STRING_ptr(bit)
-        c_len = PyString_GET_SIZE_ptr(bit)
+            bit))
+        c_bit = <Bytef *>PyString_AS_STRING(bit)
+        c_len = PyString_GET_SIZE(bit)
         crc_val = crc32(0, c_bit, c_len)
         # MSB order
         c_out[0] = (crc_val >> 24) & 0xFF
@@ -265,12 +289,12 @@
             if next_line == NULL:
                 raise ValueError('missing trailing newline')
             cur = next_line + 1
-        entry_bits = PyTuple_New(width)
+        entry_bits = StaticTuple_New(width)
         for i from 0 <= i < num_prefix_bits:
             entry = prefix_bits[i]
             # SET_ITEM 'steals' a reference
             Py_INCREF(entry)
-            PyTuple_SET_ITEM(entry_bits, i, entry)
+            StaticTuple_SET_ITEM(entry_bits, i, entry)
         value = PyString_FromStringAndSize(value_start, next_line - value_start)
         # The next entry bit needs the 'tail' from the prefix, and first part
         # of the line
@@ -288,7 +312,7 @@
             memcpy(c_entry + prefix_tail_len, line_start, next_null - line_start)
         Py_INCREF(entry)
         i = num_prefix_bits
-        PyTuple_SET_ITEM(entry_bits, i, entry)
+        StaticTuple_SET_ITEM(entry_bits, i, entry)
         while next_null != last_null: # We have remaining bits
             i = i + 1
             if i > width:
@@ -301,11 +325,12 @@
             entry = PyString_FromStringAndSize(entry_start,
                                                next_null - entry_start)
             Py_INCREF(entry)
-            PyTuple_SET_ITEM(entry_bits, i, entry)
+            StaticTuple_SET_ITEM(entry_bits, i, entry)
         if len(entry_bits) != width:
             raise AssertionError(
                 'Incorrect number of elements (%d vs %d)'
                 % (len(entry_bits)+1, width + 1))
+        entry_bits = StaticTuple_intern(entry_bits)
         PyDict_SetItem(items, entry_bits, value)
     if len(items) != length:
         raise ValueError("item count (%d) mismatch for key %s,"
@@ -384,7 +409,8 @@
         memcpy(c_item_prefix + prefix_length, cur, next_null - cur)
         flat_key = PyString_FromStringAndSize(next_null + 1,
                                               next_line - next_null - 1)
-        PyDict_SetItem(items, item_prefix, (flat_key,))
+        flat_key = StaticTuple(flat_key).intern()
+        PyDict_SetItem(items, item_prefix, flat_key)
         cur = next_line + 1
     assert len(items) > 0
     result._items = items
@@ -399,3 +425,5 @@
     result._search_prefix = PyString_FromStringAndSize(prefix, prefix_length)
     return result
 
+
+_key_type = StaticTuple

=== modified file 'bzrlib/_static_tuple_c.c'
--- a/bzrlib/_static_tuple_c.c	2009-09-30 21:17:48 +0000
+++ b/bzrlib/_static_tuple_c.c	2009-09-30 21:53:59 +0000
@@ -712,6 +712,11 @@
     PyModule_AddObject(m, "_empty_tuple", (PyObject *)_empty_tuple);
 }
 
+static int
+_StaticTuple_CheckExact(PyObject *obj)
+{
+    return StaticTuple_CheckExact(obj);
+}
 
 static void
 setup_c_api(PyObject *m)
@@ -721,6 +726,8 @@
 
     StaticTuple_API[StaticTuple_New_NUM] = (void *)StaticTuple_New;
     StaticTuple_API[StaticTuple_intern_NUM] = (void *)StaticTuple_intern;
+    StaticTuple_API[StaticTuple_CheckExact_NUM] = 
+        (void*)_StaticTuple_CheckExact; 
     c_api_object = PyCObject_FromVoidPtr((void *)StaticTuple_API, NULL);
     if (c_api_object != NULL) {
         PyModule_AddObject(m, "_C_API", c_api_object);

=== modified file 'bzrlib/_static_tuple_c.h'
--- a/bzrlib/_static_tuple_c.h	2009-09-30 21:17:48 +0000
+++ b/bzrlib/_static_tuple_c.h	2009-09-30 21:53:59 +0000
@@ -64,7 +64,7 @@
     PyObject_VAR_HEAD
     PyObject *table[1];
 } KeyIntern;
-extern PyTypeObject StaticTuple_Type;
+// extern PyTypeObject StaticTuple_Type;
 
 #define StaticTuple_CheckExact(op) (Py_TYPE(op) == &StaticTuple_Type)
 #define StaticTuple_SET_ITEM(key, offset, val) \
@@ -75,9 +75,10 @@
 /* C API Functions */
 #define StaticTuple_New_NUM 0
 #define StaticTuple_intern_NUM 1
+#define StaticTuple_CheckExact_NUM 2
 
 /* Total number of C API Pointers */
-#define StaticTuple_API_pointers 2
+#define StaticTuple_API_pointers 3
 
 #ifdef STATIC_TUPLE_MODULE
 /* Used when compiling _static_tuple_c.c */
@@ -91,6 +92,9 @@
 
 static PyObject *(*StaticTuple_New)(Py_ssize_t);
 static PyObject *(*StaticTuple_intern)(PyObject *);
+#undef StaticTuple_CheckExact
+static int (*StaticTuple_CheckExact)(PyObject *);
+
 
 /* Return -1 and set exception on error, 0 on success */
 static int
@@ -116,6 +120,7 @@
     StaticTuple_API = (void **)PyCObject_AsVoidPtr(c_api_object);
     StaticTuple_New = StaticTuple_API[StaticTuple_New_NUM];
     StaticTuple_intern = StaticTuple_API[StaticTuple_intern_NUM];
+    StaticTuple_CheckExact = StaticTuple_API[StaticTuple_CheckExact_NUM];
     Py_DECREF(c_api_object);
     return 0;
 }

=== modified file 'bzrlib/chk_map.py'
--- a/bzrlib/chk_map.py	2009-08-04 14:10:09 +0000
+++ b/bzrlib/chk_map.py	2009-09-30 21:53:59 +0000
@@ -133,7 +133,7 @@
 
     def _ensure_root(self):
         """Ensure that the root node is an object not a key."""
-        if type(self._root_node) is tuple:
+        if type(self._root_node) in (_key_type, tuple):
             # Demand-load the root
             self._root_node = self._get_node(self._root_node)
 
@@ -147,7 +147,7 @@
         :param node: A tuple key or node object.
         :return: A node object.
         """
-        if type(node) is tuple:
+        if type(node) in (tuple, _key_type):
             bytes = self._read_bytes(node)
             return _deserialise(bytes, node,
                 search_key_func=self._search_key_func)
@@ -486,7 +486,7 @@
 
     def key(self):
         """Return the key for this map."""
-        if type(self._root_node) is tuple:
+        if type(self._root_node) in (tuple, _key_type):
             return self._root_node
         else:
             return self._root_node._key
@@ -516,7 +516,7 @@
 
     def _node_key(self, node):
         """Get the key for a node whether it's a tuple or node."""
-        if type(node) is tuple:
+        if type(node) in (tuple, _key_type):
             return node
         else:
             return node._key
@@ -542,7 +542,7 @@
 
         :return: The key of the root node.
         """
-        if type(self._root_node) is tuple:
+        if type(self._root_node) in (tuple, _key_type):
             # Already saved.
             return self._root_node
         keys = list(self._root_node.serialise(self._store))
@@ -1024,7 +1024,7 @@
             # for whatever we are missing
             shortcut = True
             for prefix, node in self._items.iteritems():
-                if node.__class__ is tuple:
+                if node.__class__ in (tuple, _key_type):
                     keys[node] = (prefix, None)
                 else:
                     yield node, None
@@ -1059,7 +1059,7 @@
                     # A given key can only match 1 child node, if it isn't
                     # there, then we can just return nothing
                     return
-                if node.__class__ is tuple:
+                if node.__class__ in (tuple, _key_type):
                     keys[node] = (search_prefix, [key])
                 else:
                     # This is loaded, and the only thing that can match,
@@ -1092,7 +1092,7 @@
                         # We can ignore this one
                         continue
                     node_key_filter = prefix_to_keys[search_prefix]
-                    if node.__class__ is tuple:
+                    if node.__class__ in (tuple, _key_type):
                         keys[node] = (search_prefix, node_key_filter)
                     else:
                         yield node, node_key_filter
@@ -1107,7 +1107,7 @@
                         if sub_prefix in length_filter:
                             node_key_filter.extend(prefix_to_keys[sub_prefix])
                     if node_key_filter: # this key matched something, yield it
-                        if node.__class__ is tuple:
+                        if node.__class__ in (tuple, _key_type):
                             keys[node] = (prefix, node_key_filter)
                         else:
                             yield node, node_key_filter
@@ -1245,7 +1245,7 @@
         :return: An iterable of the keys inserted by this operation.
         """
         for node in self._items.itervalues():
-            if type(node) is tuple:
+            if type(node) in (tuple, _key_type):
                 # Never deserialised.
                 continue
             if node._key is not None:
@@ -1262,7 +1262,7 @@
         lines.append('%s\n' % (self._search_prefix,))
         prefix_len = len(self._search_prefix)
         for prefix, node in sorted(self._items.items()):
-            if type(node) is tuple:
+            if type(node) in (tuple, _key_type):
                 key = node[0]
             else:
                 key = node._key[0]
@@ -1307,7 +1307,7 @@
             raise AssertionError("unserialised nodes have no refs.")
         refs = []
         for value in self._items.itervalues():
-            if type(value) is tuple:
+            if type(value) in (tuple, _key_type):
                 refs.append(value)
             else:
                 refs.append(value.key())
@@ -1639,6 +1639,7 @@
         _search_key_255,
         _deserialise_leaf_node,
         _deserialise_internal_node,
+        _key_type,
         )
 except ImportError:
     from bzrlib._chk_map_py import (
@@ -1646,6 +1647,7 @@
         _search_key_255,
         _deserialise_leaf_node,
         _deserialise_internal_node,
+        _key_type,
         )
 search_key_registry.register('hash-16-way', _search_key_16)
 search_key_registry.register('hash-255-way', _search_key_255)

=== modified file 'bzrlib/tests/test_chk_map.py'
--- a/bzrlib/tests/test_chk_map.py	2009-07-16 23:28:49 +0000
+++ b/bzrlib/tests/test_chk_map.py	2009-09-30 21:53:59 +0000
@@ -831,13 +831,13 @@
         # 'ab' and 'ac' nodes
         chkmap.map(('aad',), 'v')
         self.assertIsInstance(chkmap._root_node._items['aa'], InternalNode)
-        self.assertIsInstance(chkmap._root_node._items['ab'], tuple)
-        self.assertIsInstance(chkmap._root_node._items['ac'], tuple)
+        self.assertIsInstance(chkmap._root_node._items['ab'], (tuple, chk_map._key_type))
+        self.assertIsInstance(chkmap._root_node._items['ac'], (tuple, chk_map._key_type))
         # Unmapping 'acd' can notice that 'aa' is an InternalNode and not have
         # to map in 'ab'
         chkmap.unmap(('acd',))
         self.assertIsInstance(chkmap._root_node._items['aa'], InternalNode)
-        self.assertIsInstance(chkmap._root_node._items['ab'], tuple)
+        self.assertIsInstance(chkmap._root_node._items['ab'], (tuple, chk_map._key_type))
 
     def test_unmap_without_fitting_doesnt_page_in(self):
         store = self.get_chk_bytes()
@@ -860,8 +860,9 @@
         chkmap.map(('aaf',), 'v')
         # At this point, the previous nodes should not be paged in, but the
         # newly added nodes would be
-        self.assertIsInstance(chkmap._root_node._items['aaa'], tuple)
-        self.assertIsInstance(chkmap._root_node._items['aab'], tuple)
+        self.assertIsInstance(chkmap._root_node._items['aaa'], (tuple,
+        chk_map._key_type))
+        self.assertIsInstance(chkmap._root_node._items['aab'], (tuple, chk_map._key_type))
         self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
         self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
         self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
@@ -869,8 +870,8 @@
         # Now unmapping one of the new nodes will use only the already-paged-in
         # nodes to determine that we don't need to do more.
         chkmap.unmap(('aaf',))
-        self.assertIsInstance(chkmap._root_node._items['aaa'], tuple)
-        self.assertIsInstance(chkmap._root_node._items['aab'], tuple)
+        self.assertIsInstance(chkmap._root_node._items['aaa'], (tuple, chk_map._key_type))
+        self.assertIsInstance(chkmap._root_node._items['aab'], (tuple, chk_map._key_type))
         self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
         self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
         self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
@@ -897,9 +898,12 @@
         chkmap.map(('aad',), 'v')
         # At this point, the previous nodes should not be paged in, but the
         # newly added node would be
-        self.assertIsInstance(chkmap._root_node._items['aaa'], tuple)
-        self.assertIsInstance(chkmap._root_node._items['aab'], tuple)
-        self.assertIsInstance(chkmap._root_node._items['aac'], tuple)
+        self.assertIsInstance(chkmap._root_node._items['aaa'], (tuple,
+        chk_map._key_type))
+        self.assertIsInstance(chkmap._root_node._items['aab'], (tuple,
+        chk_map._key_type))
+        self.assertIsInstance(chkmap._root_node._items['aac'], (tuple,
+        chk_map._key_type))
         self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
         # Unmapping the new node will check the existing nodes to see if they
         # would fit.
@@ -937,9 +941,12 @@
         chkmap.map(('aad',), 'v')
         # At this point, the previous nodes should not be paged in, but the
         # newly added node would be
-        self.assertIsInstance(chkmap._root_node._items['aaa'], tuple)
-        self.assertIsInstance(chkmap._root_node._items['aab'], tuple)
-        self.assertIsInstance(chkmap._root_node._items['aac'], tuple)
+        self.assertIsInstance(chkmap._root_node._items['aaa'], (tuple,
+        chk_map._key_type))
+        self.assertIsInstance(chkmap._root_node._items['aab'], (tuple,
+        chk_map._key_type))
+        self.assertIsInstance(chkmap._root_node._items['aac'], (tuple,
+        chk_map._key_type))
         self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
         # Now clear the page cache, and only include 2 of the children in the
         # cache
@@ -954,7 +961,8 @@
         # Unmapping the new node will check the nodes from the page cache
         # first, and not have to read in 'aaa'
         chkmap.unmap(('aad',))
-        self.assertIsInstance(chkmap._root_node._items['aaa'], tuple)
+        self.assertIsInstance(chkmap._root_node._items['aaa'], (tuple,
+        chk_map._key_type))
         self.assertIsInstance(chkmap._root_node._items['aab'], LeafNode)
         self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
 
@@ -974,9 +982,12 @@
         chkmap.map(('aaf',), 'val')
         # At this point, the previous nodes should not be paged in, but the
         # newly added node would be
-        self.assertIsInstance(chkmap._root_node._items['aaa'], tuple)
-        self.assertIsInstance(chkmap._root_node._items['aab'], tuple)
-        self.assertIsInstance(chkmap._root_node._items['aac'], tuple)
+        self.assertIsInstance(chkmap._root_node._items['aaa'], (tuple,
+        chk_map._key_type))
+        self.assertIsInstance(chkmap._root_node._items['aab'], (tuple,
+        chk_map._key_type))
+        self.assertIsInstance(chkmap._root_node._items['aac'], (tuple,
+        chk_map._key_type))
         self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
         self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
         self.assertIsInstance(chkmap._root_node._items['aaf'], LeafNode)
@@ -984,9 +995,12 @@
         # Unmapping a new node will see the other nodes that are already in
         # memory, and not need to page in anything else
         chkmap.unmap(('aad',))
-        self.assertIsInstance(chkmap._root_node._items['aaa'], tuple)
-        self.assertIsInstance(chkmap._root_node._items['aab'], tuple)
-        self.assertIsInstance(chkmap._root_node._items['aac'], tuple)
+        self.assertIsInstance(chkmap._root_node._items['aaa'], (tuple,
+        chk_map._key_type))
+        self.assertIsInstance(chkmap._root_node._items['aab'], (tuple,
+        chk_map._key_type))
+        self.assertIsInstance(chkmap._root_node._items['aac'], (tuple,
+        chk_map._key_type))
         self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
         self.assertIsInstance(chkmap._root_node._items['aaf'], LeafNode)
 
@@ -1031,8 +1045,8 @@
             {('a',): 'content here', ('b',): 'more content'},
             chk_bytes=basis._store, maximum_size=10)
         list(target.iter_changes(basis))
-        self.assertIsInstance(target._root_node, tuple)
-        self.assertIsInstance(basis._root_node, tuple)
+        self.assertIsInstance(target._root_node, (tuple, chk_map._key_type))
+        self.assertIsInstance(basis._root_node, (tuple, chk_map._key_type))
 
     def test_iter_changes_ab_ab_changed_values_shown(self):
         basis = self._get_map({('a',): 'content here', ('b',): 'more content'},
@@ -1932,7 +1946,7 @@
         # Ensure test validity: nothing paged in below the root.
         self.assertEqual(2,
             len([value for value in node._items.values()
-                if type(value) == tuple]))
+                if type(value) in (tuple, chk_map._key_type)]))
         # now, mapping to k3 should add a k3 leaf
         prefix, nodes = node.map(None, ('k3',), 'quux')
         self.assertEqual("k", prefix)
@@ -1971,7 +1985,7 @@
         # Ensure test validity: nothing paged in below the root.
         self.assertEqual(2,
             len([value for value in node._items.values()
-                if type(value) == tuple]))
+                if type(value) in (tuple, chk_map._key_type)]))
         # now, mapping to k23 causes k22 ('k2' in node) to split into k22 and
         # k23, which for simplicity in the current implementation generates
         # a new internal node between node, and k22/k23.



More information about the bazaar-commits mailing list