1
# Copyright (C) 2006-2011 Canonical Ltd
1
# Copyright (C) 2006-2010 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
40
39
KnitVersionedFiles,
42
41
_VFContentMapGenerator,
48
48
from bzrlib.patiencediff import PatienceSequenceMatcher
49
from bzrlib.repofmt import (
49
from bzrlib.repofmt import pack_repo
53
50
from bzrlib.tests import (
55
52
TestCaseWithMemoryTransport,
56
53
TestCaseWithTransport,
56
from bzrlib.transport import get_transport
59
57
from bzrlib.versionedfile import (
60
58
AbsentContentFactory,
327
325
transport.append_bytes(packname, bytes)
328
326
writer = pack.ContainerWriter(write_data)
330
access = pack_repo._DirectPackAccess({})
328
access = _DirectPackAccess({})
331
329
access.set_writer(writer, index, (transport, packname))
332
330
return access, writer
343
def test_pack_collection_pack_retries(self):
344
"""An explicit pack of a pack collection succeeds even when a
345
concurrent pack happens.
347
builder = self.make_branch_builder('.')
348
builder.start_series()
349
builder.build_snapshot('rev-1', None, [
350
('add', ('', 'root-id', 'directory', None)),
351
('add', ('file', 'file-id', 'file', 'content\nrev 1\n')),
353
builder.build_snapshot('rev-2', ['rev-1'], [
354
('modify', ('file-id', 'content\nrev 2\n')),
356
builder.build_snapshot('rev-3', ['rev-2'], [
357
('modify', ('file-id', 'content\nrev 3\n')),
359
self.addCleanup(builder.finish_series)
360
b = builder.get_branch()
361
self.addCleanup(b.lock_write().unlock)
363
collection = repo._pack_collection
364
# Concurrently repack the repo.
365
reopened_repo = repo.bzrdir.open_repository()
370
341
def make_vf_for_retrying(self):
371
342
"""Create 3 packs and a reload function.
399
370
collection = repo._pack_collection
400
371
collection.ensure_loaded()
401
372
orig_packs = collection.packs
402
packer = knitpack_repo.KnitPacker(collection, orig_packs, '.testpack')
373
packer = pack_repo.Packer(collection, orig_packs, '.testpack')
403
374
new_pack = packer.pack()
404
375
# forget about the new pack
405
376
collection.reset()
458
429
memos.extend(access.add_raw_records([('key', 5)], 'alpha'))
460
431
transport = self.get_transport()
461
access = pack_repo._DirectPackAccess({"FOO":(transport, 'packfile'),
432
access = _DirectPackAccess({"FOO":(transport, 'packfile'),
462
433
"FOOBAR":(transport, 'pack2'),
463
434
"BAZ":(transport, 'pack3')})
464
435
self.assertEqual(['1234567890', '12345', 'alpha'],
475
446
def test_set_writer(self):
476
447
"""The writer should be settable post construction."""
477
access = pack_repo._DirectPackAccess({})
448
access = _DirectPackAccess({})
478
449
transport = self.get_transport()
479
450
packname = 'packfile'
492
463
transport = self.get_transport()
493
464
reload_called, reload_func = self.make_reload_func()
494
465
# Note that the index key has changed from 'foo' to 'bar'
495
access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')},
466
access = _DirectPackAccess({'bar':(transport, 'packname')},
496
467
reload_func=reload_func)
497
468
e = self.assertListRaises(errors.RetryWithNewPacks,
498
469
access.get_raw_records, memos)
507
478
memos = self.make_pack_file()
508
479
transport = self.get_transport()
509
480
# Note that the index key has changed from 'foo' to 'bar'
510
access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')})
481
access = _DirectPackAccess({'bar':(transport, 'packname')})
511
482
e = self.assertListRaises(KeyError, access.get_raw_records, memos)
513
484
def test_missing_file_raises_retry(self):
515
486
transport = self.get_transport()
516
487
reload_called, reload_func = self.make_reload_func()
517
488
# Note that the 'filename' has been changed to 'different-packname'
518
access = pack_repo._DirectPackAccess(
519
{'foo':(transport, 'different-packname')},
520
reload_func=reload_func)
489
access = _DirectPackAccess({'foo':(transport, 'different-packname')},
490
reload_func=reload_func)
521
491
e = self.assertListRaises(errors.RetryWithNewPacks,
522
492
access.get_raw_records, memos)
523
493
# The file has gone missing, so we assume we need to reload
531
501
memos = self.make_pack_file()
532
502
transport = self.get_transport()
533
503
# Note that the 'filename' has been changed to 'different-packname'
534
access = pack_repo._DirectPackAccess(
535
{'foo': (transport, 'different-packname')})
504
access = _DirectPackAccess({'foo':(transport, 'different-packname')})
536
505
e = self.assertListRaises(errors.NoSuchFile,
537
506
access.get_raw_records, memos)
542
511
failing_transport = MockReadvFailingTransport(
543
512
[transport.get_bytes('packname')])
544
513
reload_called, reload_func = self.make_reload_func()
545
access = pack_repo._DirectPackAccess(
546
{'foo': (failing_transport, 'packname')},
547
reload_func=reload_func)
514
access = _DirectPackAccess({'foo':(failing_transport, 'packname')},
515
reload_func=reload_func)
548
516
# Asking for a single record will not trigger the Mock failure
549
517
self.assertEqual(['1234567890'],
550
518
list(access.get_raw_records(memos[:1])))
566
534
failing_transport = MockReadvFailingTransport(
567
535
[transport.get_bytes('packname')])
568
536
reload_called, reload_func = self.make_reload_func()
569
access = pack_repo._DirectPackAccess(
570
{'foo':(failing_transport, 'packname')})
537
access = _DirectPackAccess({'foo':(failing_transport, 'packname')})
571
538
# Asking for a single record will not trigger the Mock failure
572
539
self.assertEqual(['1234567890'],
573
540
list(access.get_raw_records(memos[:1])))
578
545
access.get_raw_records, memos)
580
547
def test_reload_or_raise_no_reload(self):
581
access = pack_repo._DirectPackAccess({}, reload_func=None)
548
access = _DirectPackAccess({}, reload_func=None)
582
549
retry_exc = self.make_retry_exception()
583
550
# Without a reload_func, we will just re-raise the original exception
584
551
self.assertRaises(_TestException, access.reload_or_raise, retry_exc)
586
553
def test_reload_or_raise_reload_changed(self):
587
554
reload_called, reload_func = self.make_reload_func(return_val=True)
588
access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
555
access = _DirectPackAccess({}, reload_func=reload_func)
589
556
retry_exc = self.make_retry_exception()
590
557
access.reload_or_raise(retry_exc)
591
558
self.assertEqual([1], reload_called)
596
563
def test_reload_or_raise_reload_no_change(self):
597
564
reload_called, reload_func = self.make_reload_func(return_val=False)
598
access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
565
access = _DirectPackAccess({}, reload_func=reload_func)
599
566
retry_exc = self.make_retry_exception()
600
567
# If reload_occurred is False, then we consider it an error to have
601
568
# reload_func() return False (no changes).
726
693
def create_gz_content(self, text):
728
gz_file = gzip.GzipFile(mode='wb', fileobj=sio)
695
gz_file = tuned_gzip.GzipFile(mode='wb', fileobj=sio)
729
696
gz_file.write(text)
731
698
return sio.getvalue()
1604
1571
# could leave an empty .kndx file, which bzr would later claim was a
1605
1572
# corrupted file since the header was not present. In reality, the file
1606
1573
# just wasn't created, so it should be ignored.
1607
t = transport.get_transport('.')
1574
t = get_transport('.')
1608
1575
t.put_bytes('test.kndx', '')
1610
1577
knit = self.make_test_knit()
1612
1579
def test_knit_index_checks_header(self):
1613
t = transport.get_transport('.')
1580
t = get_transport('.')
1614
1581
t.put_bytes('test.kndx', '# not really a knit header\n\n')
1615
1582
k = self.make_test_knit()
1616
1583
self.assertRaises(KnitHeaderError, k.keys)