377
366
:return: (versioned_file, reload_counter)
378
367
versioned_file a KnitVersionedFiles using the packs for access
380
builder = self.make_branch_builder('.', format="1.9")
381
builder.start_series()
382
builder.build_snapshot('rev-1', None, [
383
('add', ('', 'root-id', 'directory', None)),
384
('add', ('file', 'file-id', 'file', 'content\nrev 1\n')),
386
builder.build_snapshot('rev-2', ['rev-1'], [
387
('modify', ('file-id', 'content\nrev 2\n')),
389
builder.build_snapshot('rev-3', ['rev-2'], [
390
('modify', ('file-id', 'content\nrev 3\n')),
392
builder.finish_series()
393
b = builder.get_branch()
395
self.addCleanup(b.unlock)
369
tree = self.make_branch_and_memory_tree('tree')
371
self.addCleanup(tree.branch.repository.unlock)
372
tree.add([''], ['root-id'])
373
tree.commit('one', rev_id='rev-1')
374
tree.commit('two', rev_id='rev-2')
375
tree.commit('three', rev_id='rev-3')
396
376
# Pack these three revisions into another pack file, but don't remove
378
repo = tree.branch.repository
399
379
collection = repo._pack_collection
400
380
collection.ensure_loaded()
401
381
orig_packs = collection.packs
402
packer = knitpack_repo.KnitPacker(collection, orig_packs, '.testpack')
382
packer = pack_repo.Packer(collection, orig_packs, '.testpack')
403
383
new_pack = packer.pack()
404
384
# forget about the new pack
405
385
collection.reset()
406
386
repo.refresh_data()
387
vf = tree.branch.repository.revisions
408
389
# Set up a reload() function that switches to using the new pack file
409
390
new_index = new_pack.revision_index
410
391
access_tuple = new_pack.access_tuple()
1316
1301
class LowLevelKnitIndexTests_c(LowLevelKnitIndexTests):
1318
_test_needs_features = [compiled_knit_feature]
1303
_test_needs_features = [CompiledKnitFeature]
1320
1305
def get_knit_index(self, transport, name, mode):
1321
1306
mapper = ConstantMapper(name)
1322
from bzrlib._knit_load_data_pyx import _load_data_c
1323
self.overrideAttr(knit, '_load_data', _load_data_c)
1307
orig = knit._load_data
1309
knit._load_data = orig
1310
self.addCleanup(reset)
1311
from bzrlib._knit_load_data_c import _load_data_c
1312
knit._load_data = _load_data_c
1324
1313
allow_writes = lambda: mode == 'w'
1325
return _KndxIndex(transport, mapper, lambda:None,
1326
allow_writes, lambda:True)
1329
class Test_KnitAnnotator(TestCaseWithMemoryTransport):
1331
def make_annotator(self):
1332
factory = knit.make_pack_factory(True, True, 1)
1333
vf = factory(self.get_transport())
1334
return knit._KnitAnnotator(vf)
1336
def test__expand_fulltext(self):
1337
ann = self.make_annotator()
1338
rev_key = ('rev-id',)
1339
ann._num_compression_children[rev_key] = 1
1340
res = ann._expand_record(rev_key, (('parent-id',),), None,
1341
['line1\n', 'line2\n'], ('fulltext', True))
1342
# The content object and text lines should be cached appropriately
1343
self.assertEqual(['line1\n', 'line2'], res)
1344
content_obj = ann._content_objects[rev_key]
1345
self.assertEqual(['line1\n', 'line2\n'], content_obj._lines)
1346
self.assertEqual(res, content_obj.text())
1347
self.assertEqual(res, ann._text_cache[rev_key])
1349
def test__expand_delta_comp_parent_not_available(self):
1350
# Parent isn't available yet, so we return nothing, but queue up this
1351
# node for later processing
1352
ann = self.make_annotator()
1353
rev_key = ('rev-id',)
1354
parent_key = ('parent-id',)
1355
record = ['0,1,1\n', 'new-line\n']
1356
details = ('line-delta', False)
1357
res = ann._expand_record(rev_key, (parent_key,), parent_key,
1359
self.assertEqual(None, res)
1360
self.assertTrue(parent_key in ann._pending_deltas)
1361
pending = ann._pending_deltas[parent_key]
1362
self.assertEqual(1, len(pending))
1363
self.assertEqual((rev_key, (parent_key,), record, details), pending[0])
1365
def test__expand_record_tracks_num_children(self):
1366
ann = self.make_annotator()
1367
rev_key = ('rev-id',)
1368
rev2_key = ('rev2-id',)
1369
parent_key = ('parent-id',)
1370
record = ['0,1,1\n', 'new-line\n']
1371
details = ('line-delta', False)
1372
ann._num_compression_children[parent_key] = 2
1373
ann._expand_record(parent_key, (), None, ['line1\n', 'line2\n'],
1374
('fulltext', False))
1375
res = ann._expand_record(rev_key, (parent_key,), parent_key,
1377
self.assertEqual({parent_key: 1}, ann._num_compression_children)
1378
# Expanding the second child should remove the content object, and the
1379
# num_compression_children entry
1380
res = ann._expand_record(rev2_key, (parent_key,), parent_key,
1382
self.assertFalse(parent_key in ann._content_objects)
1383
self.assertEqual({}, ann._num_compression_children)
1384
# We should not cache the content_objects for rev2 and rev, because
1385
# they do not have compression children of their own.
1386
self.assertEqual({}, ann._content_objects)
1388
def test__expand_delta_records_blocks(self):
1389
ann = self.make_annotator()
1390
rev_key = ('rev-id',)
1391
parent_key = ('parent-id',)
1392
record = ['0,1,1\n', 'new-line\n']
1393
details = ('line-delta', True)
1394
ann._num_compression_children[parent_key] = 2
1395
ann._expand_record(parent_key, (), None,
1396
['line1\n', 'line2\n', 'line3\n'],
1397
('fulltext', False))
1398
ann._expand_record(rev_key, (parent_key,), parent_key, record, details)
1399
self.assertEqual({(rev_key, parent_key): [(1, 1, 1), (3, 3, 0)]},
1400
ann._matching_blocks)
1401
rev2_key = ('rev2-id',)
1402
record = ['0,1,1\n', 'new-line\n']
1403
details = ('line-delta', False)
1404
ann._expand_record(rev2_key, (parent_key,), parent_key, record, details)
1405
self.assertEqual([(1, 1, 2), (3, 3, 0)],
1406
ann._matching_blocks[(rev2_key, parent_key)])
1408
def test__get_parent_ann_uses_matching_blocks(self):
1409
ann = self.make_annotator()
1410
rev_key = ('rev-id',)
1411
parent_key = ('parent-id',)
1412
parent_ann = [(parent_key,)]*3
1413
block_key = (rev_key, parent_key)
1414
ann._annotations_cache[parent_key] = parent_ann
1415
ann._matching_blocks[block_key] = [(0, 1, 1), (3, 3, 0)]
1416
# We should not try to access any parent_lines content, because we know
1417
# we already have the matching blocks
1418
par_ann, blocks = ann._get_parent_annotations_and_matches(rev_key,
1419
['1\n', '2\n', '3\n'], parent_key)
1420
self.assertEqual(parent_ann, par_ann)
1421
self.assertEqual([(0, 1, 1), (3, 3, 0)], blocks)
1422
self.assertEqual({}, ann._matching_blocks)
1424
def test__process_pending(self):
1425
ann = self.make_annotator()
1426
rev_key = ('rev-id',)
1429
record = ['0,1,1\n', 'new-line\n']
1430
details = ('line-delta', False)
1431
p1_record = ['line1\n', 'line2\n']
1432
ann._num_compression_children[p1_key] = 1
1433
res = ann._expand_record(rev_key, (p1_key,p2_key), p1_key,
1435
self.assertEqual(None, res)
1436
# self.assertTrue(p1_key in ann._pending_deltas)
1437
self.assertEqual({}, ann._pending_annotation)
1438
# Now insert p1, and we should be able to expand the delta
1439
res = ann._expand_record(p1_key, (), None, p1_record,
1440
('fulltext', False))
1441
self.assertEqual(p1_record, res)
1442
ann._annotations_cache[p1_key] = [(p1_key,)]*2
1443
res = ann._process_pending(p1_key)
1444
self.assertEqual([], res)
1445
self.assertFalse(p1_key in ann._pending_deltas)
1446
self.assertTrue(p2_key in ann._pending_annotation)
1447
self.assertEqual({p2_key: [(rev_key, (p1_key, p2_key))]},
1448
ann._pending_annotation)
1449
# Now fill in parent 2, and pending annotation should be satisfied
1450
res = ann._expand_record(p2_key, (), None, [], ('fulltext', False))
1451
ann._annotations_cache[p2_key] = []
1452
res = ann._process_pending(p2_key)
1453
self.assertEqual([rev_key], res)
1454
self.assertEqual({}, ann._pending_annotation)
1455
self.assertEqual({}, ann._pending_deltas)
1457
def test_record_delta_removes_basis(self):
1458
ann = self.make_annotator()
1459
ann._expand_record(('parent-id',), (), None,
1460
['line1\n', 'line2\n'], ('fulltext', False))
1461
ann._num_compression_children['parent-id'] = 2
1463
def test_annotate_special_text(self):
1464
ann = self.make_annotator()
1466
rev1_key = ('rev-1',)
1467
rev2_key = ('rev-2',)
1468
rev3_key = ('rev-3',)
1469
spec_key = ('special:',)
1470
vf.add_lines(rev1_key, [], ['initial content\n'])
1471
vf.add_lines(rev2_key, [rev1_key], ['initial content\n',
1474
vf.add_lines(rev3_key, [rev1_key], ['initial content\n',
1477
spec_text = ('initial content\n'
1481
ann.add_special_text(spec_key, [rev2_key, rev3_key], spec_text)
1482
anns, lines = ann.annotate(spec_key)
1483
self.assertEqual([(rev1_key,),
1484
(rev2_key, rev3_key),
1488
self.assertEqualDiff(spec_text, ''.join(lines))
1314
return _KndxIndex(transport, mapper, lambda:None, allow_writes, lambda:True)
1491
1317
class KnitTests(TestCaseWithTransport):