##// END OF EJS Templates
engine: refactor how total dstsize is calculated...
Pulkit Goyal -
r46831:5dfa837d default
parent child Browse files
Show More
@@ -1,548 +1,543 b''
1 # upgrade.py - functions for in place upgrade of Mercurial repository
1 # upgrade.py - functions for in place upgrade of Mercurial repository
2 #
2 #
3 # Copyright (c) 2016-present, Gregory Szorc
3 # Copyright (c) 2016-present, Gregory Szorc
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import stat
10 import stat
11
11
12 from ..i18n import _
12 from ..i18n import _
13 from ..pycompat import getattr
13 from ..pycompat import getattr
14 from .. import (
14 from .. import (
15 changelog,
15 changelog,
16 error,
16 error,
17 filelog,
17 filelog,
18 manifest,
18 manifest,
19 metadata,
19 metadata,
20 pycompat,
20 pycompat,
21 requirements,
21 requirements,
22 revlog,
22 revlog,
23 scmutil,
23 scmutil,
24 util,
24 util,
25 vfs as vfsmod,
25 vfs as vfsmod,
26 )
26 )
27
27
28
28
29 def _revlogfrompath(repo, path):
29 def _revlogfrompath(repo, path):
30 """Obtain a revlog from a repo path.
30 """Obtain a revlog from a repo path.
31
31
32 An instance of the appropriate class is returned.
32 An instance of the appropriate class is returned.
33 """
33 """
34 if path == b'00changelog.i':
34 if path == b'00changelog.i':
35 return changelog.changelog(repo.svfs)
35 return changelog.changelog(repo.svfs)
36 elif path.endswith(b'00manifest.i'):
36 elif path.endswith(b'00manifest.i'):
37 mandir = path[: -len(b'00manifest.i')]
37 mandir = path[: -len(b'00manifest.i')]
38 return manifest.manifestrevlog(repo.svfs, tree=mandir)
38 return manifest.manifestrevlog(repo.svfs, tree=mandir)
39 else:
39 else:
40 # reverse of "/".join(("data", path + ".i"))
40 # reverse of "/".join(("data", path + ".i"))
41 return filelog.filelog(repo.svfs, path[5:-2])
41 return filelog.filelog(repo.svfs, path[5:-2])
42
42
43
43
44 def _copyrevlog(tr, destrepo, oldrl, unencodedname):
44 def _copyrevlog(tr, destrepo, oldrl, unencodedname):
45 """copy all relevant files for `oldrl` into `destrepo` store
45 """copy all relevant files for `oldrl` into `destrepo` store
46
46
47 Files are copied "as is" without any transformation. The copy is performed
47 Files are copied "as is" without any transformation. The copy is performed
48 without extra checks. Callers are responsible for making sure the copied
48 without extra checks. Callers are responsible for making sure the copied
49 content is compatible with format of the destination repository.
49 content is compatible with format of the destination repository.
50 """
50 """
51 oldrl = getattr(oldrl, '_revlog', oldrl)
51 oldrl = getattr(oldrl, '_revlog', oldrl)
52 newrl = _revlogfrompath(destrepo, unencodedname)
52 newrl = _revlogfrompath(destrepo, unencodedname)
53 newrl = getattr(newrl, '_revlog', newrl)
53 newrl = getattr(newrl, '_revlog', newrl)
54
54
55 oldvfs = oldrl.opener
55 oldvfs = oldrl.opener
56 newvfs = newrl.opener
56 newvfs = newrl.opener
57 oldindex = oldvfs.join(oldrl.indexfile)
57 oldindex = oldvfs.join(oldrl.indexfile)
58 newindex = newvfs.join(newrl.indexfile)
58 newindex = newvfs.join(newrl.indexfile)
59 olddata = oldvfs.join(oldrl.datafile)
59 olddata = oldvfs.join(oldrl.datafile)
60 newdata = newvfs.join(newrl.datafile)
60 newdata = newvfs.join(newrl.datafile)
61
61
62 with newvfs(newrl.indexfile, b'w'):
62 with newvfs(newrl.indexfile, b'w'):
63 pass # create all the directories
63 pass # create all the directories
64
64
65 util.copyfile(oldindex, newindex)
65 util.copyfile(oldindex, newindex)
66 copydata = oldrl.opener.exists(oldrl.datafile)
66 copydata = oldrl.opener.exists(oldrl.datafile)
67 if copydata:
67 if copydata:
68 util.copyfile(olddata, newdata)
68 util.copyfile(olddata, newdata)
69
69
70 if not (
70 if not (
71 unencodedname.endswith(b'00changelog.i')
71 unencodedname.endswith(b'00changelog.i')
72 or unencodedname.endswith(b'00manifest.i')
72 or unencodedname.endswith(b'00manifest.i')
73 ):
73 ):
74 destrepo.svfs.fncache.add(unencodedname)
74 destrepo.svfs.fncache.add(unencodedname)
75 if copydata:
75 if copydata:
76 destrepo.svfs.fncache.add(unencodedname[:-2] + b'.d')
76 destrepo.svfs.fncache.add(unencodedname[:-2] + b'.d')
77
77
78
78
79 UPGRADE_CHANGELOG = b"changelog"
79 UPGRADE_CHANGELOG = b"changelog"
80 UPGRADE_MANIFEST = b"manifest"
80 UPGRADE_MANIFEST = b"manifest"
81 UPGRADE_FILELOGS = b"all-filelogs"
81 UPGRADE_FILELOGS = b"all-filelogs"
82
82
83 UPGRADE_ALL_REVLOGS = frozenset(
83 UPGRADE_ALL_REVLOGS = frozenset(
84 [UPGRADE_CHANGELOG, UPGRADE_MANIFEST, UPGRADE_FILELOGS]
84 [UPGRADE_CHANGELOG, UPGRADE_MANIFEST, UPGRADE_FILELOGS]
85 )
85 )
86
86
87
87
88 def getsidedatacompanion(srcrepo, dstrepo):
88 def getsidedatacompanion(srcrepo, dstrepo):
89 sidedatacompanion = None
89 sidedatacompanion = None
90 removedreqs = srcrepo.requirements - dstrepo.requirements
90 removedreqs = srcrepo.requirements - dstrepo.requirements
91 addedreqs = dstrepo.requirements - srcrepo.requirements
91 addedreqs = dstrepo.requirements - srcrepo.requirements
92 if requirements.SIDEDATA_REQUIREMENT in removedreqs:
92 if requirements.SIDEDATA_REQUIREMENT in removedreqs:
93
93
94 def sidedatacompanion(rl, rev):
94 def sidedatacompanion(rl, rev):
95 rl = getattr(rl, '_revlog', rl)
95 rl = getattr(rl, '_revlog', rl)
96 if rl.flags(rev) & revlog.REVIDX_SIDEDATA:
96 if rl.flags(rev) & revlog.REVIDX_SIDEDATA:
97 return True, (), {}, 0, 0
97 return True, (), {}, 0, 0
98 return False, (), {}, 0, 0
98 return False, (), {}, 0, 0
99
99
100 elif requirements.COPIESSDC_REQUIREMENT in addedreqs:
100 elif requirements.COPIESSDC_REQUIREMENT in addedreqs:
101 sidedatacompanion = metadata.getsidedataadder(srcrepo, dstrepo)
101 sidedatacompanion = metadata.getsidedataadder(srcrepo, dstrepo)
102 elif requirements.COPIESSDC_REQUIREMENT in removedreqs:
102 elif requirements.COPIESSDC_REQUIREMENT in removedreqs:
103 sidedatacompanion = metadata.getsidedataremover(srcrepo, dstrepo)
103 sidedatacompanion = metadata.getsidedataremover(srcrepo, dstrepo)
104 return sidedatacompanion
104 return sidedatacompanion
105
105
106
106
107 def matchrevlog(revlogfilter, entry):
107 def matchrevlog(revlogfilter, entry):
108 """check if a revlog is selected for cloning.
108 """check if a revlog is selected for cloning.
109
109
110 In other words, are there any updates which need to be done on revlog
110 In other words, are there any updates which need to be done on revlog
111 or it can be blindly copied.
111 or it can be blindly copied.
112
112
113 The store entry is checked against the passed filter"""
113 The store entry is checked against the passed filter"""
114 if entry.endswith(b'00changelog.i'):
114 if entry.endswith(b'00changelog.i'):
115 return UPGRADE_CHANGELOG in revlogfilter
115 return UPGRADE_CHANGELOG in revlogfilter
116 elif entry.endswith(b'00manifest.i'):
116 elif entry.endswith(b'00manifest.i'):
117 return UPGRADE_MANIFEST in revlogfilter
117 return UPGRADE_MANIFEST in revlogfilter
118 return UPGRADE_FILELOGS in revlogfilter
118 return UPGRADE_FILELOGS in revlogfilter
119
119
120
120
121 def _perform_clone(
121 def _perform_clone(
122 ui,
122 ui,
123 dstrepo,
123 dstrepo,
124 tr,
124 tr,
125 old_revlog,
125 old_revlog,
126 unencoded,
126 unencoded,
127 deltareuse,
127 deltareuse,
128 forcedeltabothparents,
128 forcedeltabothparents,
129 revlogs,
129 revlogs,
130 sidedatacompanion,
130 sidedatacompanion,
131 oncopiedrevision,
131 oncopiedrevision,
132 ):
132 ):
133 """ returns the new revlog object created"""
133 """ returns the new revlog object created"""
134 newrl = None
134 newrl = None
135 if matchrevlog(revlogs, unencoded):
135 if matchrevlog(revlogs, unencoded):
136 ui.note(
136 ui.note(
137 _(b'cloning %d revisions from %s\n') % (len(old_revlog), unencoded)
137 _(b'cloning %d revisions from %s\n') % (len(old_revlog), unencoded)
138 )
138 )
139 newrl = _revlogfrompath(dstrepo, unencoded)
139 newrl = _revlogfrompath(dstrepo, unencoded)
140 old_revlog.clone(
140 old_revlog.clone(
141 tr,
141 tr,
142 newrl,
142 newrl,
143 addrevisioncb=oncopiedrevision,
143 addrevisioncb=oncopiedrevision,
144 deltareuse=deltareuse,
144 deltareuse=deltareuse,
145 forcedeltabothparents=forcedeltabothparents,
145 forcedeltabothparents=forcedeltabothparents,
146 sidedatacompanion=sidedatacompanion,
146 sidedatacompanion=sidedatacompanion,
147 )
147 )
148 else:
148 else:
149 msg = _(b'blindly copying %s containing %i revisions\n')
149 msg = _(b'blindly copying %s containing %i revisions\n')
150 ui.note(msg % (unencoded, len(old_revlog)))
150 ui.note(msg % (unencoded, len(old_revlog)))
151 _copyrevlog(tr, dstrepo, old_revlog, unencoded)
151 _copyrevlog(tr, dstrepo, old_revlog, unencoded)
152
152
153 newrl = _revlogfrompath(dstrepo, unencoded)
153 newrl = _revlogfrompath(dstrepo, unencoded)
154 return newrl
154 return newrl
155
155
156
156
157 def _clonerevlogs(
157 def _clonerevlogs(
158 ui,
158 ui,
159 srcrepo,
159 srcrepo,
160 dstrepo,
160 dstrepo,
161 tr,
161 tr,
162 deltareuse,
162 deltareuse,
163 forcedeltabothparents,
163 forcedeltabothparents,
164 revlogs=UPGRADE_ALL_REVLOGS,
164 revlogs=UPGRADE_ALL_REVLOGS,
165 ):
165 ):
166 """Copy revlogs between 2 repos."""
166 """Copy revlogs between 2 repos."""
167 revcount = 0
167 revcount = 0
168 srcsize = 0
168 srcsize = 0
169 srcrawsize = 0
169 srcrawsize = 0
170 dstsize = 0
170 dstsize = 0
171 fcount = 0
171 fcount = 0
172 frevcount = 0
172 frevcount = 0
173 fsrcsize = 0
173 fsrcsize = 0
174 frawsize = 0
174 frawsize = 0
175 fdstsize = 0
175 fdstsize = 0
176 mcount = 0
176 mcount = 0
177 mrevcount = 0
177 mrevcount = 0
178 msrcsize = 0
178 msrcsize = 0
179 mrawsize = 0
179 mrawsize = 0
180 mdstsize = 0
180 mdstsize = 0
181 crevcount = 0
181 crevcount = 0
182 csrcsize = 0
182 csrcsize = 0
183 crawsize = 0
183 crawsize = 0
184 cdstsize = 0
184 cdstsize = 0
185
185
186 alldatafiles = list(srcrepo.store.walk())
186 alldatafiles = list(srcrepo.store.walk())
187 # mapping of data files which needs to be cloned
187 # mapping of data files which needs to be cloned
188 # key is unencoded filename
188 # key is unencoded filename
189 # value is revlog_object_from_srcrepo
189 # value is revlog_object_from_srcrepo
190 manifests = {}
190 manifests = {}
191 changelogs = {}
191 changelogs = {}
192 filelogs = {}
192 filelogs = {}
193
193
194 # Perform a pass to collect metadata. This validates we can open all
194 # Perform a pass to collect metadata. This validates we can open all
195 # source files and allows a unified progress bar to be displayed.
195 # source files and allows a unified progress bar to be displayed.
196 for unencoded, encoded, size in alldatafiles:
196 for unencoded, encoded, size in alldatafiles:
197 if unencoded.endswith(b'.d'):
197 if unencoded.endswith(b'.d'):
198 continue
198 continue
199
199
200 rl = _revlogfrompath(srcrepo, unencoded)
200 rl = _revlogfrompath(srcrepo, unencoded)
201
201
202 info = rl.storageinfo(
202 info = rl.storageinfo(
203 exclusivefiles=True,
203 exclusivefiles=True,
204 revisionscount=True,
204 revisionscount=True,
205 trackedsize=True,
205 trackedsize=True,
206 storedsize=True,
206 storedsize=True,
207 )
207 )
208
208
209 revcount += info[b'revisionscount'] or 0
209 revcount += info[b'revisionscount'] or 0
210 datasize = info[b'storedsize'] or 0
210 datasize = info[b'storedsize'] or 0
211 rawsize = info[b'trackedsize'] or 0
211 rawsize = info[b'trackedsize'] or 0
212
212
213 srcsize += datasize
213 srcsize += datasize
214 srcrawsize += rawsize
214 srcrawsize += rawsize
215
215
216 # This is for the separate progress bars.
216 # This is for the separate progress bars.
217 if isinstance(rl, changelog.changelog):
217 if isinstance(rl, changelog.changelog):
218 changelogs[unencoded] = rl
218 changelogs[unencoded] = rl
219 crevcount += len(rl)
219 crevcount += len(rl)
220 csrcsize += datasize
220 csrcsize += datasize
221 crawsize += rawsize
221 crawsize += rawsize
222 elif isinstance(rl, manifest.manifestrevlog):
222 elif isinstance(rl, manifest.manifestrevlog):
223 manifests[unencoded] = rl
223 manifests[unencoded] = rl
224 mcount += 1
224 mcount += 1
225 mrevcount += len(rl)
225 mrevcount += len(rl)
226 msrcsize += datasize
226 msrcsize += datasize
227 mrawsize += rawsize
227 mrawsize += rawsize
228 elif isinstance(rl, filelog.filelog):
228 elif isinstance(rl, filelog.filelog):
229 filelogs[unencoded] = rl
229 filelogs[unencoded] = rl
230 fcount += 1
230 fcount += 1
231 frevcount += len(rl)
231 frevcount += len(rl)
232 fsrcsize += datasize
232 fsrcsize += datasize
233 frawsize += rawsize
233 frawsize += rawsize
234 else:
234 else:
235 error.ProgrammingError(b'unknown revlog type')
235 error.ProgrammingError(b'unknown revlog type')
236
236
237 if not revcount:
237 if not revcount:
238 return
238 return
239
239
240 ui.status(
240 ui.status(
241 _(
241 _(
242 b'migrating %d total revisions (%d in filelogs, %d in manifests, '
242 b'migrating %d total revisions (%d in filelogs, %d in manifests, '
243 b'%d in changelog)\n'
243 b'%d in changelog)\n'
244 )
244 )
245 % (revcount, frevcount, mrevcount, crevcount)
245 % (revcount, frevcount, mrevcount, crevcount)
246 )
246 )
247 ui.status(
247 ui.status(
248 _(b'migrating %s in store; %s tracked data\n')
248 _(b'migrating %s in store; %s tracked data\n')
249 % ((util.bytecount(srcsize), util.bytecount(srcrawsize)))
249 % ((util.bytecount(srcsize), util.bytecount(srcrawsize)))
250 )
250 )
251
251
252 # Used to keep track of progress.
252 # Used to keep track of progress.
253 progress = None
253 progress = None
254
254
255 def oncopiedrevision(rl, rev, node):
255 def oncopiedrevision(rl, rev, node):
256 progress.increment()
256 progress.increment()
257
257
258 sidedatacompanion = getsidedatacompanion(srcrepo, dstrepo)
258 sidedatacompanion = getsidedatacompanion(srcrepo, dstrepo)
259
259
260 # Migrating filelogs
260 # Migrating filelogs
261 ui.status(
261 ui.status(
262 _(
262 _(
263 b'migrating %d filelogs containing %d revisions '
263 b'migrating %d filelogs containing %d revisions '
264 b'(%s in store; %s tracked data)\n'
264 b'(%s in store; %s tracked data)\n'
265 )
265 )
266 % (
266 % (
267 fcount,
267 fcount,
268 frevcount,
268 frevcount,
269 util.bytecount(fsrcsize),
269 util.bytecount(fsrcsize),
270 util.bytecount(frawsize),
270 util.bytecount(frawsize),
271 )
271 )
272 )
272 )
273 progress = srcrepo.ui.makeprogress(_(b'file revisions'), total=frevcount)
273 progress = srcrepo.ui.makeprogress(_(b'file revisions'), total=frevcount)
274 for unencoded, oldrl in sorted(filelogs.items()):
274 for unencoded, oldrl in sorted(filelogs.items()):
275 newrl = _perform_clone(
275 newrl = _perform_clone(
276 ui,
276 ui,
277 dstrepo,
277 dstrepo,
278 tr,
278 tr,
279 oldrl,
279 oldrl,
280 unencoded,
280 unencoded,
281 deltareuse,
281 deltareuse,
282 forcedeltabothparents,
282 forcedeltabothparents,
283 revlogs,
283 revlogs,
284 sidedatacompanion,
284 sidedatacompanion,
285 oncopiedrevision,
285 oncopiedrevision,
286 )
286 )
287 info = newrl.storageinfo(storedsize=True)
287 info = newrl.storageinfo(storedsize=True)
288 datasize = info[b'storedsize'] or 0
288 fdstsize += info[b'storedsize'] or 0
289 dstsize += datasize
290 fdstsize += datasize
291 ui.status(
289 ui.status(
292 _(
290 _(
293 b'finished migrating %d filelog revisions across %d '
291 b'finished migrating %d filelog revisions across %d '
294 b'filelogs; change in size: %s\n'
292 b'filelogs; change in size: %s\n'
295 )
293 )
296 % (frevcount, fcount, util.bytecount(fdstsize - fsrcsize))
294 % (frevcount, fcount, util.bytecount(fdstsize - fsrcsize))
297 )
295 )
298
296
299 # Migrating manifests
297 # Migrating manifests
300 ui.status(
298 ui.status(
301 _(
299 _(
302 b'migrating %d manifests containing %d revisions '
300 b'migrating %d manifests containing %d revisions '
303 b'(%s in store; %s tracked data)\n'
301 b'(%s in store; %s tracked data)\n'
304 )
302 )
305 % (
303 % (
306 mcount,
304 mcount,
307 mrevcount,
305 mrevcount,
308 util.bytecount(msrcsize),
306 util.bytecount(msrcsize),
309 util.bytecount(mrawsize),
307 util.bytecount(mrawsize),
310 )
308 )
311 )
309 )
312 if progress:
310 if progress:
313 progress.complete()
311 progress.complete()
314 progress = srcrepo.ui.makeprogress(
312 progress = srcrepo.ui.makeprogress(
315 _(b'manifest revisions'), total=mrevcount
313 _(b'manifest revisions'), total=mrevcount
316 )
314 )
317 for unencoded, oldrl in sorted(manifests.items()):
315 for unencoded, oldrl in sorted(manifests.items()):
318 newrl = _perform_clone(
316 newrl = _perform_clone(
319 ui,
317 ui,
320 dstrepo,
318 dstrepo,
321 tr,
319 tr,
322 oldrl,
320 oldrl,
323 unencoded,
321 unencoded,
324 deltareuse,
322 deltareuse,
325 forcedeltabothparents,
323 forcedeltabothparents,
326 revlogs,
324 revlogs,
327 sidedatacompanion,
325 sidedatacompanion,
328 oncopiedrevision,
326 oncopiedrevision,
329 )
327 )
330 info = newrl.storageinfo(storedsize=True)
328 info = newrl.storageinfo(storedsize=True)
331 datasize = info[b'storedsize'] or 0
329 mdstsize += info[b'storedsize'] or 0
332 dstsize += datasize
333 mdstsize += datasize
334 ui.status(
330 ui.status(
335 _(
331 _(
336 b'finished migrating %d manifest revisions across %d '
332 b'finished migrating %d manifest revisions across %d '
337 b'manifests; change in size: %s\n'
333 b'manifests; change in size: %s\n'
338 )
334 )
339 % (mrevcount, mcount, util.bytecount(mdstsize - msrcsize))
335 % (mrevcount, mcount, util.bytecount(mdstsize - msrcsize))
340 )
336 )
341
337
342 # Migrating changelog
338 # Migrating changelog
343 ui.status(
339 ui.status(
344 _(
340 _(
345 b'migrating changelog containing %d revisions '
341 b'migrating changelog containing %d revisions '
346 b'(%s in store; %s tracked data)\n'
342 b'(%s in store; %s tracked data)\n'
347 )
343 )
348 % (
344 % (
349 crevcount,
345 crevcount,
350 util.bytecount(csrcsize),
346 util.bytecount(csrcsize),
351 util.bytecount(crawsize),
347 util.bytecount(crawsize),
352 )
348 )
353 )
349 )
354 if progress:
350 if progress:
355 progress.complete()
351 progress.complete()
356 progress = srcrepo.ui.makeprogress(
352 progress = srcrepo.ui.makeprogress(
357 _(b'changelog revisions'), total=crevcount
353 _(b'changelog revisions'), total=crevcount
358 )
354 )
359 for unencoded, oldrl in sorted(changelogs.items()):
355 for unencoded, oldrl in sorted(changelogs.items()):
360 newrl = _perform_clone(
356 newrl = _perform_clone(
361 ui,
357 ui,
362 dstrepo,
358 dstrepo,
363 tr,
359 tr,
364 oldrl,
360 oldrl,
365 unencoded,
361 unencoded,
366 deltareuse,
362 deltareuse,
367 forcedeltabothparents,
363 forcedeltabothparents,
368 revlogs,
364 revlogs,
369 sidedatacompanion,
365 sidedatacompanion,
370 oncopiedrevision,
366 oncopiedrevision,
371 )
367 )
372 info = newrl.storageinfo(storedsize=True)
368 info = newrl.storageinfo(storedsize=True)
373 datasize = info[b'storedsize'] or 0
369 cdstsize += info[b'storedsize'] or 0
374 dstsize += datasize
375 cdstsize += datasize
376 progress.complete()
370 progress.complete()
377 ui.status(
371 ui.status(
378 _(
372 _(
379 b'finished migrating %d changelog revisions; change in size: '
373 b'finished migrating %d changelog revisions; change in size: '
380 b'%s\n'
374 b'%s\n'
381 )
375 )
382 % (crevcount, util.bytecount(cdstsize - csrcsize))
376 % (crevcount, util.bytecount(cdstsize - csrcsize))
383 )
377 )
384
378
379 dstsize = fdstsize + mdstsize + cdstsize
385 ui.status(
380 ui.status(
386 _(
381 _(
387 b'finished migrating %d total revisions; total change in store '
382 b'finished migrating %d total revisions; total change in store '
388 b'size: %s\n'
383 b'size: %s\n'
389 )
384 )
390 % (revcount, util.bytecount(dstsize - srcsize))
385 % (revcount, util.bytecount(dstsize - srcsize))
391 )
386 )
392
387
393
388
394 def _filterstorefile(srcrepo, dstrepo, requirements, path, mode, st):
389 def _filterstorefile(srcrepo, dstrepo, requirements, path, mode, st):
395 """Determine whether to copy a store file during upgrade.
390 """Determine whether to copy a store file during upgrade.
396
391
397 This function is called when migrating store files from ``srcrepo`` to
392 This function is called when migrating store files from ``srcrepo`` to
398 ``dstrepo`` as part of upgrading a repository.
393 ``dstrepo`` as part of upgrading a repository.
399
394
400 Args:
395 Args:
401 srcrepo: repo we are copying from
396 srcrepo: repo we are copying from
402 dstrepo: repo we are copying to
397 dstrepo: repo we are copying to
403 requirements: set of requirements for ``dstrepo``
398 requirements: set of requirements for ``dstrepo``
404 path: store file being examined
399 path: store file being examined
405 mode: the ``ST_MODE`` file type of ``path``
400 mode: the ``ST_MODE`` file type of ``path``
406 st: ``stat`` data structure for ``path``
401 st: ``stat`` data structure for ``path``
407
402
408 Function should return ``True`` if the file is to be copied.
403 Function should return ``True`` if the file is to be copied.
409 """
404 """
410 # Skip revlogs.
405 # Skip revlogs.
411 if path.endswith((b'.i', b'.d', b'.n', b'.nd')):
406 if path.endswith((b'.i', b'.d', b'.n', b'.nd')):
412 return False
407 return False
413 # Skip transaction related files.
408 # Skip transaction related files.
414 if path.startswith(b'undo'):
409 if path.startswith(b'undo'):
415 return False
410 return False
416 # Only copy regular files.
411 # Only copy regular files.
417 if mode != stat.S_IFREG:
412 if mode != stat.S_IFREG:
418 return False
413 return False
419 # Skip other skipped files.
414 # Skip other skipped files.
420 if path in (b'lock', b'fncache'):
415 if path in (b'lock', b'fncache'):
421 return False
416 return False
422
417
423 return True
418 return True
424
419
425
420
426 def _finishdatamigration(ui, srcrepo, dstrepo, requirements):
421 def _finishdatamigration(ui, srcrepo, dstrepo, requirements):
427 """Hook point for extensions to perform additional actions during upgrade.
422 """Hook point for extensions to perform additional actions during upgrade.
428
423
429 This function is called after revlogs and store files have been copied but
424 This function is called after revlogs and store files have been copied but
430 before the new store is swapped into the original location.
425 before the new store is swapped into the original location.
431 """
426 """
432
427
433
428
434 def upgrade(ui, srcrepo, dstrepo, upgrade_op):
429 def upgrade(ui, srcrepo, dstrepo, upgrade_op):
435 """Do the low-level work of upgrading a repository.
430 """Do the low-level work of upgrading a repository.
436
431
437 The upgrade is effectively performed as a copy between a source
432 The upgrade is effectively performed as a copy between a source
438 repository and a temporary destination repository.
433 repository and a temporary destination repository.
439
434
440 The source repository is unmodified for as long as possible so the
435 The source repository is unmodified for as long as possible so the
441 upgrade can abort at any time without causing loss of service for
436 upgrade can abort at any time without causing loss of service for
442 readers and without corrupting the source repository.
437 readers and without corrupting the source repository.
443 """
438 """
444 assert srcrepo.currentwlock()
439 assert srcrepo.currentwlock()
445 assert dstrepo.currentwlock()
440 assert dstrepo.currentwlock()
446
441
447 ui.status(
442 ui.status(
448 _(
443 _(
449 b'(it is safe to interrupt this process any time before '
444 b'(it is safe to interrupt this process any time before '
450 b'data migration completes)\n'
445 b'data migration completes)\n'
451 )
446 )
452 )
447 )
453
448
454 if upgrade_op.has_upgrade_action(b're-delta-all'):
449 if upgrade_op.has_upgrade_action(b're-delta-all'):
455 deltareuse = revlog.revlog.DELTAREUSENEVER
450 deltareuse = revlog.revlog.DELTAREUSENEVER
456 elif upgrade_op.has_upgrade_action(b're-delta-parent'):
451 elif upgrade_op.has_upgrade_action(b're-delta-parent'):
457 deltareuse = revlog.revlog.DELTAREUSESAMEREVS
452 deltareuse = revlog.revlog.DELTAREUSESAMEREVS
458 elif upgrade_op.has_upgrade_action(b're-delta-multibase'):
453 elif upgrade_op.has_upgrade_action(b're-delta-multibase'):
459 deltareuse = revlog.revlog.DELTAREUSESAMEREVS
454 deltareuse = revlog.revlog.DELTAREUSESAMEREVS
460 elif upgrade_op.has_upgrade_action(b're-delta-fulladd'):
455 elif upgrade_op.has_upgrade_action(b're-delta-fulladd'):
461 deltareuse = revlog.revlog.DELTAREUSEFULLADD
456 deltareuse = revlog.revlog.DELTAREUSEFULLADD
462 else:
457 else:
463 deltareuse = revlog.revlog.DELTAREUSEALWAYS
458 deltareuse = revlog.revlog.DELTAREUSEALWAYS
464
459
465 with dstrepo.transaction(b'upgrade') as tr:
460 with dstrepo.transaction(b'upgrade') as tr:
466 _clonerevlogs(
461 _clonerevlogs(
467 ui,
462 ui,
468 srcrepo,
463 srcrepo,
469 dstrepo,
464 dstrepo,
470 tr,
465 tr,
471 deltareuse,
466 deltareuse,
472 upgrade_op.has_upgrade_action(b're-delta-multibase'),
467 upgrade_op.has_upgrade_action(b're-delta-multibase'),
473 revlogs=upgrade_op.revlogs_to_process,
468 revlogs=upgrade_op.revlogs_to_process,
474 )
469 )
475
470
476 # Now copy other files in the store directory.
471 # Now copy other files in the store directory.
477 # The sorted() makes execution deterministic.
472 # The sorted() makes execution deterministic.
478 for p, kind, st in sorted(srcrepo.store.vfs.readdir(b'', stat=True)):
473 for p, kind, st in sorted(srcrepo.store.vfs.readdir(b'', stat=True)):
479 if not _filterstorefile(
474 if not _filterstorefile(
480 srcrepo, dstrepo, upgrade_op.new_requirements, p, kind, st
475 srcrepo, dstrepo, upgrade_op.new_requirements, p, kind, st
481 ):
476 ):
482 continue
477 continue
483
478
484 srcrepo.ui.status(_(b'copying %s\n') % p)
479 srcrepo.ui.status(_(b'copying %s\n') % p)
485 src = srcrepo.store.rawvfs.join(p)
480 src = srcrepo.store.rawvfs.join(p)
486 dst = dstrepo.store.rawvfs.join(p)
481 dst = dstrepo.store.rawvfs.join(p)
487 util.copyfile(src, dst, copystat=True)
482 util.copyfile(src, dst, copystat=True)
488
483
489 _finishdatamigration(ui, srcrepo, dstrepo, requirements)
484 _finishdatamigration(ui, srcrepo, dstrepo, requirements)
490
485
491 ui.status(_(b'data fully migrated to temporary repository\n'))
486 ui.status(_(b'data fully migrated to temporary repository\n'))
492
487
493 backuppath = pycompat.mkdtemp(prefix=b'upgradebackup.', dir=srcrepo.path)
488 backuppath = pycompat.mkdtemp(prefix=b'upgradebackup.', dir=srcrepo.path)
494 backupvfs = vfsmod.vfs(backuppath)
489 backupvfs = vfsmod.vfs(backuppath)
495
490
496 # Make a backup of requires file first, as it is the first to be modified.
491 # Make a backup of requires file first, as it is the first to be modified.
497 util.copyfile(srcrepo.vfs.join(b'requires'), backupvfs.join(b'requires'))
492 util.copyfile(srcrepo.vfs.join(b'requires'), backupvfs.join(b'requires'))
498
493
499 # We install an arbitrary requirement that clients must not support
494 # We install an arbitrary requirement that clients must not support
500 # as a mechanism to lock out new clients during the data swap. This is
495 # as a mechanism to lock out new clients during the data swap. This is
501 # better than allowing a client to continue while the repository is in
496 # better than allowing a client to continue while the repository is in
502 # an inconsistent state.
497 # an inconsistent state.
503 ui.status(
498 ui.status(
504 _(
499 _(
505 b'marking source repository as being upgraded; clients will be '
500 b'marking source repository as being upgraded; clients will be '
506 b'unable to read from repository\n'
501 b'unable to read from repository\n'
507 )
502 )
508 )
503 )
509 scmutil.writereporequirements(
504 scmutil.writereporequirements(
510 srcrepo, srcrepo.requirements | {b'upgradeinprogress'}
505 srcrepo, srcrepo.requirements | {b'upgradeinprogress'}
511 )
506 )
512
507
513 ui.status(_(b'starting in-place swap of repository data\n'))
508 ui.status(_(b'starting in-place swap of repository data\n'))
514 ui.status(_(b'replaced files will be backed up at %s\n') % backuppath)
509 ui.status(_(b'replaced files will be backed up at %s\n') % backuppath)
515
510
516 # Now swap in the new store directory. Doing it as a rename should make
511 # Now swap in the new store directory. Doing it as a rename should make
517 # the operation nearly instantaneous and atomic (at least in well-behaved
512 # the operation nearly instantaneous and atomic (at least in well-behaved
518 # environments).
513 # environments).
519 ui.status(_(b'replacing store...\n'))
514 ui.status(_(b'replacing store...\n'))
520 tstart = util.timer()
515 tstart = util.timer()
521 util.rename(srcrepo.spath, backupvfs.join(b'store'))
516 util.rename(srcrepo.spath, backupvfs.join(b'store'))
522 util.rename(dstrepo.spath, srcrepo.spath)
517 util.rename(dstrepo.spath, srcrepo.spath)
523 elapsed = util.timer() - tstart
518 elapsed = util.timer() - tstart
524 ui.status(
519 ui.status(
525 _(
520 _(
526 b'store replacement complete; repository was inconsistent for '
521 b'store replacement complete; repository was inconsistent for '
527 b'%0.1fs\n'
522 b'%0.1fs\n'
528 )
523 )
529 % elapsed
524 % elapsed
530 )
525 )
531
526
532 # We first write the requirements file. Any new requirements will lock
527 # We first write the requirements file. Any new requirements will lock
533 # out legacy clients.
528 # out legacy clients.
534 ui.status(
529 ui.status(
535 _(
530 _(
536 b'finalizing requirements file and making repository readable '
531 b'finalizing requirements file and making repository readable '
537 b'again\n'
532 b'again\n'
538 )
533 )
539 )
534 )
540 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
535 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
541
536
542 # The lock file from the old store won't be removed because nothing has a
537 # The lock file from the old store won't be removed because nothing has a
543 # reference to its new location. So clean it up manually. Alternatively, we
538 # reference to its new location. So clean it up manually. Alternatively, we
544 # could update srcrepo.svfs and other variables to point to the new
539 # could update srcrepo.svfs and other variables to point to the new
545 # location. This is simpler.
540 # location. This is simpler.
546 backupvfs.unlink(b'store/lock')
541 backupvfs.unlink(b'store/lock')
547
542
548 return backuppath
543 return backuppath
General Comments 0
You need to be logged in to leave comments. Login now