Mercurial > hg
changeset 14622:bd88561afb4b
wireproto: add batching support to wirerepository
Adds the plumbing and wire call for batched execution, but does not
batch-enable any methods yet.
author | Peter Arrenbrecht <peter.arrenbrecht@gmail.com> |
---|---|
date | Tue, 14 Jun 2011 22:52:58 +0200 |
parents | 84094c0d2724 |
children | e7c9fdbbb902 |
files | mercurial/wireproto.py tests/test-hgweb-commands.t tests/test-wireprotocol.py tests/test-wireprotocol.py.out |
diffstat | 4 files changed, 110 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/wireproto.py Tue Jun 14 22:51:26 2011 +0200 +++ b/mercurial/wireproto.py Tue Jun 14 22:52:58 2011 +0200 @@ -126,9 +126,41 @@ def encodelist(l, sep=' '): return sep.join(map(hex, l)) +# batched call argument encoding + +def escapearg(plain): + return (plain + .replace(':', '::') + .replace(',', ':,') + .replace(';', ':;') + .replace('=', ':=')) + +def unescapearg(escaped): + return (escaped + .replace(':=', '=') + .replace(':;', ';') + .replace(':,', ',') + .replace('::', ':')) + # client side +def todict(**args): + return args + class wirerepository(repo.repository): + + def batch(self): + return remotebatch(self) + def _submitbatch(self, req): + cmds = [] + for op, argsdict in req: + args = ','.join('%s=%s' % p for p in argsdict.iteritems()) + cmds.append('%s %s' % (op, args)) + rsp = self._call("batch", cmds=';'.join(cmds)) + return rsp.split(';') + def _submitone(self, op, args): + return self._call(op, **args) + def lookup(self, key): self.requirecap('lookup', _('look up remote revision')) d = self._call("lookup", key=encoding.fromlocal(key)) @@ -302,6 +334,34 @@ % (cmd, ",".join(others))) return opts +def batch(repo, proto, cmds, others): + res = [] + for pair in cmds.split(';'): + op, args = pair.split(' ', 1) + vals = {} + for a in args.split(','): + if a: + n, v = a.split('=') + vals[n] = unescapearg(v) + func, spec = commands[op] + if spec: + keys = spec.split() + data = {} + for k in keys: + if k == '*': + star = {} + for key in vals.keys(): + if key not in keys: + star[key] = vals[key] + data['*'] = star + else: + data[k] = vals[k] + result = func(repo, proto, *[data[k] for k in keys]) + else: + result = func(repo, proto) + res.append(escapearg(result)) + return ';'.join(res) + def between(repo, proto, pairs): pairs = [decodelist(p, '-') for p in pairs.split(" ")] r = [] @@ -327,7 +387,7 @@ def capabilities(repo, proto): caps = ('lookup changegroupsubset branchmap pushkey known getbundle ' - 'unbundlehash').split() + 'unbundlehash batch').split() if _allowstream(repo.ui): requiredformats = repo.requirements & repo.supportedformats # if our local revlogs are just revlogv1, add 'stream' cap @@ -506,6 +566,7 @@ os.unlink(tempname) commands = { + 'batch': (batch, 'cmds *'), 'between': (between, 'pairs'), 'branchmap': (branchmap, ''), 'branches': (branches, 'nodes'),
--- a/tests/test-hgweb-commands.t Tue Jun 14 22:51:26 2011 +0200 +++ b/tests/test-hgweb-commands.t Tue Jun 14 22:52:58 2011 +0200 @@ -981,7 +981,7 @@ $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=capabilities'; echo 200 Script output follows - lookup changegroupsubset branchmap pushkey known getbundle unbundlehash unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 + lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 heads
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-wireprotocol.py Tue Jun 14 22:52:58 2011 +0200 @@ -0,0 +1,45 @@ +from mercurial import wireproto + +class proto(): + def __init__(self, args): + self.args = args + def getargs(self, spec): + args = self.args + args.setdefault('*', {}) + names = spec.split() + return [args[n] for n in names] + +class clientrepo(wireproto.wirerepository): + def __init__(self, serverrepo): + self.serverrepo = serverrepo + def _call(self, cmd, **args): + return wireproto.dispatch(self.serverrepo, proto(args), cmd) + + @wireproto.batchable + def greet(self, name): + f = wireproto.future() + yield wireproto.todict(name=mangle(name)), f + yield unmangle(f.value) + +class serverrepo(): + def greet(self, name): + return "Hello, " + name + +def mangle(s): + return ''.join(chr(ord(c) + 1) for c in s) +def unmangle(s): + return ''.join(chr(ord(c) - 1) for c in s) + +def greet(repo, proto, name): + return mangle(repo.greet(unmangle(name))) + +wireproto.commands['greet'] = (greet, 'name',) + +srv = serverrepo() +clt = clientrepo(srv) + +print clt.greet("Foobar") +b = clt.batch() +fs = [b.greet(s) for s in ["Fo, =;o", "Bar"]] +b.submit() +print [f.value for f in fs]