##// END OF EJS Templates
remotefilelog: reduce probability of race-condition in remotefilelog tests...
Boris Feld -
r43110:2c74337e default
parent child Browse files
Show More
@@ -1,1113 +1,1124
1 1 # __init__.py - remotefilelog extension
2 2 #
3 3 # Copyright 2013 Facebook, Inc.
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7 """remotefilelog causes Mercurial to lazilly fetch file contents (EXPERIMENTAL)
8 8
9 9 This extension is HIGHLY EXPERIMENTAL. There are NO BACKWARDS COMPATIBILITY
10 10 GUARANTEES. This means that repositories created with this extension may
11 11 only be usable with the exact version of this extension/Mercurial that was
12 12 used. The extension attempts to enforce this in order to prevent repository
13 13 corruption.
14 14
15 15 remotefilelog works by fetching file contents lazily and storing them
16 16 in a cache on the client rather than in revlogs. This allows enormous
17 17 histories to be transferred only partially, making them easier to
18 18 operate on.
19 19
20 20 Configs:
21 21
22 22 ``packs.maxchainlen`` specifies the maximum delta chain length in pack files
23 23
24 24 ``packs.maxpacksize`` specifies the maximum pack file size
25 25
26 26 ``packs.maxpackfilecount`` specifies the maximum number of packs in the
27 27 shared cache (trees only for now)
28 28
29 29 ``remotefilelog.backgroundprefetch`` runs prefetch in background when True
30 30
31 31 ``remotefilelog.bgprefetchrevs`` specifies revisions to fetch on commit and
32 32 update, and on other commands that use them. Different from pullprefetch.
33 33
34 34 ``remotefilelog.gcrepack`` does garbage collection during repack when True
35 35
36 36 ``remotefilelog.nodettl`` specifies maximum TTL of a node in seconds before
37 37 it is garbage collected
38 38
39 39 ``remotefilelog.repackonhggc`` runs repack on hg gc when True
40 40
41 41 ``remotefilelog.prefetchdays`` specifies the maximum age of a commit in
42 42 days after which it is no longer prefetched.
43 43
44 44 ``remotefilelog.prefetchdelay`` specifies delay between background
45 45 prefetches in seconds after operations that change the working copy parent
46 46
47 47 ``remotefilelog.data.gencountlimit`` constraints the minimum number of data
48 48 pack files required to be considered part of a generation. In particular,
49 49 minimum number of packs files > gencountlimit.
50 50
51 51 ``remotefilelog.data.generations`` list for specifying the lower bound of
52 52 each generation of the data pack files. For example, list ['100MB','1MB']
53 53 or ['1MB', '100MB'] will lead to three generations: [0, 1MB), [
54 54 1MB, 100MB) and [100MB, infinity).
55 55
56 56 ``remotefilelog.data.maxrepackpacks`` the maximum number of pack files to
57 57 include in an incremental data repack.
58 58
59 59 ``remotefilelog.data.repackmaxpacksize`` the maximum size of a pack file for
60 60 it to be considered for an incremental data repack.
61 61
62 62 ``remotefilelog.data.repacksizelimit`` the maximum total size of pack files
63 63 to include in an incremental data repack.
64 64
65 65 ``remotefilelog.history.gencountlimit`` constraints the minimum number of
66 66 history pack files required to be considered part of a generation. In
67 67 particular, minimum number of packs files > gencountlimit.
68 68
69 69 ``remotefilelog.history.generations`` list for specifying the lower bound of
70 70 each generation of the history pack files. For example, list [
71 71 '100MB', '1MB'] or ['1MB', '100MB'] will lead to three generations: [
72 72 0, 1MB), [1MB, 100MB) and [100MB, infinity).
73 73
74 74 ``remotefilelog.history.maxrepackpacks`` the maximum number of pack files to
75 75 include in an incremental history repack.
76 76
77 77 ``remotefilelog.history.repackmaxpacksize`` the maximum size of a pack file
78 78 for it to be considered for an incremental history repack.
79 79
80 80 ``remotefilelog.history.repacksizelimit`` the maximum total size of pack
81 81 files to include in an incremental history repack.
82 82
83 83 ``remotefilelog.backgroundrepack`` automatically consolidate packs in the
84 84 background
85 85
86 86 ``remotefilelog.cachepath`` path to cache
87 87
88 88 ``remotefilelog.cachegroup`` if set, make cache directory sgid to this
89 89 group
90 90
91 91 ``remotefilelog.cacheprocess`` binary to invoke for fetching file data
92 92
93 93 ``remotefilelog.debug`` turn on remotefilelog-specific debug output
94 94
95 95 ``remotefilelog.excludepattern`` pattern of files to exclude from pulls
96 96
97 97 ``remotefilelog.includepattern`` pattern of files to include in pulls
98 98
99 99 ``remotefilelog.fetchwarning``: message to print when too many
100 100 single-file fetches occur
101 101
102 102 ``remotefilelog.getfilesstep`` number of files to request in a single RPC
103 103
104 104 ``remotefilelog.getfilestype`` if set to 'threaded' use threads to fetch
105 105 files, otherwise use optimistic fetching
106 106
107 107 ``remotefilelog.pullprefetch`` revset for selecting files that should be
108 108 eagerly downloaded rather than lazily
109 109
110 110 ``remotefilelog.reponame`` name of the repo. If set, used to partition
111 111 data from other repos in a shared store.
112 112
113 113 ``remotefilelog.server`` if true, enable server-side functionality
114 114
115 115 ``remotefilelog.servercachepath`` path for caching blobs on the server
116 116
117 117 ``remotefilelog.serverexpiration`` number of days to keep cached server
118 118 blobs
119 119
120 120 ``remotefilelog.validatecache`` if set, check cache entries for corruption
121 121 before returning blobs
122 122
123 123 ``remotefilelog.validatecachelog`` if set, check cache entries for
124 124 corruption before returning metadata
125 125
126 126 """
127 127 from __future__ import absolute_import
128 128
129 129 import os
130 130 import time
131 131 import traceback
132 132
133 133 from mercurial.node import hex
134 134 from mercurial.i18n import _
135 135 from mercurial import (
136 136 changegroup,
137 137 changelog,
138 138 cmdutil,
139 139 commands,
140 140 configitems,
141 141 context,
142 142 copies,
143 143 debugcommands as hgdebugcommands,
144 144 dispatch,
145 145 error,
146 146 exchange,
147 147 extensions,
148 148 hg,
149 149 localrepo,
150 150 match,
151 151 merge,
152 152 node as nodemod,
153 153 patch,
154 154 pycompat,
155 155 registrar,
156 156 repair,
157 157 repoview,
158 158 revset,
159 159 scmutil,
160 160 smartset,
161 161 streamclone,
162 162 util,
163 163 )
164 164 from . import (
165 165 constants,
166 166 debugcommands,
167 167 fileserverclient,
168 168 remotefilectx,
169 169 remotefilelog,
170 170 remotefilelogserver,
171 171 repack as repackmod,
172 172 shallowbundle,
173 173 shallowrepo,
174 174 shallowstore,
175 175 shallowutil,
176 176 shallowverifier,
177 177 )
178 178
179 179 # ensures debug commands are registered
180 180 hgdebugcommands.command
181 181
182 182 cmdtable = {}
183 183 command = registrar.command(cmdtable)
184 184
185 185 configtable = {}
186 186 configitem = registrar.configitem(configtable)
187 187
188 188 configitem('remotefilelog', 'debug', default=False)
189 189
190 190 configitem('remotefilelog', 'reponame', default='')
191 191 configitem('remotefilelog', 'cachepath', default=None)
192 192 configitem('remotefilelog', 'cachegroup', default=None)
193 193 configitem('remotefilelog', 'cacheprocess', default=None)
194 194 configitem('remotefilelog', 'cacheprocess.includepath', default=None)
195 195 configitem("remotefilelog", "cachelimit", default="1000 GB")
196 196
197 197 configitem('remotefilelog', 'fallbackpath', default=configitems.dynamicdefault,
198 198 alias=[('remotefilelog', 'fallbackrepo')])
199 199
200 200 configitem('remotefilelog', 'validatecachelog', default=None)
201 201 configitem('remotefilelog', 'validatecache', default='on')
202 202 configitem('remotefilelog', 'server', default=None)
203 203 configitem('remotefilelog', 'servercachepath', default=None)
204 204 configitem("remotefilelog", "serverexpiration", default=30)
205 205 configitem('remotefilelog', 'backgroundrepack', default=False)
206 206 configitem('remotefilelog', 'bgprefetchrevs', default=None)
207 207 configitem('remotefilelog', 'pullprefetch', default=None)
208 208 configitem('remotefilelog', 'backgroundprefetch', default=False)
209 209 configitem('remotefilelog', 'prefetchdelay', default=120)
210 210 configitem('remotefilelog', 'prefetchdays', default=14)
211 211
212 212 configitem('remotefilelog', 'getfilesstep', default=10000)
213 213 configitem('remotefilelog', 'getfilestype', default='optimistic')
214 214 configitem('remotefilelog', 'batchsize', configitems.dynamicdefault)
215 215 configitem('remotefilelog', 'fetchwarning', default='')
216 216
217 217 configitem('remotefilelog', 'includepattern', default=None)
218 218 configitem('remotefilelog', 'excludepattern', default=None)
219 219
220 220 configitem('remotefilelog', 'gcrepack', default=False)
221 221 configitem('remotefilelog', 'repackonhggc', default=False)
222 222 configitem('repack', 'chainorphansbysize', default=True, experimental=True)
223 223
224 224 configitem('packs', 'maxpacksize', default=0)
225 225 configitem('packs', 'maxchainlen', default=1000)
226 226
227 configitem('devel', 'remotefilelog.ensurestart', default=False)
228
227 229 # default TTL limit is 30 days
228 230 _defaultlimit = 60 * 60 * 24 * 30
229 231 configitem('remotefilelog', 'nodettl', default=_defaultlimit)
230 232
231 233 configitem('remotefilelog', 'data.gencountlimit', default=2),
232 234 configitem('remotefilelog', 'data.generations',
233 235 default=['1GB', '100MB', '1MB'])
234 236 configitem('remotefilelog', 'data.maxrepackpacks', default=50)
235 237 configitem('remotefilelog', 'data.repackmaxpacksize', default='4GB')
236 238 configitem('remotefilelog', 'data.repacksizelimit', default='100MB')
237 239
238 240 configitem('remotefilelog', 'history.gencountlimit', default=2),
239 241 configitem('remotefilelog', 'history.generations', default=['100MB'])
240 242 configitem('remotefilelog', 'history.maxrepackpacks', default=50)
241 243 configitem('remotefilelog', 'history.repackmaxpacksize', default='400MB')
242 244 configitem('remotefilelog', 'history.repacksizelimit', default='100MB')
243 245
244 246 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
245 247 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
246 248 # be specifying the version(s) of Mercurial they are tested with, or
247 249 # leave the attribute unspecified.
248 250 testedwith = 'ships-with-hg-core'
249 251
250 252 repoclass = localrepo.localrepository
251 253 repoclass._basesupported.add(constants.SHALLOWREPO_REQUIREMENT)
252 254
253 255 isenabled = shallowutil.isenabled
254 256
255 257 def uisetup(ui):
256 258 """Wraps user facing Mercurial commands to swap them out with shallow
257 259 versions.
258 260 """
259 261 hg.wirepeersetupfuncs.append(fileserverclient.peersetup)
260 262
261 263 entry = extensions.wrapcommand(commands.table, 'clone', cloneshallow)
262 264 entry[1].append(('', 'shallow', None,
263 265 _("create a shallow clone which uses remote file "
264 266 "history")))
265 267
266 268 extensions.wrapcommand(commands.table, 'debugindex',
267 269 debugcommands.debugindex)
268 270 extensions.wrapcommand(commands.table, 'debugindexdot',
269 271 debugcommands.debugindexdot)
270 272 extensions.wrapcommand(commands.table, 'log', log)
271 273 extensions.wrapcommand(commands.table, 'pull', pull)
272 274
273 275 # Prevent 'hg manifest --all'
274 276 def _manifest(orig, ui, repo, *args, **opts):
275 277 if (isenabled(repo) and opts.get(r'all')):
276 278 raise error.Abort(_("--all is not supported in a shallow repo"))
277 279
278 280 return orig(ui, repo, *args, **opts)
279 281 extensions.wrapcommand(commands.table, "manifest", _manifest)
280 282
281 283 # Wrap remotefilelog with lfs code
282 284 def _lfsloaded(loaded=False):
283 285 lfsmod = None
284 286 try:
285 287 lfsmod = extensions.find('lfs')
286 288 except KeyError:
287 289 pass
288 290 if lfsmod:
289 291 lfsmod.wrapfilelog(remotefilelog.remotefilelog)
290 292 fileserverclient._lfsmod = lfsmod
291 293 extensions.afterloaded('lfs', _lfsloaded)
292 294
293 295 # debugdata needs remotefilelog.len to work
294 296 extensions.wrapcommand(commands.table, 'debugdata', debugdatashallow)
295 297
296 298 changegroup.cgpacker = shallowbundle.shallowcg1packer
297 299
298 300 extensions.wrapfunction(changegroup, '_addchangegroupfiles',
299 301 shallowbundle.addchangegroupfiles)
300 302 extensions.wrapfunction(
301 303 changegroup, 'makechangegroup', shallowbundle.makechangegroup)
302 304 extensions.wrapfunction(localrepo, 'makestore', storewrapper)
303 305 extensions.wrapfunction(exchange, 'pull', exchangepull)
304 306 extensions.wrapfunction(merge, 'applyupdates', applyupdates)
305 307 extensions.wrapfunction(merge, '_checkunknownfiles', checkunknownfiles)
306 308 extensions.wrapfunction(context.workingctx, '_checklookup', checklookup)
307 309 extensions.wrapfunction(scmutil, '_findrenames', findrenames)
308 310 extensions.wrapfunction(copies, '_computeforwardmissing',
309 311 computeforwardmissing)
310 312 extensions.wrapfunction(dispatch, 'runcommand', runcommand)
311 313 extensions.wrapfunction(repair, '_collectbrokencsets', _collectbrokencsets)
312 314 extensions.wrapfunction(context.changectx, 'filectx', filectx)
313 315 extensions.wrapfunction(context.workingctx, 'filectx', workingfilectx)
314 316 extensions.wrapfunction(patch, 'trydiff', trydiff)
315 317 extensions.wrapfunction(hg, 'verify', _verify)
316 318 scmutil.fileprefetchhooks.add('remotefilelog', _fileprefetchhook)
317 319
318 320 # disappointing hacks below
319 321 extensions.wrapfunction(scmutil, 'getrenamedfn', getrenamedfn)
320 322 extensions.wrapfunction(revset, 'filelog', filelogrevset)
321 323 revset.symbols['filelog'] = revset.filelog
322 324 extensions.wrapfunction(cmdutil, 'walkfilerevs', walkfilerevs)
323 325
324 326
325 327 def cloneshallow(orig, ui, repo, *args, **opts):
326 328 if opts.get(r'shallow'):
327 329 repos = []
328 330 def pull_shallow(orig, self, *args, **kwargs):
329 331 if not isenabled(self):
330 332 repos.append(self.unfiltered())
331 333 # set up the client hooks so the post-clone update works
332 334 setupclient(self.ui, self.unfiltered())
333 335
334 336 # setupclient fixed the class on the repo itself
335 337 # but we also need to fix it on the repoview
336 338 if isinstance(self, repoview.repoview):
337 339 self.__class__.__bases__ = (self.__class__.__bases__[0],
338 340 self.unfiltered().__class__)
339 341 self.requirements.add(constants.SHALLOWREPO_REQUIREMENT)
340 342 self._writerequirements()
341 343
342 344 # Since setupclient hadn't been called, exchange.pull was not
343 345 # wrapped. So we need to manually invoke our version of it.
344 346 return exchangepull(orig, self, *args, **kwargs)
345 347 else:
346 348 return orig(self, *args, **kwargs)
347 349 extensions.wrapfunction(exchange, 'pull', pull_shallow)
348 350
349 351 # Wrap the stream logic to add requirements and to pass include/exclude
350 352 # patterns around.
351 353 def setup_streamout(repo, remote):
352 354 # Replace remote.stream_out with a version that sends file
353 355 # patterns.
354 356 def stream_out_shallow(orig):
355 357 caps = remote.capabilities()
356 358 if constants.NETWORK_CAP_LEGACY_SSH_GETFILES in caps:
357 359 opts = {}
358 360 if repo.includepattern:
359 361 opts[r'includepattern'] = '\0'.join(repo.includepattern)
360 362 if repo.excludepattern:
361 363 opts[r'excludepattern'] = '\0'.join(repo.excludepattern)
362 364 return remote._callstream('stream_out_shallow', **opts)
363 365 else:
364 366 return orig()
365 367 extensions.wrapfunction(remote, 'stream_out', stream_out_shallow)
366 368 def stream_wrap(orig, op):
367 369 setup_streamout(op.repo, op.remote)
368 370 return orig(op)
369 371 extensions.wrapfunction(
370 372 streamclone, 'maybeperformlegacystreamclone', stream_wrap)
371 373
372 374 def canperformstreamclone(orig, pullop, bundle2=False):
373 375 # remotefilelog is currently incompatible with the
374 376 # bundle2 flavor of streamclones, so force us to use
375 377 # v1 instead.
376 378 if 'v2' in pullop.remotebundle2caps.get('stream', []):
377 379 pullop.remotebundle2caps['stream'] = [
378 380 c for c in pullop.remotebundle2caps['stream']
379 381 if c != 'v2']
380 382 if bundle2:
381 383 return False, None
382 384 supported, requirements = orig(pullop, bundle2=bundle2)
383 385 if requirements is not None:
384 386 requirements.add(constants.SHALLOWREPO_REQUIREMENT)
385 387 return supported, requirements
386 388 extensions.wrapfunction(
387 389 streamclone, 'canperformstreamclone', canperformstreamclone)
388 390
389 391 try:
390 392 orig(ui, repo, *args, **opts)
391 393 finally:
392 394 if opts.get(r'shallow'):
393 395 for r in repos:
394 396 if util.safehasattr(r, 'fileservice'):
395 397 r.fileservice.close()
396 398
397 399 def debugdatashallow(orig, *args, **kwds):
398 400 oldlen = remotefilelog.remotefilelog.__len__
399 401 try:
400 402 remotefilelog.remotefilelog.__len__ = lambda x: 1
401 403 return orig(*args, **kwds)
402 404 finally:
403 405 remotefilelog.remotefilelog.__len__ = oldlen
404 406
405 407 def reposetup(ui, repo):
406 408 if not repo.local():
407 409 return
408 410
409 411 # put here intentionally bc doesnt work in uisetup
410 412 ui.setconfig('hooks', 'update.prefetch', wcpprefetch)
411 413 ui.setconfig('hooks', 'commit.prefetch', wcpprefetch)
412 414
413 415 isserverenabled = ui.configbool('remotefilelog', 'server')
414 416 isshallowclient = isenabled(repo)
415 417
416 418 if isserverenabled and isshallowclient:
417 419 raise RuntimeError("Cannot be both a server and shallow client.")
418 420
419 421 if isshallowclient:
420 422 setupclient(ui, repo)
421 423
422 424 if isserverenabled:
423 425 remotefilelogserver.setupserver(ui, repo)
424 426
425 427 def setupclient(ui, repo):
426 428 if not isinstance(repo, localrepo.localrepository):
427 429 return
428 430
429 431 # Even clients get the server setup since they need to have the
430 432 # wireprotocol endpoints registered.
431 433 remotefilelogserver.onetimesetup(ui)
432 434 onetimeclientsetup(ui)
433 435
434 436 shallowrepo.wraprepo(repo)
435 437 repo.store = shallowstore.wrapstore(repo.store)
436 438
437 439 def storewrapper(orig, requirements, path, vfstype):
438 440 s = orig(requirements, path, vfstype)
439 441 if constants.SHALLOWREPO_REQUIREMENT in requirements:
440 442 s = shallowstore.wrapstore(s)
441 443
442 444 return s
443 445
444 446 # prefetch files before update
445 447 def applyupdates(orig, repo, actions, wctx, mctx, overwrite, wantfiledata,
446 448 labels=None):
447 449 if isenabled(repo):
448 450 manifest = mctx.manifest()
449 451 files = []
450 452 for f, args, msg in actions['g']:
451 453 files.append((f, hex(manifest[f])))
452 454 # batch fetch the needed files from the server
453 455 repo.fileservice.prefetch(files)
454 456 return orig(repo, actions, wctx, mctx, overwrite, wantfiledata,
455 457 labels=labels)
456 458
457 459 # Prefetch merge checkunknownfiles
458 460 def checkunknownfiles(orig, repo, wctx, mctx, force, actions,
459 461 *args, **kwargs):
460 462 if isenabled(repo):
461 463 files = []
462 464 sparsematch = repo.maybesparsematch(mctx.rev())
463 465 for f, (m, actionargs, msg) in actions.iteritems():
464 466 if sparsematch and not sparsematch(f):
465 467 continue
466 468 if m in ('c', 'dc', 'cm'):
467 469 files.append((f, hex(mctx.filenode(f))))
468 470 elif m == 'dg':
469 471 f2 = actionargs[0]
470 472 files.append((f2, hex(mctx.filenode(f2))))
471 473 # batch fetch the needed files from the server
472 474 repo.fileservice.prefetch(files)
473 475 return orig(repo, wctx, mctx, force, actions, *args, **kwargs)
474 476
475 477 # Prefetch files before status attempts to look at their size and contents
476 478 def checklookup(orig, self, files):
477 479 repo = self._repo
478 480 if isenabled(repo):
479 481 prefetchfiles = []
480 482 for parent in self._parents:
481 483 for f in files:
482 484 if f in parent:
483 485 prefetchfiles.append((f, hex(parent.filenode(f))))
484 486 # batch fetch the needed files from the server
485 487 repo.fileservice.prefetch(prefetchfiles)
486 488 return orig(self, files)
487 489
488 490 # Prefetch the logic that compares added and removed files for renames
489 491 def findrenames(orig, repo, matcher, added, removed, *args, **kwargs):
490 492 if isenabled(repo):
491 493 files = []
492 494 pmf = repo['.'].manifest()
493 495 for f in removed:
494 496 if f in pmf:
495 497 files.append((f, hex(pmf[f])))
496 498 # batch fetch the needed files from the server
497 499 repo.fileservice.prefetch(files)
498 500 return orig(repo, matcher, added, removed, *args, **kwargs)
499 501
500 502 # prefetch files before pathcopies check
501 503 def computeforwardmissing(orig, a, b, match=None):
502 504 missing = orig(a, b, match=match)
503 505 repo = a._repo
504 506 if isenabled(repo):
505 507 mb = b.manifest()
506 508
507 509 files = []
508 510 sparsematch = repo.maybesparsematch(b.rev())
509 511 if sparsematch:
510 512 sparsemissing = set()
511 513 for f in missing:
512 514 if sparsematch(f):
513 515 files.append((f, hex(mb[f])))
514 516 sparsemissing.add(f)
515 517 missing = sparsemissing
516 518
517 519 # batch fetch the needed files from the server
518 520 repo.fileservice.prefetch(files)
519 521 return missing
520 522
521 523 # close cache miss server connection after the command has finished
522 524 def runcommand(orig, lui, repo, *args, **kwargs):
523 525 fileservice = None
524 526 # repo can be None when running in chg:
525 527 # - at startup, reposetup was called because serve is not norepo
526 528 # - a norepo command like "help" is called
527 529 if repo and isenabled(repo):
528 530 fileservice = repo.fileservice
529 531 try:
530 532 return orig(lui, repo, *args, **kwargs)
531 533 finally:
532 534 if fileservice:
533 535 fileservice.close()
534 536
535 537 # prevent strip from stripping remotefilelogs
536 538 def _collectbrokencsets(orig, repo, files, striprev):
537 539 if isenabled(repo):
538 540 files = list([f for f in files if not repo.shallowmatch(f)])
539 541 return orig(repo, files, striprev)
540 542
541 543 # changectx wrappers
542 544 def filectx(orig, self, path, fileid=None, filelog=None):
543 545 if fileid is None:
544 546 fileid = self.filenode(path)
545 547 if (isenabled(self._repo) and self._repo.shallowmatch(path)):
546 548 return remotefilectx.remotefilectx(self._repo, path, fileid=fileid,
547 549 changectx=self, filelog=filelog)
548 550 return orig(self, path, fileid=fileid, filelog=filelog)
549 551
550 552 def workingfilectx(orig, self, path, filelog=None):
551 553 if (isenabled(self._repo) and self._repo.shallowmatch(path)):
552 554 return remotefilectx.remoteworkingfilectx(self._repo, path,
553 555 workingctx=self,
554 556 filelog=filelog)
555 557 return orig(self, path, filelog=filelog)
556 558
557 559 # prefetch required revisions before a diff
558 560 def trydiff(orig, repo, revs, ctx1, ctx2, modified, added, removed,
559 561 copy, getfilectx, *args, **kwargs):
560 562 if isenabled(repo):
561 563 prefetch = []
562 564 mf1 = ctx1.manifest()
563 565 for fname in modified + added + removed:
564 566 if fname in mf1:
565 567 fnode = getfilectx(fname, ctx1).filenode()
566 568 # fnode can be None if it's a edited working ctx file
567 569 if fnode:
568 570 prefetch.append((fname, hex(fnode)))
569 571 if fname not in removed:
570 572 fnode = getfilectx(fname, ctx2).filenode()
571 573 if fnode:
572 574 prefetch.append((fname, hex(fnode)))
573 575
574 576 repo.fileservice.prefetch(prefetch)
575 577
576 578 return orig(repo, revs, ctx1, ctx2, modified, added, removed, copy,
577 579 getfilectx, *args, **kwargs)
578 580
579 581 # Prevent verify from processing files
580 582 # a stub for mercurial.hg.verify()
581 583 def _verify(orig, repo, level=None):
582 584 lock = repo.lock()
583 585 try:
584 586 return shallowverifier.shallowverifier(repo).verify()
585 587 finally:
586 588 lock.release()
587 589
588 590
589 591 clientonetime = False
590 592 def onetimeclientsetup(ui):
591 593 global clientonetime
592 594 if clientonetime:
593 595 return
594 596 clientonetime = True
595 597
596 598 # Don't commit filelogs until we know the commit hash, since the hash
597 599 # is present in the filelog blob.
598 600 # This violates Mercurial's filelog->manifest->changelog write order,
599 601 # but is generally fine for client repos.
600 602 pendingfilecommits = []
601 603 def addrawrevision(orig, self, rawtext, transaction, link, p1, p2, node,
602 604 flags, cachedelta=None, _metatuple=None):
603 605 if isinstance(link, int):
604 606 pendingfilecommits.append(
605 607 (self, rawtext, transaction, link, p1, p2, node, flags,
606 608 cachedelta, _metatuple))
607 609 return node
608 610 else:
609 611 return orig(self, rawtext, transaction, link, p1, p2, node, flags,
610 612 cachedelta, _metatuple=_metatuple)
611 613 extensions.wrapfunction(
612 614 remotefilelog.remotefilelog, 'addrawrevision', addrawrevision)
613 615
614 616 def changelogadd(orig, self, *args):
615 617 oldlen = len(self)
616 618 node = orig(self, *args)
617 619 newlen = len(self)
618 620 if oldlen != newlen:
619 621 for oldargs in pendingfilecommits:
620 622 log, rt, tr, link, p1, p2, n, fl, c, m = oldargs
621 623 linknode = self.node(link)
622 624 if linknode == node:
623 625 log.addrawrevision(rt, tr, linknode, p1, p2, n, fl, c, m)
624 626 else:
625 627 raise error.ProgrammingError(
626 628 'pending multiple integer revisions are not supported')
627 629 else:
628 630 # "link" is actually wrong here (it is set to len(changelog))
629 631 # if changelog remains unchanged, skip writing file revisions
630 632 # but still do a sanity check about pending multiple revisions
631 633 if len(set(x[3] for x in pendingfilecommits)) > 1:
632 634 raise error.ProgrammingError(
633 635 'pending multiple integer revisions are not supported')
634 636 del pendingfilecommits[:]
635 637 return node
636 638 extensions.wrapfunction(changelog.changelog, 'add', changelogadd)
637 639
638 640 def getrenamedfn(orig, repo, endrev=None):
639 641 if not isenabled(repo) or copies.usechangesetcentricalgo(repo):
640 642 return orig(repo, endrev)
641 643
642 644 rcache = {}
643 645
644 646 def getrenamed(fn, rev):
645 647 '''looks up all renames for a file (up to endrev) the first
646 648 time the file is given. It indexes on the changerev and only
647 649 parses the manifest if linkrev != changerev.
648 650 Returns rename info for fn at changerev rev.'''
649 651 if rev in rcache.setdefault(fn, {}):
650 652 return rcache[fn][rev]
651 653
652 654 try:
653 655 fctx = repo[rev].filectx(fn)
654 656 for ancestor in fctx.ancestors():
655 657 if ancestor.path() == fn:
656 658 renamed = ancestor.renamed()
657 659 rcache[fn][ancestor.rev()] = renamed and renamed[0]
658 660
659 661 renamed = fctx.renamed()
660 662 return renamed and renamed[0]
661 663 except error.LookupError:
662 664 return None
663 665
664 666 return getrenamed
665 667
666 668 def walkfilerevs(orig, repo, match, follow, revs, fncache):
667 669 if not isenabled(repo):
668 670 return orig(repo, match, follow, revs, fncache)
669 671
670 672 # remotefilelog's can't be walked in rev order, so throw.
671 673 # The caller will see the exception and walk the commit tree instead.
672 674 if not follow:
673 675 raise cmdutil.FileWalkError("Cannot walk via filelog")
674 676
675 677 wanted = set()
676 678 minrev, maxrev = min(revs), max(revs)
677 679
678 680 pctx = repo['.']
679 681 for filename in match.files():
680 682 if filename not in pctx:
681 683 raise error.Abort(_('cannot follow file not in parent '
682 684 'revision: "%s"') % filename)
683 685 fctx = pctx[filename]
684 686
685 687 linkrev = fctx.linkrev()
686 688 if linkrev >= minrev and linkrev <= maxrev:
687 689 fncache.setdefault(linkrev, []).append(filename)
688 690 wanted.add(linkrev)
689 691
690 692 for ancestor in fctx.ancestors():
691 693 linkrev = ancestor.linkrev()
692 694 if linkrev >= minrev and linkrev <= maxrev:
693 695 fncache.setdefault(linkrev, []).append(ancestor.path())
694 696 wanted.add(linkrev)
695 697
696 698 return wanted
697 699
698 700 def filelogrevset(orig, repo, subset, x):
699 701 """``filelog(pattern)``
700 702 Changesets connected to the specified filelog.
701 703
702 704 For performance reasons, ``filelog()`` does not show every changeset
703 705 that affects the requested file(s). See :hg:`help log` for details. For
704 706 a slower, more accurate result, use ``file()``.
705 707 """
706 708
707 709 if not isenabled(repo):
708 710 return orig(repo, subset, x)
709 711
710 712 # i18n: "filelog" is a keyword
711 713 pat = revset.getstring(x, _("filelog requires a pattern"))
712 714 m = match.match(repo.root, repo.getcwd(), [pat], default='relpath',
713 715 ctx=repo[None])
714 716 s = set()
715 717
716 718 if not match.patkind(pat):
717 719 # slow
718 720 for r in subset:
719 721 ctx = repo[r]
720 722 cfiles = ctx.files()
721 723 for f in m.files():
722 724 if f in cfiles:
723 725 s.add(ctx.rev())
724 726 break
725 727 else:
726 728 # partial
727 729 files = (f for f in repo[None] if m(f))
728 730 for f in files:
729 731 fctx = repo[None].filectx(f)
730 732 s.add(fctx.linkrev())
731 733 for actx in fctx.ancestors():
732 734 s.add(actx.linkrev())
733 735
734 736 return smartset.baseset([r for r in subset if r in s])
735 737
736 738 @command('gc', [], _('hg gc [REPO...]'), norepo=True)
737 739 def gc(ui, *args, **opts):
738 740 '''garbage collect the client and server filelog caches
739 741 '''
740 742 cachepaths = set()
741 743
742 744 # get the system client cache
743 745 systemcache = shallowutil.getcachepath(ui, allowempty=True)
744 746 if systemcache:
745 747 cachepaths.add(systemcache)
746 748
747 749 # get repo client and server cache
748 750 repopaths = []
749 751 pwd = ui.environ.get('PWD')
750 752 if pwd:
751 753 repopaths.append(pwd)
752 754
753 755 repopaths.extend(args)
754 756 repos = []
755 757 for repopath in repopaths:
756 758 try:
757 759 repo = hg.peer(ui, {}, repopath)
758 760 repos.append(repo)
759 761
760 762 repocache = shallowutil.getcachepath(repo.ui, allowempty=True)
761 763 if repocache:
762 764 cachepaths.add(repocache)
763 765 except error.RepoError:
764 766 pass
765 767
766 768 # gc client cache
767 769 for cachepath in cachepaths:
768 770 gcclient(ui, cachepath)
769 771
770 772 # gc server cache
771 773 for repo in repos:
772 774 remotefilelogserver.gcserver(ui, repo._repo)
773 775
774 776 def gcclient(ui, cachepath):
775 777 # get list of repos that use this cache
776 778 repospath = os.path.join(cachepath, 'repos')
777 779 if not os.path.exists(repospath):
778 780 ui.warn(_("no known cache at %s\n") % cachepath)
779 781 return
780 782
781 783 reposfile = open(repospath, 'rb')
782 784 repos = {r[:-1] for r in reposfile.readlines()}
783 785 reposfile.close()
784 786
785 787 # build list of useful files
786 788 validrepos = []
787 789 keepkeys = set()
788 790
789 791 sharedcache = None
790 792 filesrepacked = False
791 793
792 794 count = 0
793 795 progress = ui.makeprogress(_("analyzing repositories"), unit="repos",
794 796 total=len(repos))
795 797 for path in repos:
796 798 progress.update(count)
797 799 count += 1
798 800 try:
799 801 path = ui.expandpath(os.path.normpath(path))
800 802 except TypeError as e:
801 803 ui.warn(_("warning: malformed path: %r:%s\n") % (path, e))
802 804 traceback.print_exc()
803 805 continue
804 806 try:
805 807 peer = hg.peer(ui, {}, path)
806 808 repo = peer._repo
807 809 except error.RepoError:
808 810 continue
809 811
810 812 validrepos.append(path)
811 813
812 814 # Protect against any repo or config changes that have happened since
813 815 # this repo was added to the repos file. We'd rather this loop succeed
814 816 # and too much be deleted, than the loop fail and nothing gets deleted.
815 817 if not isenabled(repo):
816 818 continue
817 819
818 820 if not util.safehasattr(repo, 'name'):
819 821 ui.warn(_("repo %s is a misconfigured remotefilelog repo\n") % path)
820 822 continue
821 823
822 824 # If garbage collection on repack and repack on hg gc are enabled
823 825 # then loose files are repacked and garbage collected.
824 826 # Otherwise regular garbage collection is performed.
825 827 repackonhggc = repo.ui.configbool('remotefilelog', 'repackonhggc')
826 828 gcrepack = repo.ui.configbool('remotefilelog', 'gcrepack')
827 829 if repackonhggc and gcrepack:
828 830 try:
829 831 repackmod.incrementalrepack(repo)
830 832 filesrepacked = True
831 833 continue
832 834 except (IOError, repackmod.RepackAlreadyRunning):
833 835 # If repack cannot be performed due to not enough disk space
834 836 # continue doing garbage collection of loose files w/o repack
835 837 pass
836 838
837 839 reponame = repo.name
838 840 if not sharedcache:
839 841 sharedcache = repo.sharedstore
840 842
841 843 # Compute a keepset which is not garbage collected
842 844 def keyfn(fname, fnode):
843 845 return fileserverclient.getcachekey(reponame, fname, hex(fnode))
844 846 keepkeys = repackmod.keepset(repo, keyfn=keyfn, lastkeepkeys=keepkeys)
845 847
846 848 progress.complete()
847 849
848 850 # write list of valid repos back
849 851 oldumask = os.umask(0o002)
850 852 try:
851 853 reposfile = open(repospath, 'wb')
852 854 reposfile.writelines([("%s\n" % r) for r in validrepos])
853 855 reposfile.close()
854 856 finally:
855 857 os.umask(oldumask)
856 858
857 859 # prune cache
858 860 if sharedcache is not None:
859 861 sharedcache.gc(keepkeys)
860 862 elif not filesrepacked:
861 863 ui.warn(_("warning: no valid repos in repofile\n"))
862 864
863 865 def log(orig, ui, repo, *pats, **opts):
864 866 if not isenabled(repo):
865 867 return orig(ui, repo, *pats, **opts)
866 868
867 869 follow = opts.get(r'follow')
868 870 revs = opts.get(r'rev')
869 871 if pats:
870 872 # Force slowpath for non-follow patterns and follows that start from
871 873 # non-working-copy-parent revs.
872 874 if not follow or revs:
873 875 # This forces the slowpath
874 876 opts[r'removed'] = True
875 877
876 878 # If this is a non-follow log without any revs specified, recommend that
877 879 # the user add -f to speed it up.
878 880 if not follow and not revs:
879 881 match = scmutil.match(repo['.'], pats, pycompat.byteskwargs(opts))
880 882 isfile = not match.anypats()
881 883 if isfile:
882 884 for file in match.files():
883 885 if not os.path.isfile(repo.wjoin(file)):
884 886 isfile = False
885 887 break
886 888
887 889 if isfile:
888 890 ui.warn(_("warning: file log can be slow on large repos - " +
889 891 "use -f to speed it up\n"))
890 892
891 893 return orig(ui, repo, *pats, **opts)
892 894
893 895 def revdatelimit(ui, revset):
894 896 """Update revset so that only changesets no older than 'prefetchdays' days
895 897 are included. The default value is set to 14 days. If 'prefetchdays' is set
896 898 to zero or negative value then date restriction is not applied.
897 899 """
898 900 days = ui.configint('remotefilelog', 'prefetchdays')
899 901 if days > 0:
900 902 revset = '(%s) & date(-%s)' % (revset, days)
901 903 return revset
902 904
903 905 def readytofetch(repo):
904 906 """Check that enough time has passed since the last background prefetch.
905 907 This only relates to prefetches after operations that change the working
906 908 copy parent. Default delay between background prefetches is 2 minutes.
907 909 """
908 910 timeout = repo.ui.configint('remotefilelog', 'prefetchdelay')
909 911 fname = repo.vfs.join('lastprefetch')
910 912
911 913 ready = False
912 914 with open(fname, 'a'):
913 915 # the with construct above is used to avoid race conditions
914 916 modtime = os.path.getmtime(fname)
915 917 if (time.time() - modtime) > timeout:
916 918 os.utime(fname, None)
917 919 ready = True
918 920
919 921 return ready
920 922
921 923 def wcpprefetch(ui, repo, **kwargs):
922 924 """Prefetches in background revisions specified by bgprefetchrevs revset.
923 925 Does background repack if backgroundrepack flag is set in config.
924 926 """
925 927 shallow = isenabled(repo)
926 928 bgprefetchrevs = ui.config('remotefilelog', 'bgprefetchrevs')
927 929 isready = readytofetch(repo)
928 930
929 931 if not (shallow and bgprefetchrevs and isready):
930 932 return
931 933
932 934 bgrepack = repo.ui.configbool('remotefilelog', 'backgroundrepack')
933 935 # update a revset with a date limit
934 936 bgprefetchrevs = revdatelimit(ui, bgprefetchrevs)
935 937
936 938 def anon():
937 939 if util.safehasattr(repo, 'ranprefetch') and repo.ranprefetch:
938 940 return
939 941 repo.ranprefetch = True
940 942 repo.backgroundprefetch(bgprefetchrevs, repack=bgrepack)
941 943
942 944 repo._afterlock(anon)
943 945
944 946 def pull(orig, ui, repo, *pats, **opts):
945 947 result = orig(ui, repo, *pats, **opts)
946 948
947 949 if isenabled(repo):
948 950 # prefetch if it's configured
949 951 prefetchrevset = ui.config('remotefilelog', 'pullprefetch')
950 952 bgrepack = repo.ui.configbool('remotefilelog', 'backgroundrepack')
951 953 bgprefetch = repo.ui.configbool('remotefilelog', 'backgroundprefetch')
954 ensurestart = repo.ui.configbool('devel', 'remotefilelog.ensurestart')
952 955
953 956 if prefetchrevset:
954 957 ui.status(_("prefetching file contents\n"))
955 958 revs = scmutil.revrange(repo, [prefetchrevset])
956 959 base = repo['.'].rev()
957 960 if bgprefetch:
958 repo.backgroundprefetch(prefetchrevset, repack=bgrepack)
961 repo.backgroundprefetch(prefetchrevset, repack=bgrepack,
962 ensurestart=ensurestart)
959 963 else:
960 964 repo.prefetch(revs, base=base)
961 965 if bgrepack:
962 repackmod.backgroundrepack(repo, incremental=True)
966 repackmod.backgroundrepack(repo, incremental=True,
967 ensurestart=ensurestart)
963 968 elif bgrepack:
964 repackmod.backgroundrepack(repo, incremental=True)
969 repackmod.backgroundrepack(repo, incremental=True,
970 ensurestart=ensurestart)
965 971
966 972 return result
967 973
968 974 def exchangepull(orig, repo, remote, *args, **kwargs):
969 975 # Hook into the callstream/getbundle to insert bundle capabilities
970 976 # during a pull.
971 977 def localgetbundle(orig, source, heads=None, common=None, bundlecaps=None,
972 978 **kwargs):
973 979 if not bundlecaps:
974 980 bundlecaps = set()
975 981 bundlecaps.add(constants.BUNDLE2_CAPABLITY)
976 982 return orig(source, heads=heads, common=common, bundlecaps=bundlecaps,
977 983 **kwargs)
978 984
979 985 if util.safehasattr(remote, '_callstream'):
980 986 remote._localrepo = repo
981 987 elif util.safehasattr(remote, 'getbundle'):
982 988 extensions.wrapfunction(remote, 'getbundle', localgetbundle)
983 989
984 990 return orig(repo, remote, *args, **kwargs)
985 991
986 992 def _fileprefetchhook(repo, revs, match):
987 993 if isenabled(repo):
988 994 allfiles = []
989 995 for rev in revs:
990 996 if rev == nodemod.wdirrev or rev is None:
991 997 continue
992 998 ctx = repo[rev]
993 999 mf = ctx.manifest()
994 1000 sparsematch = repo.maybesparsematch(ctx.rev())
995 1001 for path in ctx.walk(match):
996 1002 if (not sparsematch or sparsematch(path)) and path in mf:
997 1003 allfiles.append((path, hex(mf[path])))
998 1004 repo.fileservice.prefetch(allfiles)
999 1005
1000 1006 @command('debugremotefilelog', [
1001 1007 ('d', 'decompress', None, _('decompress the filelog first')),
1002 1008 ], _('hg debugremotefilelog <path>'), norepo=True)
1003 1009 def debugremotefilelog(ui, path, **opts):
1004 1010 return debugcommands.debugremotefilelog(ui, path, **opts)
1005 1011
1006 1012 @command('verifyremotefilelog', [
1007 1013 ('d', 'decompress', None, _('decompress the filelogs first')),
1008 1014 ], _('hg verifyremotefilelogs <directory>'), norepo=True)
1009 1015 def verifyremotefilelog(ui, path, **opts):
1010 1016 return debugcommands.verifyremotefilelog(ui, path, **opts)
1011 1017
1012 1018 @command('debugdatapack', [
1013 1019 ('', 'long', None, _('print the long hashes')),
1014 1020 ('', 'node', '', _('dump the contents of node'), 'NODE'),
1015 1021 ], _('hg debugdatapack <paths>'), norepo=True)
1016 1022 def debugdatapack(ui, *paths, **opts):
1017 1023 return debugcommands.debugdatapack(ui, *paths, **opts)
1018 1024
1019 1025 @command('debughistorypack', [
1020 1026 ], _('hg debughistorypack <path>'), norepo=True)
1021 1027 def debughistorypack(ui, path, **opts):
1022 1028 return debugcommands.debughistorypack(ui, path)
1023 1029
1024 1030 @command('debugkeepset', [
1025 1031 ], _('hg debugkeepset'))
1026 1032 def debugkeepset(ui, repo, **opts):
1027 1033 # The command is used to measure keepset computation time
1028 1034 def keyfn(fname, fnode):
1029 1035 return fileserverclient.getcachekey(repo.name, fname, hex(fnode))
1030 1036 repackmod.keepset(repo, keyfn)
1031 1037 return
1032 1038
1033 1039 @command('debugwaitonrepack', [
1034 1040 ], _('hg debugwaitonrepack'))
1035 1041 def debugwaitonrepack(ui, repo, **opts):
1036 1042 return debugcommands.debugwaitonrepack(repo)
1037 1043
1038 1044 @command('debugwaitonprefetch', [
1039 1045 ], _('hg debugwaitonprefetch'))
1040 1046 def debugwaitonprefetch(ui, repo, **opts):
1041 1047 return debugcommands.debugwaitonprefetch(repo)
1042 1048
1043 1049 def resolveprefetchopts(ui, opts):
1044 1050 if not opts.get('rev'):
1045 1051 revset = ['.', 'draft()']
1046 1052
1047 1053 prefetchrevset = ui.config('remotefilelog', 'pullprefetch', None)
1048 1054 if prefetchrevset:
1049 1055 revset.append('(%s)' % prefetchrevset)
1050 1056 bgprefetchrevs = ui.config('remotefilelog', 'bgprefetchrevs', None)
1051 1057 if bgprefetchrevs:
1052 1058 revset.append('(%s)' % bgprefetchrevs)
1053 1059 revset = '+'.join(revset)
1054 1060
1055 1061 # update a revset with a date limit
1056 1062 revset = revdatelimit(ui, revset)
1057 1063
1058 1064 opts['rev'] = [revset]
1059 1065
1060 1066 if not opts.get('base'):
1061 1067 opts['base'] = None
1062 1068
1063 1069 return opts
1064 1070
1065 1071 @command('prefetch', [
1066 1072 ('r', 'rev', [], _('prefetch the specified revisions'), _('REV')),
1067 1073 ('', 'repack', False, _('run repack after prefetch')),
1068 1074 ('b', 'base', '', _("rev that is assumed to already be local")),
1069 1075 ] + commands.walkopts, _('hg prefetch [OPTIONS] [FILE...]'))
1070 1076 def prefetch(ui, repo, *pats, **opts):
1071 1077 """prefetch file revisions from the server
1072 1078
1073 1079 Prefetchs file revisions for the specified revs and stores them in the
1074 1080 local remotefilelog cache. If no rev is specified, the default rev is
1075 1081 used which is the union of dot, draft, pullprefetch and bgprefetchrev.
1076 1082 File names or patterns can be used to limit which files are downloaded.
1077 1083
1078 1084 Return 0 on success.
1079 1085 """
1080 1086 opts = pycompat.byteskwargs(opts)
1081 1087 if not isenabled(repo):
1082 1088 raise error.Abort(_("repo is not shallow"))
1083 1089
1084 1090 opts = resolveprefetchopts(ui, opts)
1085 1091 revs = scmutil.revrange(repo, opts.get('rev'))
1086 1092 repo.prefetch(revs, opts.get('base'), pats, opts)
1087 1093
1094 ensurestart = repo.ui.configbool('devel', 'remotefilelog.ensurestart')
1095
1088 1096 # Run repack in background
1089 1097 if opts.get('repack'):
1090 repackmod.backgroundrepack(repo, incremental=True)
1098 repackmod.backgroundrepack(repo, incremental=True,
1099 ensurestart=ensurestart)
1091 1100
1092 1101 @command('repack', [
1093 1102 ('', 'background', None, _('run in a background process'), None),
1094 1103 ('', 'incremental', None, _('do an incremental repack'), None),
1095 1104 ('', 'packsonly', None, _('only repack packs (skip loose objects)'), None),
1096 1105 ], _('hg repack [OPTIONS]'))
1097 1106 def repack_(ui, repo, *pats, **opts):
1098 1107 if opts.get(r'background'):
1108 ensurestart = repo.ui.configbool('devel', 'remotefilelog.ensurestart')
1099 1109 repackmod.backgroundrepack(repo, incremental=opts.get(r'incremental'),
1100 packsonly=opts.get(r'packsonly', False))
1110 packsonly=opts.get(r'packsonly', False),
1111 ensurestart=ensurestart)
1101 1112 return
1102 1113
1103 1114 options = {'packsonly': opts.get(r'packsonly')}
1104 1115
1105 1116 try:
1106 1117 if opts.get(r'incremental'):
1107 1118 repackmod.incrementalrepack(repo, options=options)
1108 1119 else:
1109 1120 repackmod.fullrepack(repo, options=options)
1110 1121 except repackmod.RepackAlreadyRunning as ex:
1111 1122 # Don't propogate the exception if the repack is already in
1112 1123 # progress, since we want the command to exit 0.
1113 1124 repo.ui.warn('%s\n' % ex)
@@ -1,778 +1,779
1 1 from __future__ import absolute_import
2 2
3 3 import os
4 4 import time
5 5
6 6 from mercurial.i18n import _
7 7 from mercurial.node import (
8 8 nullid,
9 9 short,
10 10 )
11 11 from mercurial import (
12 12 encoding,
13 13 error,
14 14 mdiff,
15 15 policy,
16 16 pycompat,
17 17 scmutil,
18 18 util,
19 19 vfs,
20 20 )
21 21 from mercurial.utils import procutil
22 22 from . import (
23 23 constants,
24 24 contentstore,
25 25 datapack,
26 26 extutil,
27 27 historypack,
28 28 metadatastore,
29 29 shallowutil,
30 30 )
31 31
32 32 osutil = policy.importmod(r'osutil')
33 33
34 34 class RepackAlreadyRunning(error.Abort):
35 35 pass
36 36
37 def backgroundrepack(repo, incremental=True, packsonly=False):
37 def backgroundrepack(repo, incremental=True, packsonly=False,
38 ensurestart=False):
38 39 cmd = [procutil.hgexecutable(), '-R', repo.origroot, 'repack']
39 40 msg = _("(running background repack)\n")
40 41 if incremental:
41 42 cmd.append('--incremental')
42 43 msg = _("(running background incremental repack)\n")
43 44 if packsonly:
44 45 cmd.append('--packsonly')
45 46 repo.ui.warn(msg)
46 47 # We know this command will find a binary, so don't block on it starting.
47 procutil.runbgcommand(cmd, encoding.environ, ensurestart=False)
48 procutil.runbgcommand(cmd, encoding.environ, ensurestart=ensurestart)
48 49
49 50 def fullrepack(repo, options=None):
50 51 """If ``packsonly`` is True, stores creating only loose objects are skipped.
51 52 """
52 53 if util.safehasattr(repo, 'shareddatastores'):
53 54 datasource = contentstore.unioncontentstore(
54 55 *repo.shareddatastores)
55 56 historysource = metadatastore.unionmetadatastore(
56 57 *repo.sharedhistorystores,
57 58 allowincomplete=True)
58 59
59 60 packpath = shallowutil.getcachepackpath(
60 61 repo,
61 62 constants.FILEPACK_CATEGORY)
62 63 _runrepack(repo, datasource, historysource, packpath,
63 64 constants.FILEPACK_CATEGORY, options=options)
64 65
65 66 if util.safehasattr(repo.manifestlog, 'datastore'):
66 67 localdata, shareddata = _getmanifeststores(repo)
67 68 lpackpath, ldstores, lhstores = localdata
68 69 spackpath, sdstores, shstores = shareddata
69 70
70 71 # Repack the shared manifest store
71 72 datasource = contentstore.unioncontentstore(*sdstores)
72 73 historysource = metadatastore.unionmetadatastore(
73 74 *shstores,
74 75 allowincomplete=True)
75 76 _runrepack(repo, datasource, historysource, spackpath,
76 77 constants.TREEPACK_CATEGORY, options=options)
77 78
78 79 # Repack the local manifest store
79 80 datasource = contentstore.unioncontentstore(
80 81 *ldstores,
81 82 allowincomplete=True)
82 83 historysource = metadatastore.unionmetadatastore(
83 84 *lhstores,
84 85 allowincomplete=True)
85 86 _runrepack(repo, datasource, historysource, lpackpath,
86 87 constants.TREEPACK_CATEGORY, options=options)
87 88
88 89 def incrementalrepack(repo, options=None):
89 90 """This repacks the repo by looking at the distribution of pack files in the
90 91 repo and performing the most minimal repack to keep the repo in good shape.
91 92 """
92 93 if util.safehasattr(repo, 'shareddatastores'):
93 94 packpath = shallowutil.getcachepackpath(
94 95 repo,
95 96 constants.FILEPACK_CATEGORY)
96 97 _incrementalrepack(repo,
97 98 repo.shareddatastores,
98 99 repo.sharedhistorystores,
99 100 packpath,
100 101 constants.FILEPACK_CATEGORY,
101 102 options=options)
102 103
103 104 if util.safehasattr(repo.manifestlog, 'datastore'):
104 105 localdata, shareddata = _getmanifeststores(repo)
105 106 lpackpath, ldstores, lhstores = localdata
106 107 spackpath, sdstores, shstores = shareddata
107 108
108 109 # Repack the shared manifest store
109 110 _incrementalrepack(repo,
110 111 sdstores,
111 112 shstores,
112 113 spackpath,
113 114 constants.TREEPACK_CATEGORY,
114 115 options=options)
115 116
116 117 # Repack the local manifest store
117 118 _incrementalrepack(repo,
118 119 ldstores,
119 120 lhstores,
120 121 lpackpath,
121 122 constants.TREEPACK_CATEGORY,
122 123 allowincompletedata=True,
123 124 options=options)
124 125
125 126 def _getmanifeststores(repo):
126 127 shareddatastores = repo.manifestlog.shareddatastores
127 128 localdatastores = repo.manifestlog.localdatastores
128 129 sharedhistorystores = repo.manifestlog.sharedhistorystores
129 130 localhistorystores = repo.manifestlog.localhistorystores
130 131
131 132 sharedpackpath = shallowutil.getcachepackpath(repo,
132 133 constants.TREEPACK_CATEGORY)
133 134 localpackpath = shallowutil.getlocalpackpath(repo.svfs.vfs.base,
134 135 constants.TREEPACK_CATEGORY)
135 136
136 137 return ((localpackpath, localdatastores, localhistorystores),
137 138 (sharedpackpath, shareddatastores, sharedhistorystores))
138 139
139 140 def _topacks(packpath, files, constructor):
140 141 paths = list(os.path.join(packpath, p) for p in files)
141 142 packs = list(constructor(p) for p in paths)
142 143 return packs
143 144
144 145 def _deletebigpacks(repo, folder, files):
145 146 """Deletes packfiles that are bigger than ``packs.maxpacksize``.
146 147
147 148 Returns ``files` with the removed files omitted."""
148 149 maxsize = repo.ui.configbytes("packs", "maxpacksize")
149 150 if maxsize <= 0:
150 151 return files
151 152
152 153 # This only considers datapacks today, but we could broaden it to include
153 154 # historypacks.
154 155 VALIDEXTS = [".datapack", ".dataidx"]
155 156
156 157 # Either an oversize index or datapack will trigger cleanup of the whole
157 158 # pack:
158 159 oversized = {os.path.splitext(path)[0] for path, ftype, stat in files
159 160 if (stat.st_size > maxsize and (os.path.splitext(path)[1]
160 161 in VALIDEXTS))}
161 162
162 163 for rootfname in oversized:
163 164 rootpath = os.path.join(folder, rootfname)
164 165 for ext in VALIDEXTS:
165 166 path = rootpath + ext
166 167 repo.ui.debug('removing oversize packfile %s (%s)\n' %
167 168 (path, util.bytecount(os.stat(path).st_size)))
168 169 os.unlink(path)
169 170 return [row for row in files if os.path.basename(row[0]) not in oversized]
170 171
171 172 def _incrementalrepack(repo, datastore, historystore, packpath, category,
172 173 allowincompletedata=False, options=None):
173 174 shallowutil.mkstickygroupdir(repo.ui, packpath)
174 175
175 176 files = osutil.listdir(packpath, stat=True)
176 177 files = _deletebigpacks(repo, packpath, files)
177 178 datapacks = _topacks(packpath,
178 179 _computeincrementaldatapack(repo.ui, files),
179 180 datapack.datapack)
180 181 datapacks.extend(s for s in datastore
181 182 if not isinstance(s, datapack.datapackstore))
182 183
183 184 historypacks = _topacks(packpath,
184 185 _computeincrementalhistorypack(repo.ui, files),
185 186 historypack.historypack)
186 187 historypacks.extend(s for s in historystore
187 188 if not isinstance(s, historypack.historypackstore))
188 189
189 190 # ``allhistory{files,packs}`` contains all known history packs, even ones we
190 191 # don't plan to repack. They are used during the datapack repack to ensure
191 192 # good ordering of nodes.
192 193 allhistoryfiles = _allpackfileswithsuffix(files, historypack.PACKSUFFIX,
193 194 historypack.INDEXSUFFIX)
194 195 allhistorypacks = _topacks(packpath,
195 196 (f for f, mode, stat in allhistoryfiles),
196 197 historypack.historypack)
197 198 allhistorypacks.extend(s for s in historystore
198 199 if not isinstance(s, historypack.historypackstore))
199 200 _runrepack(repo,
200 201 contentstore.unioncontentstore(
201 202 *datapacks,
202 203 allowincomplete=allowincompletedata),
203 204 metadatastore.unionmetadatastore(
204 205 *historypacks,
205 206 allowincomplete=True),
206 207 packpath, category,
207 208 fullhistory=metadatastore.unionmetadatastore(
208 209 *allhistorypacks,
209 210 allowincomplete=True),
210 211 options=options)
211 212
212 213 def _computeincrementaldatapack(ui, files):
213 214 opts = {
214 215 'gencountlimit' : ui.configint(
215 216 'remotefilelog', 'data.gencountlimit'),
216 217 'generations' : ui.configlist(
217 218 'remotefilelog', 'data.generations'),
218 219 'maxrepackpacks' : ui.configint(
219 220 'remotefilelog', 'data.maxrepackpacks'),
220 221 'repackmaxpacksize' : ui.configbytes(
221 222 'remotefilelog', 'data.repackmaxpacksize'),
222 223 'repacksizelimit' : ui.configbytes(
223 224 'remotefilelog', 'data.repacksizelimit'),
224 225 }
225 226
226 227 packfiles = _allpackfileswithsuffix(
227 228 files, datapack.PACKSUFFIX, datapack.INDEXSUFFIX)
228 229 return _computeincrementalpack(packfiles, opts)
229 230
230 231 def _computeincrementalhistorypack(ui, files):
231 232 opts = {
232 233 'gencountlimit' : ui.configint(
233 234 'remotefilelog', 'history.gencountlimit'),
234 235 'generations' : ui.configlist(
235 236 'remotefilelog', 'history.generations', ['100MB']),
236 237 'maxrepackpacks' : ui.configint(
237 238 'remotefilelog', 'history.maxrepackpacks'),
238 239 'repackmaxpacksize' : ui.configbytes(
239 240 'remotefilelog', 'history.repackmaxpacksize', '400MB'),
240 241 'repacksizelimit' : ui.configbytes(
241 242 'remotefilelog', 'history.repacksizelimit'),
242 243 }
243 244
244 245 packfiles = _allpackfileswithsuffix(
245 246 files, historypack.PACKSUFFIX, historypack.INDEXSUFFIX)
246 247 return _computeincrementalpack(packfiles, opts)
247 248
248 249 def _allpackfileswithsuffix(files, packsuffix, indexsuffix):
249 250 result = []
250 251 fileset = set(fn for fn, mode, stat in files)
251 252 for filename, mode, stat in files:
252 253 if not filename.endswith(packsuffix):
253 254 continue
254 255
255 256 prefix = filename[:-len(packsuffix)]
256 257
257 258 # Don't process a pack if it doesn't have an index.
258 259 if (prefix + indexsuffix) not in fileset:
259 260 continue
260 261 result.append((prefix, mode, stat))
261 262
262 263 return result
263 264
264 265 def _computeincrementalpack(files, opts):
265 266 """Given a set of pack files along with the configuration options, this
266 267 function computes the list of files that should be packed as part of an
267 268 incremental repack.
268 269
269 270 It tries to strike a balance between keeping incremental repacks cheap (i.e.
270 271 packing small things when possible, and rolling the packs up to the big ones
271 272 over time).
272 273 """
273 274
274 275 limits = list(sorted((util.sizetoint(s) for s in opts['generations']),
275 276 reverse=True))
276 277 limits.append(0)
277 278
278 279 # Group the packs by generation (i.e. by size)
279 280 generations = []
280 281 for i in pycompat.xrange(len(limits)):
281 282 generations.append([])
282 283
283 284 sizes = {}
284 285 for prefix, mode, stat in files:
285 286 size = stat.st_size
286 287 if size > opts['repackmaxpacksize']:
287 288 continue
288 289
289 290 sizes[prefix] = size
290 291 for i, limit in enumerate(limits):
291 292 if size > limit:
292 293 generations[i].append(prefix)
293 294 break
294 295
295 296 # Steps for picking what packs to repack:
296 297 # 1. Pick the largest generation with > gencountlimit pack files.
297 298 # 2. Take the smallest three packs.
298 299 # 3. While total-size-of-packs < repacksizelimit: add another pack
299 300
300 301 # Find the largest generation with more than gencountlimit packs
301 302 genpacks = []
302 303 for i, limit in enumerate(limits):
303 304 if len(generations[i]) > opts['gencountlimit']:
304 305 # Sort to be smallest last, for easy popping later
305 306 genpacks.extend(sorted(generations[i], reverse=True,
306 307 key=lambda x: sizes[x]))
307 308 break
308 309
309 310 # Take as many packs from the generation as we can
310 311 chosenpacks = genpacks[-3:]
311 312 genpacks = genpacks[:-3]
312 313 repacksize = sum(sizes[n] for n in chosenpacks)
313 314 while (repacksize < opts['repacksizelimit'] and genpacks and
314 315 len(chosenpacks) < opts['maxrepackpacks']):
315 316 chosenpacks.append(genpacks.pop())
316 317 repacksize += sizes[chosenpacks[-1]]
317 318
318 319 return chosenpacks
319 320
320 321 def _runrepack(repo, data, history, packpath, category, fullhistory=None,
321 322 options=None):
322 323 shallowutil.mkstickygroupdir(repo.ui, packpath)
323 324
324 325 def isold(repo, filename, node):
325 326 """Check if the file node is older than a limit.
326 327 Unless a limit is specified in the config the default limit is taken.
327 328 """
328 329 filectx = repo.filectx(filename, fileid=node)
329 330 filetime = repo[filectx.linkrev()].date()
330 331
331 332 ttl = repo.ui.configint('remotefilelog', 'nodettl')
332 333
333 334 limit = time.time() - ttl
334 335 return filetime[0] < limit
335 336
336 337 garbagecollect = repo.ui.configbool('remotefilelog', 'gcrepack')
337 338 if not fullhistory:
338 339 fullhistory = history
339 340 packer = repacker(repo, data, history, fullhistory, category,
340 341 gc=garbagecollect, isold=isold, options=options)
341 342
342 343 with datapack.mutabledatapack(repo.ui, packpath) as dpack:
343 344 with historypack.mutablehistorypack(repo.ui, packpath) as hpack:
344 345 try:
345 346 packer.run(dpack, hpack)
346 347 except error.LockHeld:
347 348 raise RepackAlreadyRunning(_("skipping repack - another repack "
348 349 "is already running"))
349 350
350 351 def keepset(repo, keyfn, lastkeepkeys=None):
351 352 """Computes a keepset which is not garbage collected.
352 353 'keyfn' is a function that maps filename, node to a unique key.
353 354 'lastkeepkeys' is an optional argument and if provided the keepset
354 355 function updates lastkeepkeys with more keys and returns the result.
355 356 """
356 357 if not lastkeepkeys:
357 358 keepkeys = set()
358 359 else:
359 360 keepkeys = lastkeepkeys
360 361
361 362 # We want to keep:
362 363 # 1. Working copy parent
363 364 # 2. Draft commits
364 365 # 3. Parents of draft commits
365 366 # 4. Pullprefetch and bgprefetchrevs revsets if specified
366 367 revs = ['.', 'draft()', 'parents(draft())']
367 368 prefetchrevs = repo.ui.config('remotefilelog', 'pullprefetch', None)
368 369 if prefetchrevs:
369 370 revs.append('(%s)' % prefetchrevs)
370 371 prefetchrevs = repo.ui.config('remotefilelog', 'bgprefetchrevs', None)
371 372 if prefetchrevs:
372 373 revs.append('(%s)' % prefetchrevs)
373 374 revs = '+'.join(revs)
374 375
375 376 revs = ['sort((%s), "topo")' % revs]
376 377 keep = scmutil.revrange(repo, revs)
377 378
378 379 processed = set()
379 380 lastmanifest = None
380 381
381 382 # process the commits in toposorted order starting from the oldest
382 383 for r in reversed(keep._list):
383 384 if repo[r].p1().rev() in processed:
384 385 # if the direct parent has already been processed
385 386 # then we only need to process the delta
386 387 m = repo[r].manifestctx().readdelta()
387 388 else:
388 389 # otherwise take the manifest and diff it
389 390 # with the previous manifest if one exists
390 391 if lastmanifest:
391 392 m = repo[r].manifest().diff(lastmanifest)
392 393 else:
393 394 m = repo[r].manifest()
394 395 lastmanifest = repo[r].manifest()
395 396 processed.add(r)
396 397
397 398 # populate keepkeys with keys from the current manifest
398 399 if type(m) is dict:
399 400 # m is a result of diff of two manifests and is a dictionary that
400 401 # maps filename to ((newnode, newflag), (oldnode, oldflag)) tuple
401 402 for filename, diff in m.iteritems():
402 403 if diff[0][0] is not None:
403 404 keepkeys.add(keyfn(filename, diff[0][0]))
404 405 else:
405 406 # m is a manifest object
406 407 for filename, filenode in m.iteritems():
407 408 keepkeys.add(keyfn(filename, filenode))
408 409
409 410 return keepkeys
410 411
411 412 class repacker(object):
412 413 """Class for orchestrating the repack of data and history information into a
413 414 new format.
414 415 """
415 416 def __init__(self, repo, data, history, fullhistory, category, gc=False,
416 417 isold=None, options=None):
417 418 self.repo = repo
418 419 self.data = data
419 420 self.history = history
420 421 self.fullhistory = fullhistory
421 422 self.unit = constants.getunits(category)
422 423 self.garbagecollect = gc
423 424 self.options = options
424 425 if self.garbagecollect:
425 426 if not isold:
426 427 raise ValueError("Function 'isold' is not properly specified")
427 428 # use (filename, node) tuple as a keepset key
428 429 self.keepkeys = keepset(repo, lambda f, n : (f, n))
429 430 self.isold = isold
430 431
431 432 def run(self, targetdata, targethistory):
432 433 ledger = repackledger()
433 434
434 435 with extutil.flock(repacklockvfs(self.repo).join("repacklock"),
435 436 _('repacking %s') % self.repo.origroot, timeout=0):
436 437 self.repo.hook('prerepack')
437 438
438 439 # Populate ledger from source
439 440 self.data.markledger(ledger, options=self.options)
440 441 self.history.markledger(ledger, options=self.options)
441 442
442 443 # Run repack
443 444 self.repackdata(ledger, targetdata)
444 445 self.repackhistory(ledger, targethistory)
445 446
446 447 # Call cleanup on each source
447 448 for source in ledger.sources:
448 449 source.cleanup(ledger)
449 450
450 451 def _chainorphans(self, ui, filename, nodes, orphans, deltabases):
451 452 """Reorderes ``orphans`` into a single chain inside ``nodes`` and
452 453 ``deltabases``.
453 454
454 455 We often have orphan entries (nodes without a base that aren't
455 456 referenced by other nodes -- i.e., part of a chain) due to gaps in
456 457 history. Rather than store them as individual fulltexts, we prefer to
457 458 insert them as one chain sorted by size.
458 459 """
459 460 if not orphans:
460 461 return nodes
461 462
462 463 def getsize(node, default=0):
463 464 meta = self.data.getmeta(filename, node)
464 465 if constants.METAKEYSIZE in meta:
465 466 return meta[constants.METAKEYSIZE]
466 467 else:
467 468 return default
468 469
469 470 # Sort orphans by size; biggest first is preferred, since it's more
470 471 # likely to be the newest version assuming files grow over time.
471 472 # (Sort by node first to ensure the sort is stable.)
472 473 orphans = sorted(orphans)
473 474 orphans = list(sorted(orphans, key=getsize, reverse=True))
474 475 if ui.debugflag:
475 476 ui.debug("%s: orphan chain: %s\n" % (filename,
476 477 ", ".join([short(s) for s in orphans])))
477 478
478 479 # Create one contiguous chain and reassign deltabases.
479 480 for i, node in enumerate(orphans):
480 481 if i == 0:
481 482 deltabases[node] = (nullid, 0)
482 483 else:
483 484 parent = orphans[i - 1]
484 485 deltabases[node] = (parent, deltabases[parent][1] + 1)
485 486 nodes = [n for n in nodes if n not in orphans]
486 487 nodes += orphans
487 488 return nodes
488 489
489 490 def repackdata(self, ledger, target):
490 491 ui = self.repo.ui
491 492 maxchainlen = ui.configint('packs', 'maxchainlen', 1000)
492 493
493 494 byfile = {}
494 495 for entry in ledger.entries.itervalues():
495 496 if entry.datasource:
496 497 byfile.setdefault(entry.filename, {})[entry.node] = entry
497 498
498 499 count = 0
499 500 repackprogress = ui.makeprogress(_("repacking data"), unit=self.unit,
500 501 total=len(byfile))
501 502 for filename, entries in sorted(byfile.iteritems()):
502 503 repackprogress.update(count)
503 504
504 505 ancestors = {}
505 506 nodes = list(node for node in entries)
506 507 nohistory = []
507 508 buildprogress = ui.makeprogress(_("building history"), unit='nodes',
508 509 total=len(nodes))
509 510 for i, node in enumerate(nodes):
510 511 if node in ancestors:
511 512 continue
512 513 buildprogress.update(i)
513 514 try:
514 515 ancestors.update(self.fullhistory.getancestors(filename,
515 516 node, known=ancestors))
516 517 except KeyError:
517 518 # Since we're packing data entries, we may not have the
518 519 # corresponding history entries for them. It's not a big
519 520 # deal, but the entries won't be delta'd perfectly.
520 521 nohistory.append(node)
521 522 buildprogress.complete()
522 523
523 524 # Order the nodes children first, so we can produce reverse deltas
524 525 orderednodes = list(reversed(self._toposort(ancestors)))
525 526 if len(nohistory) > 0:
526 527 ui.debug('repackdata: %d nodes without history\n' %
527 528 len(nohistory))
528 529 orderednodes.extend(sorted(nohistory))
529 530
530 531 # Filter orderednodes to just the nodes we want to serialize (it
531 532 # currently also has the edge nodes' ancestors).
532 533 orderednodes = list(filter(lambda node: node in nodes,
533 534 orderednodes))
534 535
535 536 # Garbage collect old nodes:
536 537 if self.garbagecollect:
537 538 neworderednodes = []
538 539 for node in orderednodes:
539 540 # If the node is old and is not in the keepset, we skip it,
540 541 # and mark as garbage collected
541 542 if ((filename, node) not in self.keepkeys and
542 543 self.isold(self.repo, filename, node)):
543 544 entries[node].gced = True
544 545 continue
545 546 neworderednodes.append(node)
546 547 orderednodes = neworderednodes
547 548
548 549 # Compute delta bases for nodes:
549 550 deltabases = {}
550 551 nobase = set()
551 552 referenced = set()
552 553 nodes = set(nodes)
553 554 processprogress = ui.makeprogress(_("processing nodes"),
554 555 unit='nodes',
555 556 total=len(orderednodes))
556 557 for i, node in enumerate(orderednodes):
557 558 processprogress.update(i)
558 559 # Find delta base
559 560 # TODO: allow delta'ing against most recent descendant instead
560 561 # of immediate child
561 562 deltatuple = deltabases.get(node, None)
562 563 if deltatuple is None:
563 564 deltabase, chainlen = nullid, 0
564 565 deltabases[node] = (nullid, 0)
565 566 nobase.add(node)
566 567 else:
567 568 deltabase, chainlen = deltatuple
568 569 referenced.add(deltabase)
569 570
570 571 # Use available ancestor information to inform our delta choices
571 572 ancestorinfo = ancestors.get(node)
572 573 if ancestorinfo:
573 574 p1, p2, linknode, copyfrom = ancestorinfo
574 575
575 576 # The presence of copyfrom means we're at a point where the
576 577 # file was copied from elsewhere. So don't attempt to do any
577 578 # deltas with the other file.
578 579 if copyfrom:
579 580 p1 = nullid
580 581
581 582 if chainlen < maxchainlen:
582 583 # Record this child as the delta base for its parents.
583 584 # This may be non optimal, since the parents may have
584 585 # many children, and this will only choose the last one.
585 586 # TODO: record all children and try all deltas to find
586 587 # best
587 588 if p1 != nullid:
588 589 deltabases[p1] = (node, chainlen + 1)
589 590 if p2 != nullid:
590 591 deltabases[p2] = (node, chainlen + 1)
591 592
592 593 # experimental config: repack.chainorphansbysize
593 594 if ui.configbool('repack', 'chainorphansbysize'):
594 595 orphans = nobase - referenced
595 596 orderednodes = self._chainorphans(ui, filename, orderednodes,
596 597 orphans, deltabases)
597 598
598 599 # Compute deltas and write to the pack
599 600 for i, node in enumerate(orderednodes):
600 601 deltabase, chainlen = deltabases[node]
601 602 # Compute delta
602 603 # TODO: Optimize the deltachain fetching. Since we're
603 604 # iterating over the different version of the file, we may
604 605 # be fetching the same deltachain over and over again.
605 606 if deltabase != nullid:
606 607 deltaentry = self.data.getdelta(filename, node)
607 608 delta, deltabasename, origdeltabase, meta = deltaentry
608 609 size = meta.get(constants.METAKEYSIZE)
609 610 if (deltabasename != filename or origdeltabase != deltabase
610 611 or size is None):
611 612 deltabasetext = self.data.get(filename, deltabase)
612 613 original = self.data.get(filename, node)
613 614 size = len(original)
614 615 delta = mdiff.textdiff(deltabasetext, original)
615 616 else:
616 617 delta = self.data.get(filename, node)
617 618 size = len(delta)
618 619 meta = self.data.getmeta(filename, node)
619 620
620 621 # TODO: don't use the delta if it's larger than the fulltext
621 622 if constants.METAKEYSIZE not in meta:
622 623 meta[constants.METAKEYSIZE] = size
623 624 target.add(filename, node, deltabase, delta, meta)
624 625
625 626 entries[node].datarepacked = True
626 627
627 628 processprogress.complete()
628 629 count += 1
629 630
630 631 repackprogress.complete()
631 632 target.close(ledger=ledger)
632 633
633 634 def repackhistory(self, ledger, target):
634 635 ui = self.repo.ui
635 636
636 637 byfile = {}
637 638 for entry in ledger.entries.itervalues():
638 639 if entry.historysource:
639 640 byfile.setdefault(entry.filename, {})[entry.node] = entry
640 641
641 642 progress = ui.makeprogress(_("repacking history"), unit=self.unit,
642 643 total=len(byfile))
643 644 for filename, entries in sorted(byfile.iteritems()):
644 645 ancestors = {}
645 646 nodes = list(node for node in entries)
646 647
647 648 for node in nodes:
648 649 if node in ancestors:
649 650 continue
650 651 ancestors.update(self.history.getancestors(filename, node,
651 652 known=ancestors))
652 653
653 654 # Order the nodes children first
654 655 orderednodes = reversed(self._toposort(ancestors))
655 656
656 657 # Write to the pack
657 658 dontprocess = set()
658 659 for node in orderednodes:
659 660 p1, p2, linknode, copyfrom = ancestors[node]
660 661
661 662 # If the node is marked dontprocess, but it's also in the
662 663 # explicit entries set, that means the node exists both in this
663 664 # file and in another file that was copied to this file.
664 665 # Usually this happens if the file was copied to another file,
665 666 # then the copy was deleted, then reintroduced without copy
666 667 # metadata. The original add and the new add have the same hash
667 668 # since the content is identical and the parents are null.
668 669 if node in dontprocess and node not in entries:
669 670 # If copyfrom == filename, it means the copy history
670 671 # went to come other file, then came back to this one, so we
671 672 # should continue processing it.
672 673 if p1 != nullid and copyfrom != filename:
673 674 dontprocess.add(p1)
674 675 if p2 != nullid:
675 676 dontprocess.add(p2)
676 677 continue
677 678
678 679 if copyfrom:
679 680 dontprocess.add(p1)
680 681
681 682 target.add(filename, node, p1, p2, linknode, copyfrom)
682 683
683 684 if node in entries:
684 685 entries[node].historyrepacked = True
685 686
686 687 progress.increment()
687 688
688 689 progress.complete()
689 690 target.close(ledger=ledger)
690 691
691 692 def _toposort(self, ancestors):
692 693 def parentfunc(node):
693 694 p1, p2, linknode, copyfrom = ancestors[node]
694 695 parents = []
695 696 if p1 != nullid:
696 697 parents.append(p1)
697 698 if p2 != nullid:
698 699 parents.append(p2)
699 700 return parents
700 701
701 702 sortednodes = shallowutil.sortnodes(ancestors.keys(), parentfunc)
702 703 return sortednodes
703 704
704 705 class repackledger(object):
705 706 """Storage for all the bookkeeping that happens during a repack. It contains
706 707 the list of revisions being repacked, what happened to each revision, and
707 708 which source store contained which revision originally (for later cleanup).
708 709 """
709 710 def __init__(self):
710 711 self.entries = {}
711 712 self.sources = {}
712 713 self.created = set()
713 714
714 715 def markdataentry(self, source, filename, node):
715 716 """Mark the given filename+node revision as having a data rev in the
716 717 given source.
717 718 """
718 719 entry = self._getorcreateentry(filename, node)
719 720 entry.datasource = True
720 721 entries = self.sources.get(source)
721 722 if not entries:
722 723 entries = set()
723 724 self.sources[source] = entries
724 725 entries.add(entry)
725 726
726 727 def markhistoryentry(self, source, filename, node):
727 728 """Mark the given filename+node revision as having a history rev in the
728 729 given source.
729 730 """
730 731 entry = self._getorcreateentry(filename, node)
731 732 entry.historysource = True
732 733 entries = self.sources.get(source)
733 734 if not entries:
734 735 entries = set()
735 736 self.sources[source] = entries
736 737 entries.add(entry)
737 738
738 739 def _getorcreateentry(self, filename, node):
739 740 key = (filename, node)
740 741 value = self.entries.get(key)
741 742 if not value:
742 743 value = repackentry(filename, node)
743 744 self.entries[key] = value
744 745
745 746 return value
746 747
747 748 def addcreated(self, value):
748 749 self.created.add(value)
749 750
750 751 class repackentry(object):
751 752 """Simple class representing a single revision entry in the repackledger.
752 753 """
753 754 __slots__ = (r'filename', r'node', r'datasource', r'historysource',
754 755 r'datarepacked', r'historyrepacked', r'gced')
755 756 def __init__(self, filename, node):
756 757 self.filename = filename
757 758 self.node = node
758 759 # If the revision has a data entry in the source
759 760 self.datasource = False
760 761 # If the revision has a history entry in the source
761 762 self.historysource = False
762 763 # If the revision's data entry was repacked into the repack target
763 764 self.datarepacked = False
764 765 # If the revision's history entry was repacked into the repack target
765 766 self.historyrepacked = False
766 767 # If garbage collected
767 768 self.gced = False
768 769
769 770 def repacklockvfs(repo):
770 771 if util.safehasattr(repo, 'name'):
771 772 # Lock in the shared cache so repacks across multiple copies of the same
772 773 # repo are coordinated.
773 774 sharedcachepath = shallowutil.getcachepackpath(
774 775 repo,
775 776 constants.FILEPACK_CATEGORY)
776 777 return vfs.vfs(sharedcachepath)
777 778 else:
778 779 return repo.svfs
@@ -1,301 +1,302
1 1 # shallowrepo.py - shallow repository that uses remote filelogs
2 2 #
3 3 # Copyright 2013 Facebook, Inc.
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7 from __future__ import absolute_import
8 8
9 9 import os
10 10
11 11 from mercurial.i18n import _
12 12 from mercurial.node import hex, nullid, nullrev
13 13 from mercurial import (
14 14 encoding,
15 15 error,
16 16 localrepo,
17 17 match,
18 18 scmutil,
19 19 sparse,
20 20 util,
21 21 )
22 22 from mercurial.utils import procutil
23 23 from . import (
24 24 connectionpool,
25 25 constants,
26 26 contentstore,
27 27 datapack,
28 28 fileserverclient,
29 29 historypack,
30 30 metadatastore,
31 31 remotefilectx,
32 32 remotefilelog,
33 33 shallowutil,
34 34 )
35 35
36 36 # These make*stores functions are global so that other extensions can replace
37 37 # them.
38 38 def makelocalstores(repo):
39 39 """In-repo stores, like .hg/store/data; can not be discarded."""
40 40 localpath = os.path.join(repo.svfs.vfs.base, 'data')
41 41 if not os.path.exists(localpath):
42 42 os.makedirs(localpath)
43 43
44 44 # Instantiate local data stores
45 45 localcontent = contentstore.remotefilelogcontentstore(
46 46 repo, localpath, repo.name, shared=False)
47 47 localmetadata = metadatastore.remotefilelogmetadatastore(
48 48 repo, localpath, repo.name, shared=False)
49 49 return localcontent, localmetadata
50 50
51 51 def makecachestores(repo):
52 52 """Typically machine-wide, cache of remote data; can be discarded."""
53 53 # Instantiate shared cache stores
54 54 cachepath = shallowutil.getcachepath(repo.ui)
55 55 cachecontent = contentstore.remotefilelogcontentstore(
56 56 repo, cachepath, repo.name, shared=True)
57 57 cachemetadata = metadatastore.remotefilelogmetadatastore(
58 58 repo, cachepath, repo.name, shared=True)
59 59
60 60 repo.sharedstore = cachecontent
61 61 repo.shareddatastores.append(cachecontent)
62 62 repo.sharedhistorystores.append(cachemetadata)
63 63
64 64 return cachecontent, cachemetadata
65 65
66 66 def makeremotestores(repo, cachecontent, cachemetadata):
67 67 """These stores fetch data from a remote server."""
68 68 # Instantiate remote stores
69 69 repo.fileservice = fileserverclient.fileserverclient(repo)
70 70 remotecontent = contentstore.remotecontentstore(
71 71 repo.ui, repo.fileservice, cachecontent)
72 72 remotemetadata = metadatastore.remotemetadatastore(
73 73 repo.ui, repo.fileservice, cachemetadata)
74 74 return remotecontent, remotemetadata
75 75
76 76 def makepackstores(repo):
77 77 """Packs are more efficient (to read from) cache stores."""
78 78 # Instantiate pack stores
79 79 packpath = shallowutil.getcachepackpath(repo,
80 80 constants.FILEPACK_CATEGORY)
81 81 packcontentstore = datapack.datapackstore(repo.ui, packpath)
82 82 packmetadatastore = historypack.historypackstore(repo.ui, packpath)
83 83
84 84 repo.shareddatastores.append(packcontentstore)
85 85 repo.sharedhistorystores.append(packmetadatastore)
86 86 shallowutil.reportpackmetrics(repo.ui, 'filestore', packcontentstore,
87 87 packmetadatastore)
88 88 return packcontentstore, packmetadatastore
89 89
90 90 def makeunionstores(repo):
91 91 """Union stores iterate the other stores and return the first result."""
92 92 repo.shareddatastores = []
93 93 repo.sharedhistorystores = []
94 94
95 95 packcontentstore, packmetadatastore = makepackstores(repo)
96 96 cachecontent, cachemetadata = makecachestores(repo)
97 97 localcontent, localmetadata = makelocalstores(repo)
98 98 remotecontent, remotemetadata = makeremotestores(repo, cachecontent,
99 99 cachemetadata)
100 100
101 101 # Instantiate union stores
102 102 repo.contentstore = contentstore.unioncontentstore(
103 103 packcontentstore, cachecontent,
104 104 localcontent, remotecontent, writestore=localcontent)
105 105 repo.metadatastore = metadatastore.unionmetadatastore(
106 106 packmetadatastore, cachemetadata, localmetadata, remotemetadata,
107 107 writestore=localmetadata)
108 108
109 109 fileservicedatawrite = cachecontent
110 110 fileservicehistorywrite = cachemetadata
111 111 repo.fileservice.setstore(repo.contentstore, repo.metadatastore,
112 112 fileservicedatawrite, fileservicehistorywrite)
113 113 shallowutil.reportpackmetrics(repo.ui, 'filestore',
114 114 packcontentstore, packmetadatastore)
115 115
116 116 def wraprepo(repo):
117 117 class shallowrepository(repo.__class__):
118 118 @util.propertycache
119 119 def name(self):
120 120 return self.ui.config('remotefilelog', 'reponame')
121 121
122 122 @util.propertycache
123 123 def fallbackpath(self):
124 124 path = repo.ui.config("remotefilelog", "fallbackpath",
125 125 repo.ui.config('paths', 'default'))
126 126 if not path:
127 127 raise error.Abort("no remotefilelog server "
128 128 "configured - is your .hg/hgrc trusted?")
129 129
130 130 return path
131 131
132 132 def maybesparsematch(self, *revs, **kwargs):
133 133 '''
134 134 A wrapper that allows the remotefilelog to invoke sparsematch() if
135 135 this is a sparse repository, or returns None if this is not a
136 136 sparse repository.
137 137 '''
138 138 if revs:
139 139 ret = sparse.matcher(repo, revs=revs)
140 140 else:
141 141 ret = sparse.matcher(repo)
142 142
143 143 if ret.always():
144 144 return None
145 145 return ret
146 146
147 147 def file(self, f):
148 148 if f[0] == '/':
149 149 f = f[1:]
150 150
151 151 if self.shallowmatch(f):
152 152 return remotefilelog.remotefilelog(self.svfs, f, self)
153 153 else:
154 154 return super(shallowrepository, self).file(f)
155 155
156 156 def filectx(self, path, *args, **kwargs):
157 157 if self.shallowmatch(path):
158 158 return remotefilectx.remotefilectx(self, path, *args, **kwargs)
159 159 else:
160 160 return super(shallowrepository, self).filectx(path, *args,
161 161 **kwargs)
162 162
163 163 @localrepo.unfilteredmethod
164 164 def commitctx(self, ctx, error=False, origctx=None):
165 165 """Add a new revision to current repository.
166 166 Revision information is passed via the context argument.
167 167 """
168 168
169 169 # some contexts already have manifest nodes, they don't need any
170 170 # prefetching (for example if we're just editing a commit message
171 171 # we can reuse manifest
172 172 if not ctx.manifestnode():
173 173 # prefetch files that will likely be compared
174 174 m1 = ctx.p1().manifest()
175 175 files = []
176 176 for f in ctx.modified() + ctx.added():
177 177 fparent1 = m1.get(f, nullid)
178 178 if fparent1 != nullid:
179 179 files.append((f, hex(fparent1)))
180 180 self.fileservice.prefetch(files)
181 181 return super(shallowrepository, self).commitctx(ctx,
182 182 error=error,
183 183 origctx=origctx)
184 184
185 185 def backgroundprefetch(self, revs, base=None, repack=False, pats=None,
186 opts=None):
186 opts=None, ensurestart=False):
187 187 """Runs prefetch in background with optional repack
188 188 """
189 189 cmd = [procutil.hgexecutable(), '-R', repo.origroot, 'prefetch']
190 190 if repack:
191 191 cmd.append('--repack')
192 192 if revs:
193 193 cmd += ['-r', revs]
194 194 # We know this command will find a binary, so don't block
195 195 # on it starting.
196 procutil.runbgcommand(cmd, encoding.environ, ensurestart=False)
196 procutil.runbgcommand(cmd, encoding.environ,
197 ensurestart=ensurestart)
197 198
198 199 def prefetch(self, revs, base=None, pats=None, opts=None):
199 200 """Prefetches all the necessary file revisions for the given revs
200 201 Optionally runs repack in background
201 202 """
202 203 with repo._lock(repo.svfs, 'prefetchlock', True, None, None,
203 204 _('prefetching in %s') % repo.origroot):
204 205 self._prefetch(revs, base, pats, opts)
205 206
206 207 def _prefetch(self, revs, base=None, pats=None, opts=None):
207 208 fallbackpath = self.fallbackpath
208 209 if fallbackpath:
209 210 # If we know a rev is on the server, we should fetch the server
210 211 # version of those files, since our local file versions might
211 212 # become obsolete if the local commits are stripped.
212 213 localrevs = repo.revs('outgoing(%s)', fallbackpath)
213 214 if base is not None and base != nullrev:
214 215 serverbase = list(repo.revs('first(reverse(::%s) - %ld)',
215 216 base, localrevs))
216 217 if serverbase:
217 218 base = serverbase[0]
218 219 else:
219 220 localrevs = repo
220 221
221 222 mfl = repo.manifestlog
222 223 mfrevlog = mfl.getstorage('')
223 224 if base is not None:
224 225 mfdict = mfl[repo[base].manifestnode()].read()
225 226 skip = set(mfdict.iteritems())
226 227 else:
227 228 skip = set()
228 229
229 230 # Copy the skip set to start large and avoid constant resizing,
230 231 # and since it's likely to be very similar to the prefetch set.
231 232 files = skip.copy()
232 233 serverfiles = skip.copy()
233 234 visited = set()
234 235 visited.add(nullrev)
235 236 revcount = len(revs)
236 237 progress = self.ui.makeprogress(_('prefetching'), total=revcount)
237 238 progress.update(0)
238 239 for rev in sorted(revs):
239 240 ctx = repo[rev]
240 241 if pats:
241 242 m = scmutil.match(ctx, pats, opts)
242 243 sparsematch = repo.maybesparsematch(rev)
243 244
244 245 mfnode = ctx.manifestnode()
245 246 mfrev = mfrevlog.rev(mfnode)
246 247
247 248 # Decompressing manifests is expensive.
248 249 # When possible, only read the deltas.
249 250 p1, p2 = mfrevlog.parentrevs(mfrev)
250 251 if p1 in visited and p2 in visited:
251 252 mfdict = mfl[mfnode].readfast()
252 253 else:
253 254 mfdict = mfl[mfnode].read()
254 255
255 256 diff = mfdict.iteritems()
256 257 if pats:
257 258 diff = (pf for pf in diff if m(pf[0]))
258 259 if sparsematch:
259 260 diff = (pf for pf in diff if sparsematch(pf[0]))
260 261 if rev not in localrevs:
261 262 serverfiles.update(diff)
262 263 else:
263 264 files.update(diff)
264 265
265 266 visited.add(mfrev)
266 267 progress.increment()
267 268
268 269 files.difference_update(skip)
269 270 serverfiles.difference_update(skip)
270 271 progress.complete()
271 272
272 273 # Fetch files known to be on the server
273 274 if serverfiles:
274 275 results = [(path, hex(fnode)) for (path, fnode) in serverfiles]
275 276 repo.fileservice.prefetch(results, force=True)
276 277
277 278 # Fetch files that may or may not be on the server
278 279 if files:
279 280 results = [(path, hex(fnode)) for (path, fnode) in files]
280 281 repo.fileservice.prefetch(results)
281 282
282 283 def close(self):
283 284 super(shallowrepository, self).close()
284 285 self.connectionpool.close()
285 286
286 287 repo.__class__ = shallowrepository
287 288
288 289 repo.shallowmatch = match.always()
289 290
290 291 makeunionstores(repo)
291 292
292 293 repo.includepattern = repo.ui.configlist("remotefilelog", "includepattern",
293 294 None)
294 295 repo.excludepattern = repo.ui.configlist("remotefilelog", "excludepattern",
295 296 None)
296 297 if not util.safehasattr(repo, 'connectionpool'):
297 298 repo.connectionpool = connectionpool.connectionpool(repo)
298 299
299 300 if repo.includepattern or repo.excludepattern:
300 301 repo.shallowmatch = match.match(repo.root, '', None,
301 302 repo.includepattern, repo.excludepattern)
@@ -1,375 +1,381
1 1 #require no-windows
2 2
3 3 $ . "$TESTDIR/remotefilelog-library.sh"
4 # devel.remotefilelog.ensurestart: reduce race condition with
5 # waiton{repack/prefetch}
6 $ cat >> $HGRCPATH <<EOF
7 > [devel]
8 > remotefilelog.ensurestart=True
9 > EOF
4 10
5 11 $ hg init master
6 12 $ cd master
7 13 $ cat >> .hg/hgrc <<EOF
8 14 > [remotefilelog]
9 15 > server=True
10 16 > EOF
11 17 $ echo x > x
12 18 $ echo z > z
13 19 $ hg commit -qAm x
14 20 $ echo x2 > x
15 21 $ echo y > y
16 22 $ hg commit -qAm y
17 23 $ echo w > w
18 24 $ rm z
19 25 $ hg commit -qAm w
20 26 $ hg bookmark foo
21 27
22 28 $ cd ..
23 29
24 30 # clone the repo
25 31
26 32 $ hgcloneshallow ssh://user@dummy/master shallow --noupdate
27 33 streaming all changes
28 34 2 files to transfer, 776 bytes of data
29 35 transferred 776 bytes in * seconds (*/sec) (glob)
30 36 searching for changes
31 37 no changes found
32 38
33 39 # Set the prefetchdays config to zero so that all commits are prefetched
34 40 # no matter what their creation date is. Also set prefetchdelay config
35 41 # to zero so that there is no delay between prefetches.
36 42 $ cd shallow
37 43 $ cat >> .hg/hgrc <<EOF
38 44 > [remotefilelog]
39 45 > prefetchdays=0
40 46 > prefetchdelay=0
41 47 > EOF
42 48 $ cd ..
43 49
44 50 # prefetch a revision
45 51 $ cd shallow
46 52
47 53 $ hg prefetch -r 0
48 54 2 files fetched over 1 fetches - (2 misses, 0.00% hit ratio) over *s (glob)
49 55
50 56 $ hg cat -r 0 x
51 57 x
52 58
53 59 # background prefetch on pull when configured
54 60
55 61 $ cat >> .hg/hgrc <<EOF
56 62 > [remotefilelog]
57 63 > pullprefetch=bookmark()
58 64 > backgroundprefetch=True
59 65 > EOF
60 66 $ hg strip tip
61 67 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/6b4b6f66ef8c-b4b8bdaf-backup.hg (glob)
62 68
63 69 $ clearcache
64 70 $ hg pull
65 71 pulling from ssh://user@dummy/master
66 72 searching for changes
67 73 adding changesets
68 74 adding manifests
69 75 adding file changes
70 76 added 1 changesets with 0 changes to 0 files
71 77 updating bookmark foo
72 78 new changesets 6b4b6f66ef8c
73 79 (run 'hg update' to get a working copy)
74 80 prefetching file contents
75 81 $ sleep 0.5
76 82 $ hg debugwaitonprefetch >/dev/null 2>%1
77 83 $ find $CACHEDIR -type f | sort
78 84 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/ef95c5376f34698742fe34f315fd82136f8f68c0
79 85 $TESTTMP/hgcache/master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/076f5e2225b3ff0400b98c92aa6cdf403ee24cca
80 86 $TESTTMP/hgcache/master/af/f024fe4ab0fece4091de044c58c9ae4233383a/bb6ccd5dceaa5e9dc220e0dad65e051b94f69a2c
81 87 $TESTTMP/hgcache/repos
82 88
83 89 # background prefetch with repack on pull when configured
84 90
85 91 $ cat >> .hg/hgrc <<EOF
86 92 > [remotefilelog]
87 93 > backgroundrepack=True
88 94 > EOF
89 95 $ hg strip tip
90 96 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/6b4b6f66ef8c-b4b8bdaf-backup.hg (glob)
91 97
92 98 $ clearcache
93 99 $ hg pull
94 100 pulling from ssh://user@dummy/master
95 101 searching for changes
96 102 adding changesets
97 103 adding manifests
98 104 adding file changes
99 105 added 1 changesets with 0 changes to 0 files
100 106 updating bookmark foo
101 107 new changesets 6b4b6f66ef8c
102 108 (run 'hg update' to get a working copy)
103 109 prefetching file contents
104 110 $ sleep 0.5
105 111 $ hg debugwaitonprefetch >/dev/null 2>%1
106 112 $ sleep 0.5
107 113 $ hg debugwaitonrepack >/dev/null 2>%1
108 114 $ sleep 0.5
109 115 $ find $CACHEDIR -type f | sort
110 116 $TESTTMP/hgcache/master/packs/6e8633deba6e544e5f8edbd7b996d6e31a2c42ae.histidx
111 117 $TESTTMP/hgcache/master/packs/6e8633deba6e544e5f8edbd7b996d6e31a2c42ae.histpack
112 118 $TESTTMP/hgcache/master/packs/8ce5ab3745465ab83bba30a7b9c295e0c8404652.dataidx
113 119 $TESTTMP/hgcache/master/packs/8ce5ab3745465ab83bba30a7b9c295e0c8404652.datapack
114 120 $TESTTMP/hgcache/master/packs/repacklock
115 121 $TESTTMP/hgcache/repos
116 122
117 123 # background prefetch with repack on update when wcprevset configured
118 124
119 125 $ clearcache
120 126 $ hg up -r 0
121 127 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 128 2 files fetched over 1 fetches - (2 misses, 0.00% hit ratio) over *s (glob)
123 129 $ find $CACHEDIR -type f | sort
124 130 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0
125 131 $TESTTMP/hgcache/master/39/5df8f7c51f007019cb30201c49e884b46b92fa/69a1b67522704ec122181c0890bd16e9d3e7516a
126 132 $TESTTMP/hgcache/repos
127 133
128 134 $ hg up -r 1
129 135 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
130 136 2 files fetched over 2 fetches - (2 misses, 0.00% hit ratio) over *s (glob)
131 137
132 138 $ cat >> .hg/hgrc <<EOF
133 139 > [remotefilelog]
134 140 > bgprefetchrevs=.::
135 141 > EOF
136 142
137 143 $ clearcache
138 144 $ hg up -r 0
139 145 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
140 146 * files fetched over * fetches - (* misses, 0.00% hit ratio) over *s (glob)
141 147 $ sleep 1
142 148 $ hg debugwaitonprefetch >/dev/null 2>%1
143 149 $ sleep 1
144 150 $ hg debugwaitonrepack >/dev/null 2>%1
145 151 $ sleep 1
146 152 $ find $CACHEDIR -type f | sort
147 153 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
148 154 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
149 155 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
150 156 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
151 157 $TESTTMP/hgcache/master/packs/repacklock
152 158 $TESTTMP/hgcache/repos
153 159
154 160 # Ensure that file 'w' was prefetched - it was not part of the update operation and therefore
155 161 # could only be downloaded by the background prefetch
156 162
157 163 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
158 164 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
159 165 w:
160 166 Node Delta Base Delta Length Blob Size
161 167 bb6ccd5dceaa 000000000000 2 2
162 168
163 169 Total: 2 2 (0.0% bigger)
164 170 x:
165 171 Node Delta Base Delta Length Blob Size
166 172 ef95c5376f34 000000000000 3 3
167 173 1406e7411862 ef95c5376f34 14 2
168 174
169 175 Total: 17 5 (240.0% bigger)
170 176 y:
171 177 Node Delta Base Delta Length Blob Size
172 178 076f5e2225b3 000000000000 2 2
173 179
174 180 Total: 2 2 (0.0% bigger)
175 181 z:
176 182 Node Delta Base Delta Length Blob Size
177 183 69a1b6752270 000000000000 2 2
178 184
179 185 Total: 2 2 (0.0% bigger)
180 186
181 187 # background prefetch with repack on commit when wcprevset configured
182 188
183 189 $ cat >> .hg/hgrc <<EOF
184 190 > [remotefilelog]
185 191 > bgprefetchrevs=0::
186 192 > EOF
187 193
188 194 $ clearcache
189 195 $ find $CACHEDIR -type f | sort
190 196 $ echo b > b
191 197 $ hg commit -qAm b
192 198 * files fetched over 1 fetches - (* misses, 0.00% hit ratio) over *s (glob)
193 199 $ hg bookmark temporary
194 200 $ sleep 1
195 201 $ hg debugwaitonprefetch >/dev/null 2>%1
196 202 $ sleep 1
197 203 $ hg debugwaitonrepack >/dev/null 2>%1
198 204 $ sleep 1
199 205 $ find $CACHEDIR -type f | sort
200 206 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
201 207 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
202 208 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
203 209 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
204 210 $TESTTMP/hgcache/master/packs/repacklock
205 211 $TESTTMP/hgcache/repos
206 212
207 213 # Ensure that file 'w' was prefetched - it was not part of the commit operation and therefore
208 214 # could only be downloaded by the background prefetch
209 215
210 216 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
211 217 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
212 218 w:
213 219 Node Delta Base Delta Length Blob Size
214 220 bb6ccd5dceaa 000000000000 2 2
215 221
216 222 Total: 2 2 (0.0% bigger)
217 223 x:
218 224 Node Delta Base Delta Length Blob Size
219 225 ef95c5376f34 000000000000 3 3
220 226 1406e7411862 ef95c5376f34 14 2
221 227
222 228 Total: 17 5 (240.0% bigger)
223 229 y:
224 230 Node Delta Base Delta Length Blob Size
225 231 076f5e2225b3 000000000000 2 2
226 232
227 233 Total: 2 2 (0.0% bigger)
228 234 z:
229 235 Node Delta Base Delta Length Blob Size
230 236 69a1b6752270 000000000000 2 2
231 237
232 238 Total: 2 2 (0.0% bigger)
233 239
234 240 # background prefetch with repack on rebase when wcprevset configured
235 241
236 242 $ hg up -r 2
237 243 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
238 244 (leaving bookmark temporary)
239 245 $ clearcache
240 246 $ find $CACHEDIR -type f | sort
241 247 $ hg rebase -s temporary -d foo
242 248 rebasing 3:58147a5b5242 "b" (temporary tip)
243 249 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/58147a5b5242-c3678817-rebase.hg (glob)
244 250 3 files fetched over 1 fetches - (3 misses, 0.00% hit ratio) over *s (glob)
245 251 $ sleep 1
246 252 $ hg debugwaitonprefetch >/dev/null 2>%1
247 253 $ sleep 1
248 254 $ hg debugwaitonrepack >/dev/null 2>%1
249 255 $ sleep 1
250 256
251 257 # Ensure that file 'y' was prefetched - it was not part of the rebase operation and therefore
252 258 # could only be downloaded by the background prefetch
253 259
254 260 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
255 261 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
256 262 w:
257 263 Node Delta Base Delta Length Blob Size
258 264 bb6ccd5dceaa 000000000000 2 2
259 265
260 266 Total: 2 2 (0.0% bigger)
261 267 x:
262 268 Node Delta Base Delta Length Blob Size
263 269 ef95c5376f34 000000000000 3 3
264 270 1406e7411862 ef95c5376f34 14 2
265 271
266 272 Total: 17 5 (240.0% bigger)
267 273 y:
268 274 Node Delta Base Delta Length Blob Size
269 275 076f5e2225b3 000000000000 2 2
270 276
271 277 Total: 2 2 (0.0% bigger)
272 278 z:
273 279 Node Delta Base Delta Length Blob Size
274 280 69a1b6752270 000000000000 2 2
275 281
276 282 Total: 2 2 (0.0% bigger)
277 283
278 284 # Check that foregound prefetch with no arguments blocks until background prefetches finish
279 285
280 286 $ hg up -r 3
281 287 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
282 288 $ clearcache
283 289 $ hg prefetch --repack
284 290 waiting for lock on prefetching in $TESTTMP/shallow held by process * on host * (glob) (?)
285 291 got lock after * seconds (glob) (?)
286 292 (running background incremental repack)
287 293 * files fetched over 1 fetches - (* misses, 0.00% hit ratio) over *s (glob) (?)
288 294
289 295 $ sleep 0.5
290 296 $ hg debugwaitonrepack >/dev/null 2>%1
291 297 $ sleep 0.5
292 298
293 299 $ find $CACHEDIR -type f | sort
294 300 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
295 301 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
296 302 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
297 303 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
298 304 $TESTTMP/hgcache/master/packs/repacklock
299 305 $TESTTMP/hgcache/repos
300 306
301 307 # Ensure that files were prefetched
302 308 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
303 309 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
304 310 w:
305 311 Node Delta Base Delta Length Blob Size
306 312 bb6ccd5dceaa 000000000000 2 2
307 313
308 314 Total: 2 2 (0.0% bigger)
309 315 x:
310 316 Node Delta Base Delta Length Blob Size
311 317 ef95c5376f34 000000000000 3 3
312 318 1406e7411862 ef95c5376f34 14 2
313 319
314 320 Total: 17 5 (240.0% bigger)
315 321 y:
316 322 Node Delta Base Delta Length Blob Size
317 323 076f5e2225b3 000000000000 2 2
318 324
319 325 Total: 2 2 (0.0% bigger)
320 326 z:
321 327 Node Delta Base Delta Length Blob Size
322 328 69a1b6752270 000000000000 2 2
323 329
324 330 Total: 2 2 (0.0% bigger)
325 331
326 332 # Check that foreground prefetch fetches revs specified by '. + draft() + bgprefetchrevs + pullprefetch'
327 333
328 334 $ clearcache
329 335 $ hg prefetch --repack
330 336 waiting for lock on prefetching in $TESTTMP/shallow held by process * on host * (glob) (?)
331 337 got lock after * seconds (glob) (?)
332 338 (running background incremental repack)
333 339 * files fetched over 1 fetches - (* misses, 0.00% hit ratio) over *s (glob) (?)
334 340 $ sleep 0.5
335 341 $ hg debugwaitonrepack >/dev/null 2>%1
336 342 $ sleep 0.5
337 343
338 344 $ find $CACHEDIR -type f | sort
339 345 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
340 346 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
341 347 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
342 348 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
343 349 $TESTTMP/hgcache/master/packs/repacklock
344 350 $TESTTMP/hgcache/repos
345 351
346 352 # Ensure that files were prefetched
347 353 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
348 354 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
349 355 w:
350 356 Node Delta Base Delta Length Blob Size
351 357 bb6ccd5dceaa 000000000000 2 2
352 358
353 359 Total: 2 2 (0.0% bigger)
354 360 x:
355 361 Node Delta Base Delta Length Blob Size
356 362 ef95c5376f34 000000000000 3 3
357 363 1406e7411862 ef95c5376f34 14 2
358 364
359 365 Total: 17 5 (240.0% bigger)
360 366 y:
361 367 Node Delta Base Delta Length Blob Size
362 368 076f5e2225b3 000000000000 2 2
363 369
364 370 Total: 2 2 (0.0% bigger)
365 371 z:
366 372 Node Delta Base Delta Length Blob Size
367 373 69a1b6752270 000000000000 2 2
368 374
369 375 Total: 2 2 (0.0% bigger)
370 376
371 377 # Test that if data was prefetched and repacked we dont need to prefetch it again
372 378 # It ensures that Mercurial looks not only in loose files but in packs as well
373 379
374 380 $ hg prefetch --repack
375 381 (running background incremental repack)
@@ -1,384 +1,387
1 1 #require no-windows
2 2
3 3 $ . "$TESTDIR/remotefilelog-library.sh"
4
4 # devel.remotefilelog.ensurestart: reduce race condition with
5 # waiton{repack/prefetch}
5 6 $ cat >> $HGRCPATH <<EOF
6 7 > [remotefilelog]
7 8 > fastdatapack=True
9 > [devel]
10 > remotefilelog.ensurestart=True
8 11 > EOF
9 12
10 13 $ hg init master
11 14 $ cd master
12 15 $ cat >> .hg/hgrc <<EOF
13 16 > [remotefilelog]
14 17 > server=True
15 18 > serverexpiration=-1
16 19 > EOF
17 20 $ echo x > x
18 21 $ hg commit -qAm x
19 22 $ echo x >> x
20 23 $ hg commit -qAm x2
21 24 $ cd ..
22 25
23 26 $ hgcloneshallow ssh://user@dummy/master shallow -q
24 27 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over *s (glob)
25 28
26 29 # Set the prefetchdays config to zero so that all commits are prefetched
27 30 # no matter what their creation date is.
28 31 $ cd shallow
29 32 $ cat >> .hg/hgrc <<EOF
30 33 > [remotefilelog]
31 34 > prefetchdays=0
32 35 > EOF
33 36 $ cd ..
34 37
35 38 # Test that repack cleans up the old files and creates new packs
36 39
37 40 $ cd shallow
38 41 $ find $CACHEDIR | sort
39 42 $TESTTMP/hgcache
40 43 $TESTTMP/hgcache/master
41 44 $TESTTMP/hgcache/master/11
42 45 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072
43 46 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/aee31534993a501858fb6dd96a065671922e7d51
44 47 $TESTTMP/hgcache/repos
45 48
46 49 $ hg repack
47 50
48 51 $ find $CACHEDIR | sort
49 52 $TESTTMP/hgcache
50 53 $TESTTMP/hgcache/master
51 54 $TESTTMP/hgcache/master/packs
52 55 $TESTTMP/hgcache/master/packs/1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histidx
53 56 $TESTTMP/hgcache/master/packs/1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histpack
54 57 $TESTTMP/hgcache/master/packs/b1e0cfc7f345e408a7825e3081501959488d59ce.dataidx
55 58 $TESTTMP/hgcache/master/packs/b1e0cfc7f345e408a7825e3081501959488d59ce.datapack
56 59 $TESTTMP/hgcache/master/packs/repacklock
57 60 $TESTTMP/hgcache/repos
58 61
59 62 # Test that the packs are readonly
60 63 $ ls_l $CACHEDIR/master/packs
61 64 -r--r--r-- 1145 1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histidx
62 65 -r--r--r-- 172 1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histpack
63 66 -r--r--r-- 1074 b1e0cfc7f345e408a7825e3081501959488d59ce.dataidx
64 67 -r--r--r-- 72 b1e0cfc7f345e408a7825e3081501959488d59ce.datapack
65 68 -rw-r--r-- 0 repacklock
66 69
67 70 # Test that the data in the new packs is accessible
68 71 $ hg cat -r . x
69 72 x
70 73 x
71 74
72 75 # Test that adding new data and repacking it results in the loose data and the
73 76 # old packs being combined.
74 77
75 78 $ cd ../master
76 79 $ echo x >> x
77 80 $ hg commit -m x3
78 81 $ cd ../shallow
79 82 $ hg pull -q
80 83 $ hg up -q tip
81 84 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
82 85
83 86 $ find $CACHEDIR -type f | sort
84 87 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/d4a3ed9310e5bd9887e3bf779da5077efab28216
85 88 $TESTTMP/hgcache/master/packs/1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histidx
86 89 $TESTTMP/hgcache/master/packs/1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histpack
87 90 $TESTTMP/hgcache/master/packs/b1e0cfc7f345e408a7825e3081501959488d59ce.dataidx
88 91 $TESTTMP/hgcache/master/packs/b1e0cfc7f345e408a7825e3081501959488d59ce.datapack
89 92 $TESTTMP/hgcache/master/packs/repacklock
90 93 $TESTTMP/hgcache/repos
91 94
92 95 $ hg repack --traceback
93 96
94 97 $ find $CACHEDIR -type f | sort
95 98 $TESTTMP/hgcache/master/packs/78840d69389c7404327f7477e3931c89945c37d1.dataidx
96 99 $TESTTMP/hgcache/master/packs/78840d69389c7404327f7477e3931c89945c37d1.datapack
97 100 $TESTTMP/hgcache/master/packs/8abe7889aae389337d12ebe6085d4ee13854c7c9.histidx
98 101 $TESTTMP/hgcache/master/packs/8abe7889aae389337d12ebe6085d4ee13854c7c9.histpack
99 102 $TESTTMP/hgcache/master/packs/repacklock
100 103 $TESTTMP/hgcache/repos
101 104
102 105 # Verify all the file data is still available
103 106 $ hg cat -r . x
104 107 x
105 108 x
106 109 x
107 110 $ hg cat -r '.^' x
108 111 x
109 112 x
110 113
111 114 # Test that repacking again without new data does not delete the pack files
112 115 # and did not change the pack names
113 116 $ hg repack
114 117 $ find $CACHEDIR -type f | sort
115 118 $TESTTMP/hgcache/master/packs/78840d69389c7404327f7477e3931c89945c37d1.dataidx
116 119 $TESTTMP/hgcache/master/packs/78840d69389c7404327f7477e3931c89945c37d1.datapack
117 120 $TESTTMP/hgcache/master/packs/8abe7889aae389337d12ebe6085d4ee13854c7c9.histidx
118 121 $TESTTMP/hgcache/master/packs/8abe7889aae389337d12ebe6085d4ee13854c7c9.histpack
119 122 $TESTTMP/hgcache/master/packs/repacklock
120 123 $TESTTMP/hgcache/repos
121 124
122 125 # Run two repacks at once
123 126 $ hg repack --config "hooks.prerepack=sleep 3" &
124 127 $ sleep 1
125 128 $ hg repack
126 129 skipping repack - another repack is already running
127 130 $ hg debugwaitonrepack >/dev/null 2>&1
128 131
129 132 # Run repack in the background
130 133 $ cd ../master
131 134 $ echo x >> x
132 135 $ hg commit -m x4
133 136 $ cd ../shallow
134 137 $ hg pull -q
135 138 $ hg up -q tip
136 139 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
137 140 $ find $CACHEDIR -type f | sort
138 141 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1bb2e6237e035c8f8ef508e281f1ce075bc6db72
139 142 $TESTTMP/hgcache/master/packs/78840d69389c7404327f7477e3931c89945c37d1.dataidx
140 143 $TESTTMP/hgcache/master/packs/78840d69389c7404327f7477e3931c89945c37d1.datapack
141 144 $TESTTMP/hgcache/master/packs/8abe7889aae389337d12ebe6085d4ee13854c7c9.histidx
142 145 $TESTTMP/hgcache/master/packs/8abe7889aae389337d12ebe6085d4ee13854c7c9.histpack
143 146 $TESTTMP/hgcache/master/packs/repacklock
144 147 $TESTTMP/hgcache/repos
145 148
146 149 $ hg repack --background
147 150 (running background repack)
148 151 $ sleep 0.5
149 152 $ hg debugwaitonrepack >/dev/null 2>&1
150 153 $ find $CACHEDIR -type f | sort
151 154 $TESTTMP/hgcache/master/packs/39443fa1064182e93d968b5cba292eb5283260d0.dataidx
152 155 $TESTTMP/hgcache/master/packs/39443fa1064182e93d968b5cba292eb5283260d0.datapack
153 156 $TESTTMP/hgcache/master/packs/604552d403a1381749faf656feca0ca265a6d52c.histidx
154 157 $TESTTMP/hgcache/master/packs/604552d403a1381749faf656feca0ca265a6d52c.histpack
155 158 $TESTTMP/hgcache/master/packs/repacklock
156 159 $TESTTMP/hgcache/repos
157 160
158 161 # Test debug commands
159 162
160 163 $ hg debugdatapack $TESTTMP/hgcache/master/packs/*.datapack
161 164 $TESTTMP/hgcache/master/packs/39443fa1064182e93d968b5cba292eb5283260d0:
162 165 x:
163 166 Node Delta Base Delta Length Blob Size
164 167 1bb2e6237e03 000000000000 8 8
165 168 d4a3ed9310e5 1bb2e6237e03 12 6
166 169 aee31534993a d4a3ed9310e5 12 4
167 170
168 171 Total: 32 18 (77.8% bigger)
169 172 $ hg debugdatapack --long $TESTTMP/hgcache/master/packs/*.datapack
170 173 $TESTTMP/hgcache/master/packs/39443fa1064182e93d968b5cba292eb5283260d0:
171 174 x:
172 175 Node Delta Base Delta Length Blob Size
173 176 1bb2e6237e035c8f8ef508e281f1ce075bc6db72 0000000000000000000000000000000000000000 8 8
174 177 d4a3ed9310e5bd9887e3bf779da5077efab28216 1bb2e6237e035c8f8ef508e281f1ce075bc6db72 12 6
175 178 aee31534993a501858fb6dd96a065671922e7d51 d4a3ed9310e5bd9887e3bf779da5077efab28216 12 4
176 179
177 180 Total: 32 18 (77.8% bigger)
178 181 $ hg debugdatapack $TESTTMP/hgcache/master/packs/*.datapack --node d4a3ed9310e5bd9887e3bf779da5077efab28216
179 182 $TESTTMP/hgcache/master/packs/39443fa1064182e93d968b5cba292eb5283260d0:
180 183
181 184 x
182 185 Node Delta Base Delta SHA1 Delta Length
183 186 d4a3ed9310e5bd9887e3bf779da5077efab28216 1bb2e6237e035c8f8ef508e281f1ce075bc6db72 77029ab56e83ea2115dd53ff87483682abe5d7ca 12
184 187 Node Delta Base Delta SHA1 Delta Length
185 188 1bb2e6237e035c8f8ef508e281f1ce075bc6db72 0000000000000000000000000000000000000000 7ca8c71a64f7b56380e77573da2f7a5fdd2ecdb5 8
186 189 $ hg debughistorypack $TESTTMP/hgcache/master/packs/*.histidx
187 190
188 191 x
189 192 Node P1 Node P2 Node Link Node Copy From
190 193 1bb2e6237e03 d4a3ed9310e5 000000000000 0b03bbc9e1e7
191 194 d4a3ed9310e5 aee31534993a 000000000000 421535db10b6
192 195 aee31534993a 1406e7411862 000000000000 a89d614e2364
193 196 1406e7411862 000000000000 000000000000 b292c1e3311f
194 197
195 198 # Test copy tracing from a pack
196 199 $ cd ../master
197 200 $ hg mv x y
198 201 $ hg commit -m 'move x to y'
199 202 $ cd ../shallow
200 203 $ hg pull -q
201 204 $ hg up -q tip
202 205 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
203 206 $ hg repack
204 207 $ hg log -f y -T '{desc}\n'
205 208 move x to y
206 209 x4
207 210 x3
208 211 x2
209 212 x
210 213
211 214 # Test copy trace across rename and back
212 215 $ cp -R $TESTTMP/hgcache/master/packs $TESTTMP/backuppacks
213 216 $ cd ../master
214 217 $ hg mv y x
215 218 $ hg commit -m 'move y back to x'
216 219 $ hg revert -r 0 x
217 220 $ mv x y
218 221 $ hg add y
219 222 $ echo >> y
220 223 $ hg revert x
221 224 $ hg commit -m 'add y back without metadata'
222 225 $ cd ../shallow
223 226 $ hg pull -q
224 227 $ hg up -q tip
225 228 2 files fetched over 2 fetches - (2 misses, 0.00% hit ratio) over * (glob)
226 229 $ hg repack
227 230 $ ls $TESTTMP/hgcache/master/packs
228 231 bfd60adb76018bb952e27cd23fc151bf94865d7d.histidx
229 232 bfd60adb76018bb952e27cd23fc151bf94865d7d.histpack
230 233 fb3aa57b22789ebcc45706c352e2d6af099c5816.dataidx
231 234 fb3aa57b22789ebcc45706c352e2d6af099c5816.datapack
232 235 repacklock
233 236 $ hg debughistorypack $TESTTMP/hgcache/master/packs/*.histidx
234 237
235 238 x
236 239 Node P1 Node P2 Node Link Node Copy From
237 240 cd410a44d584 577959738234 000000000000 609547eda446 y
238 241 1bb2e6237e03 d4a3ed9310e5 000000000000 0b03bbc9e1e7
239 242 d4a3ed9310e5 aee31534993a 000000000000 421535db10b6
240 243 aee31534993a 1406e7411862 000000000000 a89d614e2364
241 244 1406e7411862 000000000000 000000000000 b292c1e3311f
242 245
243 246 y
244 247 Node P1 Node P2 Node Link Node Copy From
245 248 577959738234 1bb2e6237e03 000000000000 c7faf2fc439a x
246 249 21f46f2721e7 000000000000 000000000000 d6868642b790
247 250 $ hg strip -r '.^'
248 251 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
249 252 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/609547eda446-b26b56a8-backup.hg (glob)
250 253 $ hg -R ../master strip -r '.^'
251 254 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
252 255 saved backup bundle to $TESTTMP/master/.hg/strip-backup/609547eda446-b26b56a8-backup.hg (glob)
253 256
254 257 $ rm -rf $TESTTMP/hgcache/master/packs
255 258 $ cp -R $TESTTMP/backuppacks $TESTTMP/hgcache/master/packs
256 259
257 260 # Test repacking datapack without history
258 261 $ rm -rf $CACHEDIR/master/packs/*hist*
259 262 $ hg repack
260 263 $ hg debugdatapack $TESTTMP/hgcache/master/packs/*.datapack
261 264 $TESTTMP/hgcache/master/packs/922aca43dbbeda4d250565372e8892ec7b08da6a:
262 265 x:
263 266 Node Delta Base Delta Length Blob Size
264 267 1bb2e6237e03 000000000000 8 8
265 268 d4a3ed9310e5 1bb2e6237e03 12 6
266 269 aee31534993a d4a3ed9310e5 12 4
267 270
268 271 Total: 32 18 (77.8% bigger)
269 272 y:
270 273 Node Delta Base Delta Length Blob Size
271 274 577959738234 000000000000 70 8
272 275
273 276 Total: 70 8 (775.0% bigger)
274 277
275 278 $ hg cat -r ".^" x
276 279 x
277 280 x
278 281 x
279 282 x
280 283
281 284 Incremental repack
282 285 $ rm -rf $CACHEDIR/master/packs/*
283 286 $ cat >> .hg/hgrc <<EOF
284 287 > [remotefilelog]
285 288 > data.generations=60
286 289 > 150
287 290 > EOF
288 291
289 292 Single pack - repack does nothing
290 293 $ hg prefetch -r 0
291 294 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
292 295 $ ls_l $TESTTMP/hgcache/master/packs/ | grep datapack
293 296 [1]
294 297 $ ls_l $TESTTMP/hgcache/master/packs/ | grep histpack
295 298 [1]
296 299 $ hg repack --incremental
297 300 $ ls_l $TESTTMP/hgcache/master/packs/ | grep datapack
298 301 -r--r--r-- 70 052643fdcdebbd42d7c180a651a30d46098e6fe1.datapack
299 302 $ ls_l $TESTTMP/hgcache/master/packs/ | grep histpack
300 303 -r--r--r-- 90 955a622173324b2d8b53e1147f209f1cf125302e.histpack
301 304
302 305 3 gen1 packs, 1 gen0 pack - packs 3 gen1 into 1
303 306 $ hg prefetch -r 1
304 307 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
305 308 $ hg prefetch -r 2
306 309 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
307 310 $ hg prefetch -r 3
308 311 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
309 312 $ ls_l $TESTTMP/hgcache/master/packs/ | grep datapack
310 313 -r--r--r-- 70 052643fdcdebbd42d7c180a651a30d46098e6fe1.datapack
311 314 $ ls_l $TESTTMP/hgcache/master/packs/ | grep histpack
312 315 -r--r--r-- 90 955a622173324b2d8b53e1147f209f1cf125302e.histpack
313 316 $ hg repack --incremental
314 317 $ ls_l $TESTTMP/hgcache/master/packs/ | grep datapack
315 318 -r--r--r-- 70 052643fdcdebbd42d7c180a651a30d46098e6fe1.datapack
316 319 -r--r--r-- 226 39443fa1064182e93d968b5cba292eb5283260d0.datapack
317 320 $ ls_l $TESTTMP/hgcache/master/packs/ | grep histpack
318 321 -r--r--r-- 336 604552d403a1381749faf656feca0ca265a6d52c.histpack
319 322 -r--r--r-- 90 955a622173324b2d8b53e1147f209f1cf125302e.histpack
320 323
321 324 1 gen3 pack, 1 gen0 pack - does nothing
322 325 $ hg repack --incremental
323 326 $ ls_l $TESTTMP/hgcache/master/packs/ | grep datapack
324 327 -r--r--r-- 70 052643fdcdebbd42d7c180a651a30d46098e6fe1.datapack
325 328 -r--r--r-- 226 39443fa1064182e93d968b5cba292eb5283260d0.datapack
326 329 $ ls_l $TESTTMP/hgcache/master/packs/ | grep histpack
327 330 -r--r--r-- 336 604552d403a1381749faf656feca0ca265a6d52c.histpack
328 331 -r--r--r-- 90 955a622173324b2d8b53e1147f209f1cf125302e.histpack
329 332
330 333 Pull should run background repack
331 334 $ cat >> .hg/hgrc <<EOF
332 335 > [remotefilelog]
333 336 > backgroundrepack=True
334 337 > EOF
335 338 $ clearcache
336 339 $ hg prefetch -r 0
337 340 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
338 341 $ hg prefetch -r 1
339 342 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
340 343 $ hg prefetch -r 2
341 344 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
342 345 $ hg prefetch -r 3
343 346 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
344 347
345 348 $ hg pull
346 349 pulling from ssh://user@dummy/master
347 350 searching for changes
348 351 no changes found
349 352 (running background incremental repack)
350 353 $ sleep 0.5
351 354 $ hg debugwaitonrepack >/dev/null 2>&1
352 355 $ ls_l $TESTTMP/hgcache/master/packs/ | grep datapack
353 356 -r--r--r-- 303 156a6c1c83aeb69422d7936e0a46ba9bc06a71c0.datapack
354 357 $ ls_l $TESTTMP/hgcache/master/packs/ | grep histpack
355 358 -r--r--r-- 336 604552d403a1381749faf656feca0ca265a6d52c.histpack
356 359
357 360 Test environment variable resolution
358 361 $ CACHEPATH=$TESTTMP/envcache hg prefetch --config 'remotefilelog.cachepath=$CACHEPATH'
359 362 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
360 363 $ find $TESTTMP/envcache | sort
361 364 $TESTTMP/envcache
362 365 $TESTTMP/envcache/master
363 366 $TESTTMP/envcache/master/95
364 367 $TESTTMP/envcache/master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a
365 368 $TESTTMP/envcache/master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/577959738234a1eb241ed3ed4b22a575833f56e0
366 369 $TESTTMP/envcache/repos
367 370
368 371 Test local remotefilelog blob is correct when based on a pack
369 372 $ hg prefetch -r .
370 373 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
371 374 $ echo >> y
372 375 $ hg commit -m y2
373 376 $ hg debugremotefilelog .hg/store/data/95cb0bfd2977c761298d9624e4b4d4c72a39974a/b70860edba4f8242a1d52f2a94679dd23cb76808
374 377 size: 9 bytes
375 378 path: .hg/store/data/95cb0bfd2977c761298d9624e4b4d4c72a39974a/b70860edba4f8242a1d52f2a94679dd23cb76808
376 379 key: b70860edba4f
377 380
378 381 node => p1 p2 linknode copyfrom
379 382 b70860edba4f => 577959738234 000000000000 08d3fbc98c48
380 383 577959738234 => 1bb2e6237e03 000000000000 c7faf2fc439a x
381 384 1bb2e6237e03 => d4a3ed9310e5 000000000000 0b03bbc9e1e7
382 385 d4a3ed9310e5 => aee31534993a 000000000000 421535db10b6
383 386 aee31534993a => 1406e7411862 000000000000 a89d614e2364
384 387 1406e7411862 => 000000000000 000000000000 b292c1e3311f
@@ -1,462 +1,468
1 1 #require no-windows
2 2
3 3 $ . "$TESTDIR/remotefilelog-library.sh"
4 # devel.remotefilelog.ensurestart: reduce race condition with
5 # waiton{repack/prefetch}
6 $ cat >> $HGRCPATH <<EOF
7 > [devel]
8 > remotefilelog.ensurestart=True
9 > EOF
4 10
5 11 $ hg init master
6 12 $ cd master
7 13 $ cat >> .hg/hgrc <<EOF
8 14 > [remotefilelog]
9 15 > server=True
10 16 > serverexpiration=-1
11 17 > EOF
12 18 $ echo x > x
13 19 $ hg commit -qAm x
14 20 $ echo x >> x
15 21 $ hg commit -qAm x2
16 22 $ cd ..
17 23
18 24 $ hgcloneshallow ssh://user@dummy/master shallow -q
19 25 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over *s (glob)
20 26
21 27 # Set the prefetchdays config to zero so that all commits are prefetched
22 28 # no matter what their creation date is.
23 29 $ cd shallow
24 30 $ cat >> .hg/hgrc <<EOF
25 31 > [remotefilelog]
26 32 > prefetchdays=0
27 33 > EOF
28 34 $ cd ..
29 35
30 36 # Test that repack cleans up the old files and creates new packs
31 37
32 38 $ cd shallow
33 39 $ find $CACHEDIR | sort
34 40 $TESTTMP/hgcache
35 41 $TESTTMP/hgcache/master
36 42 $TESTTMP/hgcache/master/11
37 43 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072
38 44 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/aee31534993a501858fb6dd96a065671922e7d51
39 45 $TESTTMP/hgcache/repos
40 46
41 47 $ hg repack
42 48
43 49 $ find $CACHEDIR | sort
44 50 $TESTTMP/hgcache
45 51 $TESTTMP/hgcache/master
46 52 $TESTTMP/hgcache/master/packs
47 53 $TESTTMP/hgcache/master/packs/1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histidx
48 54 $TESTTMP/hgcache/master/packs/1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histpack
49 55 $TESTTMP/hgcache/master/packs/b1e0cfc7f345e408a7825e3081501959488d59ce.dataidx
50 56 $TESTTMP/hgcache/master/packs/b1e0cfc7f345e408a7825e3081501959488d59ce.datapack
51 57 $TESTTMP/hgcache/master/packs/repacklock
52 58 $TESTTMP/hgcache/repos
53 59
54 60 # Test that the packs are readonly
55 61 $ ls_l $CACHEDIR/master/packs
56 62 -r--r--r-- 1145 1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histidx
57 63 -r--r--r-- 172 1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histpack
58 64 -r--r--r-- 1074 b1e0cfc7f345e408a7825e3081501959488d59ce.dataidx
59 65 -r--r--r-- 72 b1e0cfc7f345e408a7825e3081501959488d59ce.datapack
60 66 -rw-r--r-- 0 repacklock
61 67
62 68 # Test that the data in the new packs is accessible
63 69 $ hg cat -r . x
64 70 x
65 71 x
66 72
67 73 # Test that adding new data and repacking it results in the loose data and the
68 74 # old packs being combined.
69 75
70 76 $ cd ../master
71 77 $ echo x >> x
72 78 $ hg commit -m x3
73 79 $ cd ../shallow
74 80 $ hg pull -q
75 81 $ hg up -q tip
76 82 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
77 83
78 84 $ find $CACHEDIR -type f | sort
79 85 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/d4a3ed9310e5bd9887e3bf779da5077efab28216
80 86 $TESTTMP/hgcache/master/packs/1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histidx
81 87 $TESTTMP/hgcache/master/packs/1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histpack
82 88 $TESTTMP/hgcache/master/packs/b1e0cfc7f345e408a7825e3081501959488d59ce.dataidx
83 89 $TESTTMP/hgcache/master/packs/b1e0cfc7f345e408a7825e3081501959488d59ce.datapack
84 90 $TESTTMP/hgcache/master/packs/repacklock
85 91 $TESTTMP/hgcache/repos
86 92
87 93 # First assert that with --packsonly, the loose object will be ignored:
88 94
89 95 $ hg repack --packsonly
90 96
91 97 $ find $CACHEDIR -type f | sort
92 98 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/d4a3ed9310e5bd9887e3bf779da5077efab28216
93 99 $TESTTMP/hgcache/master/packs/1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histidx
94 100 $TESTTMP/hgcache/master/packs/1e91b207daf5d7b48f1be9c587d6b5ae654ce78c.histpack
95 101 $TESTTMP/hgcache/master/packs/b1e0cfc7f345e408a7825e3081501959488d59ce.dataidx
96 102 $TESTTMP/hgcache/master/packs/b1e0cfc7f345e408a7825e3081501959488d59ce.datapack
97 103 $TESTTMP/hgcache/master/packs/repacklock
98 104 $TESTTMP/hgcache/repos
99 105
100 106 $ hg repack --traceback
101 107
102 108 $ find $CACHEDIR -type f | sort
103 109 $TESTTMP/hgcache/master/packs/78840d69389c7404327f7477e3931c89945c37d1.dataidx
104 110 $TESTTMP/hgcache/master/packs/78840d69389c7404327f7477e3931c89945c37d1.datapack
105 111 $TESTTMP/hgcache/master/packs/8abe7889aae389337d12ebe6085d4ee13854c7c9.histidx
106 112 $TESTTMP/hgcache/master/packs/8abe7889aae389337d12ebe6085d4ee13854c7c9.histpack
107 113 $TESTTMP/hgcache/master/packs/repacklock
108 114 $TESTTMP/hgcache/repos
109 115
110 116 # Verify all the file data is still available
111 117 $ hg cat -r . x
112 118 x
113 119 x
114 120 x
115 121 $ hg cat -r '.^' x
116 122 x
117 123 x
118 124
119 125 # Test that repacking again without new data does not delete the pack files
120 126 # and did not change the pack names
121 127 $ hg repack
122 128 $ find $CACHEDIR -type f | sort
123 129 $TESTTMP/hgcache/master/packs/78840d69389c7404327f7477e3931c89945c37d1.dataidx
124 130 $TESTTMP/hgcache/master/packs/78840d69389c7404327f7477e3931c89945c37d1.datapack
125 131 $TESTTMP/hgcache/master/packs/8abe7889aae389337d12ebe6085d4ee13854c7c9.histidx
126 132 $TESTTMP/hgcache/master/packs/8abe7889aae389337d12ebe6085d4ee13854c7c9.histpack
127 133 $TESTTMP/hgcache/master/packs/repacklock
128 134 $TESTTMP/hgcache/repos
129 135
130 136 # Run two repacks at once
131 137 $ hg repack --config "hooks.prerepack=sleep 3" &
132 138 $ sleep 1
133 139 $ hg repack
134 140 skipping repack - another repack is already running
135 141 $ hg debugwaitonrepack >/dev/null 2>&1
136 142
137 143 # Run repack in the background
138 144 $ cd ../master
139 145 $ echo x >> x
140 146 $ hg commit -m x4
141 147 $ cd ../shallow
142 148 $ hg pull -q
143 149 $ hg up -q tip
144 150 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
145 151 $ find $CACHEDIR -type f | sort
146 152 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1bb2e6237e035c8f8ef508e281f1ce075bc6db72
147 153 $TESTTMP/hgcache/master/packs/78840d69389c7404327f7477e3931c89945c37d1.dataidx
148 154 $TESTTMP/hgcache/master/packs/78840d69389c7404327f7477e3931c89945c37d1.datapack
149 155 $TESTTMP/hgcache/master/packs/8abe7889aae389337d12ebe6085d4ee13854c7c9.histidx
150 156 $TESTTMP/hgcache/master/packs/8abe7889aae389337d12ebe6085d4ee13854c7c9.histpack
151 157 $TESTTMP/hgcache/master/packs/repacklock
152 158 $TESTTMP/hgcache/repos
153 159
154 160 $ hg repack --background
155 161 (running background repack)
156 162 $ sleep 0.5
157 163 $ hg debugwaitonrepack >/dev/null 2>&1
158 164 $ find $CACHEDIR -type f | sort
159 165 $TESTTMP/hgcache/master/packs/39443fa1064182e93d968b5cba292eb5283260d0.dataidx
160 166 $TESTTMP/hgcache/master/packs/39443fa1064182e93d968b5cba292eb5283260d0.datapack
161 167 $TESTTMP/hgcache/master/packs/604552d403a1381749faf656feca0ca265a6d52c.histidx
162 168 $TESTTMP/hgcache/master/packs/604552d403a1381749faf656feca0ca265a6d52c.histpack
163 169 $TESTTMP/hgcache/master/packs/repacklock
164 170 $TESTTMP/hgcache/repos
165 171
166 172 # Test debug commands
167 173
168 174 $ hg debugdatapack $TESTTMP/hgcache/master/packs/*.datapack
169 175 $TESTTMP/hgcache/master/packs/39443fa1064182e93d968b5cba292eb5283260d0:
170 176 x:
171 177 Node Delta Base Delta Length Blob Size
172 178 1bb2e6237e03 000000000000 8 8
173 179 d4a3ed9310e5 1bb2e6237e03 12 6
174 180 aee31534993a d4a3ed9310e5 12 4
175 181
176 182 Total: 32 18 (77.8% bigger)
177 183 $ hg debugdatapack --long $TESTTMP/hgcache/master/packs/*.datapack
178 184 $TESTTMP/hgcache/master/packs/39443fa1064182e93d968b5cba292eb5283260d0:
179 185 x:
180 186 Node Delta Base Delta Length Blob Size
181 187 1bb2e6237e035c8f8ef508e281f1ce075bc6db72 0000000000000000000000000000000000000000 8 8
182 188 d4a3ed9310e5bd9887e3bf779da5077efab28216 1bb2e6237e035c8f8ef508e281f1ce075bc6db72 12 6
183 189 aee31534993a501858fb6dd96a065671922e7d51 d4a3ed9310e5bd9887e3bf779da5077efab28216 12 4
184 190
185 191 Total: 32 18 (77.8% bigger)
186 192 $ hg debugdatapack $TESTTMP/hgcache/master/packs/*.datapack --node d4a3ed9310e5bd9887e3bf779da5077efab28216
187 193 $TESTTMP/hgcache/master/packs/39443fa1064182e93d968b5cba292eb5283260d0:
188 194
189 195 x
190 196 Node Delta Base Delta SHA1 Delta Length
191 197 d4a3ed9310e5bd9887e3bf779da5077efab28216 1bb2e6237e035c8f8ef508e281f1ce075bc6db72 77029ab56e83ea2115dd53ff87483682abe5d7ca 12
192 198 Node Delta Base Delta SHA1 Delta Length
193 199 1bb2e6237e035c8f8ef508e281f1ce075bc6db72 0000000000000000000000000000000000000000 7ca8c71a64f7b56380e77573da2f7a5fdd2ecdb5 8
194 200 $ hg debughistorypack $TESTTMP/hgcache/master/packs/*.histidx
195 201
196 202 x
197 203 Node P1 Node P2 Node Link Node Copy From
198 204 1bb2e6237e03 d4a3ed9310e5 000000000000 0b03bbc9e1e7
199 205 d4a3ed9310e5 aee31534993a 000000000000 421535db10b6
200 206 aee31534993a 1406e7411862 000000000000 a89d614e2364
201 207 1406e7411862 000000000000 000000000000 b292c1e3311f
202 208
203 209 # Test copy tracing from a pack
204 210 $ cd ../master
205 211 $ hg mv x y
206 212 $ hg commit -m 'move x to y'
207 213 $ cd ../shallow
208 214 $ hg pull -q
209 215 $ hg up -q tip
210 216 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
211 217 $ hg repack
212 218 $ hg log -f y -T '{desc}\n'
213 219 move x to y
214 220 x4
215 221 x3
216 222 x2
217 223 x
218 224
219 225 # Test copy trace across rename and back
220 226 $ cp -R $TESTTMP/hgcache/master/packs $TESTTMP/backuppacks
221 227 $ cd ../master
222 228 $ hg mv y x
223 229 $ hg commit -m 'move y back to x'
224 230 $ hg revert -r 0 x
225 231 $ mv x y
226 232 $ hg add y
227 233 $ echo >> y
228 234 $ hg revert x
229 235 $ hg commit -m 'add y back without metadata'
230 236 $ cd ../shallow
231 237 $ hg pull -q
232 238 $ hg up -q tip
233 239 2 files fetched over 2 fetches - (2 misses, 0.00% hit ratio) over * (glob)
234 240 $ hg repack
235 241 $ ls $TESTTMP/hgcache/master/packs
236 242 bfd60adb76018bb952e27cd23fc151bf94865d7d.histidx
237 243 bfd60adb76018bb952e27cd23fc151bf94865d7d.histpack
238 244 fb3aa57b22789ebcc45706c352e2d6af099c5816.dataidx
239 245 fb3aa57b22789ebcc45706c352e2d6af099c5816.datapack
240 246 repacklock
241 247 $ hg debughistorypack $TESTTMP/hgcache/master/packs/*.histidx
242 248
243 249 x
244 250 Node P1 Node P2 Node Link Node Copy From
245 251 cd410a44d584 577959738234 000000000000 609547eda446 y
246 252 1bb2e6237e03 d4a3ed9310e5 000000000000 0b03bbc9e1e7
247 253 d4a3ed9310e5 aee31534993a 000000000000 421535db10b6
248 254 aee31534993a 1406e7411862 000000000000 a89d614e2364
249 255 1406e7411862 000000000000 000000000000 b292c1e3311f
250 256
251 257 y
252 258 Node P1 Node P2 Node Link Node Copy From
253 259 577959738234 1bb2e6237e03 000000000000 c7faf2fc439a x
254 260 21f46f2721e7 000000000000 000000000000 d6868642b790
255 261 $ hg strip -r '.^'
256 262 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
257 263 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/609547eda446-b26b56a8-backup.hg (glob)
258 264 $ hg -R ../master strip -r '.^'
259 265 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
260 266 saved backup bundle to $TESTTMP/master/.hg/strip-backup/609547eda446-b26b56a8-backup.hg (glob)
261 267
262 268 $ rm -rf $TESTTMP/hgcache/master/packs
263 269 $ cp -R $TESTTMP/backuppacks $TESTTMP/hgcache/master/packs
264 270
265 271 # Test repacking datapack without history
266 272 $ rm -rf $CACHEDIR/master/packs/*hist*
267 273 $ hg repack
268 274 $ hg debugdatapack $TESTTMP/hgcache/master/packs/*.datapack
269 275 $TESTTMP/hgcache/master/packs/922aca43dbbeda4d250565372e8892ec7b08da6a:
270 276 x:
271 277 Node Delta Base Delta Length Blob Size
272 278 1bb2e6237e03 000000000000 8 8
273 279 d4a3ed9310e5 1bb2e6237e03 12 6
274 280 aee31534993a d4a3ed9310e5 12 4
275 281
276 282 Total: 32 18 (77.8% bigger)
277 283 y:
278 284 Node Delta Base Delta Length Blob Size
279 285 577959738234 000000000000 70 8
280 286
281 287 Total: 70 8 (775.0% bigger)
282 288
283 289 $ hg cat -r ".^" x
284 290 x
285 291 x
286 292 x
287 293 x
288 294
289 295 Incremental repack
290 296 $ rm -rf $CACHEDIR/master/packs/*
291 297 $ cat >> .hg/hgrc <<EOF
292 298 > [remotefilelog]
293 299 > data.generations=60
294 300 > 150
295 301 > EOF
296 302
297 303 Single pack - repack does nothing
298 304 $ hg prefetch -r 0
299 305 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
300 306 $ ls_l $TESTTMP/hgcache/master/packs/ | grep datapack
301 307 [1]
302 308 $ ls_l $TESTTMP/hgcache/master/packs/ | grep histpack
303 309 [1]
304 310 $ hg repack --incremental
305 311 $ ls_l $TESTTMP/hgcache/master/packs/ | grep datapack
306 312 -r--r--r-- 70 052643fdcdebbd42d7c180a651a30d46098e6fe1.datapack
307 313 $ ls_l $TESTTMP/hgcache/master/packs/ | grep histpack
308 314 -r--r--r-- 90 955a622173324b2d8b53e1147f209f1cf125302e.histpack
309 315
310 316 3 gen1 packs, 1 gen0 pack - packs 3 gen1 into 1
311 317 $ hg prefetch -r 1
312 318 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
313 319 $ hg prefetch -r 2
314 320 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
315 321 $ hg prefetch -r 38
316 322 abort: unknown revision '38'!
317 323 [255]
318 324 $ ls_l $TESTTMP/hgcache/master/packs/ | grep datapack
319 325 -r--r--r-- 70 052643fdcdebbd42d7c180a651a30d46098e6fe1.datapack
320 326 $ ls_l $TESTTMP/hgcache/master/packs/ | grep histpack
321 327 -r--r--r-- 90 955a622173324b2d8b53e1147f209f1cf125302e.histpack
322 328
323 329 For the data packs, setting the limit for the repackmaxpacksize to be 64 such
324 330 that data pack with size 65 is more than the limit. This effectively ensures
325 331 that no generation has 3 packs and therefore, no packs are chosen for the
326 332 incremental repacking. As for the history packs, setting repackmaxpacksize to be
327 333 0 which should always result in no repacking.
328 334 $ hg repack --incremental --config remotefilelog.data.repackmaxpacksize=64 \
329 335 > --config remotefilelog.history.repackmaxpacksize=0
330 336 $ ls_l $TESTTMP/hgcache/master/packs/ | grep datapack
331 337 -r--r--r-- 70 052643fdcdebbd42d7c180a651a30d46098e6fe1.datapack
332 338 -r--r--r-- 149 78840d69389c7404327f7477e3931c89945c37d1.datapack
333 339 $ ls_l $TESTTMP/hgcache/master/packs/ | grep histpack
334 340 -r--r--r-- 254 8abe7889aae389337d12ebe6085d4ee13854c7c9.histpack
335 341 -r--r--r-- 90 955a622173324b2d8b53e1147f209f1cf125302e.histpack
336 342
337 343 Setting limit for the repackmaxpacksize to be the size of the biggest pack file
338 344 which ensures that it is effectively ignored in the incremental repacking.
339 345 $ hg repack --incremental --config remotefilelog.data.repackmaxpacksize=65 \
340 346 > --config remotefilelog.history.repackmaxpacksize=336
341 347 $ ls_l $TESTTMP/hgcache/master/packs/ | grep datapack
342 348 -r--r--r-- 70 052643fdcdebbd42d7c180a651a30d46098e6fe1.datapack
343 349 -r--r--r-- 149 78840d69389c7404327f7477e3931c89945c37d1.datapack
344 350 $ ls_l $TESTTMP/hgcache/master/packs/ | grep histpack
345 351 -r--r--r-- 254 8abe7889aae389337d12ebe6085d4ee13854c7c9.histpack
346 352 -r--r--r-- 90 955a622173324b2d8b53e1147f209f1cf125302e.histpack
347 353
348 354 1 gen3 pack, 1 gen0 pack - does nothing
349 355 $ hg repack --incremental
350 356 $ ls_l $TESTTMP/hgcache/master/packs/ | grep datapack
351 357 -r--r--r-- 70 052643fdcdebbd42d7c180a651a30d46098e6fe1.datapack
352 358 -r--r--r-- 149 78840d69389c7404327f7477e3931c89945c37d1.datapack
353 359 $ ls_l $TESTTMP/hgcache/master/packs/ | grep histpack
354 360 -r--r--r-- 254 8abe7889aae389337d12ebe6085d4ee13854c7c9.histpack
355 361 -r--r--r-- 90 955a622173324b2d8b53e1147f209f1cf125302e.histpack
356 362
357 363 Pull should run background repack
358 364 $ cat >> .hg/hgrc <<EOF
359 365 > [remotefilelog]
360 366 > backgroundrepack=True
361 367 > EOF
362 368 $ clearcache
363 369 $ hg prefetch -r 0
364 370 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
365 371 $ hg prefetch -r 1
366 372 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
367 373 $ hg prefetch -r 2
368 374 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
369 375 $ hg prefetch -r 3
370 376 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
371 377
372 378 $ hg pull
373 379 pulling from ssh://user@dummy/master
374 380 searching for changes
375 381 no changes found
376 382 (running background incremental repack)
377 383 $ sleep 0.5
378 384 $ hg debugwaitonrepack >/dev/null 2>&1
379 385 $ ls_l $TESTTMP/hgcache/master/packs/ | grep datapack
380 386 -r--r--r-- 303 156a6c1c83aeb69422d7936e0a46ba9bc06a71c0.datapack
381 387 $ ls_l $TESTTMP/hgcache/master/packs/ | grep histpack
382 388 -r--r--r-- 336 604552d403a1381749faf656feca0ca265a6d52c.histpack
383 389
384 390 Test environment variable resolution
385 391 $ CACHEPATH=$TESTTMP/envcache hg prefetch --config 'remotefilelog.cachepath=$CACHEPATH'
386 392 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
387 393 $ find $TESTTMP/envcache | sort
388 394 $TESTTMP/envcache
389 395 $TESTTMP/envcache/master
390 396 $TESTTMP/envcache/master/95
391 397 $TESTTMP/envcache/master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a
392 398 $TESTTMP/envcache/master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/577959738234a1eb241ed3ed4b22a575833f56e0
393 399 $TESTTMP/envcache/repos
394 400
395 401 Test local remotefilelog blob is correct when based on a pack
396 402 $ hg prefetch -r .
397 403 1 files fetched over 1 fetches - (1 misses, 0.00% hit ratio) over * (glob)
398 404 $ echo >> y
399 405 $ hg commit -m y2
400 406 $ hg debugremotefilelog .hg/store/data/95cb0bfd2977c761298d9624e4b4d4c72a39974a/b70860edba4f8242a1d52f2a94679dd23cb76808
401 407 size: 9 bytes
402 408 path: .hg/store/data/95cb0bfd2977c761298d9624e4b4d4c72a39974a/b70860edba4f8242a1d52f2a94679dd23cb76808
403 409 key: b70860edba4f
404 410
405 411 node => p1 p2 linknode copyfrom
406 412 b70860edba4f => 577959738234 000000000000 08d3fbc98c48
407 413 577959738234 => 1bb2e6237e03 000000000000 c7faf2fc439a x
408 414 1bb2e6237e03 => d4a3ed9310e5 000000000000 0b03bbc9e1e7
409 415 d4a3ed9310e5 => aee31534993a 000000000000 421535db10b6
410 416 aee31534993a => 1406e7411862 000000000000 a89d614e2364
411 417 1406e7411862 => 000000000000 000000000000 b292c1e3311f
412 418
413 419 Test limiting the max delta chain length
414 420 $ hg repack --config packs.maxchainlen=1
415 421 $ hg debugdatapack $TESTTMP/hgcache/master/packs/*.dataidx
416 422 $TESTTMP/hgcache/master/packs/f258af4c033dd5cd32b4dbc42a1efcd8e4c7d909:
417 423 x:
418 424 Node Delta Base Delta Length Blob Size
419 425 1bb2e6237e03 000000000000 8 8
420 426 d4a3ed9310e5 1bb2e6237e03 12 6
421 427 aee31534993a 000000000000 4 4
422 428 1406e7411862 aee31534993a 12 2
423 429
424 430 Total: 36 20 (80.0% bigger)
425 431 y:
426 432 Node Delta Base Delta Length Blob Size
427 433 577959738234 000000000000 70 8
428 434
429 435 Total: 70 8 (775.0% bigger)
430 436
431 437 Test huge pack cleanup using different values of packs.maxpacksize:
432 438 $ hg repack --incremental --debug
433 439 $ hg repack --incremental --debug --config packs.maxpacksize=512
434 440 removing oversize packfile $TESTTMP/hgcache/master/packs/f258af4c033dd5cd32b4dbc42a1efcd8e4c7d909.datapack (425 bytes)
435 441 removing oversize packfile $TESTTMP/hgcache/master/packs/f258af4c033dd5cd32b4dbc42a1efcd8e4c7d909.dataidx (1.21 KB)
436 442
437 443 Do a repack where the new pack reuses a delta from the old pack
438 444 $ clearcache
439 445 $ hg prefetch -r '2::3'
440 446 2 files fetched over 1 fetches - (2 misses, 0.00% hit ratio) over * (glob)
441 447 $ hg repack
442 448 $ hg debugdatapack $CACHEDIR/master/packs/*.datapack
443 449 $TESTTMP/hgcache/master/packs/9ec6b30891bd851320acb7c66b69a2bdf41c8df3:
444 450 x:
445 451 Node Delta Base Delta Length Blob Size
446 452 1bb2e6237e03 000000000000 8 8
447 453 d4a3ed9310e5 1bb2e6237e03 12 6
448 454
449 455 Total: 20 14 (42.9% bigger)
450 456 $ hg prefetch -r '0::1'
451 457 2 files fetched over 1 fetches - (2 misses, 0.00% hit ratio) over * (glob)
452 458 $ hg repack
453 459 $ hg debugdatapack $CACHEDIR/master/packs/*.datapack
454 460 $TESTTMP/hgcache/master/packs/156a6c1c83aeb69422d7936e0a46ba9bc06a71c0:
455 461 x:
456 462 Node Delta Base Delta Length Blob Size
457 463 1bb2e6237e03 000000000000 8 8
458 464 d4a3ed9310e5 1bb2e6237e03 12 6
459 465 aee31534993a d4a3ed9310e5 12 4
460 466 1406e7411862 aee31534993a 12 2
461 467
462 468 Total: 44 20 (120.0% bigger)
General Comments 0
You need to be logged in to leave comments. Login now