1
# Copyright (C) 2006-2010 Canonical Ltd
1
# Copyright (C) 2006-2011 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
40
KnitVersionedFiles,
42
42
_VFContentMapGenerator,
49
48
from bzrlib.patiencediff import PatienceSequenceMatcher
50
from bzrlib.repofmt import pack_repo
49
from bzrlib.repofmt import (
51
53
from bzrlib.tests import (
53
55
TestCaseWithMemoryTransport,
325
327
transport.append_bytes(packname, bytes)
326
328
writer = pack.ContainerWriter(write_data)
328
access = _DirectPackAccess({})
330
access = pack_repo._DirectPackAccess({})
329
331
access.set_writer(writer, index, (transport, packname))
330
332
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()
341
370
def make_vf_for_retrying(self):
342
371
"""Create 3 packs and a reload function.
370
399
collection = repo._pack_collection
371
400
collection.ensure_loaded()
372
401
orig_packs = collection.packs
373
packer = pack_repo.Packer(collection, orig_packs, '.testpack')
402
packer = knitpack_repo.KnitPacker(collection, orig_packs, '.testpack')
374
403
new_pack = packer.pack()
375
404
# forget about the new pack
376
405
collection.reset()
429
458
memos.extend(access.add_raw_records([('key', 5)], 'alpha'))
431
460
transport = self.get_transport()
432
access = _DirectPackAccess({"FOO":(transport, 'packfile'),
461
access = pack_repo._DirectPackAccess({"FOO":(transport, 'packfile'),
433
462
"FOOBAR":(transport, 'pack2'),
434
463
"BAZ":(transport, 'pack3')})
435
464
self.assertEqual(['1234567890', '12345', 'alpha'],
446
475
def test_set_writer(self):
447
476
"""The writer should be settable post construction."""
448
access = _DirectPackAccess({})
477
access = pack_repo._DirectPackAccess({})
449
478
transport = self.get_transport()
450
479
packname = 'packfile'
463
492
transport = self.get_transport()
464
493
reload_called, reload_func = self.make_reload_func()
465
494
# Note that the index key has changed from 'foo' to 'bar'
466
access = _DirectPackAccess({'bar':(transport, 'packname')},
495
access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')},
467
496
reload_func=reload_func)
468
497
e = self.assertListRaises(errors.RetryWithNewPacks,
469
498
access.get_raw_records, memos)
478
507
memos = self.make_pack_file()
479
508
transport = self.get_transport()
480
509
# Note that the index key has changed from 'foo' to 'bar'
481
access = _DirectPackAccess({'bar':(transport, 'packname')})
510
access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')})
482
511
e = self.assertListRaises(KeyError, access.get_raw_records, memos)
484
513
def test_missing_file_raises_retry(self):
486
515
transport = self.get_transport()
487
516
reload_called, reload_func = self.make_reload_func()
488
517
# Note that the 'filename' has been changed to 'different-packname'
489
access = _DirectPackAccess({'foo':(transport, 'different-packname')},
490
reload_func=reload_func)
518
access = pack_repo._DirectPackAccess(
519
{'foo':(transport, 'different-packname')},
520
reload_func=reload_func)
491
521
e = self.assertListRaises(errors.RetryWithNewPacks,
492
522
access.get_raw_records, memos)
493
523
# The file has gone missing, so we assume we need to reload
501
531
memos = self.make_pack_file()
502
532
transport = self.get_transport()
503
533
# Note that the 'filename' has been changed to 'different-packname'
504
access = _DirectPackAccess({'foo':(transport, 'different-packname')})
534
access = pack_repo._DirectPackAccess(
535
{'foo': (transport, 'different-packname')})
505
536
e = self.assertListRaises(errors.NoSuchFile,
506
537
access.get_raw_records, memos)
511
542
failing_transport = MockReadvFailingTransport(
512
543
[transport.get_bytes('packname')])
513
544
reload_called, reload_func = self.make_reload_func()
514
access = _DirectPackAccess({'foo':(failing_transport, 'packname')},
515
reload_func=reload_func)
545
access = pack_repo._DirectPackAccess(
546
{'foo': (failing_transport, 'packname')},
547
reload_func=reload_func)
516
548
# Asking for a single record will not trigger the Mock failure
517
549
self.assertEqual(['1234567890'],
518
550
list(access.get_raw_records(memos[:1])))
534
566
failing_transport = MockReadvFailingTransport(
535
567
[transport.get_bytes('packname')])
536
568
reload_called, reload_func = self.make_reload_func()
537
access = _DirectPackAccess({'foo':(failing_transport, 'packname')})
569
access = pack_repo._DirectPackAccess(
570
{'foo':(failing_transport, 'packname')})
538
571
# Asking for a single record will not trigger the Mock failure
539
572
self.assertEqual(['1234567890'],
540
573
list(access.get_raw_records(memos[:1])))
545
578
access.get_raw_records, memos)
547
580
def test_reload_or_raise_no_reload(self):
548
access = _DirectPackAccess({}, reload_func=None)
581
access = pack_repo._DirectPackAccess({}, reload_func=None)
549
582
retry_exc = self.make_retry_exception()
550
583
# Without a reload_func, we will just re-raise the original exception
551
584
self.assertRaises(_TestException, access.reload_or_raise, retry_exc)
553
586
def test_reload_or_raise_reload_changed(self):
554
587
reload_called, reload_func = self.make_reload_func(return_val=True)
555
access = _DirectPackAccess({}, reload_func=reload_func)
588
access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
556
589
retry_exc = self.make_retry_exception()
557
590
access.reload_or_raise(retry_exc)
558
591
self.assertEqual([1], reload_called)
563
596
def test_reload_or_raise_reload_no_change(self):
564
597
reload_called, reload_func = self.make_reload_func(return_val=False)
565
access = _DirectPackAccess({}, reload_func=reload_func)
598
access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
566
599
retry_exc = self.make_retry_exception()
567
600
# If reload_occurred is False, then we consider it an error to have
568
601
# reload_func() return False (no changes).
693
726
def create_gz_content(self, text):
695
gz_file = tuned_gzip.GzipFile(mode='wb', fileobj=sio)
728
gz_file = gzip.GzipFile(mode='wb', fileobj=sio)
696
729
gz_file.write(text)
698
731
return sio.getvalue()