Rev 6301: (jelmer) Add HPSS calls for the write group methods. (Jelmer Vernooij) in file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/
Patch Queue Manager
pqm at pqm.ubuntu.com
Fri Nov 25 16:02:51 UTC 2011
At file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 6301 [merge]
revision-id: pqm at pqm.ubuntu.com-20111125160251-zz514fqebn1gqgbi
parent: pqm at pqm.ubuntu.com-20111125153645-7ojsm3a4oz24m754
parent: jelmer at samba.org-20111125151216-3urnbfvwveoyq1gn
committer: Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Fri 2011-11-25 16:02:51 +0000
message:
(jelmer) Add HPSS calls for the write group methods. (Jelmer Vernooij)
modified:
bzrlib/remote.py remote.py-20060720103555-yeeg2x51vn0rbtdp-1
bzrlib/repository.py rev_storage.py-20051111201905-119e9401e46257e3
bzrlib/smart/repository.py repository.py-20061128022038-vr5wy5bubyb8xttk-1
bzrlib/smart/request.py request.py-20061108095550-gunadhxmzkdjfeek-1
bzrlib/tests/test_remote.py test_remote.py-20060720103555-yeeg2x51vn0rbtdp-2
bzrlib/tests/test_smart.py test_smart.py-20061122024551-ol0l0o0oofsu9b3t-2
doc/en/release-notes/bzr-2.5.txt bzr2.5.txt-20110708125756-587p0hpw7oke4h05-1
=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py 2011-11-25 15:10:43 +0000
+++ b/bzrlib/remote.py 2011-11-25 15:12:16 +0000
@@ -49,7 +49,7 @@
from bzrlib.revision import NULL_REVISION
from bzrlib.revisiontree import InventoryRevisionTree
from bzrlib.repository import RepositoryWriteLockResult, _LazyListJoin
-from bzrlib.trace import mutter, note, warning
+from bzrlib.trace import mutter, note, warning, log_exception_quietly
_DEFAULT_SEARCH_DEPTH = 100
@@ -1036,6 +1036,7 @@
self._format = format
self._lock_mode = None
self._lock_token = None
+ self._write_group_tokens = None
self._lock_count = 0
self._leave_lock = False
# Cache of revision parents; misses are cached during read locks, and
@@ -1081,9 +1082,30 @@
:param suppress_errors: see Repository.abort_write_group.
"""
- self._ensure_real()
- return self._real_repository.abort_write_group(
- suppress_errors=suppress_errors)
+ if self._real_repository:
+ self._ensure_real()
+ return self._real_repository.abort_write_group(
+ suppress_errors=suppress_errors)
+ if not self.is_in_write_group():
+ if suppress_errors:
+ mutter('(suppressed) not in write group')
+ return
+ raise errors.BzrError("not in write group")
+ path = self.bzrdir._path_for_remote_call(self._client)
+ try:
+ response = self._call('Repository.abort_write_group', path,
+ self._lock_token, self._write_group_tokens)
+ except Exception, exc:
+ self._write_group = None
+ if not suppress_errors:
+ raise
+ mutter('abort_write_group failed')
+ log_exception_quietly()
+ note(gettext('bzr: ERROR (ignored): %s'), exc)
+ else:
+ if response != ('ok', ):
+ raise errors.UnexpectedSmartServerResponse(response)
+ self._write_group_tokens = None
@property
def chk_bytes(self):
@@ -1103,16 +1125,38 @@
for older plugins that don't use e.g. the CommitBuilder
facility.
"""
- self._ensure_real()
- return self._real_repository.commit_write_group()
+ if self._real_repository:
+ self._ensure_real()
+ return self._real_repository.commit_write_group()
+ if not self.is_in_write_group():
+ raise errors.BzrError("not in write group")
+ path = self.bzrdir._path_for_remote_call(self._client)
+ response = self._call('Repository.commit_write_group', path,
+ self._lock_token, self._write_group_tokens)
+ if response != ('ok', ):
+ raise errors.UnexpectedSmartServerResponse(response)
+ self._write_group_tokens = None
def resume_write_group(self, tokens):
- self._ensure_real()
- return self._real_repository.resume_write_group(tokens)
+ if self._real_repository:
+ return self._real_repository.resume_write_group(tokens)
+ path = self.bzrdir._path_for_remote_call(self._client)
+ try:
+ response = self._call('Repository.check_write_group', path,
+ self._lock_token, tokens)
+ except errors.UnknownSmartMethod:
+ self._ensure_real()
+ return self._real_repository.resume_write_group(tokens)
+ if response != ('ok', ):
+ raise errors.UnexpectedSmartServerResponse(response)
+ self._write_group_tokens = tokens
def suspend_write_group(self):
- self._ensure_real()
- return self._real_repository.suspend_write_group()
+ if self._real_repository:
+ return self._real_repository.suspend_write_group()
+ ret = self._write_group_tokens or []
+ self._write_group_tokens = None
+ return ret
def get_missing_parent_inventories(self, check_for_missing_texts=True):
self._ensure_real()
@@ -1343,6 +1387,8 @@
write groups are only applicable locally for the smart server..
"""
+ if self._write_group_tokens is not None:
+ return True
if self._real_repository:
return self._real_repository.is_in_write_group()
@@ -1483,6 +1529,10 @@
self._real_repository.lock_write(self._lock_token)
elif self._lock_mode == 'r':
self._real_repository.lock_read()
+ if self._write_group_tokens is not None:
+ # if we are already in a write group, resume it
+ self._real_repository.resume_write_group(self._write_group_tokens)
+ self._write_group_tokens = None
def start_write_group(self):
"""Start a write group on the decorated repository.
@@ -1492,8 +1542,23 @@
for older plugins that don't use e.g. the CommitBuilder
facility.
"""
- self._ensure_real()
- return self._real_repository.start_write_group()
+ if self._real_repository:
+ self._ensure_real()
+ return self._real_repository.start_write_group()
+ if not self.is_write_locked():
+ raise errors.NotWriteLocked(self)
+ if self._write_group_tokens is not None:
+ raise errors.BzrError('already in a write group')
+ path = self.bzrdir._path_for_remote_call(self._client)
+ try:
+ response = self._call('Repository.start_write_group', path,
+ self._lock_token)
+ except (errors.UnknownSmartMethod, errors.UnsuspendableWriteGroup):
+ self._ensure_real()
+ return self._real_repository.start_write_group()
+ if response[0] != 'ok':
+ raise errors.UnexpectedSmartServerResponse(response)
+ self._write_group_tokens = response[1]
def _unlock(self, token):
path = self.bzrdir._path_for_remote_call(self._client)
@@ -1526,6 +1591,8 @@
# This is just to let the _real_repository stay up to date.
if self._real_repository is not None:
self._real_repository.unlock()
+ elif self._write_group_tokens is not None:
+ self.abort_write_group()
finally:
# The rpc-level lock should be released even if there was a
# problem releasing the vfs-based lock.
@@ -3690,3 +3757,14 @@
no_context_error_translators.register('MemoryError',
lambda err: errors.BzrError("remote server out of memory\n"
"Retry non-remotely, or contact the server admin for details."))
+
+no_context_error_translators.register('BzrCheckError',
+ lambda err: errors.BzrCheckError(msg=err.error_args[0]))
+
+error_translators.register('UnsuspendableWriteGroup',
+ lambda err, find, get_path: errors.UnsuspendableWriteGroup(
+ repository=find('repository')))
+error_translators.register('UnresumableWriteGroup',
+ lambda err, find, get_path: errors.UnresumableWriteGroup(
+ repository=find('repository'), write_groups=err.error_args[0],
+ reason=err.error_args[1]))
=== modified file 'bzrlib/repository.py'
--- a/bzrlib/repository.py 2011-11-15 15:27:38 +0000
+++ b/bzrlib/repository.py 2011-11-19 17:39:55 +0000
@@ -642,6 +642,12 @@
"""
def suspend_write_group(self):
+ """Suspend a write group.
+
+ :raise UnsuspendableWriteGroup: If the write group can not be
+ suspended.
+ :return: List of tokens
+ """
raise errors.UnsuspendableWriteGroup(self)
def refresh_data(self):
=== modified file 'bzrlib/smart/repository.py'
--- a/bzrlib/smart/repository.py 2011-11-25 14:05:18 +0000
+++ b/bzrlib/smart/repository.py 2011-11-25 15:12:16 +0000
@@ -934,6 +934,96 @@
self.do_insert_stream_request(repository, resume_tokens)
+class SmartServerRepositoryStartWriteGroup(SmartServerRepositoryRequest):
+ """Start a write group.
+
+ New in 2.5.
+ """
+
+ def do_repository_request(self, repository, lock_token):
+ """Start a write group."""
+ repository.lock_write(token=lock_token)
+ try:
+ repository.start_write_group()
+ try:
+ tokens = repository.suspend_write_group()
+ except errors.UnsuspendableWriteGroup:
+ return FailedSmartServerResponse(('UnsuspendableWriteGroup',))
+ finally:
+ repository.unlock()
+ return SuccessfulSmartServerResponse(('ok', tokens))
+
+
+class SmartServerRepositoryCommitWriteGroup(SmartServerRepositoryRequest):
+ """Commit a write group.
+
+ New in 2.5.
+ """
+
+ def do_repository_request(self, repository, lock_token,
+ write_group_tokens):
+ """Commit a write group."""
+ repository.lock_write(token=lock_token)
+ try:
+ try:
+ repository.resume_write_group(write_group_tokens)
+ except errors.UnresumableWriteGroup, e:
+ return FailedSmartServerResponse(
+ ('UnresumableWriteGroup', e.write_groups, e.reason))
+ try:
+ repository.commit_write_group()
+ except:
+ write_group_tokens = repository.suspend_write_group()
+ # FIXME JRV 2011-11-19: What if the write_group_tokens
+ # have changed?
+ raise
+ finally:
+ repository.unlock()
+ return SuccessfulSmartServerResponse(('ok', ))
+
+
+class SmartServerRepositoryAbortWriteGroup(SmartServerRepositoryRequest):
+ """Abort a write group.
+
+ New in 2.5.
+ """
+
+ def do_repository_request(self, repository, lock_token, write_group_tokens):
+ """Abort a write group."""
+ repository.lock_write(token=lock_token)
+ try:
+ try:
+ repository.resume_write_group(write_group_tokens)
+ except errors.UnresumableWriteGroup, e:
+ return FailedSmartServerResponse(
+ ('UnresumableWriteGroup', e.write_groups, e.reason))
+ repository.abort_write_group()
+ finally:
+ repository.unlock()
+ return SuccessfulSmartServerResponse(('ok', ))
+
+
+class SmartServerRepositoryCheckWriteGroup(SmartServerRepositoryRequest):
+ """Check that a write group is still valid.
+
+ New in 2.5.
+ """
+
+ def do_repository_request(self, repository, lock_token, write_group_tokens):
+ """Abort a write group."""
+ repository.lock_write(token=lock_token)
+ try:
+ try:
+ repository.resume_write_group(write_group_tokens)
+ except errors.UnresumableWriteGroup, e:
+ return FailedSmartServerResponse(
+ ('UnresumableWriteGroup', e.write_groups, e.reason))
+ else:
+ repository.suspend_write_group()
+ finally:
+ repository.unlock()
+ return SuccessfulSmartServerResponse(('ok', ))
+
class SmartServerRepositoryAllRevisionIds(SmartServerRepositoryRequest):
"""Retrieve all of the revision ids in a repository.
=== modified file 'bzrlib/smart/request.py'
--- a/bzrlib/smart/request.py 2011-11-25 15:10:43 +0000
+++ b/bzrlib/smart/request.py 2011-11-25 15:12:16 +0000
@@ -421,6 +421,8 @@
return ('UnstackableBranchFormat', str(err.format), err.url)
elif isinstance(err, errors.NotStacked):
return ('NotStacked',)
+ elif isinstance(err, errors.BzrCheckError):
+ return ('BzrCheckError', err.msg)
elif isinstance(err, UnicodeError):
# If it is a DecodeError, than most likely we are starting
# with a plain string
@@ -674,6 +676,18 @@
'Repository.tarball', 'bzrlib.smart.repository',
'SmartServerRepositoryTarball')
request_handlers.register_lazy(
+ 'Repository.start_write_group', 'bzrlib.smart.repository',
+ 'SmartServerRepositoryStartWriteGroup')
+request_handlers.register_lazy(
+ 'Repository.commit_write_group', 'bzrlib.smart.repository',
+ 'SmartServerRepositoryCommitWriteGroup')
+request_handlers.register_lazy(
+ 'Repository.abort_write_group', 'bzrlib.smart.repository',
+ 'SmartServerRepositoryAbortWriteGroup')
+request_handlers.register_lazy(
+ 'Repository.check_write_group', 'bzrlib.smart.repository',
+ 'SmartServerRepositoryCheckWriteGroup')
+request_handlers.register_lazy(
'VersionedFileRepository.get_serializer_format', 'bzrlib.smart.repository',
'SmartServerRepositoryGetSerializerFormat')
request_handlers.register_lazy(
=== modified file 'bzrlib/tests/test_remote.py'
--- a/bzrlib/tests/test_remote.py 2011-11-25 15:10:43 +0000
+++ b/bzrlib/tests/test_remote.py 2011-11-25 15:12:16 +0000
@@ -1568,9 +1568,6 @@
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
'success', ('ok',))
branch = self.make_remote_branch(transport, client)
- # This is a hack to work around the problem that RemoteBranch currently
- # unnecessarily invokes _ensure_real upon a call to lock_write.
- branch._ensure_real = lambda: None
branch.lock_write()
result = branch._set_last_revision(NULL_REVISION)
branch.unlock()
@@ -1605,9 +1602,6 @@
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
'success', ('ok',))
branch = self.make_remote_branch(transport, client)
- # This is a hack to work around the problem that RemoteBranch currently
- # unnecessarily invokes _ensure_real upon a call to lock_write.
- branch._ensure_real = lambda: None
# Lock the branch, reset the record of remote calls.
branch.lock_write()
result = branch._set_last_revision('rev-id2')
@@ -1680,7 +1674,6 @@
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
'success', ('ok',))
branch = self.make_remote_branch(transport, client)
- branch._ensure_real = lambda: None
branch.lock_write()
# The 'TipChangeRejected' error response triggered by calling
# set_last_revision_info causes a TipChangeRejected exception.
@@ -2880,6 +2873,91 @@
client._calls)
+class TestRepositoryWriteGroups(TestRemoteRepository):
+
+ def test_start_write_group(self):
+ transport_path = 'quack'
+ repo, client = self.setup_fake_client_and_repository(transport_path)
+ client.add_expected_call(
+ 'Repository.lock_write', ('quack/', ''),
+ 'success', ('ok', 'a token'))
+ client.add_expected_call(
+ 'Repository.start_write_group', ('quack/', 'a token'),
+ 'success', ('ok', 'token1'))
+ repo.lock_write()
+ repo.start_write_group()
+
+ def test_start_write_group_unsuspendable(self):
+ # Some repositories do not support suspending write
+ # groups. For those, fall back to the "real" repository.
+ transport_path = 'quack'
+ repo, client = self.setup_fake_client_and_repository(transport_path)
+ def stub_ensure_real():
+ client._calls.append(('_ensure_real',))
+ repo._real_repository = _StubRealPackRepository(client._calls)
+ repo._ensure_real = stub_ensure_real
+ client.add_expected_call(
+ 'Repository.lock_write', ('quack/', ''),
+ 'success', ('ok', 'a token'))
+ client.add_expected_call(
+ 'Repository.start_write_group', ('quack/', 'a token'),
+ 'error', ('UnsuspendableWriteGroup',))
+ repo.lock_write()
+ repo.start_write_group()
+ self.assertEquals(client._calls[-2:], [
+ ('_ensure_real',),
+ ('start_write_group',)])
+
+ def test_commit_write_group(self):
+ transport_path = 'quack'
+ repo, client = self.setup_fake_client_and_repository(transport_path)
+ client.add_expected_call(
+ 'Repository.lock_write', ('quack/', ''),
+ 'success', ('ok', 'a token'))
+ client.add_expected_call(
+ 'Repository.start_write_group', ('quack/', 'a token'),
+ 'success', ('ok', ['token1']))
+ client.add_expected_call(
+ 'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
+ 'success', ('ok',))
+ repo.lock_write()
+ repo.start_write_group()
+ repo.commit_write_group()
+
+ def test_abort_write_group(self):
+ transport_path = 'quack'
+ repo, client = self.setup_fake_client_and_repository(transport_path)
+ client.add_expected_call(
+ 'Repository.lock_write', ('quack/', ''),
+ 'success', ('ok', 'a token'))
+ client.add_expected_call(
+ 'Repository.start_write_group', ('quack/', 'a token'),
+ 'success', ('ok', ['token1']))
+ client.add_expected_call(
+ 'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
+ 'success', ('ok',))
+ repo.lock_write()
+ repo.start_write_group()
+ repo.abort_write_group(False)
+
+ def test_suspend_write_group(self):
+ transport_path = 'quack'
+ repo, client = self.setup_fake_client_and_repository(transport_path)
+ self.assertEquals([], repo.suspend_write_group())
+
+ def test_resume_write_group(self):
+ transport_path = 'quack'
+ repo, client = self.setup_fake_client_and_repository(transport_path)
+ client.add_expected_call(
+ 'Repository.lock_write', ('quack/', ''),
+ 'success', ('ok', 'a token'))
+ client.add_expected_call(
+ 'Repository.check_write_group', ('quack/', 'a token', ['token1']),
+ 'success', ('ok',))
+ repo.lock_write()
+ repo.resume_write_group(['token1'])
+
+
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
def test_backwards_compat(self):
@@ -3224,6 +3302,9 @@
self.calls = calls
self._pack_collection = _StubPackCollection(calls)
+ def start_write_group(self):
+ self.calls.append(('start_write_group',))
+
def is_in_write_group(self):
return False
=== modified file 'bzrlib/tests/test_smart.py'
--- a/bzrlib/tests/test_smart.py 2011-11-25 15:10:43 +0000
+++ b/bzrlib/tests/test_smart.py 2011-11-25 15:12:16 +0000
@@ -2139,6 +2139,79 @@
request.execute(''))
+class TestSmartServerRepositoryWriteGroup(
+ tests.TestCaseWithMemoryTransport):
+
+ def test_start_write_group(self):
+ backing = self.get_transport()
+ repo = self.make_repository('.')
+ lock_token = repo.lock_write().repository_token
+ self.addCleanup(repo.unlock)
+ request_class = smart_repo.SmartServerRepositoryStartWriteGroup
+ request = request_class(backing)
+ self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok', [])),
+ request.execute('', lock_token))
+
+ def test_start_write_group_unsuspendable(self):
+ backing = self.get_transport()
+ repo = self.make_repository('.', format='knit')
+ lock_token = repo.lock_write().repository_token
+ self.addCleanup(repo.unlock)
+ request_class = smart_repo.SmartServerRepositoryStartWriteGroup
+ request = request_class(backing)
+ self.assertEqual(
+ smart_req.FailedSmartServerResponse(('UnsuspendableWriteGroup',)),
+ request.execute('', lock_token))
+
+ def test_commit_write_group(self):
+ backing = self.get_transport()
+ repo = self.make_repository('.')
+ lock_token = repo.lock_write().repository_token
+ self.addCleanup(repo.unlock)
+ repo.start_write_group()
+ tokens = repo.suspend_write_group()
+ request_class = smart_repo.SmartServerRepositoryCommitWriteGroup
+ request = request_class(backing)
+ self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
+ request.execute('', lock_token, tokens))
+
+ def test_abort_write_group(self):
+ backing = self.get_transport()
+ repo = self.make_repository('.')
+ lock_token = repo.lock_write().repository_token
+ repo.start_write_group()
+ tokens = repo.suspend_write_group()
+ self.addCleanup(repo.unlock)
+ request_class = smart_repo.SmartServerRepositoryAbortWriteGroup
+ request = request_class(backing)
+ self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
+ request.execute('', lock_token, tokens))
+
+ def test_check_write_group(self):
+ backing = self.get_transport()
+ repo = self.make_repository('.')
+ lock_token = repo.lock_write().repository_token
+ repo.start_write_group()
+ tokens = repo.suspend_write_group()
+ self.addCleanup(repo.unlock)
+ request_class = smart_repo.SmartServerRepositoryCheckWriteGroup
+ request = request_class(backing)
+ self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
+ request.execute('', lock_token, tokens))
+
+ def test_check_write_group_invalid(self):
+ backing = self.get_transport()
+ repo = self.make_repository('.')
+ lock_token = repo.lock_write().repository_token
+ self.addCleanup(repo.unlock)
+ request_class = smart_repo.SmartServerRepositoryCheckWriteGroup
+ request = request_class(backing)
+ self.assertEqual(smart_req.FailedSmartServerResponse(
+ ('UnresumableWriteGroup', ['random'],
+ 'Malformed write group token')),
+ request.execute('', lock_token, ["random"]))
+
+
class TestSmartServerPackRepositoryAutopack(tests.TestCaseWithTransport):
def make_repo_needing_autopacking(self, path='.'):
@@ -2306,6 +2379,14 @@
smart_repo.SmartServerRepositoryTarball)
self.assertHandlerEqual('Repository.unlock',
smart_repo.SmartServerRepositoryUnlock)
+ self.assertHandlerEqual('Repository.start_write_group',
+ smart_repo.SmartServerRepositoryStartWriteGroup)
+ self.assertHandlerEqual('Repository.check_write_group',
+ smart_repo.SmartServerRepositoryCheckWriteGroup)
+ self.assertHandlerEqual('Repository.commit_write_group',
+ smart_repo.SmartServerRepositoryCommitWriteGroup)
+ self.assertHandlerEqual('Repository.abort_write_group',
+ smart_repo.SmartServerRepositoryAbortWriteGroup)
self.assertHandlerEqual('VersionedFileRepository.get_serializer_format',
smart_repo.SmartServerRepositoryGetSerializerFormat)
self.assertHandlerEqual('Transport.is_readonly',
=== modified file 'doc/en/release-notes/bzr-2.5.txt'
--- a/doc/en/release-notes/bzr-2.5.txt 2011-11-25 15:10:43 +0000
+++ b/doc/en/release-notes/bzr-2.5.txt 2011-11-25 15:12:16 +0000
@@ -111,8 +111,10 @@
``Branch.get_physical_lock_status``,
``Branch.put_config_file``, ``Branch.break_lock``,
``BzrDir.destroy_branch``, ``Repository.break_lock``,
- ``VersionedFileRepository.get_serializer_format`` and
- ``Repository.all_revision_ids``.
+ ``VersionedFileRepository.get_serializer_format``,
+ ``Repository.all_revision_ids``, ``Repository.start_write_group``,
+ ``Repository.commit_write_group``, ``Repository.abort_write_group``
+ and ``Repository.check_write_group``.
(Jelmer Vernooij)
* Custom HPSS error handlers can now be installed in the smart server client
More information about the bazaar-commits
mailing list