Merge lp:~jameinel/bzr/2.0.4-autopack-507566 into lp:bzr/2.0

Proposed by John A Meinel
Status: Merged
Merged at revision: not available
Proposed branch: lp:~jameinel/bzr/2.0.4-autopack-507566
Merge into: lp:bzr/2.0
Diff against target: 105 lines (+54/-4)
3 files modified
NEWS (+5/-0)
bzrlib/repofmt/pack_repo.py (+8/-3)
bzrlib/tests/test_repository.py (+41/-1)
To merge this branch: bzr merge lp:~jameinel/bzr/2.0.4-autopack-507566
Reviewer Review Type Date Requested Status
Robert Collins (community) Approve
Review via email: mp+17523@code.launchpad.net
To post a comment you must log in.
Revision history for this message
John A Meinel (jameinel) wrote :

This is a bugfix for the 'critical' bug #507566. It seems that if you had concurrent autopacking, the second one would restart, but 'forget' that it had a new pack which needed to be added.

This seems localized enough that it is worth fixing in the 2.0 series.

Revision history for this message
Robert Collins (lifeless) wrote :

 review: +1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2010-01-15 03:34:28 +0000
3+++ NEWS 2010-01-16 20:52:12 +0000
4@@ -38,6 +38,11 @@
5 returns ``EINTR`` by calling ``PyErr_CheckSignals``. This affected the
6 optional ``_readdir_pyx`` extension. (Andrew Bennetts, #495023)
7
8+* Concurrent autopacks will no longer lose a newly created pack file.
9+ There was a race condition, where if the reload happened at the right
10+ time, the second packer would forget the name of the newly added pack
11+ file. (John Arbash Meinel, Gareth White, #507566)
12+
13 * Give a clearer message if the lockdir disappears after being apparently
14 successfully taken. (Martin Pool, #498378)
15
16
17=== modified file 'bzrlib/repofmt/pack_repo.py'
18--- bzrlib/repofmt/pack_repo.py 2009-09-09 18:52:56 +0000
19+++ bzrlib/repofmt/pack_repo.py 2010-01-16 20:52:12 +0000
20@@ -1,4 +1,4 @@
21-# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
22+# Copyright (C) 2007-2010 Canonical Ltd
23 #
24 # This program is free software; you can redistribute it and/or modify
25 # it under the terms of the GNU General Public License as published by
26@@ -1987,8 +1987,13 @@
27 if first_read:
28 return True
29 # out the new value.
30- disk_nodes, _, _ = self._diff_pack_names()
31- self._packs_at_load = disk_nodes
32+ disk_nodes, deleted_nodes, new_nodes = self._diff_pack_names()
33+ # _packs_at_load is meant to be the explicit list of names in
34+ # 'pack-names' at then start. As such, it should not contain any
35+ # pending names that haven't been written out yet.
36+ pack_names_nodes = disk_nodes.difference(new_nodes)
37+ pack_names_nodes.update(deleted_nodes)
38+ self._packs_at_load = pack_names_nodes
39 (removed, added,
40 modified) = self._syncronize_pack_names_from_disk_nodes(disk_nodes)
41 if removed or added or modified:
42
43=== modified file 'bzrlib/tests/test_repository.py'
44--- bzrlib/tests/test_repository.py 2009-09-09 01:58:47 +0000
45+++ bzrlib/tests/test_repository.py 2010-01-16 20:52:12 +0000
46@@ -1,4 +1,4 @@
47-# Copyright (C) 2006, 2007, 2008, 2009 Canonical Ltd
48+# Copyright (C) 2006-2010 Canonical Ltd
49 #
50 # This program is free software; you can redistribute it and/or modify
51 # it under the terms of the GNU General Public License as published by
52@@ -62,6 +62,7 @@
53 revision as _mod_revision,
54 symbol_versioning,
55 upgrade,
56+ versionedfile,
57 workingtree,
58 )
59 from bzrlib.repofmt import (
60@@ -1279,6 +1280,45 @@
61 self.assertEqual({revs[-1]:(revs[-2],)}, r.get_parent_map([revs[-1]]))
62 self.assertFalse(packs.reload_pack_names())
63
64+ def test_reload_pack_names_preserves_pending(self):
65+ # TODO: Update this to also test for pending-deleted names
66+ tree, r, packs, revs = self.make_packs_and_alt_repo(write_lock=True)
67+ # We will add one pack (via start_write_group + insert_record_stream),
68+ # and remove another pack (via _remove_pack_from_memory)
69+ orig_names = packs.names()
70+ orig_at_load = packs._packs_at_load
71+ to_remove_name = iter(orig_names).next()
72+ r.start_write_group()
73+ self.addCleanup(r.abort_write_group)
74+ r.texts.insert_record_stream([versionedfile.FulltextContentFactory(
75+ ('text', 'rev'), (), None, 'content\n')])
76+ new_pack = packs._new_pack
77+ self.assertTrue(new_pack.data_inserted())
78+ new_pack.finish()
79+ packs.allocate(new_pack)
80+ packs._new_pack = None
81+ removed_pack = packs.get_pack_by_name(to_remove_name)
82+ packs._remove_pack_from_memory(removed_pack)
83+ names = packs.names()
84+ all_nodes, deleted_nodes, new_nodes = packs._diff_pack_names()
85+ new_names = set([x[0][0] for x in new_nodes])
86+ self.assertEqual(names, sorted([x[0][0] for x in all_nodes]))
87+ self.assertEqual(set(names) - set(orig_names), new_names)
88+ self.assertEqual(set([new_pack.name]), new_names)
89+ self.assertEqual([to_remove_name],
90+ sorted([x[0][0] for x in deleted_nodes]))
91+ packs.reload_pack_names()
92+ reloaded_names = packs.names()
93+ self.assertEqual(orig_at_load, packs._packs_at_load)
94+ self.assertEqual(names, reloaded_names)
95+ all_nodes, deleted_nodes, new_nodes = packs._diff_pack_names()
96+ new_names = set([x[0][0] for x in new_nodes])
97+ self.assertEqual(names, sorted([x[0][0] for x in all_nodes]))
98+ self.assertEqual(set(names) - set(orig_names), new_names)
99+ self.assertEqual(set([new_pack.name]), new_names)
100+ self.assertEqual([to_remove_name],
101+ sorted([x[0][0] for x in deleted_nodes]))
102+
103 def test_autopack_reloads_and_stops(self):
104 tree, r, packs, revs = self.make_packs_and_alt_repo(write_lock=True)
105 # After we have determined what needs to be autopacked, trigger a

Subscribers

People subscribed via source and target branches