~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/index.py

  • Committer: Robert Collins
  • Date: 2007-10-17 09:39:41 UTC
  • mfrom: (2911 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2933.
  • Revision ID: robertc@robertcollins.net-20071017093941-v7d1djrt2617citb
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
249
249
        """
250
250
        self._transport = transport
251
251
        self._name = name
252
 
        # becomes a dict of key:(value, reference-list-byte-locations) 
253
 
        # used by the bisection interface to store parsed but not resolved
254
 
        # keys.
 
252
        # Becomes a dict of key:(value, reference-list-byte-locations) used by
 
253
        # the bisection interface to store parsed but not resolved keys.
255
254
        self._bisect_nodes = None
 
255
        # Becomes a dict of key:(value, reference-list-keys) which are ready to
 
256
        # be returned directly to callers.
256
257
        self._nodes = None
257
258
        # a sorted list of slice-addresses for the parsed bytes of the file.
258
259
        # e.g. (0,1) would mean that byte 0 is parsed.
286
287
            mutter('Reading entire index %s', self._transport.abspath(self._name))
287
288
        stream = self._transport.get(self._name)
288
289
        self._read_prefix(stream)
289
 
        expected_elements = 3 + self._key_length
 
290
        self._expected_elements = 3 + self._key_length
290
291
        line_count = 0
291
292
        # raw data keyed by offset
292
293
        self._keys_by_offset = {}
295
296
        self._nodes_by_key = {}
296
297
        trailers = 0
297
298
        pos = stream.tell()
298
 
        for line in stream.readlines():
299
 
            if line == '\n':
300
 
                trailers += 1
301
 
                continue
302
 
            elements = line.split('\0')
303
 
            if len(elements) != expected_elements:
304
 
                raise errors.BadIndexData(self)
305
 
            # keys are tuples
306
 
            key = tuple(elements[:self._key_length])
307
 
            absent, references, value = elements[-3:]
308
 
            value = value[:-1] # remove the newline
309
 
            ref_lists = []
310
 
            for ref_string in references.split('\t'):
311
 
                ref_lists.append(tuple([
312
 
                    int(ref) for ref in ref_string.split('\r') if ref
313
 
                    ]))
314
 
            ref_lists = tuple(ref_lists)
315
 
            self._keys_by_offset[pos] = (key, absent, ref_lists, value)
316
 
            pos += len(line)
 
299
        lines = stream.read().split('\n')
 
300
        del lines[-1]
 
301
        _, _, _, trailers = self._parse_lines(lines, pos)
317
302
        for key, absent, references, value in self._keys_by_offset.itervalues():
318
303
            if absent:
319
304
                continue
320
305
            # resolve references:
321
306
            if self.node_ref_lists:
322
 
                node_refs = []
323
 
                for ref_list in references:
324
 
                    node_refs.append(tuple([self._keys_by_offset[ref][0] for ref in ref_list]))
325
 
                node_value = (value, tuple(node_refs))
 
307
                node_value = (value, self._resolve_references(references))
326
308
            else:
327
309
                node_value = value
328
310
            self._nodes[key] = node_value
394
376
            raise errors.BadIndexOptions(self)
395
377
 
396
378
    def _resolve_references(self, references):
397
 
        """Return the resolved key references for references."""
 
379
        """Return the resolved key references for references.
 
380
        
 
381
        References are resolved by looking up the location of the key in the
 
382
        _keys_by_offset map and substituting the key name, preserving ordering.
 
383
 
 
384
        :param references: An iterable of iterables of key locations. e.g. 
 
385
            [[123, 456], [123]]
 
386
        :return: A tuple of tuples of keys.
 
387
        """
398
388
        node_refs = []
399
389
        for ref_list in references:
400
390
            node_refs.append(tuple([self._keys_by_offset[ref][0] for ref in ref_list]))
480
470
            return self._iter_entries_from_total_buffer(keys)
481
471
        else:
482
472
            return (result[1] for result in bisect_multi_bytes(
483
 
                self.lookup_keys_via_location, self._size, keys))
 
473
                self._lookup_keys_via_location, self._size, keys))
484
474
 
485
475
    def iter_entries_prefix(self, keys):
486
476
        """Iterate over keys within the index using prefix matching.
569
559
            self._buffer_all()
570
560
        return self._key_count
571
561
 
572
 
    def lookup_keys_via_location(self, location_keys):
 
562
    def _lookup_keys_via_location(self, location_keys):
573
563
        """Public interface for implementing bisection.
574
564
 
575
565
        If _buffer_all has been called, then all the data for the index is in
577
567
        cache because it cannot pre-resolve all indices, which buffer_all does
578
568
        for performance.
579
569
 
580
 
        :param location_keys: A list of location, key tuples.
 
570
        :param location_keys: A list of location(byte offset), key tuples.
581
571
        :return: A list of (location_key, result) tuples as expected by
582
572
            bzrlib.bisect_multi.bisect_multi_bytes.
583
573
        """
673
663
            if location + length > self._size:
674
664
                length = self._size - location
675
665
            # TODO: trim out parsed locations (e.g. if the 800 is into the
676
 
            # parsed region trim it, and dont use the ajust_for_latency
 
666
            # parsed region trim it, and dont use the adjust_for_latency
677
667
            # facility)
678
668
            if length > 0:
679
669
                readv_ranges.append((location, length))
851
841
        lines = trimmed_data.split('\n')
852
842
        del lines[-1]
853
843
        pos = offset
 
844
        first_key, last_key, nodes, _ = self._parse_lines(lines, pos)
 
845
        for key, value in nodes:
 
846
            self._bisect_nodes[key] = value
 
847
        self._parsed_bytes(offset, first_key,
 
848
            offset + len(trimmed_data), last_key)
 
849
        return offset + len(trimmed_data), last_segment
 
850
 
 
851
    def _parse_lines(self, lines, pos):
 
852
        key = None
854
853
        first_key = None
855
 
        key = None
 
854
        trailers = 0
 
855
        nodes = []
856
856
        for line in lines:
857
857
            if line == '':
858
858
                # must be at the end
859
 
                assert self._size == pos + 1, "%s %s" % (self._size, pos)
 
859
                if self._size:
 
860
                    assert self._size == pos + 1, "%s %s" % (self._size, pos)
 
861
                trailers += 1
860
862
                continue
861
863
            elements = line.split('\0')
862
864
            if len(elements) != self._expected_elements:
880
882
                node_value = (value, ref_lists)
881
883
            else:
882
884
                node_value = value
883
 
            self._bisect_nodes[key] = node_value
 
885
            nodes.append((key, node_value))
884
886
            # print "parsed ", key
885
 
        self._parsed_bytes(offset, first_key, offset + len(trimmed_data), key)
886
 
        return offset + len(trimmed_data), last_segment
 
887
        return first_key, key, nodes, trailers
887
888
 
888
889
    def _parsed_bytes(self, start, start_key, end, end_key):
889
890
        """Mark the bytes from start to end as parsed.