comparison mercurial/wireproto.py @ 13942:88f0e41d8802

wireproto: allow unbundle with hashed heads parameter (issue2126) Current wire protocol of unbundle sends the list of all heads in the remote repository to avoid race condition. This causes "URL too long" error on HTTP server when the repository has many heads. This change allows clients to send SHA1 hash of sorted head hashes instead. Also, this introduces "unbundlehash" capability to inform them that the server accepts hashed heads parameter.
author Shuhei Takahashi <takahashi.shuhei@gmail.com>
date Sat, 16 Apr 2011 01:05:56 +0900
parents b51bf961b3cb
children 58e58406ed19
comparison
equal deleted inserted replaced
13941:924f40b977ee 13942:88f0e41d8802
137 '''Send cg (a readable file-like object representing the 137 '''Send cg (a readable file-like object representing the
138 changegroup to push, typically a chunkbuffer object) to the 138 changegroup to push, typically a chunkbuffer object) to the
139 remote server as a bundle. Return an integer indicating the 139 remote server as a bundle. Return an integer indicating the
140 result of the push (see localrepository.addchangegroup()).''' 140 result of the push (see localrepository.addchangegroup()).'''
141 141
142 ret, output = self._callpush("unbundle", cg, heads=encodelist(heads)) 142 if self.capable('unbundlehash'):
143 heads = encodelist(['hashed',
144 util.sha1(''.join(sorted(heads))).digest()])
145 else:
146 heads = encodelist(heads)
147
148 ret, output = self._callpush("unbundle", cg, heads=heads)
143 if ret == "": 149 if ret == "":
144 raise error.ResponseError( 150 raise error.ResponseError(
145 _('push failed:'), output) 151 _('push failed:'), output)
146 try: 152 try:
147 ret = int(ret) 153 ret = int(ret)
214 for b in repo.branches(nodes): 220 for b in repo.branches(nodes):
215 r.append(encodelist(b) + "\n") 221 r.append(encodelist(b) + "\n")
216 return "".join(r) 222 return "".join(r)
217 223
218 def capabilities(repo, proto): 224 def capabilities(repo, proto):
219 caps = 'lookup changegroupsubset branchmap pushkey known getbundle'.split() 225 caps = ('lookup changegroupsubset branchmap pushkey known getbundle '
226 'unbundlehash').split()
220 if _allowstream(repo.ui): 227 if _allowstream(repo.ui):
221 requiredformats = repo.requirements & repo.supportedformats 228 requiredformats = repo.requirements & repo.supportedformats
222 # if our local revlogs are just revlogv1, add 'stream' cap 229 # if our local revlogs are just revlogv1, add 'stream' cap
223 if not requiredformats - set(('revlogv1',)): 230 if not requiredformats - set(('revlogv1',)):
224 caps.append('stream') 231 caps.append('stream')
351 def unbundle(repo, proto, heads): 358 def unbundle(repo, proto, heads):
352 their_heads = decodelist(heads) 359 their_heads = decodelist(heads)
353 360
354 def check_heads(): 361 def check_heads():
355 heads = repo.heads() 362 heads = repo.heads()
356 return their_heads == ['force'] or their_heads == heads 363 heads_hash = util.sha1(''.join(sorted(heads))).digest()
364 return (their_heads == ['force'] or their_heads == heads or
365 their_heads == ['hashed', heads_hash])
357 366
358 proto.redirect() 367 proto.redirect()
359 368
360 # fail early if possible 369 # fail early if possible
361 if not check_heads(): 370 if not check_heads():