202
203
if reference not in self._nodes:
203
204
self._check_key(reference)
204
205
absent_references.append(reference)
205
207
node_refs.append(tuple(reference_list))
206
209
return tuple(node_refs), absent_references
208
211
def add_node(self, key, value, references=()):
333
343
if combine_backing_indices is not None:
334
344
self._combine_backing_indices = combine_backing_indices
346
def find_ancestry(self, keys, ref_list_num):
347
"""See CombinedGraphIndex.find_ancestry()"""
353
for _, key, value, ref_lists in self.iter_entries(pending):
354
parent_keys = ref_lists[ref_list_num]
355
parent_map[key] = parent_keys
356
next_pending.update([p for p in parent_keys if p not in
358
missing_keys.update(pending.difference(parent_map))
359
pending = next_pending
360
return parent_map, missing_keys
337
363
class GraphIndex(object):
338
364
"""An index for data with embedded graphs.
352
378
suitable for production use. :XXX
355
def __init__(self, transport, name, size):
381
def __init__(self, transport, name, size, unlimited_cache=False):
356
382
"""Open an index called name on transport.
358
384
:param transport: A bzrlib.transport.Transport.
442
468
# there must be one line - the empty trailer line.
443
469
raise errors.BadIndexData(self)
471
def clear_cache(self):
472
"""Clear out any cached/memoized values.
474
This can be called at any time, but generally it is used when we have
475
extracted some information, but don't expect to be requesting any more
445
479
def external_references(self, ref_list_num):
446
480
"""Return references that are not present in this index.
702
736
# the last thing looked up was a terminal element
703
737
yield (self, ) + key_dict
739
def _find_ancestors(self, keys, ref_list_num, parent_map, missing_keys):
740
"""See BTreeIndex._find_ancestors."""
741
# The api can be implemented as a trivial overlay on top of
742
# iter_entries, it is not an efficient implementation, but it at least
746
for index, key, value, refs in self.iter_entries(keys):
747
parent_keys = refs[ref_list_num]
749
parent_map[key] = parent_keys
750
search_keys.update(parent_keys)
751
# Figure out what, if anything, was missing
752
missing_keys.update(set(keys).difference(found_keys))
753
search_keys = search_keys.difference(parent_map)
705
756
def key_count(self):
706
757
"""Return an estimate of the number of keys in this index.
1297
1353
except errors.NoSuchFile:
1298
1354
self._reload_or_raise()
1356
def find_ancestry(self, keys, ref_list_num):
1357
"""Find the complete ancestry for the given set of keys.
1359
Note that this is a whole-ancestry request, so it should be used
1362
:param keys: An iterable of keys to look for
1363
:param ref_list_num: The reference list which references the parents
1365
:return: (parent_map, missing_keys)
1367
missing_keys = set()
1369
keys_to_lookup = set(keys)
1371
while keys_to_lookup:
1372
# keys that *all* indexes claim are missing, stop searching them
1374
all_index_missing = None
1375
# print 'gen\tidx\tsub\tn_keys\tn_pmap\tn_miss'
1376
# print '%4d\t\t\t%4d\t%5d\t%5d' % (generation, len(keys_to_lookup),
1378
# len(missing_keys))
1379
for index_idx, index in enumerate(self._indices):
1380
# TODO: we should probably be doing something with
1381
# 'missing_keys' since we've already determined that
1382
# those revisions have not been found anywhere
1383
index_missing_keys = set()
1384
# Find all of the ancestry we can from this index
1385
# keep looking until the search_keys set is empty, which means
1386
# things we didn't find should be in index_missing_keys
1387
search_keys = keys_to_lookup
1389
# print ' \t%2d\t\t%4d\t%5d\t%5d' % (
1390
# index_idx, len(search_keys),
1391
# len(parent_map), len(index_missing_keys))
1394
# TODO: ref_list_num should really be a parameter, since
1395
# CombinedGraphIndex does not know what the ref lists
1397
search_keys = index._find_ancestors(search_keys,
1398
ref_list_num, parent_map, index_missing_keys)
1399
# print ' \t \t%2d\t%4d\t%5d\t%5d' % (
1400
# sub_generation, len(search_keys),
1401
# len(parent_map), len(index_missing_keys))
1402
# Now set whatever was missing to be searched in the next index
1403
keys_to_lookup = index_missing_keys
1404
if all_index_missing is None:
1405
all_index_missing = set(index_missing_keys)
1407
all_index_missing.intersection_update(index_missing_keys)
1408
if not keys_to_lookup:
1410
if all_index_missing is None:
1411
# There were no indexes, so all search keys are 'missing'
1412
missing_keys.update(keys_to_lookup)
1413
keys_to_lookup = None
1415
missing_keys.update(all_index_missing)
1416
keys_to_lookup.difference_update(all_index_missing)
1417
return parent_map, missing_keys
1300
1419
def key_count(self):
1301
1420
"""Return an estimate of the number of keys in this index.