~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/btree_index.py

MergeĀ lp:bzr.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
"""B+Tree indices"""
19
19
 
 
20
import cStringIO
20
21
from bisect import bisect_right
21
22
import math
22
23
import tempfile
60
61
    def __init__(self):
61
62
        """Create a _BuilderRow."""
62
63
        self.nodes = 0
63
 
        self.spool = tempfile.TemporaryFile()
 
64
        self.spool = None# tempfile.TemporaryFile(prefix='bzr-index-row-')
64
65
        self.writer = None
65
66
 
66
67
    def finish_node(self, pad=True):
67
68
        byte_lines, _, padding = self.writer.finish()
68
69
        if self.nodes == 0:
 
70
            self.spool = cStringIO.StringIO()
69
71
            # padded note:
70
72
            self.spool.write("\x00" * _RESERVED_HEADER_BYTES)
 
73
        elif self.nodes == 1:
 
74
            # We got bigger than 1 node, switch to a temp file
 
75
            spool = tempfile.TemporaryFile(prefix='bzr-index-row-')
 
76
            spool.write(self.spool.getvalue())
 
77
            self.spool = spool
71
78
        skipped_bytes = 0
72
79
        if not pad and padding:
73
80
            del byte_lines[-1]
182
189
             backing_pos) = self._spill_mem_keys_and_combine()
183
190
        else:
184
191
            new_backing_file, size = self._spill_mem_keys_without_combining()
185
 
        dir_path, base_name = osutils.split(new_backing_file.name)
186
192
        # Note: The transport here isn't strictly needed, because we will use
187
193
        #       direct access to the new_backing._file object
188
 
        new_backing = BTreeGraphIndex(get_transport(dir_path),
189
 
                                      base_name, size)
 
194
        new_backing = BTreeGraphIndex(get_transport('.'), '<temp>', size)
190
195
        # GC will clean up the file
191
196
        new_backing._file = new_backing_file
192
197
        if self._combine_backing_indices:
379
384
        for row in reversed(rows):
380
385
            pad = (type(row) != _LeafBuilderRow)
381
386
            row.finish_node(pad=pad)
382
 
        result = tempfile.NamedTemporaryFile(prefix='bzr-index-')
383
387
        lines = [_BTSIGNATURE]
384
388
        lines.append(_OPTION_NODE_REFS + str(self.reference_lists) + '\n')
385
389
        lines.append(_OPTION_KEY_ELEMENTS + str(self._key_length) + '\n')
386
390
        lines.append(_OPTION_LEN + str(key_count) + '\n')
387
391
        row_lengths = [row.nodes for row in rows]
388
392
        lines.append(_OPTION_ROW_LENGTHS + ','.join(map(str, row_lengths)) + '\n')
 
393
        if row_lengths and row_lengths[-1] > 1:
 
394
            result = tempfile.NamedTemporaryFile(prefix='bzr-index-')
 
395
        else:
 
396
            result = cStringIO.StringIO()
389
397
        result.writelines(lines)
390
398
        position = sum(map(len, lines))
391
399
        root_row = True
628
636
    memory except when very large walks are done.
629
637
    """
630
638
 
631
 
    def __init__(self, transport, name, size):
 
639
    def __init__(self, transport, name, size, unlimited_cache=False):
632
640
        """Create a B+Tree index object on the index name.
633
641
 
634
642
        :param transport: The transport to read data for the index from.
638
646
            the initial read (to read the root node header) can be done
639
647
            without over-reading even on empty indices, and on small indices
640
648
            allows single-IO to read the entire index.
 
649
        :param unlimited_cache: If set to True, then instead of using an
 
650
            LRUCache with size _NODE_CACHE_SIZE, we will use a dict and always
 
651
            cache all leaf nodes.
641
652
        """
642
653
        self._transport = transport
643
654
        self._name = name
647
658
        self._root_node = None
648
659
        # Default max size is 100,000 leave values
649
660
        self._leaf_value_cache = None # lru_cache.LRUCache(100*1000)
650
 
        self._leaf_node_cache = lru_cache.LRUCache(_NODE_CACHE_SIZE)
651
 
        # We could limit this, but even a 300k record btree has only 3k leaf
652
 
        # nodes, and only 20 internal nodes. So the default of 100 nodes in an
653
 
        # LRU would mean we always cache everything anyway, no need to pay the
654
 
        # overhead of LRU
655
 
        self._internal_node_cache = fifo_cache.FIFOCache(100)
 
661
        if unlimited_cache:
 
662
            self._leaf_node_cache = {}
 
663
            self._internal_node_cache = {}
 
664
        else:
 
665
            self._leaf_node_cache = lru_cache.LRUCache(_NODE_CACHE_SIZE)
 
666
            # We use a FIFO here just to prevent possible blowout. However, a
 
667
            # 300k record btree has only 3k leaf nodes, and only 20 internal
 
668
            # nodes. A value of 100 scales to ~100*100*100 = 1M records.
 
669
            self._internal_node_cache = fifo_cache.FIFOCache(100)
656
670
        self._key_count = None
657
671
        self._row_lengths = None
658
672
        self._row_offsets = None # Start of each row, [-1] is the end
690
704
                if start_of_leaves is None:
691
705
                    start_of_leaves = self._row_offsets[-2]
692
706
                if node_pos < start_of_leaves:
693
 
                    self._internal_node_cache.add(node_pos, node)
 
707
                    self._internal_node_cache[node_pos] = node
694
708
                else:
695
 
                    self._leaf_node_cache.add(node_pos, node)
 
709
                    self._leaf_node_cache[node_pos] = node
696
710
            found[node_pos] = node
697
711
        return found
698
712
 
1526
1540
 
1527
1541
try:
1528
1542
    from bzrlib import _btree_serializer_pyx as _btree_serializer
1529
 
except ImportError:
 
1543
except ImportError, e:
 
1544
    osutils.failed_to_load_extension(e)
1530
1545
    from bzrlib import _btree_serializer_py as _btree_serializer