##// END OF EJS Templates
undo-files: clean existing files up before writing new one...
marmoute -
r51198:92734603 stable
parent child Browse files
Show More
@@ -1,886 +1,891 b''
1 # transaction.py - simple journaling scheme for mercurial
1 # transaction.py - simple journaling scheme for mercurial
2 #
2 #
3 # This transaction scheme is intended to gracefully handle program
3 # This transaction scheme is intended to gracefully handle program
4 # errors and interruptions. More serious failures like system crashes
4 # errors and interruptions. More serious failures like system crashes
5 # can be recovered with an fsck-like tool. As the whole repository is
5 # can be recovered with an fsck-like tool. As the whole repository is
6 # effectively log-structured, this should amount to simply truncating
6 # effectively log-structured, this should amount to simply truncating
7 # anything that isn't referenced in the changelog.
7 # anything that isn't referenced in the changelog.
8 #
8 #
9 # Copyright 2005, 2006 Olivia Mackall <olivia@selenic.com>
9 # Copyright 2005, 2006 Olivia Mackall <olivia@selenic.com>
10 #
10 #
11 # This software may be used and distributed according to the terms of the
11 # This software may be used and distributed according to the terms of the
12 # GNU General Public License version 2 or any later version.
12 # GNU General Public License version 2 or any later version.
13
13
14 import errno
14 import errno
15 import os
15 import os
16
16
17 from .i18n import _
17 from .i18n import _
18 from . import (
18 from . import (
19 error,
19 error,
20 pycompat,
20 pycompat,
21 util,
21 util,
22 )
22 )
23 from .utils import stringutil
23 from .utils import stringutil
24
24
25 version = 2
25 version = 2
26
26
27 GEN_GROUP_ALL = b'all'
27 GEN_GROUP_ALL = b'all'
28 GEN_GROUP_PRE_FINALIZE = b'prefinalize'
28 GEN_GROUP_PRE_FINALIZE = b'prefinalize'
29 GEN_GROUP_POST_FINALIZE = b'postfinalize'
29 GEN_GROUP_POST_FINALIZE = b'postfinalize'
30
30
31
31
32 def active(func):
32 def active(func):
33 def _active(self, *args, **kwds):
33 def _active(self, *args, **kwds):
34 if self._count == 0:
34 if self._count == 0:
35 raise error.ProgrammingError(
35 raise error.ProgrammingError(
36 b'cannot use transaction when it is already committed/aborted'
36 b'cannot use transaction when it is already committed/aborted'
37 )
37 )
38 return func(self, *args, **kwds)
38 return func(self, *args, **kwds)
39
39
40 return _active
40 return _active
41
41
42
42
43 UNDO_BACKUP = b'%s.backupfiles'
43 UNDO_BACKUP = b'%s.backupfiles'
44
44
45 UNDO_FILES_MAY_NEED_CLEANUP = [
45 UNDO_FILES_MAY_NEED_CLEANUP = [
46 (b'plain', b'%s.desc'),
46 (b'plain', b'%s.desc'),
47 # Always delete undo last to make sure we detect that a clean up is needed if
47 # Always delete undo last to make sure we detect that a clean up is needed if
48 # the process is interrupted.
48 # the process is interrupted.
49 (b'store', b'%s'),
49 (b'store', b'%s'),
50 ]
50 ]
51
51
52
52
53 def cleanup_undo_files(report, vfsmap, undo_prefix=b'undo'):
53 def cleanup_undo_files(report, vfsmap, undo_prefix=b'undo'):
54 """remove "undo" files used by the rollback logic
54 """remove "undo" files used by the rollback logic
55
55
56 This is useful to prevent rollback running in situation were it does not
56 This is useful to prevent rollback running in situation were it does not
57 make sense. For example after a strip.
57 make sense. For example after a strip.
58 """
58 """
59 backup_listing = UNDO_BACKUP % undo_prefix
59 backup_listing = UNDO_BACKUP % undo_prefix
60
60
61 backup_entries = []
61 backup_entries = []
62 undo_files = []
62 undo_files = []
63 svfs = vfsmap[b'store']
63 svfs = vfsmap[b'store']
64 try:
64 try:
65 with svfs(backup_listing) as f:
65 with svfs(backup_listing) as f:
66 backup_entries = read_backup_files(report, f)
66 backup_entries = read_backup_files(report, f)
67 except OSError as e:
67 except OSError as e:
68 if e.errno != errno.ENOENT:
68 if e.errno != errno.ENOENT:
69 msg = _(b'could not read %s: %s\n')
69 msg = _(b'could not read %s: %s\n')
70 msg %= (svfs.join(backup_listing), stringutil.forcebytestr(e))
70 msg %= (svfs.join(backup_listing), stringutil.forcebytestr(e))
71 report(msg)
71 report(msg)
72
72
73 for location, f, backup_path, c in backup_entries:
73 for location, f, backup_path, c in backup_entries:
74 if location in vfsmap and backup_path:
74 if location in vfsmap and backup_path:
75 undo_files.append((vfsmap[location], backup_path))
75 undo_files.append((vfsmap[location], backup_path))
76
76
77 undo_files.append((svfs, backup_listing))
77 undo_files.append((svfs, backup_listing))
78 for location, undo_path in UNDO_FILES_MAY_NEED_CLEANUP:
78 for location, undo_path in UNDO_FILES_MAY_NEED_CLEANUP:
79 undo_files.append((vfsmap[location], undo_path % undo_prefix))
79 undo_files.append((vfsmap[location], undo_path % undo_prefix))
80 for undovfs, undofile in undo_files:
80 for undovfs, undofile in undo_files:
81 try:
81 try:
82 undovfs.unlink(undofile)
82 undovfs.unlink(undofile)
83 except OSError as e:
83 except OSError as e:
84 if e.errno != errno.ENOENT:
84 if e.errno != errno.ENOENT:
85 msg = _(b'error removing %s: %s\n')
85 msg = _(b'error removing %s: %s\n')
86 msg %= (undovfs.join(undofile), stringutil.forcebytestr(e))
86 msg %= (undovfs.join(undofile), stringutil.forcebytestr(e))
87 report(msg)
87 report(msg)
88
88
89
89
90 def _playback(
90 def _playback(
91 journal,
91 journal,
92 report,
92 report,
93 opener,
93 opener,
94 vfsmap,
94 vfsmap,
95 entries,
95 entries,
96 backupentries,
96 backupentries,
97 unlink=True,
97 unlink=True,
98 checkambigfiles=None,
98 checkambigfiles=None,
99 ):
99 ):
100 for f, o in sorted(dict(entries).items()):
100 for f, o in sorted(dict(entries).items()):
101 if o or not unlink:
101 if o or not unlink:
102 checkambig = checkambigfiles and (f, b'') in checkambigfiles
102 checkambig = checkambigfiles and (f, b'') in checkambigfiles
103 try:
103 try:
104 fp = opener(f, b'a', checkambig=checkambig)
104 fp = opener(f, b'a', checkambig=checkambig)
105 if fp.tell() < o:
105 if fp.tell() < o:
106 raise error.Abort(
106 raise error.Abort(
107 _(
107 _(
108 b"attempted to truncate %s to %d bytes, but it was "
108 b"attempted to truncate %s to %d bytes, but it was "
109 b"already %d bytes\n"
109 b"already %d bytes\n"
110 )
110 )
111 % (f, o, fp.tell())
111 % (f, o, fp.tell())
112 )
112 )
113 fp.truncate(o)
113 fp.truncate(o)
114 fp.close()
114 fp.close()
115 except IOError:
115 except IOError:
116 report(_(b"failed to truncate %s\n") % f)
116 report(_(b"failed to truncate %s\n") % f)
117 raise
117 raise
118 else:
118 else:
119 try:
119 try:
120 opener.unlink(f)
120 opener.unlink(f)
121 except FileNotFoundError:
121 except FileNotFoundError:
122 pass
122 pass
123
123
124 backupfiles = []
124 backupfiles = []
125 for l, f, b, c in backupentries:
125 for l, f, b, c in backupentries:
126 if l not in vfsmap and c:
126 if l not in vfsmap and c:
127 report(b"couldn't handle %s: unknown cache location %s\n" % (b, l))
127 report(b"couldn't handle %s: unknown cache location %s\n" % (b, l))
128 vfs = vfsmap[l]
128 vfs = vfsmap[l]
129 try:
129 try:
130 if f and b:
130 if f and b:
131 filepath = vfs.join(f)
131 filepath = vfs.join(f)
132 backuppath = vfs.join(b)
132 backuppath = vfs.join(b)
133 checkambig = checkambigfiles and (f, l) in checkambigfiles
133 checkambig = checkambigfiles and (f, l) in checkambigfiles
134 try:
134 try:
135 util.copyfile(backuppath, filepath, checkambig=checkambig)
135 util.copyfile(backuppath, filepath, checkambig=checkambig)
136 backupfiles.append(b)
136 backupfiles.append(b)
137 except IOError as exc:
137 except IOError as exc:
138 e_msg = stringutil.forcebytestr(exc)
138 e_msg = stringutil.forcebytestr(exc)
139 report(_(b"failed to recover %s (%s)\n") % (f, e_msg))
139 report(_(b"failed to recover %s (%s)\n") % (f, e_msg))
140 else:
140 else:
141 target = f or b
141 target = f or b
142 try:
142 try:
143 vfs.unlink(target)
143 vfs.unlink(target)
144 except FileNotFoundError:
144 except FileNotFoundError:
145 pass
145 pass
146 except (IOError, OSError, error.Abort):
146 except (IOError, OSError, error.Abort):
147 if not c:
147 if not c:
148 raise
148 raise
149
149
150 backuppath = b"%s.backupfiles" % journal
150 backuppath = b"%s.backupfiles" % journal
151 if opener.exists(backuppath):
151 if opener.exists(backuppath):
152 opener.unlink(backuppath)
152 opener.unlink(backuppath)
153 opener.unlink(journal)
153 opener.unlink(journal)
154 try:
154 try:
155 for f in backupfiles:
155 for f in backupfiles:
156 if opener.exists(f):
156 if opener.exists(f):
157 opener.unlink(f)
157 opener.unlink(f)
158 except (IOError, OSError, error.Abort):
158 except (IOError, OSError, error.Abort):
159 # only pure backup file remains, it is sage to ignore any error
159 # only pure backup file remains, it is sage to ignore any error
160 pass
160 pass
161
161
162
162
163 class transaction(util.transactional):
163 class transaction(util.transactional):
164 def __init__(
164 def __init__(
165 self,
165 self,
166 report,
166 report,
167 opener,
167 opener,
168 vfsmap,
168 vfsmap,
169 journalname,
169 journalname,
170 undoname=None,
170 undoname=None,
171 after=None,
171 after=None,
172 createmode=None,
172 createmode=None,
173 validator=None,
173 validator=None,
174 releasefn=None,
174 releasefn=None,
175 checkambigfiles=None,
175 checkambigfiles=None,
176 name='<unnamed>',
176 name='<unnamed>',
177 ):
177 ):
178 """Begin a new transaction
178 """Begin a new transaction
179
179
180 Begins a new transaction that allows rolling back writes in the event of
180 Begins a new transaction that allows rolling back writes in the event of
181 an exception.
181 an exception.
182
182
183 * `after`: called after the transaction has been committed
183 * `after`: called after the transaction has been committed
184 * `createmode`: the mode of the journal file that will be created
184 * `createmode`: the mode of the journal file that will be created
185 * `releasefn`: called after releasing (with transaction and result)
185 * `releasefn`: called after releasing (with transaction and result)
186
186
187 `checkambigfiles` is a set of (path, vfs-location) tuples,
187 `checkambigfiles` is a set of (path, vfs-location) tuples,
188 which determine whether file stat ambiguity should be avoided
188 which determine whether file stat ambiguity should be avoided
189 for corresponded files.
189 for corresponded files.
190 """
190 """
191 self._count = 1
191 self._count = 1
192 self._usages = 1
192 self._usages = 1
193 self._report = report
193 self._report = report
194 # a vfs to the store content
194 # a vfs to the store content
195 self._opener = opener
195 self._opener = opener
196 # a map to access file in various {location -> vfs}
196 # a map to access file in various {location -> vfs}
197 vfsmap = vfsmap.copy()
197 vfsmap = vfsmap.copy()
198 vfsmap[b''] = opener # set default value
198 vfsmap[b''] = opener # set default value
199 self._vfsmap = vfsmap
199 self._vfsmap = vfsmap
200 self._after = after
200 self._after = after
201 self._offsetmap = {}
201 self._offsetmap = {}
202 self._newfiles = set()
202 self._newfiles = set()
203 self._journal = journalname
203 self._journal = journalname
204 self._journal_files = []
204 self._journal_files = []
205 self._undoname = undoname
205 self._undoname = undoname
206 self._queue = []
206 self._queue = []
207 # A callback to do something just after releasing transaction.
207 # A callback to do something just after releasing transaction.
208 if releasefn is None:
208 if releasefn is None:
209 releasefn = lambda tr, success: None
209 releasefn = lambda tr, success: None
210 self._releasefn = releasefn
210 self._releasefn = releasefn
211
211
212 self._checkambigfiles = set()
212 self._checkambigfiles = set()
213 if checkambigfiles:
213 if checkambigfiles:
214 self._checkambigfiles.update(checkambigfiles)
214 self._checkambigfiles.update(checkambigfiles)
215
215
216 self._names = [name]
216 self._names = [name]
217
217
218 # A dict dedicated to precisely tracking the changes introduced in the
218 # A dict dedicated to precisely tracking the changes introduced in the
219 # transaction.
219 # transaction.
220 self.changes = {}
220 self.changes = {}
221
221
222 # a dict of arguments to be passed to hooks
222 # a dict of arguments to be passed to hooks
223 self.hookargs = {}
223 self.hookargs = {}
224 self._file = opener.open(self._journal, b"w+")
224 self._file = opener.open(self._journal, b"w+")
225
225
226 # a list of ('location', 'path', 'backuppath', cache) entries.
226 # a list of ('location', 'path', 'backuppath', cache) entries.
227 # - if 'backuppath' is empty, no file existed at backup time
227 # - if 'backuppath' is empty, no file existed at backup time
228 # - if 'path' is empty, this is a temporary transaction file
228 # - if 'path' is empty, this is a temporary transaction file
229 # - if 'location' is not empty, the path is outside main opener reach.
229 # - if 'location' is not empty, the path is outside main opener reach.
230 # use 'location' value as a key in a vfsmap to find the right 'vfs'
230 # use 'location' value as a key in a vfsmap to find the right 'vfs'
231 # (cache is currently unused)
231 # (cache is currently unused)
232 self._backupentries = []
232 self._backupentries = []
233 self._backupmap = {}
233 self._backupmap = {}
234 self._backupjournal = b"%s.backupfiles" % self._journal
234 self._backupjournal = b"%s.backupfiles" % self._journal
235 self._backupsfile = opener.open(self._backupjournal, b'w')
235 self._backupsfile = opener.open(self._backupjournal, b'w')
236 self._backupsfile.write(b'%d\n' % version)
236 self._backupsfile.write(b'%d\n' % version)
237
237
238 if createmode is not None:
238 if createmode is not None:
239 opener.chmod(self._journal, createmode & 0o666)
239 opener.chmod(self._journal, createmode & 0o666)
240 opener.chmod(self._backupjournal, createmode & 0o666)
240 opener.chmod(self._backupjournal, createmode & 0o666)
241
241
242 # hold file generations to be performed on commit
242 # hold file generations to be performed on commit
243 self._filegenerators = {}
243 self._filegenerators = {}
244 # hold callback to write pending data for hooks
244 # hold callback to write pending data for hooks
245 self._pendingcallback = {}
245 self._pendingcallback = {}
246 # True is any pending data have been written ever
246 # True is any pending data have been written ever
247 self._anypending = False
247 self._anypending = False
248 # holds callback to call when writing the transaction
248 # holds callback to call when writing the transaction
249 self._finalizecallback = {}
249 self._finalizecallback = {}
250 # holds callback to call when validating the transaction
250 # holds callback to call when validating the transaction
251 # should raise exception if anything is wrong
251 # should raise exception if anything is wrong
252 self._validatecallback = {}
252 self._validatecallback = {}
253 if validator is not None:
253 if validator is not None:
254 self._validatecallback[b'001-userhooks'] = validator
254 self._validatecallback[b'001-userhooks'] = validator
255 # hold callback for post transaction close
255 # hold callback for post transaction close
256 self._postclosecallback = {}
256 self._postclosecallback = {}
257 # holds callbacks to call during abort
257 # holds callbacks to call during abort
258 self._abortcallback = {}
258 self._abortcallback = {}
259
259
260 def __repr__(self):
260 def __repr__(self):
261 name = '/'.join(self._names)
261 name = '/'.join(self._names)
262 return '<transaction name=%s, count=%d, usages=%d>' % (
262 return '<transaction name=%s, count=%d, usages=%d>' % (
263 name,
263 name,
264 self._count,
264 self._count,
265 self._usages,
265 self._usages,
266 )
266 )
267
267
268 def __del__(self):
268 def __del__(self):
269 if self._journal:
269 if self._journal:
270 self._abort()
270 self._abort()
271
271
272 @property
272 @property
273 def finalized(self):
273 def finalized(self):
274 return self._finalizecallback is None
274 return self._finalizecallback is None
275
275
276 @active
276 @active
277 def startgroup(self):
277 def startgroup(self):
278 """delay registration of file entry
278 """delay registration of file entry
279
279
280 This is used by strip to delay vision of strip offset. The transaction
280 This is used by strip to delay vision of strip offset. The transaction
281 sees either none or all of the strip actions to be done."""
281 sees either none or all of the strip actions to be done."""
282 self._queue.append([])
282 self._queue.append([])
283
283
284 @active
284 @active
285 def endgroup(self):
285 def endgroup(self):
286 """apply delayed registration of file entry.
286 """apply delayed registration of file entry.
287
287
288 This is used by strip to delay vision of strip offset. The transaction
288 This is used by strip to delay vision of strip offset. The transaction
289 sees either none or all of the strip actions to be done."""
289 sees either none or all of the strip actions to be done."""
290 q = self._queue.pop()
290 q = self._queue.pop()
291 for f, o in q:
291 for f, o in q:
292 self._addentry(f, o)
292 self._addentry(f, o)
293
293
294 @active
294 @active
295 def add(self, file, offset):
295 def add(self, file, offset):
296 """record the state of an append-only file before update"""
296 """record the state of an append-only file before update"""
297 if (
297 if (
298 file in self._newfiles
298 file in self._newfiles
299 or file in self._offsetmap
299 or file in self._offsetmap
300 or file in self._backupmap
300 or file in self._backupmap
301 ):
301 ):
302 return
302 return
303 if self._queue:
303 if self._queue:
304 self._queue[-1].append((file, offset))
304 self._queue[-1].append((file, offset))
305 return
305 return
306
306
307 self._addentry(file, offset)
307 self._addentry(file, offset)
308
308
309 def _addentry(self, file, offset):
309 def _addentry(self, file, offset):
310 """add a append-only entry to memory and on-disk state"""
310 """add a append-only entry to memory and on-disk state"""
311 if (
311 if (
312 file in self._newfiles
312 file in self._newfiles
313 or file in self._offsetmap
313 or file in self._offsetmap
314 or file in self._backupmap
314 or file in self._backupmap
315 ):
315 ):
316 return
316 return
317 if offset:
317 if offset:
318 self._offsetmap[file] = offset
318 self._offsetmap[file] = offset
319 else:
319 else:
320 self._newfiles.add(file)
320 self._newfiles.add(file)
321 # add enough data to the journal to do the truncate
321 # add enough data to the journal to do the truncate
322 self._file.write(b"%s\0%d\n" % (file, offset))
322 self._file.write(b"%s\0%d\n" % (file, offset))
323 self._file.flush()
323 self._file.flush()
324
324
325 @active
325 @active
326 def addbackup(self, file, hardlink=True, location=b''):
326 def addbackup(self, file, hardlink=True, location=b''):
327 """Adds a backup of the file to the transaction
327 """Adds a backup of the file to the transaction
328
328
329 Calling addbackup() creates a hardlink backup of the specified file
329 Calling addbackup() creates a hardlink backup of the specified file
330 that is used to recover the file in the event of the transaction
330 that is used to recover the file in the event of the transaction
331 aborting.
331 aborting.
332
332
333 * `file`: the file path, relative to .hg/store
333 * `file`: the file path, relative to .hg/store
334 * `hardlink`: use a hardlink to quickly create the backup
334 * `hardlink`: use a hardlink to quickly create the backup
335 """
335 """
336 if self._queue:
336 if self._queue:
337 msg = b'cannot use transaction.addbackup inside "group"'
337 msg = b'cannot use transaction.addbackup inside "group"'
338 raise error.ProgrammingError(msg)
338 raise error.ProgrammingError(msg)
339
339
340 if (
340 if (
341 file in self._newfiles
341 file in self._newfiles
342 or file in self._offsetmap
342 or file in self._offsetmap
343 or file in self._backupmap
343 or file in self._backupmap
344 ):
344 ):
345 return
345 return
346 vfs = self._vfsmap[location]
346 vfs = self._vfsmap[location]
347 dirname, filename = vfs.split(file)
347 dirname, filename = vfs.split(file)
348 backupfilename = b"%s.backup.%s" % (self._journal, filename)
348 backupfilename = b"%s.backup.%s" % (self._journal, filename)
349 backupfile = vfs.reljoin(dirname, backupfilename)
349 backupfile = vfs.reljoin(dirname, backupfilename)
350 if vfs.exists(file):
350 if vfs.exists(file):
351 filepath = vfs.join(file)
351 filepath = vfs.join(file)
352 backuppath = vfs.join(backupfile)
352 backuppath = vfs.join(backupfile)
353 util.copyfile(filepath, backuppath, hardlink=hardlink)
353 util.copyfile(filepath, backuppath, hardlink=hardlink)
354 else:
354 else:
355 backupfile = b''
355 backupfile = b''
356
356
357 self._addbackupentry((location, file, backupfile, False))
357 self._addbackupentry((location, file, backupfile, False))
358
358
359 def _addbackupentry(self, entry):
359 def _addbackupentry(self, entry):
360 """register a new backup entry and write it to disk"""
360 """register a new backup entry and write it to disk"""
361 self._backupentries.append(entry)
361 self._backupentries.append(entry)
362 self._backupmap[entry[1]] = len(self._backupentries) - 1
362 self._backupmap[entry[1]] = len(self._backupentries) - 1
363 self._backupsfile.write(b"%s\0%s\0%s\0%d\n" % entry)
363 self._backupsfile.write(b"%s\0%s\0%s\0%d\n" % entry)
364 self._backupsfile.flush()
364 self._backupsfile.flush()
365
365
366 @active
366 @active
367 def registertmp(self, tmpfile, location=b''):
367 def registertmp(self, tmpfile, location=b''):
368 """register a temporary transaction file
368 """register a temporary transaction file
369
369
370 Such files will be deleted when the transaction exits (on both
370 Such files will be deleted when the transaction exits (on both
371 failure and success).
371 failure and success).
372 """
372 """
373 self._addbackupentry((location, b'', tmpfile, False))
373 self._addbackupentry((location, b'', tmpfile, False))
374
374
375 @active
375 @active
376 def addfilegenerator(
376 def addfilegenerator(
377 self,
377 self,
378 genid,
378 genid,
379 filenames,
379 filenames,
380 genfunc,
380 genfunc,
381 order=0,
381 order=0,
382 location=b'',
382 location=b'',
383 post_finalize=False,
383 post_finalize=False,
384 ):
384 ):
385 """add a function to generates some files at transaction commit
385 """add a function to generates some files at transaction commit
386
386
387 The `genfunc` argument is a function capable of generating proper
387 The `genfunc` argument is a function capable of generating proper
388 content of each entry in the `filename` tuple.
388 content of each entry in the `filename` tuple.
389
389
390 At transaction close time, `genfunc` will be called with one file
390 At transaction close time, `genfunc` will be called with one file
391 object argument per entries in `filenames`.
391 object argument per entries in `filenames`.
392
392
393 The transaction itself is responsible for the backup, creation and
393 The transaction itself is responsible for the backup, creation and
394 final write of such file.
394 final write of such file.
395
395
396 The `genid` argument is used to ensure the same set of file is only
396 The `genid` argument is used to ensure the same set of file is only
397 generated once. Call to `addfilegenerator` for a `genid` already
397 generated once. Call to `addfilegenerator` for a `genid` already
398 present will overwrite the old entry.
398 present will overwrite the old entry.
399
399
400 The `order` argument may be used to control the order in which multiple
400 The `order` argument may be used to control the order in which multiple
401 generator will be executed.
401 generator will be executed.
402
402
403 The `location` arguments may be used to indicate the files are located
403 The `location` arguments may be used to indicate the files are located
404 outside of the the standard directory for transaction. It should match
404 outside of the the standard directory for transaction. It should match
405 one of the key of the `transaction.vfsmap` dictionary.
405 one of the key of the `transaction.vfsmap` dictionary.
406
406
407 The `post_finalize` argument can be set to `True` for file generation
407 The `post_finalize` argument can be set to `True` for file generation
408 that must be run after the transaction has been finalized.
408 that must be run after the transaction has been finalized.
409 """
409 """
410 # For now, we are unable to do proper backup and restore of custom vfs
410 # For now, we are unable to do proper backup and restore of custom vfs
411 # but for bookmarks that are handled outside this mechanism.
411 # but for bookmarks that are handled outside this mechanism.
412 entry = (order, filenames, genfunc, location, post_finalize)
412 entry = (order, filenames, genfunc, location, post_finalize)
413 self._filegenerators[genid] = entry
413 self._filegenerators[genid] = entry
414
414
415 @active
415 @active
416 def removefilegenerator(self, genid):
416 def removefilegenerator(self, genid):
417 """reverse of addfilegenerator, remove a file generator function"""
417 """reverse of addfilegenerator, remove a file generator function"""
418 if genid in self._filegenerators:
418 if genid in self._filegenerators:
419 del self._filegenerators[genid]
419 del self._filegenerators[genid]
420
420
421 def _generatefiles(self, suffix=b'', group=GEN_GROUP_ALL):
421 def _generatefiles(self, suffix=b'', group=GEN_GROUP_ALL):
422 # write files registered for generation
422 # write files registered for generation
423 any = False
423 any = False
424
424
425 if group == GEN_GROUP_ALL:
425 if group == GEN_GROUP_ALL:
426 skip_post = skip_pre = False
426 skip_post = skip_pre = False
427 else:
427 else:
428 skip_pre = group == GEN_GROUP_POST_FINALIZE
428 skip_pre = group == GEN_GROUP_POST_FINALIZE
429 skip_post = group == GEN_GROUP_PRE_FINALIZE
429 skip_post = group == GEN_GROUP_PRE_FINALIZE
430
430
431 for id, entry in sorted(self._filegenerators.items()):
431 for id, entry in sorted(self._filegenerators.items()):
432 any = True
432 any = True
433 order, filenames, genfunc, location, post_finalize = entry
433 order, filenames, genfunc, location, post_finalize = entry
434
434
435 # for generation at closing, check if it's before or after finalize
435 # for generation at closing, check if it's before or after finalize
436 if skip_post and post_finalize:
436 if skip_post and post_finalize:
437 continue
437 continue
438 elif skip_pre and not post_finalize:
438 elif skip_pre and not post_finalize:
439 continue
439 continue
440
440
441 vfs = self._vfsmap[location]
441 vfs = self._vfsmap[location]
442 files = []
442 files = []
443 try:
443 try:
444 for name in filenames:
444 for name in filenames:
445 name += suffix
445 name += suffix
446 if suffix:
446 if suffix:
447 self.registertmp(name, location=location)
447 self.registertmp(name, location=location)
448 checkambig = False
448 checkambig = False
449 else:
449 else:
450 self.addbackup(name, location=location)
450 self.addbackup(name, location=location)
451 checkambig = (name, location) in self._checkambigfiles
451 checkambig = (name, location) in self._checkambigfiles
452 files.append(
452 files.append(
453 vfs(name, b'w', atomictemp=True, checkambig=checkambig)
453 vfs(name, b'w', atomictemp=True, checkambig=checkambig)
454 )
454 )
455 genfunc(*files)
455 genfunc(*files)
456 for f in files:
456 for f in files:
457 f.close()
457 f.close()
458 # skip discard() loop since we're sure no open file remains
458 # skip discard() loop since we're sure no open file remains
459 del files[:]
459 del files[:]
460 finally:
460 finally:
461 for f in files:
461 for f in files:
462 f.discard()
462 f.discard()
463 return any
463 return any
464
464
465 @active
465 @active
466 def findoffset(self, file):
466 def findoffset(self, file):
467 if file in self._newfiles:
467 if file in self._newfiles:
468 return 0
468 return 0
469 return self._offsetmap.get(file)
469 return self._offsetmap.get(file)
470
470
471 @active
471 @active
472 def readjournal(self):
472 def readjournal(self):
473 self._file.seek(0)
473 self._file.seek(0)
474 entries = []
474 entries = []
475 for l in self._file.readlines():
475 for l in self._file.readlines():
476 file, troffset = l.split(b'\0')
476 file, troffset = l.split(b'\0')
477 entries.append((file, int(troffset)))
477 entries.append((file, int(troffset)))
478 return entries
478 return entries
479
479
480 @active
480 @active
481 def replace(self, file, offset):
481 def replace(self, file, offset):
482 """
482 """
483 replace can only replace already committed entries
483 replace can only replace already committed entries
484 that are not pending in the queue
484 that are not pending in the queue
485 """
485 """
486 if file in self._newfiles:
486 if file in self._newfiles:
487 if not offset:
487 if not offset:
488 return
488 return
489 self._newfiles.remove(file)
489 self._newfiles.remove(file)
490 self._offsetmap[file] = offset
490 self._offsetmap[file] = offset
491 elif file in self._offsetmap:
491 elif file in self._offsetmap:
492 if not offset:
492 if not offset:
493 del self._offsetmap[file]
493 del self._offsetmap[file]
494 self._newfiles.add(file)
494 self._newfiles.add(file)
495 else:
495 else:
496 self._offsetmap[file] = offset
496 self._offsetmap[file] = offset
497 else:
497 else:
498 raise KeyError(file)
498 raise KeyError(file)
499 self._file.write(b"%s\0%d\n" % (file, offset))
499 self._file.write(b"%s\0%d\n" % (file, offset))
500 self._file.flush()
500 self._file.flush()
501
501
502 @active
502 @active
503 def nest(self, name='<unnamed>'):
503 def nest(self, name='<unnamed>'):
504 self._count += 1
504 self._count += 1
505 self._usages += 1
505 self._usages += 1
506 self._names.append(name)
506 self._names.append(name)
507 return self
507 return self
508
508
509 def release(self):
509 def release(self):
510 if self._count > 0:
510 if self._count > 0:
511 self._usages -= 1
511 self._usages -= 1
512 if self._names:
512 if self._names:
513 self._names.pop()
513 self._names.pop()
514 # if the transaction scopes are left without being closed, fail
514 # if the transaction scopes are left without being closed, fail
515 if self._count > 0 and self._usages == 0:
515 if self._count > 0 and self._usages == 0:
516 self._abort()
516 self._abort()
517
517
518 def running(self):
518 def running(self):
519 return self._count > 0
519 return self._count > 0
520
520
521 def addpending(self, category, callback):
521 def addpending(self, category, callback):
522 """add a callback to be called when the transaction is pending
522 """add a callback to be called when the transaction is pending
523
523
524 The transaction will be given as callback's first argument.
524 The transaction will be given as callback's first argument.
525
525
526 Category is a unique identifier to allow overwriting an old callback
526 Category is a unique identifier to allow overwriting an old callback
527 with a newer callback.
527 with a newer callback.
528 """
528 """
529 self._pendingcallback[category] = callback
529 self._pendingcallback[category] = callback
530
530
531 @active
531 @active
532 def writepending(self):
532 def writepending(self):
533 """write pending file to temporary version
533 """write pending file to temporary version
534
534
535 This is used to allow hooks to view a transaction before commit"""
535 This is used to allow hooks to view a transaction before commit"""
536 categories = sorted(self._pendingcallback)
536 categories = sorted(self._pendingcallback)
537 for cat in categories:
537 for cat in categories:
538 # remove callback since the data will have been flushed
538 # remove callback since the data will have been flushed
539 any = self._pendingcallback.pop(cat)(self)
539 any = self._pendingcallback.pop(cat)(self)
540 self._anypending = self._anypending or any
540 self._anypending = self._anypending or any
541 self._anypending |= self._generatefiles(suffix=b'.pending')
541 self._anypending |= self._generatefiles(suffix=b'.pending')
542 return self._anypending
542 return self._anypending
543
543
544 @active
544 @active
545 def hasfinalize(self, category):
545 def hasfinalize(self, category):
546 """check is a callback already exist for a category"""
546 """check is a callback already exist for a category"""
547 return category in self._finalizecallback
547 return category in self._finalizecallback
548
548
549 @active
549 @active
550 def addfinalize(self, category, callback):
550 def addfinalize(self, category, callback):
551 """add a callback to be called when the transaction is closed
551 """add a callback to be called when the transaction is closed
552
552
553 The transaction will be given as callback's first argument.
553 The transaction will be given as callback's first argument.
554
554
555 Category is a unique identifier to allow overwriting old callbacks with
555 Category is a unique identifier to allow overwriting old callbacks with
556 newer callbacks.
556 newer callbacks.
557 """
557 """
558 self._finalizecallback[category] = callback
558 self._finalizecallback[category] = callback
559
559
560 @active
560 @active
561 def addpostclose(self, category, callback):
561 def addpostclose(self, category, callback):
562 """add or replace a callback to be called after the transaction closed
562 """add or replace a callback to be called after the transaction closed
563
563
564 The transaction will be given as callback's first argument.
564 The transaction will be given as callback's first argument.
565
565
566 Category is a unique identifier to allow overwriting an old callback
566 Category is a unique identifier to allow overwriting an old callback
567 with a newer callback.
567 with a newer callback.
568 """
568 """
569 self._postclosecallback[category] = callback
569 self._postclosecallback[category] = callback
570
570
571 @active
571 @active
572 def getpostclose(self, category):
572 def getpostclose(self, category):
573 """return a postclose callback added before, or None"""
573 """return a postclose callback added before, or None"""
574 return self._postclosecallback.get(category, None)
574 return self._postclosecallback.get(category, None)
575
575
576 @active
576 @active
577 def addabort(self, category, callback):
577 def addabort(self, category, callback):
578 """add a callback to be called when the transaction is aborted.
578 """add a callback to be called when the transaction is aborted.
579
579
580 The transaction will be given as the first argument to the callback.
580 The transaction will be given as the first argument to the callback.
581
581
582 Category is a unique identifier to allow overwriting an old callback
582 Category is a unique identifier to allow overwriting an old callback
583 with a newer callback.
583 with a newer callback.
584 """
584 """
585 self._abortcallback[category] = callback
585 self._abortcallback[category] = callback
586
586
587 @active
587 @active
588 def addvalidator(self, category, callback):
588 def addvalidator(self, category, callback):
589 """adds a callback to be called when validating the transaction.
589 """adds a callback to be called when validating the transaction.
590
590
591 The transaction will be given as the first argument to the callback.
591 The transaction will be given as the first argument to the callback.
592
592
593 callback should raise exception if to abort transaction"""
593 callback should raise exception if to abort transaction"""
594 self._validatecallback[category] = callback
594 self._validatecallback[category] = callback
595
595
596 @active
596 @active
597 def close(self):
597 def close(self):
598 '''commit the transaction'''
598 '''commit the transaction'''
599 if self._count == 1:
599 if self._count == 1:
600 for category in sorted(self._validatecallback):
600 for category in sorted(self._validatecallback):
601 self._validatecallback[category](self)
601 self._validatecallback[category](self)
602 self._validatecallback = None # Help prevent cycles.
602 self._validatecallback = None # Help prevent cycles.
603 self._generatefiles(group=GEN_GROUP_PRE_FINALIZE)
603 self._generatefiles(group=GEN_GROUP_PRE_FINALIZE)
604 while self._finalizecallback:
604 while self._finalizecallback:
605 callbacks = self._finalizecallback
605 callbacks = self._finalizecallback
606 self._finalizecallback = {}
606 self._finalizecallback = {}
607 categories = sorted(callbacks)
607 categories = sorted(callbacks)
608 for cat in categories:
608 for cat in categories:
609 callbacks[cat](self)
609 callbacks[cat](self)
610 # Prevent double usage and help clear cycles.
610 # Prevent double usage and help clear cycles.
611 self._finalizecallback = None
611 self._finalizecallback = None
612 self._generatefiles(group=GEN_GROUP_POST_FINALIZE)
612 self._generatefiles(group=GEN_GROUP_POST_FINALIZE)
613
613
614 self._count -= 1
614 self._count -= 1
615 if self._count != 0:
615 if self._count != 0:
616 return
616 return
617 self._file.close()
617 self._file.close()
618 self._backupsfile.close()
618 self._backupsfile.close()
619 # cleanup temporary files
619 # cleanup temporary files
620 for l, f, b, c in self._backupentries:
620 for l, f, b, c in self._backupentries:
621 if l not in self._vfsmap and c:
621 if l not in self._vfsmap and c:
622 self._report(
622 self._report(
623 b"couldn't remove %s: unknown cache location %s\n" % (b, l)
623 b"couldn't remove %s: unknown cache location %s\n" % (b, l)
624 )
624 )
625 continue
625 continue
626 vfs = self._vfsmap[l]
626 vfs = self._vfsmap[l]
627 if not f and b and vfs.exists(b):
627 if not f and b and vfs.exists(b):
628 try:
628 try:
629 vfs.unlink(b)
629 vfs.unlink(b)
630 except (IOError, OSError, error.Abort) as inst:
630 except (IOError, OSError, error.Abort) as inst:
631 if not c:
631 if not c:
632 raise
632 raise
633 # Abort may be raise by read only opener
633 # Abort may be raise by read only opener
634 self._report(
634 self._report(
635 b"couldn't remove %s: %s\n" % (vfs.join(b), inst)
635 b"couldn't remove %s: %s\n" % (vfs.join(b), inst)
636 )
636 )
637 self._offsetmap = {}
637 self._offsetmap = {}
638 self._newfiles = set()
638 self._newfiles = set()
639 self._writeundo()
639 self._writeundo()
640 if self._after:
640 if self._after:
641 self._after()
641 self._after()
642 self._after = None # Help prevent cycles.
642 self._after = None # Help prevent cycles.
643 if self._opener.isfile(self._backupjournal):
643 if self._opener.isfile(self._backupjournal):
644 self._opener.unlink(self._backupjournal)
644 self._opener.unlink(self._backupjournal)
645 if self._opener.isfile(self._journal):
645 if self._opener.isfile(self._journal):
646 self._opener.unlink(self._journal)
646 self._opener.unlink(self._journal)
647 for l, _f, b, c in self._backupentries:
647 for l, _f, b, c in self._backupentries:
648 if l not in self._vfsmap and c:
648 if l not in self._vfsmap and c:
649 self._report(
649 self._report(
650 b"couldn't remove %s: unknown cache location"
650 b"couldn't remove %s: unknown cache location"
651 b"%s\n" % (b, l)
651 b"%s\n" % (b, l)
652 )
652 )
653 continue
653 continue
654 vfs = self._vfsmap[l]
654 vfs = self._vfsmap[l]
655 if b and vfs.exists(b):
655 if b and vfs.exists(b):
656 try:
656 try:
657 vfs.unlink(b)
657 vfs.unlink(b)
658 except (IOError, OSError, error.Abort) as inst:
658 except (IOError, OSError, error.Abort) as inst:
659 if not c:
659 if not c:
660 raise
660 raise
661 # Abort may be raise by read only opener
661 # Abort may be raise by read only opener
662 self._report(
662 self._report(
663 b"couldn't remove %s: %s\n" % (vfs.join(b), inst)
663 b"couldn't remove %s: %s\n" % (vfs.join(b), inst)
664 )
664 )
665 self._backupentries = []
665 self._backupentries = []
666 self._journal = None
666 self._journal = None
667
667
668 self._releasefn(self, True) # notify success of closing transaction
668 self._releasefn(self, True) # notify success of closing transaction
669 self._releasefn = None # Help prevent cycles.
669 self._releasefn = None # Help prevent cycles.
670
670
671 # run post close action
671 # run post close action
672 categories = sorted(self._postclosecallback)
672 categories = sorted(self._postclosecallback)
673 for cat in categories:
673 for cat in categories:
674 self._postclosecallback[cat](self)
674 self._postclosecallback[cat](self)
675 # Prevent double usage and help clear cycles.
675 # Prevent double usage and help clear cycles.
676 self._postclosecallback = None
676 self._postclosecallback = None
677
677
678 @active
678 @active
679 def abort(self):
679 def abort(self):
680 """abort the transaction (generally called on error, or when the
680 """abort the transaction (generally called on error, or when the
681 transaction is not explicitly committed before going out of
681 transaction is not explicitly committed before going out of
682 scope)"""
682 scope)"""
683 self._abort()
683 self._abort()
684
684
685 @active
685 @active
686 def add_journal(self, vfs_id, path):
686 def add_journal(self, vfs_id, path):
687 self._journal_files.append((vfs_id, path))
687 self._journal_files.append((vfs_id, path))
688
688
689 def _writeundo(self):
689 def _writeundo(self):
690 """write transaction data for possible future undo call"""
690 """write transaction data for possible future undo call"""
691 if self._undoname is None:
691 if self._undoname is None:
692 return
692 return
693 cleanup_undo_files(
694 self._report,
695 self._vfsmap,
696 undo_prefix=self._undoname,
697 )
693
698
694 def undoname(fn: bytes) -> bytes:
699 def undoname(fn: bytes) -> bytes:
695 base, name = os.path.split(fn)
700 base, name = os.path.split(fn)
696 assert name.startswith(self._journal)
701 assert name.startswith(self._journal)
697 new_name = name.replace(self._journal, self._undoname, 1)
702 new_name = name.replace(self._journal, self._undoname, 1)
698 return os.path.join(base, new_name)
703 return os.path.join(base, new_name)
699
704
700 undo_backup_path = b"%s.backupfiles" % self._undoname
705 undo_backup_path = b"%s.backupfiles" % self._undoname
701 undobackupfile = self._opener.open(undo_backup_path, b'w')
706 undobackupfile = self._opener.open(undo_backup_path, b'w')
702 undobackupfile.write(b'%d\n' % version)
707 undobackupfile.write(b'%d\n' % version)
703 for l, f, b, c in self._backupentries:
708 for l, f, b, c in self._backupentries:
704 if not f: # temporary file
709 if not f: # temporary file
705 continue
710 continue
706 if not b:
711 if not b:
707 u = b''
712 u = b''
708 else:
713 else:
709 if l not in self._vfsmap and c:
714 if l not in self._vfsmap and c:
710 self._report(
715 self._report(
711 b"couldn't remove %s: unknown cache location"
716 b"couldn't remove %s: unknown cache location"
712 b"%s\n" % (b, l)
717 b"%s\n" % (b, l)
713 )
718 )
714 continue
719 continue
715 vfs = self._vfsmap[l]
720 vfs = self._vfsmap[l]
716 u = undoname(b)
721 u = undoname(b)
717 util.copyfile(vfs.join(b), vfs.join(u), hardlink=True)
722 util.copyfile(vfs.join(b), vfs.join(u), hardlink=True)
718 undobackupfile.write(b"%s\0%s\0%s\0%d\n" % (l, f, u, c))
723 undobackupfile.write(b"%s\0%s\0%s\0%d\n" % (l, f, u, c))
719 undobackupfile.close()
724 undobackupfile.close()
720 for vfs, src in self._journal_files:
725 for vfs, src in self._journal_files:
721 dest = undoname(src)
726 dest = undoname(src)
722 # if src and dest refer to a same file, vfs.rename is a no-op,
727 # if src and dest refer to a same file, vfs.rename is a no-op,
723 # leaving both src and dest on disk. delete dest to make sure
728 # leaving both src and dest on disk. delete dest to make sure
724 # the rename couldn't be such a no-op.
729 # the rename couldn't be such a no-op.
725 vfs.tryunlink(dest)
730 vfs.tryunlink(dest)
726 try:
731 try:
727 vfs.rename(src, dest)
732 vfs.rename(src, dest)
728 except FileNotFoundError: # journal file does not yet exist
733 except FileNotFoundError: # journal file does not yet exist
729 pass
734 pass
730
735
731 def _abort(self):
736 def _abort(self):
732 entries = self.readjournal()
737 entries = self.readjournal()
733 self._count = 0
738 self._count = 0
734 self._usages = 0
739 self._usages = 0
735 self._file.close()
740 self._file.close()
736 self._backupsfile.close()
741 self._backupsfile.close()
737
742
738 quick = self._can_quick_abort(entries)
743 quick = self._can_quick_abort(entries)
739 try:
744 try:
740 if not quick:
745 if not quick:
741 self._report(_(b"transaction abort!\n"))
746 self._report(_(b"transaction abort!\n"))
742 for cat in sorted(self._abortcallback):
747 for cat in sorted(self._abortcallback):
743 self._abortcallback[cat](self)
748 self._abortcallback[cat](self)
744 # Prevent double usage and help clear cycles.
749 # Prevent double usage and help clear cycles.
745 self._abortcallback = None
750 self._abortcallback = None
746 if quick:
751 if quick:
747 self._do_quick_abort(entries)
752 self._do_quick_abort(entries)
748 else:
753 else:
749 self._do_full_abort(entries)
754 self._do_full_abort(entries)
750 finally:
755 finally:
751 self._journal = None
756 self._journal = None
752 self._releasefn(self, False) # notify failure of transaction
757 self._releasefn(self, False) # notify failure of transaction
753 self._releasefn = None # Help prevent cycles.
758 self._releasefn = None # Help prevent cycles.
754
759
755 def _can_quick_abort(self, entries):
760 def _can_quick_abort(self, entries):
756 """False if any semantic content have been written on disk
761 """False if any semantic content have been written on disk
757
762
758 True if nothing, except temporary files has been writen on disk."""
763 True if nothing, except temporary files has been writen on disk."""
759 if entries:
764 if entries:
760 return False
765 return False
761 for e in self._backupentries:
766 for e in self._backupentries:
762 if e[1]:
767 if e[1]:
763 return False
768 return False
764 return True
769 return True
765
770
766 def _do_quick_abort(self, entries):
771 def _do_quick_abort(self, entries):
767 """(Silently) do a quick cleanup (see _can_quick_abort)"""
772 """(Silently) do a quick cleanup (see _can_quick_abort)"""
768 assert self._can_quick_abort(entries)
773 assert self._can_quick_abort(entries)
769 tmp_files = [e for e in self._backupentries if not e[1]]
774 tmp_files = [e for e in self._backupentries if not e[1]]
770 for vfs_id, old_path, tmp_path, xxx in tmp_files:
775 for vfs_id, old_path, tmp_path, xxx in tmp_files:
771 vfs = self._vfsmap[vfs_id]
776 vfs = self._vfsmap[vfs_id]
772 try:
777 try:
773 vfs.unlink(tmp_path)
778 vfs.unlink(tmp_path)
774 except FileNotFoundError:
779 except FileNotFoundError:
775 pass
780 pass
776 if self._backupjournal:
781 if self._backupjournal:
777 self._opener.unlink(self._backupjournal)
782 self._opener.unlink(self._backupjournal)
778 if self._journal:
783 if self._journal:
779 self._opener.unlink(self._journal)
784 self._opener.unlink(self._journal)
780
785
781 def _do_full_abort(self, entries):
786 def _do_full_abort(self, entries):
782 """(Noisily) rollback all the change introduced by the transaction"""
787 """(Noisily) rollback all the change introduced by the transaction"""
783 try:
788 try:
784 _playback(
789 _playback(
785 self._journal,
790 self._journal,
786 self._report,
791 self._report,
787 self._opener,
792 self._opener,
788 self._vfsmap,
793 self._vfsmap,
789 entries,
794 entries,
790 self._backupentries,
795 self._backupentries,
791 False,
796 False,
792 checkambigfiles=self._checkambigfiles,
797 checkambigfiles=self._checkambigfiles,
793 )
798 )
794 self._report(_(b"rollback completed\n"))
799 self._report(_(b"rollback completed\n"))
795 except BaseException as exc:
800 except BaseException as exc:
796 self._report(_(b"rollback failed - please run hg recover\n"))
801 self._report(_(b"rollback failed - please run hg recover\n"))
797 self._report(
802 self._report(
798 _(b"(failure reason: %s)\n") % stringutil.forcebytestr(exc)
803 _(b"(failure reason: %s)\n") % stringutil.forcebytestr(exc)
799 )
804 )
800
805
801
806
802 BAD_VERSION_MSG = _(
807 BAD_VERSION_MSG = _(
803 b"journal was created by a different version of Mercurial\n"
808 b"journal was created by a different version of Mercurial\n"
804 )
809 )
805
810
806
811
807 def read_backup_files(report, fp):
812 def read_backup_files(report, fp):
808 """parse an (already open) backup file an return contained backup entries
813 """parse an (already open) backup file an return contained backup entries
809
814
810 entries are in the form: (location, file, backupfile, xxx)
815 entries are in the form: (location, file, backupfile, xxx)
811
816
812 :location: the vfs identifier (vfsmap's key)
817 :location: the vfs identifier (vfsmap's key)
813 :file: original file path (in the vfs)
818 :file: original file path (in the vfs)
814 :backupfile: path of the backup (in the vfs)
819 :backupfile: path of the backup (in the vfs)
815 :cache: a boolean currently always set to False
820 :cache: a boolean currently always set to False
816 """
821 """
817 lines = fp.readlines()
822 lines = fp.readlines()
818 backupentries = []
823 backupentries = []
819 if lines:
824 if lines:
820 ver = lines[0][:-1]
825 ver = lines[0][:-1]
821 if ver != (b'%d' % version):
826 if ver != (b'%d' % version):
822 report(BAD_VERSION_MSG)
827 report(BAD_VERSION_MSG)
823 else:
828 else:
824 for line in lines[1:]:
829 for line in lines[1:]:
825 if line:
830 if line:
826 # Shave off the trailing newline
831 # Shave off the trailing newline
827 line = line[:-1]
832 line = line[:-1]
828 l, f, b, c = line.split(b'\0')
833 l, f, b, c = line.split(b'\0')
829 backupentries.append((l, f, b, bool(c)))
834 backupentries.append((l, f, b, bool(c)))
830 return backupentries
835 return backupentries
831
836
832
837
833 def rollback(
838 def rollback(
834 opener,
839 opener,
835 vfsmap,
840 vfsmap,
836 file,
841 file,
837 report,
842 report,
838 checkambigfiles=None,
843 checkambigfiles=None,
839 skip_journal_pattern=None,
844 skip_journal_pattern=None,
840 ):
845 ):
841 """Rolls back the transaction contained in the given file
846 """Rolls back the transaction contained in the given file
842
847
843 Reads the entries in the specified file, and the corresponding
848 Reads the entries in the specified file, and the corresponding
844 '*.backupfiles' file, to recover from an incomplete transaction.
849 '*.backupfiles' file, to recover from an incomplete transaction.
845
850
846 * `file`: a file containing a list of entries, specifying where
851 * `file`: a file containing a list of entries, specifying where
847 to truncate each file. The file should contain a list of
852 to truncate each file. The file should contain a list of
848 file\0offset pairs, delimited by newlines. The corresponding
853 file\0offset pairs, delimited by newlines. The corresponding
849 '*.backupfiles' file should contain a list of file\0backupfile
854 '*.backupfiles' file should contain a list of file\0backupfile
850 pairs, delimited by \0.
855 pairs, delimited by \0.
851
856
852 `checkambigfiles` is a set of (path, vfs-location) tuples,
857 `checkambigfiles` is a set of (path, vfs-location) tuples,
853 which determine whether file stat ambiguity should be avoided at
858 which determine whether file stat ambiguity should be avoided at
854 restoring corresponded files.
859 restoring corresponded files.
855 """
860 """
856 entries = []
861 entries = []
857 backupentries = []
862 backupentries = []
858
863
859 with opener.open(file) as fp:
864 with opener.open(file) as fp:
860 lines = fp.readlines()
865 lines = fp.readlines()
861 for l in lines:
866 for l in lines:
862 try:
867 try:
863 f, o = l.split(b'\0')
868 f, o = l.split(b'\0')
864 entries.append((f, int(o)))
869 entries.append((f, int(o)))
865 except ValueError:
870 except ValueError:
866 report(
871 report(
867 _(b"couldn't read journal entry %r!\n") % pycompat.bytestr(l)
872 _(b"couldn't read journal entry %r!\n") % pycompat.bytestr(l)
868 )
873 )
869
874
870 backupjournal = b"%s.backupfiles" % file
875 backupjournal = b"%s.backupfiles" % file
871 if opener.exists(backupjournal):
876 if opener.exists(backupjournal):
872 with opener.open(backupjournal) as fp:
877 with opener.open(backupjournal) as fp:
873 backupentries = read_backup_files(report, fp)
878 backupentries = read_backup_files(report, fp)
874 if skip_journal_pattern is not None:
879 if skip_journal_pattern is not None:
875 keep = lambda x: not skip_journal_pattern.match(x[1])
880 keep = lambda x: not skip_journal_pattern.match(x[1])
876 backupentries = [x for x in backupentries if keep(x)]
881 backupentries = [x for x in backupentries if keep(x)]
877
882
878 _playback(
883 _playback(
879 file,
884 file,
880 report,
885 report,
881 opener,
886 opener,
882 vfsmap,
887 vfsmap,
883 entries,
888 entries,
884 backupentries,
889 backupentries,
885 checkambigfiles=checkambigfiles,
890 checkambigfiles=checkambigfiles,
886 )
891 )
@@ -1,431 +1,425 b''
1 #require hardlink reporevlogstore
1 #require hardlink reporevlogstore
2
2
3 $ cat > nlinks.py <<EOF
3 $ cat > nlinks.py <<EOF
4 > import sys
4 > import sys
5 > from mercurial import pycompat, util
5 > from mercurial import pycompat, util
6 > for f in sorted(sys.stdin.readlines()):
6 > for f in sorted(sys.stdin.readlines()):
7 > f = f[:-1]
7 > f = f[:-1]
8 > print(util.nlinks(pycompat.fsencode(f)), f)
8 > print(util.nlinks(pycompat.fsencode(f)), f)
9 > EOF
9 > EOF
10
10
11 $ nlinksdir()
11 $ nlinksdir()
12 > {
12 > {
13 > find "$@" -type f | "$PYTHON" $TESTTMP/nlinks.py
13 > find "$@" -type f | "$PYTHON" $TESTTMP/nlinks.py
14 > }
14 > }
15
15
16 Some implementations of cp can't create hardlinks (replaces 'cp -al' on Linux):
16 Some implementations of cp can't create hardlinks (replaces 'cp -al' on Linux):
17
17
18 $ cat > linkcp.py <<EOF
18 $ cat > linkcp.py <<EOF
19 > import sys
19 > import sys
20 > from mercurial import pycompat, util
20 > from mercurial import pycompat, util
21 > util.copyfiles(pycompat.fsencode(sys.argv[1]),
21 > util.copyfiles(pycompat.fsencode(sys.argv[1]),
22 > pycompat.fsencode(sys.argv[2]), hardlink=True)
22 > pycompat.fsencode(sys.argv[2]), hardlink=True)
23 > EOF
23 > EOF
24
24
25 $ linkcp()
25 $ linkcp()
26 > {
26 > {
27 > "$PYTHON" $TESTTMP/linkcp.py $1 $2
27 > "$PYTHON" $TESTTMP/linkcp.py $1 $2
28 > }
28 > }
29
29
30 Prepare repo r1:
30 Prepare repo r1:
31
31
32 $ hg init r1
32 $ hg init r1
33 $ cd r1
33 $ cd r1
34
34
35 $ echo c1 > f1
35 $ echo c1 > f1
36 $ hg add f1
36 $ hg add f1
37 $ hg ci -m0
37 $ hg ci -m0
38
38
39 $ mkdir d1
39 $ mkdir d1
40 $ cd d1
40 $ cd d1
41 $ echo c2 > f2
41 $ echo c2 > f2
42 $ hg add f2
42 $ hg add f2
43 $ hg ci -m1
43 $ hg ci -m1
44 $ cd ../..
44 $ cd ../..
45
45
46 $ nlinksdir r1/.hg/store
46 $ nlinksdir r1/.hg/store
47 1 r1/.hg/store/00changelog.i
47 1 r1/.hg/store/00changelog.i
48 1 r1/.hg/store/00manifest.i
48 1 r1/.hg/store/00manifest.i
49 1 r1/.hg/store/data/d1/f2.i
49 1 r1/.hg/store/data/d1/f2.i
50 1 r1/.hg/store/data/f1.i
50 1 r1/.hg/store/data/f1.i
51 1 r1/.hg/store/fncache (repofncache !)
51 1 r1/.hg/store/fncache (repofncache !)
52 1 r1/.hg/store/phaseroots
52 1 r1/.hg/store/phaseroots
53 1 r1/.hg/store/requires
53 1 r1/.hg/store/requires
54 1 r1/.hg/store/undo
54 1 r1/.hg/store/undo
55 1 r1/.hg/store/undo.backup.fncache (repofncache !)
55 1 r1/.hg/store/undo.backup.fncache (repofncache !)
56 1 r1/.hg/store/undo.backupfiles
56 1 r1/.hg/store/undo.backupfiles
57
57
58
58
59 Create hardlinked clone r2:
59 Create hardlinked clone r2:
60
60
61 $ hg clone -U --debug r1 r2 --config progress.debug=true
61 $ hg clone -U --debug r1 r2 --config progress.debug=true
62 linking: 1/7 files (14.29%)
62 linking: 1/7 files (14.29%)
63 linking: 2/7 files (28.57%)
63 linking: 2/7 files (28.57%)
64 linking: 3/7 files (42.86%)
64 linking: 3/7 files (42.86%)
65 linking: 4/7 files (57.14%)
65 linking: 4/7 files (57.14%)
66 linking: 5/7 files (71.43%)
66 linking: 5/7 files (71.43%)
67 linking: 6/7 files (85.71%)
67 linking: 6/7 files (85.71%)
68 linking: 7/7 files (100.00%)
68 linking: 7/7 files (100.00%)
69 linked 7 files
69 linked 7 files
70 updating the branch cache
70 updating the branch cache
71
71
72 Create non-hardlinked clone r3:
72 Create non-hardlinked clone r3:
73
73
74 $ hg clone --pull r1 r3
74 $ hg clone --pull r1 r3
75 requesting all changes
75 requesting all changes
76 adding changesets
76 adding changesets
77 adding manifests
77 adding manifests
78 adding file changes
78 adding file changes
79 added 2 changesets with 2 changes to 2 files
79 added 2 changesets with 2 changes to 2 files
80 new changesets 40d85e9847f2:7069c422939c
80 new changesets 40d85e9847f2:7069c422939c
81 updating to branch default
81 updating to branch default
82 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
82 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
83
83
84
84
85 Repos r1 and r2 should now contain hardlinked files:
85 Repos r1 and r2 should now contain hardlinked files:
86
86
87 $ nlinksdir r1/.hg/store
87 $ nlinksdir r1/.hg/store
88 2 r1/.hg/store/00changelog.i
88 2 r1/.hg/store/00changelog.i
89 2 r1/.hg/store/00manifest.i
89 2 r1/.hg/store/00manifest.i
90 2 r1/.hg/store/data/d1/f2.i
90 2 r1/.hg/store/data/d1/f2.i
91 2 r1/.hg/store/data/f1.i
91 2 r1/.hg/store/data/f1.i
92 1 r1/.hg/store/fncache (repofncache !)
92 1 r1/.hg/store/fncache (repofncache !)
93 1 r1/.hg/store/phaseroots
93 1 r1/.hg/store/phaseroots
94 1 r1/.hg/store/requires
94 1 r1/.hg/store/requires
95 1 r1/.hg/store/undo
95 1 r1/.hg/store/undo
96 1 r1/.hg/store/undo.backup.fncache (repofncache !)
96 1 r1/.hg/store/undo.backup.fncache (repofncache !)
97 1 r1/.hg/store/undo.backupfiles
97 1 r1/.hg/store/undo.backupfiles
98
98
99 $ nlinksdir r2/.hg/store
99 $ nlinksdir r2/.hg/store
100 2 r2/.hg/store/00changelog.i
100 2 r2/.hg/store/00changelog.i
101 2 r2/.hg/store/00manifest.i
101 2 r2/.hg/store/00manifest.i
102 2 r2/.hg/store/data/d1/f2.i
102 2 r2/.hg/store/data/d1/f2.i
103 2 r2/.hg/store/data/f1.i
103 2 r2/.hg/store/data/f1.i
104 1 r2/.hg/store/fncache (repofncache !)
104 1 r2/.hg/store/fncache (repofncache !)
105 1 r2/.hg/store/requires
105 1 r2/.hg/store/requires
106
106
107 Repo r3 should not be hardlinked:
107 Repo r3 should not be hardlinked:
108
108
109 $ nlinksdir r3/.hg/store
109 $ nlinksdir r3/.hg/store
110 1 r3/.hg/store/00changelog.i
110 1 r3/.hg/store/00changelog.i
111 1 r3/.hg/store/00manifest.i
111 1 r3/.hg/store/00manifest.i
112 1 r3/.hg/store/data/d1/f2.i
112 1 r3/.hg/store/data/d1/f2.i
113 1 r3/.hg/store/data/f1.i
113 1 r3/.hg/store/data/f1.i
114 1 r3/.hg/store/fncache (repofncache !)
114 1 r3/.hg/store/fncache (repofncache !)
115 1 r3/.hg/store/phaseroots
115 1 r3/.hg/store/phaseroots
116 1 r3/.hg/store/requires
116 1 r3/.hg/store/requires
117 1 r3/.hg/store/undo
117 1 r3/.hg/store/undo
118 1 r3/.hg/store/undo.backupfiles
118 1 r3/.hg/store/undo.backupfiles
119
119
120
120
121 Create a non-inlined filelog in r3:
121 Create a non-inlined filelog in r3:
122
122
123 $ cd r3/d1
123 $ cd r3/d1
124 >>> f = open('data1', 'wb')
124 >>> f = open('data1', 'wb')
125 >>> for x in range(10000):
125 >>> for x in range(10000):
126 ... f.write(b"%d\n" % x) and None
126 ... f.write(b"%d\n" % x) and None
127 >>> f.close()
127 >>> f.close()
128 $ for j in 0 1 2 3 4 5 6 7 8 9; do
128 $ for j in 0 1 2 3 4 5 6 7 8 9; do
129 > cat data1 >> f2
129 > cat data1 >> f2
130 > hg commit -m$j
130 > hg commit -m$j
131 > done
131 > done
132 $ cd ../..
132 $ cd ../..
133
133
134 $ nlinksdir r3/.hg/store
134 $ nlinksdir r3/.hg/store
135 1 r3/.hg/store/00changelog.i
135 1 r3/.hg/store/00changelog.i
136 1 r3/.hg/store/00manifest.i
136 1 r3/.hg/store/00manifest.i
137 1 r3/.hg/store/data/d1/f2.d
137 1 r3/.hg/store/data/d1/f2.d
138 1 r3/.hg/store/data/d1/f2.i
138 1 r3/.hg/store/data/d1/f2.i
139 1 r3/.hg/store/data/f1.i
139 1 r3/.hg/store/data/f1.i
140 1 r3/.hg/store/fncache (repofncache !)
140 1 r3/.hg/store/fncache (repofncache !)
141 1 r3/.hg/store/phaseroots
141 1 r3/.hg/store/phaseroots
142 1 r3/.hg/store/requires
142 1 r3/.hg/store/requires
143 1 r3/.hg/store/undo
143 1 r3/.hg/store/undo
144 1 r3/.hg/store/undo.backup.fncache (repofncache !)
145 1 r3/.hg/store/undo.backup.phaseroots
146 1 r3/.hg/store/undo.backupfiles
144 1 r3/.hg/store/undo.backupfiles
147
145
148 Push to repo r1 should break up most hardlinks in r2:
146 Push to repo r1 should break up most hardlinks in r2:
149
147
150 $ hg -R r2 verify -q
148 $ hg -R r2 verify -q
151
149
152 $ cd r3
150 $ cd r3
153 $ hg push
151 $ hg push
154 pushing to $TESTTMP/r1
152 pushing to $TESTTMP/r1
155 searching for changes
153 searching for changes
156 adding changesets
154 adding changesets
157 adding manifests
155 adding manifests
158 adding file changes
156 adding file changes
159 added 10 changesets with 10 changes to 1 files
157 added 10 changesets with 10 changes to 1 files
160
158
161 $ cd ..
159 $ cd ..
162
160
163 $ nlinksdir r2/.hg/store
161 $ nlinksdir r2/.hg/store
164 1 r2/.hg/store/00changelog.i
162 1 r2/.hg/store/00changelog.i
165 1 r2/.hg/store/00manifest.i
163 1 r2/.hg/store/00manifest.i
166 1 r2/.hg/store/data/d1/f2.i
164 1 r2/.hg/store/data/d1/f2.i
167 2 r2/.hg/store/data/f1.i
165 2 r2/.hg/store/data/f1.i
168 [12] r2/\.hg/store/fncache (re) (repofncache !)
166 [12] r2/\.hg/store/fncache (re) (repofncache !)
169 1 r2/.hg/store/requires
167 1 r2/.hg/store/requires
170
168
171 #if hardlink-whitelisted repofncache
169 #if hardlink-whitelisted repofncache
172 $ nlinksdir r2/.hg/store/fncache
170 $ nlinksdir r2/.hg/store/fncache
173 1 r2/.hg/store/fncache
171 1 r2/.hg/store/fncache
174 #endif
172 #endif
175
173
176 $ hg -R r2 verify -q
174 $ hg -R r2 verify -q
177
175
178 $ cd r1
176 $ cd r1
179 $ hg up
177 $ hg up
180 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
178 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
181
179
182 Committing a change to f1 in r1 must break up hardlink f1.i in r2:
180 Committing a change to f1 in r1 must break up hardlink f1.i in r2:
183
181
184 $ echo c1c1 >> f1
182 $ echo c1c1 >> f1
185 $ hg ci -m00
183 $ hg ci -m00
186 $ cd ..
184 $ cd ..
187
185
188 $ nlinksdir r2/.hg/store
186 $ nlinksdir r2/.hg/store
189 1 r2/.hg/store/00changelog.i
187 1 r2/.hg/store/00changelog.i
190 1 r2/.hg/store/00manifest.i
188 1 r2/.hg/store/00manifest.i
191 1 r2/.hg/store/data/d1/f2.i
189 1 r2/.hg/store/data/d1/f2.i
192 1 r2/.hg/store/data/f1.i
190 1 r2/.hg/store/data/f1.i
193 1 r2/.hg/store/fncache (repofncache !)
191 1 r2/.hg/store/fncache (repofncache !)
194 1 r2/.hg/store/requires
192 1 r2/.hg/store/requires
195
193
196 #if hardlink-whitelisted repofncache
194 #if hardlink-whitelisted repofncache
197 $ nlinksdir r2/.hg/store/fncache
195 $ nlinksdir r2/.hg/store/fncache
198 1 r2/.hg/store/fncache
196 1 r2/.hg/store/fncache
199 #endif
197 #endif
200
198
201 Create a file which exec permissions we will change
199 Create a file which exec permissions we will change
202 $ cd r3
200 $ cd r3
203 $ echo "echo hello world" > f3
201 $ echo "echo hello world" > f3
204 $ hg add f3
202 $ hg add f3
205 $ hg ci -mf3
203 $ hg ci -mf3
206 $ cd ..
204 $ cd ..
207
205
208 $ cd r3
206 $ cd r3
209 $ hg tip --template '{rev}:{node|short}\n'
207 $ hg tip --template '{rev}:{node|short}\n'
210 12:d3b77733a28a
208 12:d3b77733a28a
211 $ echo bla > f1
209 $ echo bla > f1
212 $ chmod +x f3
210 $ chmod +x f3
213 $ hg ci -m1
211 $ hg ci -m1
214 $ cd ..
212 $ cd ..
215
213
216 Create hardlinked copy r4 of r3 (on Linux, we would call 'cp -al'):
214 Create hardlinked copy r4 of r3 (on Linux, we would call 'cp -al'):
217
215
218 $ linkcp r3 r4
216 $ linkcp r3 r4
219
217
220 'checklink' is produced by hardlinking a symlink, which is undefined whether
218 'checklink' is produced by hardlinking a symlink, which is undefined whether
221 the symlink should be followed or not. It does behave differently on Linux and
219 the symlink should be followed or not. It does behave differently on Linux and
222 BSD. Just remove it so the test pass on both platforms.
220 BSD. Just remove it so the test pass on both platforms.
223
221
224 $ rm -f r4/.hg/wcache/checklink
222 $ rm -f r4/.hg/wcache/checklink
225
223
226 r4 has hardlinks in the working dir (not just inside .hg):
224 r4 has hardlinks in the working dir (not just inside .hg):
227
225
228 $ nlinksdir r4
226 $ nlinksdir r4
229 2 r4/.hg/00changelog.i
227 2 r4/.hg/00changelog.i
230 [24] r4/.hg/branch (re)
228 [24] r4/.hg/branch (re)
231 2 r4/.hg/cache/branch2-base
229 2 r4/.hg/cache/branch2-base
232 2 r4/.hg/cache/branch2-immutable
230 2 r4/.hg/cache/branch2-immutable
233 2 r4/.hg/cache/branch2-served
231 2 r4/.hg/cache/branch2-served
234 2 r4/.hg/cache/branch2-served.hidden
232 2 r4/.hg/cache/branch2-served.hidden
235 2 r4/.hg/cache/branch2-visible
233 2 r4/.hg/cache/branch2-visible
236 2 r4/.hg/cache/branch2-visible-hidden
234 2 r4/.hg/cache/branch2-visible-hidden
237 2 r4/.hg/cache/rbc-names-v1
235 2 r4/.hg/cache/rbc-names-v1
238 2 r4/.hg/cache/rbc-revs-v1
236 2 r4/.hg/cache/rbc-revs-v1
239 2 r4/.hg/cache/tags2
237 2 r4/.hg/cache/tags2
240 2 r4/.hg/cache/tags2-served
238 2 r4/.hg/cache/tags2-served
241 2 r4/.hg/dirstate
239 2 r4/.hg/dirstate
242 2 r4/.hg/fsmonitor.state (fsmonitor !)
240 2 r4/.hg/fsmonitor.state (fsmonitor !)
243 2 r4/.hg/hgrc
241 2 r4/.hg/hgrc
244 2 r4/.hg/last-message.txt
242 2 r4/.hg/last-message.txt
245 2 r4/.hg/requires
243 2 r4/.hg/requires
246 2 r4/.hg/store/00changelog.i
244 2 r4/.hg/store/00changelog.i
247 2 r4/.hg/store/00manifest.i
245 2 r4/.hg/store/00manifest.i
248 2 r4/.hg/store/data/d1/f2.d
246 2 r4/.hg/store/data/d1/f2.d
249 2 r4/.hg/store/data/d1/f2.i
247 2 r4/.hg/store/data/d1/f2.i
250 2 r4/.hg/store/data/f1.i
248 2 r4/.hg/store/data/f1.i
251 2 r4/.hg/store/data/f3.i
249 2 r4/.hg/store/data/f3.i
252 2 r4/.hg/store/fncache (repofncache !)
250 2 r4/.hg/store/fncache (repofncache !)
253 2 r4/.hg/store/phaseroots
251 2 r4/.hg/store/phaseroots
254 2 r4/.hg/store/requires
252 2 r4/.hg/store/requires
255 2 r4/.hg/store/undo
253 2 r4/.hg/store/undo
256 2 r4/.hg/store/undo.backup.fncache (repofncache !)
257 2 r4/.hg/store/undo.backup.phaseroots
258 2 r4/.hg/store/undo.backupfiles
254 2 r4/.hg/store/undo.backupfiles
259 [24] r4/.hg/undo.backup.branch (re)
255 [24] r4/.hg/undo.backup.branch (re)
260 2 r4/\.hg/undo\.backup\.dirstate (re)
256 2 r4/\.hg/undo\.backup\.dirstate (re)
261 2 r4/.hg/undo.desc
257 2 r4/.hg/undo.desc
262 2 r4/.hg/wcache/checkisexec (execbit !)
258 2 r4/.hg/wcache/checkisexec (execbit !)
263 2 r4/.hg/wcache/checklink-target (symlink !)
259 2 r4/.hg/wcache/checklink-target (symlink !)
264 2 r4/.hg/wcache/checknoexec (execbit !)
260 2 r4/.hg/wcache/checknoexec (execbit !)
265 2 r4/.hg/wcache/manifestfulltextcache (reporevlogstore !)
261 2 r4/.hg/wcache/manifestfulltextcache (reporevlogstore !)
266 2 r4/d1/data1
262 2 r4/d1/data1
267 2 r4/d1/f2
263 2 r4/d1/f2
268 2 r4/f1
264 2 r4/f1
269 2 r4/f3
265 2 r4/f3
270
266
271 Update back to revision 12 in r4 should break hardlink of file f1 and f3:
267 Update back to revision 12 in r4 should break hardlink of file f1 and f3:
272 #if hardlink-whitelisted
268 #if hardlink-whitelisted
273 $ nlinksdir r4/.hg/undo.backup.dirstate r4/.hg/dirstate
269 $ nlinksdir r4/.hg/undo.backup.dirstate r4/.hg/dirstate
274 2 r4/.hg/dirstate
270 2 r4/.hg/dirstate
275 2 r4/.hg/undo.backup.dirstate
271 2 r4/.hg/undo.backup.dirstate
276 #endif
272 #endif
277
273
278
274
279 $ hg -R r4 up 12
275 $ hg -R r4 up 12
280 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (execbit !)
276 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (execbit !)
281 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-execbit !)
277 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-execbit !)
282
278
283 $ nlinksdir r4
279 $ nlinksdir r4
284 2 r4/.hg/00changelog.i
280 2 r4/.hg/00changelog.i
285 1 r4/.hg/branch
281 1 r4/.hg/branch
286 2 r4/.hg/cache/branch2-base
282 2 r4/.hg/cache/branch2-base
287 2 r4/.hg/cache/branch2-immutable
283 2 r4/.hg/cache/branch2-immutable
288 2 r4/.hg/cache/branch2-served
284 2 r4/.hg/cache/branch2-served
289 2 r4/.hg/cache/branch2-served.hidden
285 2 r4/.hg/cache/branch2-served.hidden
290 2 r4/.hg/cache/branch2-visible
286 2 r4/.hg/cache/branch2-visible
291 2 r4/.hg/cache/branch2-visible-hidden
287 2 r4/.hg/cache/branch2-visible-hidden
292 2 r4/.hg/cache/rbc-names-v1
288 2 r4/.hg/cache/rbc-names-v1
293 2 r4/.hg/cache/rbc-revs-v1
289 2 r4/.hg/cache/rbc-revs-v1
294 2 r4/.hg/cache/tags2
290 2 r4/.hg/cache/tags2
295 2 r4/.hg/cache/tags2-served
291 2 r4/.hg/cache/tags2-served
296 1 r4/.hg/dirstate
292 1 r4/.hg/dirstate
297 1 r4/.hg/fsmonitor.state (fsmonitor !)
293 1 r4/.hg/fsmonitor.state (fsmonitor !)
298 2 r4/.hg/hgrc
294 2 r4/.hg/hgrc
299 2 r4/.hg/last-message.txt
295 2 r4/.hg/last-message.txt
300 2 r4/.hg/requires
296 2 r4/.hg/requires
301 2 r4/.hg/store/00changelog.i
297 2 r4/.hg/store/00changelog.i
302 2 r4/.hg/store/00manifest.i
298 2 r4/.hg/store/00manifest.i
303 2 r4/.hg/store/data/d1/f2.d
299 2 r4/.hg/store/data/d1/f2.d
304 2 r4/.hg/store/data/d1/f2.i
300 2 r4/.hg/store/data/d1/f2.i
305 2 r4/.hg/store/data/f1.i
301 2 r4/.hg/store/data/f1.i
306 2 r4/.hg/store/data/f3.i
302 2 r4/.hg/store/data/f3.i
307 2 r4/.hg/store/fncache
303 2 r4/.hg/store/fncache
308 2 r4/.hg/store/phaseroots
304 2 r4/.hg/store/phaseroots
309 2 r4/.hg/store/requires
305 2 r4/.hg/store/requires
310 2 r4/.hg/store/undo
306 2 r4/.hg/store/undo
311 2 r4/.hg/store/undo.backup.fncache (repofncache !)
312 2 r4/.hg/store/undo.backup.phaseroots
313 2 r4/.hg/store/undo.backupfiles
307 2 r4/.hg/store/undo.backupfiles
314 [23] r4/.hg/undo.backup.branch (re)
308 [23] r4/.hg/undo.backup.branch (re)
315 2 r4/\.hg/undo\.backup\.dirstate (re)
309 2 r4/\.hg/undo\.backup\.dirstate (re)
316 2 r4/.hg/undo.desc
310 2 r4/.hg/undo.desc
317 2 r4/.hg/wcache/checkisexec (execbit !)
311 2 r4/.hg/wcache/checkisexec (execbit !)
318 2 r4/.hg/wcache/checklink-target (symlink !)
312 2 r4/.hg/wcache/checklink-target (symlink !)
319 2 r4/.hg/wcache/checknoexec (execbit !)
313 2 r4/.hg/wcache/checknoexec (execbit !)
320 1 r4/.hg/wcache/manifestfulltextcache (reporevlogstore !)
314 1 r4/.hg/wcache/manifestfulltextcache (reporevlogstore !)
321 2 r4/d1/data1
315 2 r4/d1/data1
322 2 r4/d1/f2
316 2 r4/d1/f2
323 1 r4/f1
317 1 r4/f1
324 1 r4/f3 (execbit !)
318 1 r4/f3 (execbit !)
325 2 r4/f3 (no-execbit !)
319 2 r4/f3 (no-execbit !)
326
320
327 #if hardlink-whitelisted
321 #if hardlink-whitelisted
328 $ nlinksdir r4/.hg/undo.backup.dirstate r4/.hg/dirstate
322 $ nlinksdir r4/.hg/undo.backup.dirstate r4/.hg/dirstate
329 1 r4/.hg/dirstate
323 1 r4/.hg/dirstate
330 2 r4/.hg/undo.backup.dirstate
324 2 r4/.hg/undo.backup.dirstate
331 #endif
325 #endif
332
326
333 Test hardlinking outside hg:
327 Test hardlinking outside hg:
334
328
335 $ mkdir x
329 $ mkdir x
336 $ echo foo > x/a
330 $ echo foo > x/a
337
331
338 $ linkcp x y
332 $ linkcp x y
339 $ echo bar >> y/a
333 $ echo bar >> y/a
340
334
341 No diff if hardlink:
335 No diff if hardlink:
342
336
343 $ diff x/a y/a
337 $ diff x/a y/a
344
338
345 Test mq hardlinking:
339 Test mq hardlinking:
346
340
347 $ echo "[extensions]" >> $HGRCPATH
341 $ echo "[extensions]" >> $HGRCPATH
348 $ echo "mq=" >> $HGRCPATH
342 $ echo "mq=" >> $HGRCPATH
349
343
350 $ hg init a
344 $ hg init a
351 $ cd a
345 $ cd a
352
346
353 $ hg qimport -n foo - << EOF
347 $ hg qimport -n foo - << EOF
354 > # HG changeset patch
348 > # HG changeset patch
355 > # Date 1 0
349 > # Date 1 0
356 > diff -r 2588a8b53d66 a
350 > diff -r 2588a8b53d66 a
357 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
351 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
358 > +++ b/a Wed Jul 23 15:54:29 2008 +0200
352 > +++ b/a Wed Jul 23 15:54:29 2008 +0200
359 > @@ -0,0 +1,1 @@
353 > @@ -0,0 +1,1 @@
360 > +a
354 > +a
361 > EOF
355 > EOF
362 adding foo to series file
356 adding foo to series file
363
357
364 $ hg qpush
358 $ hg qpush
365 applying foo
359 applying foo
366 now at: foo
360 now at: foo
367
361
368 $ cd ..
362 $ cd ..
369 $ linkcp a b
363 $ linkcp a b
370 $ cd b
364 $ cd b
371
365
372 $ hg qimport -n bar - << EOF
366 $ hg qimport -n bar - << EOF
373 > # HG changeset patch
367 > # HG changeset patch
374 > # Date 2 0
368 > # Date 2 0
375 > diff -r 2588a8b53d66 a
369 > diff -r 2588a8b53d66 a
376 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
370 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
377 > +++ b/b Wed Jul 23 15:54:29 2008 +0200
371 > +++ b/b Wed Jul 23 15:54:29 2008 +0200
378 > @@ -0,0 +1,1 @@
372 > @@ -0,0 +1,1 @@
379 > +b
373 > +b
380 > EOF
374 > EOF
381 adding bar to series file
375 adding bar to series file
382
376
383 $ hg qpush
377 $ hg qpush
384 applying bar
378 applying bar
385 now at: bar
379 now at: bar
386
380
387 $ cat .hg/patches/status
381 $ cat .hg/patches/status
388 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
382 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
389 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c:bar
383 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c:bar
390
384
391 $ cat .hg/patches/series
385 $ cat .hg/patches/series
392 foo
386 foo
393 bar
387 bar
394
388
395 $ cat ../a/.hg/patches/status
389 $ cat ../a/.hg/patches/status
396 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
390 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
397
391
398 $ cat ../a/.hg/patches/series
392 $ cat ../a/.hg/patches/series
399 foo
393 foo
400
394
401 Test tags hardlinking:
395 Test tags hardlinking:
402
396
403 $ hg qdel -r qbase:qtip
397 $ hg qdel -r qbase:qtip
404 patch foo finalized without changeset message
398 patch foo finalized without changeset message
405 patch bar finalized without changeset message
399 patch bar finalized without changeset message
406
400
407 $ hg tag -l lfoo
401 $ hg tag -l lfoo
408 $ hg tag foo
402 $ hg tag foo
409
403
410 $ cd ..
404 $ cd ..
411 $ linkcp b c
405 $ linkcp b c
412 $ cd c
406 $ cd c
413
407
414 $ hg tag -l -r 0 lbar
408 $ hg tag -l -r 0 lbar
415 $ hg tag -r 0 bar
409 $ hg tag -r 0 bar
416
410
417 $ cat .hgtags
411 $ cat .hgtags
418 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
412 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
419 430ed4828a74fa4047bc816a25500f7472ab4bfe bar
413 430ed4828a74fa4047bc816a25500f7472ab4bfe bar
420
414
421 $ cat .hg/localtags
415 $ cat .hg/localtags
422 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
416 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
423 430ed4828a74fa4047bc816a25500f7472ab4bfe lbar
417 430ed4828a74fa4047bc816a25500f7472ab4bfe lbar
424
418
425 $ cat ../b/.hgtags
419 $ cat ../b/.hgtags
426 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
420 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
427
421
428 $ cat ../b/.hg/localtags
422 $ cat ../b/.hg/localtags
429 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
423 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
430
424
431 $ cd ..
425 $ cd ..
@@ -1,264 +1,263 b''
1 Create user cache directory
1 Create user cache directory
2
2
3 $ USERCACHE=`pwd`/cache; export USERCACHE
3 $ USERCACHE=`pwd`/cache; export USERCACHE
4 $ cat <<EOF >> ${HGRCPATH}
4 $ cat <<EOF >> ${HGRCPATH}
5 > [extensions]
5 > [extensions]
6 > hgext.largefiles=
6 > hgext.largefiles=
7 > [largefiles]
7 > [largefiles]
8 > usercache=${USERCACHE}
8 > usercache=${USERCACHE}
9 > EOF
9 > EOF
10 $ mkdir -p ${USERCACHE}
10 $ mkdir -p ${USERCACHE}
11
11
12 Create source repo, and commit adding largefile.
12 Create source repo, and commit adding largefile.
13
13
14 $ hg init src
14 $ hg init src
15 $ cd src
15 $ cd src
16 $ echo large > large
16 $ echo large > large
17 $ hg add --large large
17 $ hg add --large large
18 $ hg commit -m 'add largefile'
18 $ hg commit -m 'add largefile'
19 $ hg rm large
19 $ hg rm large
20 $ hg commit -m 'branchhead without largefile' large
20 $ hg commit -m 'branchhead without largefile' large
21 $ hg up -qr 0
21 $ hg up -qr 0
22 $ rm large
22 $ rm large
23 $ echo "0000000000000000000000000000000000000000" > .hglf/large
23 $ echo "0000000000000000000000000000000000000000" > .hglf/large
24 $ hg commit -m 'commit missing file with corrupt standin' large
24 $ hg commit -m 'commit missing file with corrupt standin' large
25 abort: large: file not found!
25 abort: large: file not found!
26 [255]
26 [255]
27 $ hg up -Cqr 0
27 $ hg up -Cqr 0
28 $ cd ..
28 $ cd ..
29
29
30 Discard all cached largefiles in USERCACHE
30 Discard all cached largefiles in USERCACHE
31
31
32 $ rm -rf ${USERCACHE}
32 $ rm -rf ${USERCACHE}
33
33
34 Create mirror repo, and pull from source without largefile:
34 Create mirror repo, and pull from source without largefile:
35 "pull" is used instead of "clone" for suppression of (1) updating to
35 "pull" is used instead of "clone" for suppression of (1) updating to
36 tip (= caching largefile from source repo), and (2) recording source
36 tip (= caching largefile from source repo), and (2) recording source
37 repo as "default" path in .hg/hgrc.
37 repo as "default" path in .hg/hgrc.
38
38
39 $ hg init mirror
39 $ hg init mirror
40 $ cd mirror
40 $ cd mirror
41 $ hg pull ../src
41 $ hg pull ../src
42 pulling from ../src
42 pulling from ../src
43 requesting all changes
43 requesting all changes
44 adding changesets
44 adding changesets
45 adding manifests
45 adding manifests
46 adding file changes
46 adding file changes
47 added 2 changesets with 1 changes to 1 files
47 added 2 changesets with 1 changes to 1 files
48 new changesets eb85d9124f3f:26c18ce05e4e
48 new changesets eb85d9124f3f:26c18ce05e4e
49 (run 'hg update' to get a working copy)
49 (run 'hg update' to get a working copy)
50
50
51 Update working directory to "tip", which requires largefile("large"),
51 Update working directory to "tip", which requires largefile("large"),
52 but there is no cache file for it. So, hg must treat it as
52 but there is no cache file for it. So, hg must treat it as
53 "missing"(!) file.
53 "missing"(!) file.
54
54
55 $ hg update -r0
55 $ hg update -r0
56 getting changed largefiles
56 getting changed largefiles
57 large: largefile 7f7097b041ccf68cc5561e9600da4655d21c6d18 not available from file:/*/$TESTTMP/mirror (glob)
57 large: largefile 7f7097b041ccf68cc5561e9600da4655d21c6d18 not available from file:/*/$TESTTMP/mirror (glob)
58 0 largefiles updated, 0 removed
58 0 largefiles updated, 0 removed
59 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 $ hg status
60 $ hg status
61 ! large
61 ! large
62
62
63 Update working directory to null: this cleanup .hg/largefiles/dirstate
63 Update working directory to null: this cleanup .hg/largefiles/dirstate
64
64
65 $ hg update null
65 $ hg update null
66 getting changed largefiles
66 getting changed largefiles
67 0 largefiles updated, 0 removed
67 0 largefiles updated, 0 removed
68 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
68 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
69
69
70 Update working directory to tip, again.
70 Update working directory to tip, again.
71
71
72 $ hg update -r0
72 $ hg update -r0
73 getting changed largefiles
73 getting changed largefiles
74 large: largefile 7f7097b041ccf68cc5561e9600da4655d21c6d18 not available from file:/*/$TESTTMP/mirror (glob)
74 large: largefile 7f7097b041ccf68cc5561e9600da4655d21c6d18 not available from file:/*/$TESTTMP/mirror (glob)
75 0 largefiles updated, 0 removed
75 0 largefiles updated, 0 removed
76 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
76 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
77 $ hg status
77 $ hg status
78 ! large
78 ! large
79 $ cd ..
79 $ cd ..
80
80
81 Verify that largefiles from pulled branchheads are fetched, also to an empty repo
81 Verify that largefiles from pulled branchheads are fetched, also to an empty repo
82
82
83 $ hg init mirror2
83 $ hg init mirror2
84 $ hg -R mirror2 pull src -r0
84 $ hg -R mirror2 pull src -r0
85 pulling from src
85 pulling from src
86 adding changesets
86 adding changesets
87 adding manifests
87 adding manifests
88 adding file changes
88 adding file changes
89 added 1 changesets with 1 changes to 1 files
89 added 1 changesets with 1 changes to 1 files
90 new changesets eb85d9124f3f
90 new changesets eb85d9124f3f
91 (run 'hg update' to get a working copy)
91 (run 'hg update' to get a working copy)
92
92
93 #if unix-permissions
93 #if unix-permissions
94
94
95 Portable way to print file permissions:
95 Portable way to print file permissions:
96
96
97 $ cat > ls-l.py <<EOF
97 $ cat > ls-l.py <<EOF
98 > #!$PYTHON
98 > #!$PYTHON
99 > import os
99 > import os
100 > import sys
100 > import sys
101 > path = sys.argv[1]
101 > path = sys.argv[1]
102 > print('%03o' % (os.lstat(path).st_mode & 0o777))
102 > print('%03o' % (os.lstat(path).st_mode & 0o777))
103 > EOF
103 > EOF
104 $ chmod +x ls-l.py
104 $ chmod +x ls-l.py
105
105
106 Test that files in .hg/largefiles inherit mode from .hg/store, not
106 Test that files in .hg/largefiles inherit mode from .hg/store, not
107 from file in working copy:
107 from file in working copy:
108
108
109 $ cd src
109 $ cd src
110 $ chmod 750 .hg/store
110 $ chmod 750 .hg/store
111 $ chmod 660 large
111 $ chmod 660 large
112 $ echo change >> large
112 $ echo change >> large
113 $ hg commit -m change
113 $ hg commit -m change
114 created new head
114 created new head
115 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
115 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
116 640
116 640
117
117
118 Test permission of with files in .hg/largefiles created by update:
118 Test permission of with files in .hg/largefiles created by update:
119
119
120 $ cd ../mirror
120 $ cd ../mirror
121 $ rm -r "$USERCACHE" .hg/largefiles # avoid links
121 $ rm -r "$USERCACHE" .hg/largefiles # avoid links
122 $ chmod 750 .hg/store
122 $ chmod 750 .hg/store
123 $ hg pull ../src --update -q
123 $ hg pull ../src --update -q
124 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
124 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
125 640
125 640
126
126
127 Test permission of files created by push:
127 Test permission of files created by push:
128
128
129 $ hg serve -R ../src -d -p $HGPORT --pid-file hg.pid \
129 $ hg serve -R ../src -d -p $HGPORT --pid-file hg.pid \
130 > --config "web.allow_push=*" --config web.push_ssl=no
130 > --config "web.allow_push=*" --config web.push_ssl=no
131 $ cat hg.pid >> $DAEMON_PIDS
131 $ cat hg.pid >> $DAEMON_PIDS
132
132
133 $ echo change >> large
133 $ echo change >> large
134 $ hg commit -m change
134 $ hg commit -m change
135
135
136 $ rm -r "$USERCACHE"
136 $ rm -r "$USERCACHE"
137
137
138 $ hg push -q http://localhost:$HGPORT/
138 $ hg push -q http://localhost:$HGPORT/
139
139
140 $ ../ls-l.py ../src/.hg/largefiles/b734e14a0971e370408ab9bce8d56d8485e368a9
140 $ ../ls-l.py ../src/.hg/largefiles/b734e14a0971e370408ab9bce8d56d8485e368a9
141 640
141 640
142
142
143 $ cd ..
143 $ cd ..
144
144
145 #endif
145 #endif
146
146
147 Test issue 4053 (remove --after on a deleted, uncommitted file shouldn't say
147 Test issue 4053 (remove --after on a deleted, uncommitted file shouldn't say
148 it is missing, but a remove on a nonexistent unknown file still should. Same
148 it is missing, but a remove on a nonexistent unknown file still should. Same
149 for a forget.)
149 for a forget.)
150
150
151 $ cd src
151 $ cd src
152 $ touch x
152 $ touch x
153 $ hg add x
153 $ hg add x
154 $ mv x y
154 $ mv x y
155 $ hg remove -A x y ENOENT
155 $ hg remove -A x y ENOENT
156 ENOENT: * (glob)
156 ENOENT: * (glob)
157 not removing y: file is untracked
157 not removing y: file is untracked
158 [1]
158 [1]
159 $ hg add y
159 $ hg add y
160 $ mv y z
160 $ mv y z
161 $ hg forget y z ENOENT
161 $ hg forget y z ENOENT
162 ENOENT: * (glob)
162 ENOENT: * (glob)
163 not removing z: file is already untracked
163 not removing z: file is already untracked
164 [1]
164 [1]
165
165
166 Largefiles are accessible from the share's store
166 Largefiles are accessible from the share's store
167 $ cd ..
167 $ cd ..
168 $ hg share -q src share_dst --config extensions.share=
168 $ hg share -q src share_dst --config extensions.share=
169 $ hg -R share_dst update -r0
169 $ hg -R share_dst update -r0
170 getting changed largefiles
170 getting changed largefiles
171 1 largefiles updated, 0 removed
171 1 largefiles updated, 0 removed
172 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
172 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
173
173
174 $ echo modified > share_dst/large
174 $ echo modified > share_dst/large
175 $ hg -R share_dst ci -m modified
175 $ hg -R share_dst ci -m modified
176 created new head
176 created new head
177
177
178 Only dirstate is in the local store for the share, and the largefile is in the
178 Only dirstate is in the local store for the share, and the largefile is in the
179 share source's local store. Avoid the extra largefiles added in the unix
179 share source's local store. Avoid the extra largefiles added in the unix
180 conditional above.
180 conditional above.
181 $ hash=`hg -R share_dst cat share_dst/.hglf/large`
181 $ hash=`hg -R share_dst cat share_dst/.hglf/large`
182 $ echo $hash
182 $ echo $hash
183 e2fb5f2139d086ded2cb600d5a91a196e76bf020
183 e2fb5f2139d086ded2cb600d5a91a196e76bf020
184
184
185 $ find share_dst/.hg/largefiles/* | sort
185 $ find share_dst/.hg/largefiles/* | sort
186 share_dst/.hg/largefiles/dirstate
186 share_dst/.hg/largefiles/dirstate
187 share_dst/.hg/largefiles/undo.backup.dirstate
187 share_dst/.hg/largefiles/undo.backup.dirstate
188
188
189 $ find src/.hg/largefiles/* | egrep "(dirstate|$hash)" | sort
189 $ find src/.hg/largefiles/* | egrep "(dirstate|$hash)" | sort
190 src/.hg/largefiles/dirstate
190 src/.hg/largefiles/dirstate
191 src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
191 src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
192 src/.hg/largefiles/undo.backup.dirstate
193
192
194 Verify that backwards compatibility is maintained for old storage layout
193 Verify that backwards compatibility is maintained for old storage layout
195 $ mv src/.hg/largefiles/$hash share_dst/.hg/largefiles
194 $ mv src/.hg/largefiles/$hash share_dst/.hg/largefiles
196 $ hg verify --quiet --lfa -R share_dst --config largefiles.usercache=
195 $ hg verify --quiet --lfa -R share_dst --config largefiles.usercache=
197
196
198 Inject corruption into the largefiles store and see how update handles that:
197 Inject corruption into the largefiles store and see how update handles that:
199
198
200 $ cd src
199 $ cd src
201 $ hg up -qC tip
200 $ hg up -qC tip
202 $ cat large
201 $ cat large
203 modified
202 modified
204 $ rm large
203 $ rm large
205 $ cat .hglf/large
204 $ cat .hglf/large
206 e2fb5f2139d086ded2cb600d5a91a196e76bf020
205 e2fb5f2139d086ded2cb600d5a91a196e76bf020
207 $ mv .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 ..
206 $ mv .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 ..
208 $ echo corruption > .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
207 $ echo corruption > .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
209 $ hg up -C
208 $ hg up -C
210 getting changed largefiles
209 getting changed largefiles
211 large: data corruption in $TESTTMP/src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 with hash 6a7bb2556144babe3899b25e5428123735bb1e27
210 large: data corruption in $TESTTMP/src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 with hash 6a7bb2556144babe3899b25e5428123735bb1e27
212 0 largefiles updated, 0 removed
211 0 largefiles updated, 0 removed
213 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
212 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
214 updated to "cd24c147f45c: modified"
213 updated to "cd24c147f45c: modified"
215 [12] other heads for branch "default" (re)
214 [12] other heads for branch "default" (re)
216 $ hg st
215 $ hg st
217 ! large
216 ! large
218 ? z
217 ? z
219 $ rm .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
218 $ rm .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
220
219
221 #if serve
220 #if serve
222
221
223 Test coverage of error handling from putlfile:
222 Test coverage of error handling from putlfile:
224
223
225 $ mkdir $TESTTMP/mirrorcache
224 $ mkdir $TESTTMP/mirrorcache
226 $ hg serve -R ../mirror -d -p $HGPORT1 --pid-file hg.pid --config largefiles.usercache=$TESTTMP/mirrorcache
225 $ hg serve -R ../mirror -d -p $HGPORT1 --pid-file hg.pid --config largefiles.usercache=$TESTTMP/mirrorcache
227 $ cat hg.pid >> $DAEMON_PIDS
226 $ cat hg.pid >> $DAEMON_PIDS
228
227
229 $ hg push http://localhost:$HGPORT1 -f --config files.usercache=nocache
228 $ hg push http://localhost:$HGPORT1 -f --config files.usercache=nocache
230 pushing to http://localhost:$HGPORT1/
229 pushing to http://localhost:$HGPORT1/
231 searching for changes
230 searching for changes
232 abort: remotestore: could not open file $TESTTMP/src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020: HTTP Error 403: ssl required
231 abort: remotestore: could not open file $TESTTMP/src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020: HTTP Error 403: ssl required
233 [255]
232 [255]
234
233
235 $ rm .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
234 $ rm .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
236
235
237 Test coverage of 'missing from store':
236 Test coverage of 'missing from store':
238
237
239 $ hg serve -R ../mirror -d -p $HGPORT2 --pid-file hg.pid --config largefiles.usercache=$TESTTMP/mirrorcache --config "web.allow_push=*" --config web.push_ssl=no
238 $ hg serve -R ../mirror -d -p $HGPORT2 --pid-file hg.pid --config largefiles.usercache=$TESTTMP/mirrorcache --config "web.allow_push=*" --config web.push_ssl=no
240 $ cat hg.pid >> $DAEMON_PIDS
239 $ cat hg.pid >> $DAEMON_PIDS
241
240
242 $ hg push http://localhost:$HGPORT2 -f --config largefiles.usercache=nocache
241 $ hg push http://localhost:$HGPORT2 -f --config largefiles.usercache=nocache
243 pushing to http://localhost:$HGPORT2/
242 pushing to http://localhost:$HGPORT2/
244 searching for changes
243 searching for changes
245 abort: largefile e2fb5f2139d086ded2cb600d5a91a196e76bf020 missing from store (needs to be uploaded)
244 abort: largefile e2fb5f2139d086ded2cb600d5a91a196e76bf020 missing from store (needs to be uploaded)
246 [255]
245 [255]
247
246
248 Verify that --lfrev controls which revisions are checked for largefiles to push
247 Verify that --lfrev controls which revisions are checked for largefiles to push
249
248
250 $ hg push http://localhost:$HGPORT2 -f --config largefiles.usercache=nocache --lfrev tip
249 $ hg push http://localhost:$HGPORT2 -f --config largefiles.usercache=nocache --lfrev tip
251 pushing to http://localhost:$HGPORT2/
250 pushing to http://localhost:$HGPORT2/
252 searching for changes
251 searching for changes
253 abort: largefile e2fb5f2139d086ded2cb600d5a91a196e76bf020 missing from store (needs to be uploaded)
252 abort: largefile e2fb5f2139d086ded2cb600d5a91a196e76bf020 missing from store (needs to be uploaded)
254 [255]
253 [255]
255
254
256 $ hg push http://localhost:$HGPORT2 -f --config largefiles.usercache=nocache --lfrev null
255 $ hg push http://localhost:$HGPORT2 -f --config largefiles.usercache=nocache --lfrev null
257 pushing to http://localhost:$HGPORT2/
256 pushing to http://localhost:$HGPORT2/
258 searching for changes
257 searching for changes
259 remote: adding changesets
258 remote: adding changesets
260 remote: adding manifests
259 remote: adding manifests
261 remote: adding file changes
260 remote: adding file changes
262 remote: added 1 changesets with 1 changes to 1 files (+1 heads)
261 remote: added 1 changesets with 1 changes to 1 files (+1 heads)
263
262
264 #endif
263 #endif
@@ -1,1263 +1,1260 b''
1 ===================================
1 ===================================
2 Test the persistent on-disk nodemap
2 Test the persistent on-disk nodemap
3 ===================================
3 ===================================
4
4
5
5
6 $ cat << EOF >> $HGRCPATH
6 $ cat << EOF >> $HGRCPATH
7 > [format]
7 > [format]
8 > use-share-safe=yes
8 > use-share-safe=yes
9 > [extensions]
9 > [extensions]
10 > share=
10 > share=
11 > EOF
11 > EOF
12
12
13 #if no-rust
13 #if no-rust
14
14
15 $ cat << EOF >> $HGRCPATH
15 $ cat << EOF >> $HGRCPATH
16 > [format]
16 > [format]
17 > use-persistent-nodemap=yes
17 > use-persistent-nodemap=yes
18 > [devel]
18 > [devel]
19 > persistent-nodemap=yes
19 > persistent-nodemap=yes
20 > EOF
20 > EOF
21
21
22 #endif
22 #endif
23
23
24 $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow
24 $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow
25 $ cd test-repo
25 $ cd test-repo
26
26
27 Check handling of the default slow-path value
27 Check handling of the default slow-path value
28
28
29 #if no-pure no-rust
29 #if no-pure no-rust
30
30
31 $ hg id
31 $ hg id
32 abort: accessing `persistent-nodemap` repository without associated fast implementation.
32 abort: accessing `persistent-nodemap` repository without associated fast implementation.
33 (check `hg help config.format.use-persistent-nodemap` for details)
33 (check `hg help config.format.use-persistent-nodemap` for details)
34 [255]
34 [255]
35
35
36 Unlock further check (we are here to test the feature)
36 Unlock further check (we are here to test the feature)
37
37
38 $ cat << EOF >> $HGRCPATH
38 $ cat << EOF >> $HGRCPATH
39 > [storage]
39 > [storage]
40 > # to avoid spamming the test
40 > # to avoid spamming the test
41 > revlog.persistent-nodemap.slow-path=allow
41 > revlog.persistent-nodemap.slow-path=allow
42 > EOF
42 > EOF
43
43
44 #endif
44 #endif
45
45
46 #if rust
46 #if rust
47
47
48 Regression test for a previous bug in Rust/C FFI for the `Revlog_CAPI` capsule:
48 Regression test for a previous bug in Rust/C FFI for the `Revlog_CAPI` capsule:
49 in places where `mercurial/cext/revlog.c` function signatures use `Py_ssize_t`
49 in places where `mercurial/cext/revlog.c` function signatures use `Py_ssize_t`
50 (64 bits on Linux x86_64), corresponding declarations in `rust/hg-cpython/src/cindex.rs`
50 (64 bits on Linux x86_64), corresponding declarations in `rust/hg-cpython/src/cindex.rs`
51 incorrectly used `libc::c_int` (32 bits).
51 incorrectly used `libc::c_int` (32 bits).
52 As a result, -1 passed from Rust for the null revision became 4294967295 in C.
52 As a result, -1 passed from Rust for the null revision became 4294967295 in C.
53
53
54 $ hg log -r 00000000
54 $ hg log -r 00000000
55 changeset: -1:000000000000
55 changeset: -1:000000000000
56 tag: tip
56 tag: tip
57 user:
57 user:
58 date: Thu Jan 01 00:00:00 1970 +0000
58 date: Thu Jan 01 00:00:00 1970 +0000
59
59
60
60
61 #endif
61 #endif
62
62
63
63
64 $ hg debugformat
64 $ hg debugformat
65 format-variant repo
65 format-variant repo
66 fncache: yes
66 fncache: yes
67 dirstate-v2: no
67 dirstate-v2: no
68 tracked-hint: no
68 tracked-hint: no
69 dotencode: yes
69 dotencode: yes
70 generaldelta: yes
70 generaldelta: yes
71 share-safe: yes
71 share-safe: yes
72 sparserevlog: yes
72 sparserevlog: yes
73 persistent-nodemap: yes
73 persistent-nodemap: yes
74 copies-sdc: no
74 copies-sdc: no
75 revlog-v2: no
75 revlog-v2: no
76 changelog-v2: no
76 changelog-v2: no
77 plain-cl-delta: yes
77 plain-cl-delta: yes
78 compression: zlib (no-zstd !)
78 compression: zlib (no-zstd !)
79 compression: zstd (zstd !)
79 compression: zstd (zstd !)
80 compression-level: default
80 compression-level: default
81 $ hg debugbuilddag .+5000 --new-file
81 $ hg debugbuilddag .+5000 --new-file
82
82
83 $ hg debugnodemap --metadata
83 $ hg debugnodemap --metadata
84 uid: ???????? (glob)
84 uid: ???????? (glob)
85 tip-rev: 5000
85 tip-rev: 5000
86 tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c
86 tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c
87 data-length: 121088
87 data-length: 121088
88 data-unused: 0
88 data-unused: 0
89 data-unused: 0.000%
89 data-unused: 0.000%
90 $ f --size .hg/store/00changelog.n
90 $ f --size .hg/store/00changelog.n
91 .hg/store/00changelog.n: size=62
91 .hg/store/00changelog.n: size=62
92
92
93 Simple lookup works
93 Simple lookup works
94
94
95 $ ANYNODE=`hg log --template '{node|short}\n' --rev tip`
95 $ ANYNODE=`hg log --template '{node|short}\n' --rev tip`
96 $ hg log -r "$ANYNODE" --template '{rev}\n'
96 $ hg log -r "$ANYNODE" --template '{rev}\n'
97 5000
97 5000
98
98
99
99
100 #if rust
100 #if rust
101
101
102 $ f --sha256 .hg/store/00changelog-*.nd
102 $ f --sha256 .hg/store/00changelog-*.nd
103 .hg/store/00changelog-????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob)
103 .hg/store/00changelog-????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob)
104
104
105 $ f --sha256 .hg/store/00manifest-*.nd
105 $ f --sha256 .hg/store/00manifest-*.nd
106 .hg/store/00manifest-????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob)
106 .hg/store/00manifest-????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob)
107 $ hg debugnodemap --dump-new | f --sha256 --size
107 $ hg debugnodemap --dump-new | f --sha256 --size
108 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
108 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
109 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
109 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
110 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
110 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
111 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........|
111 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........|
112 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."|
112 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."|
113 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^|
113 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^|
114 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....|
114 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....|
115 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8|
115 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8|
116 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i|
116 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i|
117 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....|
117 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....|
118 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........|
118 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........|
119 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....|
119 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....|
120 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................|
120 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................|
121 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+|
121 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+|
122 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................|
122 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................|
123 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5|
123 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5|
124 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U|
124 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U|
125 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................|
125 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................|
126 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................|
126 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................|
127
127
128
128
129 #else
129 #else
130
130
131 $ f --sha256 .hg/store/00changelog-*.nd
131 $ f --sha256 .hg/store/00changelog-*.nd
132 .hg/store/00changelog-????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob)
132 .hg/store/00changelog-????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob)
133 $ hg debugnodemap --dump-new | f --sha256 --size
133 $ hg debugnodemap --dump-new | f --sha256 --size
134 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
134 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
135 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
135 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
136 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
136 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
137 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
137 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
138 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
138 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
139 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................|
139 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................|
140 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................|
140 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................|
141 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
141 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
142 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................|
142 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................|
143 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............|
143 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............|
144 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
144 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
145 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
145 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
146 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................|
146 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................|
147 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........|
147 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........|
148 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
148 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
149 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
149 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
150 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
150 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
151 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................|
151 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................|
152 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................|
152 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................|
153
153
154 #endif
154 #endif
155
155
156 $ hg debugnodemap --check
156 $ hg debugnodemap --check
157 revision in index: 5001
157 revision in index: 5001
158 revision in nodemap: 5001
158 revision in nodemap: 5001
159
159
160 add a new commit
160 add a new commit
161
161
162 $ hg up
162 $ hg up
163 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
163 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
164 $ echo foo > foo
164 $ echo foo > foo
165 $ hg add foo
165 $ hg add foo
166
166
167
167
168 Check slow-path config value handling
168 Check slow-path config value handling
169 -------------------------------------
169 -------------------------------------
170
170
171 #if no-pure no-rust
171 #if no-pure no-rust
172
172
173 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
173 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
174 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
174 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
175 falling back to default value: abort
175 falling back to default value: abort
176 abort: accessing `persistent-nodemap` repository without associated fast implementation.
176 abort: accessing `persistent-nodemap` repository without associated fast implementation.
177 (check `hg help config.format.use-persistent-nodemap` for details)
177 (check `hg help config.format.use-persistent-nodemap` for details)
178 [255]
178 [255]
179
179
180 $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn"
180 $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn"
181 warning: accessing `persistent-nodemap` repository without associated fast implementation.
181 warning: accessing `persistent-nodemap` repository without associated fast implementation.
182 (check `hg help config.format.use-persistent-nodemap` for details)
182 (check `hg help config.format.use-persistent-nodemap` for details)
183 changeset: 5000:6b02b8c7b966
183 changeset: 5000:6b02b8c7b966
184 tag: tip
184 tag: tip
185 user: debugbuilddag
185 user: debugbuilddag
186 date: Thu Jan 01 01:23:20 1970 +0000
186 date: Thu Jan 01 01:23:20 1970 +0000
187 summary: r5000
187 summary: r5000
188
188
189 $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort"
189 $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort"
190 abort: accessing `persistent-nodemap` repository without associated fast implementation.
190 abort: accessing `persistent-nodemap` repository without associated fast implementation.
191 (check `hg help config.format.use-persistent-nodemap` for details)
191 (check `hg help config.format.use-persistent-nodemap` for details)
192 [255]
192 [255]
193
193
194 #else
194 #else
195
195
196 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
196 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
197 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
197 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
198 falling back to default value: abort
198 falling back to default value: abort
199 6b02b8c7b966+ tip
199 6b02b8c7b966+ tip
200
200
201 #endif
201 #endif
202
202
203 $ hg ci -m 'foo'
203 $ hg ci -m 'foo'
204
204
205 #if no-pure no-rust
205 #if no-pure no-rust
206 $ hg debugnodemap --metadata
206 $ hg debugnodemap --metadata
207 uid: ???????? (glob)
207 uid: ???????? (glob)
208 tip-rev: 5001
208 tip-rev: 5001
209 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
209 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
210 data-length: 121088
210 data-length: 121088
211 data-unused: 0
211 data-unused: 0
212 data-unused: 0.000%
212 data-unused: 0.000%
213 #else
213 #else
214 $ hg debugnodemap --metadata
214 $ hg debugnodemap --metadata
215 uid: ???????? (glob)
215 uid: ???????? (glob)
216 tip-rev: 5001
216 tip-rev: 5001
217 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
217 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
218 data-length: 121344
218 data-length: 121344
219 data-unused: 256
219 data-unused: 256
220 data-unused: 0.211%
220 data-unused: 0.211%
221 #endif
221 #endif
222
222
223 $ f --size .hg/store/00changelog.n
223 $ f --size .hg/store/00changelog.n
224 .hg/store/00changelog.n: size=62
224 .hg/store/00changelog.n: size=62
225
225
226 (The pure code use the debug code that perform incremental update, the C code reencode from scratch)
226 (The pure code use the debug code that perform incremental update, the C code reencode from scratch)
227
227
228 #if pure
228 #if pure
229 $ f --sha256 .hg/store/00changelog-*.nd --size
229 $ f --sha256 .hg/store/00changelog-*.nd --size
230 .hg/store/00changelog-????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob)
230 .hg/store/00changelog-????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob)
231 #endif
231 #endif
232
232
233 #if rust
233 #if rust
234 $ f --sha256 .hg/store/00changelog-*.nd --size
234 $ f --sha256 .hg/store/00changelog-*.nd --size
235 .hg/store/00changelog-????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob)
235 .hg/store/00changelog-????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob)
236 #endif
236 #endif
237
237
238 #if no-pure no-rust
238 #if no-pure no-rust
239 $ f --sha256 .hg/store/00changelog-*.nd --size
239 $ f --sha256 .hg/store/00changelog-*.nd --size
240 .hg/store/00changelog-????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob)
240 .hg/store/00changelog-????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob)
241 #endif
241 #endif
242
242
243 $ hg debugnodemap --check
243 $ hg debugnodemap --check
244 revision in index: 5002
244 revision in index: 5002
245 revision in nodemap: 5002
245 revision in nodemap: 5002
246
246
247 Test code path without mmap
247 Test code path without mmap
248 ---------------------------
248 ---------------------------
249
249
250 $ echo bar > bar
250 $ echo bar > bar
251 $ hg add bar
251 $ hg add bar
252 $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no
252 $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no
253
253
254 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes
254 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes
255 revision in index: 5003
255 revision in index: 5003
256 revision in nodemap: 5003
256 revision in nodemap: 5003
257 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no
257 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no
258 revision in index: 5003
258 revision in index: 5003
259 revision in nodemap: 5003
259 revision in nodemap: 5003
260
260
261
261
262 #if pure
262 #if pure
263 $ hg debugnodemap --metadata
263 $ hg debugnodemap --metadata
264 uid: ???????? (glob)
264 uid: ???????? (glob)
265 tip-rev: 5002
265 tip-rev: 5002
266 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
266 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
267 data-length: 121600
267 data-length: 121600
268 data-unused: 512
268 data-unused: 512
269 data-unused: 0.421%
269 data-unused: 0.421%
270 $ f --sha256 .hg/store/00changelog-*.nd --size
270 $ f --sha256 .hg/store/00changelog-*.nd --size
271 .hg/store/00changelog-????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob)
271 .hg/store/00changelog-????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob)
272 #endif
272 #endif
273 #if rust
273 #if rust
274 $ hg debugnodemap --metadata
274 $ hg debugnodemap --metadata
275 uid: ???????? (glob)
275 uid: ???????? (glob)
276 tip-rev: 5002
276 tip-rev: 5002
277 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
277 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
278 data-length: 121600
278 data-length: 121600
279 data-unused: 512
279 data-unused: 512
280 data-unused: 0.421%
280 data-unused: 0.421%
281 $ f --sha256 .hg/store/00changelog-*.nd --size
281 $ f --sha256 .hg/store/00changelog-*.nd --size
282 .hg/store/00changelog-????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob)
282 .hg/store/00changelog-????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob)
283 #endif
283 #endif
284 #if no-pure no-rust
284 #if no-pure no-rust
285 $ hg debugnodemap --metadata
285 $ hg debugnodemap --metadata
286 uid: ???????? (glob)
286 uid: ???????? (glob)
287 tip-rev: 5002
287 tip-rev: 5002
288 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
288 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
289 data-length: 121088
289 data-length: 121088
290 data-unused: 0
290 data-unused: 0
291 data-unused: 0.000%
291 data-unused: 0.000%
292 $ f --sha256 .hg/store/00changelog-*.nd --size
292 $ f --sha256 .hg/store/00changelog-*.nd --size
293 .hg/store/00changelog-????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob)
293 .hg/store/00changelog-????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob)
294 #endif
294 #endif
295
295
296 Test force warming the cache
296 Test force warming the cache
297
297
298 $ rm .hg/store/00changelog.n
298 $ rm .hg/store/00changelog.n
299 $ hg debugnodemap --metadata
299 $ hg debugnodemap --metadata
300 $ hg debugupdatecache
300 $ hg debugupdatecache
301 #if pure
301 #if pure
302 $ hg debugnodemap --metadata
302 $ hg debugnodemap --metadata
303 uid: ???????? (glob)
303 uid: ???????? (glob)
304 tip-rev: 5002
304 tip-rev: 5002
305 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
305 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
306 data-length: 121088
306 data-length: 121088
307 data-unused: 0
307 data-unused: 0
308 data-unused: 0.000%
308 data-unused: 0.000%
309 #else
309 #else
310 $ hg debugnodemap --metadata
310 $ hg debugnodemap --metadata
311 uid: ???????? (glob)
311 uid: ???????? (glob)
312 tip-rev: 5002
312 tip-rev: 5002
313 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
313 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
314 data-length: 121088
314 data-length: 121088
315 data-unused: 0
315 data-unused: 0
316 data-unused: 0.000%
316 data-unused: 0.000%
317 #endif
317 #endif
318
318
319 Check out of sync nodemap
319 Check out of sync nodemap
320 =========================
320 =========================
321
321
322 First copy old data on the side.
322 First copy old data on the side.
323
323
324 $ mkdir ../tmp-copies
324 $ mkdir ../tmp-copies
325 $ cp .hg/store/00changelog-????????.nd .hg/store/00changelog.n ../tmp-copies
325 $ cp .hg/store/00changelog-????????.nd .hg/store/00changelog.n ../tmp-copies
326
326
327 Nodemap lagging behind
327 Nodemap lagging behind
328 ----------------------
328 ----------------------
329
329
330 make a new commit
330 make a new commit
331
331
332 $ echo bar2 > bar
332 $ echo bar2 > bar
333 $ hg ci -m 'bar2'
333 $ hg ci -m 'bar2'
334 $ NODE=`hg log -r tip -T '{node}\n'`
334 $ NODE=`hg log -r tip -T '{node}\n'`
335 $ hg log -r "$NODE" -T '{rev}\n'
335 $ hg log -r "$NODE" -T '{rev}\n'
336 5003
336 5003
337
337
338 If the nodemap is lagging behind, it can catch up fine
338 If the nodemap is lagging behind, it can catch up fine
339
339
340 $ hg debugnodemap --metadata
340 $ hg debugnodemap --metadata
341 uid: ???????? (glob)
341 uid: ???????? (glob)
342 tip-rev: 5003
342 tip-rev: 5003
343 tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3
343 tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3
344 data-length: 121344 (pure !)
344 data-length: 121344 (pure !)
345 data-length: 121344 (rust !)
345 data-length: 121344 (rust !)
346 data-length: 121152 (no-rust no-pure !)
346 data-length: 121152 (no-rust no-pure !)
347 data-unused: 192 (pure !)
347 data-unused: 192 (pure !)
348 data-unused: 192 (rust !)
348 data-unused: 192 (rust !)
349 data-unused: 0 (no-rust no-pure !)
349 data-unused: 0 (no-rust no-pure !)
350 data-unused: 0.158% (pure !)
350 data-unused: 0.158% (pure !)
351 data-unused: 0.158% (rust !)
351 data-unused: 0.158% (rust !)
352 data-unused: 0.000% (no-rust no-pure !)
352 data-unused: 0.000% (no-rust no-pure !)
353 $ cp -f ../tmp-copies/* .hg/store/
353 $ cp -f ../tmp-copies/* .hg/store/
354 $ hg debugnodemap --metadata
354 $ hg debugnodemap --metadata
355 uid: ???????? (glob)
355 uid: ???????? (glob)
356 tip-rev: 5002
356 tip-rev: 5002
357 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
357 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
358 data-length: 121088
358 data-length: 121088
359 data-unused: 0
359 data-unused: 0
360 data-unused: 0.000%
360 data-unused: 0.000%
361 $ hg log -r "$NODE" -T '{rev}\n'
361 $ hg log -r "$NODE" -T '{rev}\n'
362 5003
362 5003
363
363
364 changelog altered
364 changelog altered
365 -----------------
365 -----------------
366
366
367 If the nodemap is not gated behind a requirements, an unaware client can alter
367 If the nodemap is not gated behind a requirements, an unaware client can alter
368 the repository so the revlog used to generate the nodemap is not longer
368 the repository so the revlog used to generate the nodemap is not longer
369 compatible with the persistent nodemap. We need to detect that.
369 compatible with the persistent nodemap. We need to detect that.
370
370
371 $ hg up "$NODE~5"
371 $ hg up "$NODE~5"
372 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
372 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
373 $ echo bar > babar
373 $ echo bar > babar
374 $ hg add babar
374 $ hg add babar
375 $ hg ci -m 'babar'
375 $ hg ci -m 'babar'
376 created new head
376 created new head
377 $ OTHERNODE=`hg log -r tip -T '{node}\n'`
377 $ OTHERNODE=`hg log -r tip -T '{node}\n'`
378 $ hg log -r "$OTHERNODE" -T '{rev}\n'
378 $ hg log -r "$OTHERNODE" -T '{rev}\n'
379 5004
379 5004
380
380
381 $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup
381 $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup
382
382
383 the nodemap should detect the changelog have been tampered with and recover.
383 the nodemap should detect the changelog have been tampered with and recover.
384
384
385 $ hg debugnodemap --metadata
385 $ hg debugnodemap --metadata
386 uid: ???????? (glob)
386 uid: ???????? (glob)
387 tip-rev: 5002
387 tip-rev: 5002
388 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
388 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
389 data-length: 121536 (pure !)
389 data-length: 121536 (pure !)
390 data-length: 121088 (rust !)
390 data-length: 121088 (rust !)
391 data-length: 121088 (no-pure no-rust !)
391 data-length: 121088 (no-pure no-rust !)
392 data-unused: 448 (pure !)
392 data-unused: 448 (pure !)
393 data-unused: 0 (rust !)
393 data-unused: 0 (rust !)
394 data-unused: 0 (no-pure no-rust !)
394 data-unused: 0 (no-pure no-rust !)
395 data-unused: 0.000% (rust !)
395 data-unused: 0.000% (rust !)
396 data-unused: 0.369% (pure !)
396 data-unused: 0.369% (pure !)
397 data-unused: 0.000% (no-pure no-rust !)
397 data-unused: 0.000% (no-pure no-rust !)
398
398
399 $ cp -f ../tmp-copies/* .hg/store/
399 $ cp -f ../tmp-copies/* .hg/store/
400 $ hg debugnodemap --metadata
400 $ hg debugnodemap --metadata
401 uid: ???????? (glob)
401 uid: ???????? (glob)
402 tip-rev: 5002
402 tip-rev: 5002
403 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
403 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
404 data-length: 121088
404 data-length: 121088
405 data-unused: 0
405 data-unused: 0
406 data-unused: 0.000%
406 data-unused: 0.000%
407 $ hg log -r "$OTHERNODE" -T '{rev}\n'
407 $ hg log -r "$OTHERNODE" -T '{rev}\n'
408 5002
408 5002
409
409
410 missing data file
410 missing data file
411 -----------------
411 -----------------
412
412
413 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
413 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
414 > sed 's/uid: //'`
414 > sed 's/uid: //'`
415 $ FILE=.hg/store/00changelog-"${UUID}".nd
415 $ FILE=.hg/store/00changelog-"${UUID}".nd
416 $ mv $FILE ../tmp-data-file
416 $ mv $FILE ../tmp-data-file
417 $ cp .hg/store/00changelog.n ../tmp-docket
417 $ cp .hg/store/00changelog.n ../tmp-docket
418
418
419 mercurial don't crash
419 mercurial don't crash
420
420
421 $ hg log -r .
421 $ hg log -r .
422 changeset: 5002:b355ef8adce0
422 changeset: 5002:b355ef8adce0
423 tag: tip
423 tag: tip
424 parent: 4998:d918ad6d18d3
424 parent: 4998:d918ad6d18d3
425 user: test
425 user: test
426 date: Thu Jan 01 00:00:00 1970 +0000
426 date: Thu Jan 01 00:00:00 1970 +0000
427 summary: babar
427 summary: babar
428
428
429 $ hg debugnodemap --metadata
429 $ hg debugnodemap --metadata
430
430
431 $ hg debugupdatecache
431 $ hg debugupdatecache
432 $ hg debugnodemap --metadata
432 $ hg debugnodemap --metadata
433 uid: * (glob)
433 uid: * (glob)
434 tip-rev: 5002
434 tip-rev: 5002
435 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
435 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
436 data-length: 121088
436 data-length: 121088
437 data-unused: 0
437 data-unused: 0
438 data-unused: 0.000%
438 data-unused: 0.000%
439 $ mv ../tmp-data-file $FILE
439 $ mv ../tmp-data-file $FILE
440 $ mv ../tmp-docket .hg/store/00changelog.n
440 $ mv ../tmp-docket .hg/store/00changelog.n
441
441
442 Check transaction related property
442 Check transaction related property
443 ==================================
443 ==================================
444
444
445 An up to date nodemap should be available to shell hooks,
445 An up to date nodemap should be available to shell hooks,
446
446
447 $ echo dsljfl > a
447 $ echo dsljfl > a
448 $ hg add a
448 $ hg add a
449 $ hg ci -m a
449 $ hg ci -m a
450 $ hg debugnodemap --metadata
450 $ hg debugnodemap --metadata
451 uid: ???????? (glob)
451 uid: ???????? (glob)
452 tip-rev: 5003
452 tip-rev: 5003
453 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
453 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
454 data-length: 121088
454 data-length: 121088
455 data-unused: 0
455 data-unused: 0
456 data-unused: 0.000%
456 data-unused: 0.000%
457 $ echo babar2 > babar
457 $ echo babar2 > babar
458 $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata"
458 $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata"
459 uid: ???????? (glob)
459 uid: ???????? (glob)
460 tip-rev: 5004
460 tip-rev: 5004
461 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
461 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
462 data-length: 121280 (pure !)
462 data-length: 121280 (pure !)
463 data-length: 121280 (rust !)
463 data-length: 121280 (rust !)
464 data-length: 121088 (no-pure no-rust !)
464 data-length: 121088 (no-pure no-rust !)
465 data-unused: 192 (pure !)
465 data-unused: 192 (pure !)
466 data-unused: 192 (rust !)
466 data-unused: 192 (rust !)
467 data-unused: 0 (no-pure no-rust !)
467 data-unused: 0 (no-pure no-rust !)
468 data-unused: 0.158% (pure !)
468 data-unused: 0.158% (pure !)
469 data-unused: 0.158% (rust !)
469 data-unused: 0.158% (rust !)
470 data-unused: 0.000% (no-pure no-rust !)
470 data-unused: 0.000% (no-pure no-rust !)
471 $ hg debugnodemap --metadata
471 $ hg debugnodemap --metadata
472 uid: ???????? (glob)
472 uid: ???????? (glob)
473 tip-rev: 5004
473 tip-rev: 5004
474 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
474 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
475 data-length: 121280 (pure !)
475 data-length: 121280 (pure !)
476 data-length: 121280 (rust !)
476 data-length: 121280 (rust !)
477 data-length: 121088 (no-pure no-rust !)
477 data-length: 121088 (no-pure no-rust !)
478 data-unused: 192 (pure !)
478 data-unused: 192 (pure !)
479 data-unused: 192 (rust !)
479 data-unused: 192 (rust !)
480 data-unused: 0 (no-pure no-rust !)
480 data-unused: 0 (no-pure no-rust !)
481 data-unused: 0.158% (pure !)
481 data-unused: 0.158% (pure !)
482 data-unused: 0.158% (rust !)
482 data-unused: 0.158% (rust !)
483 data-unused: 0.000% (no-pure no-rust !)
483 data-unused: 0.000% (no-pure no-rust !)
484
484
485 Another process does not see the pending nodemap content during run.
485 Another process does not see the pending nodemap content during run.
486
486
487 $ echo qpoasp > a
487 $ echo qpoasp > a
488 $ hg ci -m a2 \
488 $ hg ci -m a2 \
489 > --config "hooks.pretxnclose=sh \"$RUNTESTDIR/testlib/wait-on-file\" 20 sync-repo-read sync-txn-pending" \
489 > --config "hooks.pretxnclose=sh \"$RUNTESTDIR/testlib/wait-on-file\" 20 sync-repo-read sync-txn-pending" \
490 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
490 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
491
491
492 (read the repository while the commit transaction is pending)
492 (read the repository while the commit transaction is pending)
493
493
494 $ sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-pending && \
494 $ sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-pending && \
495 > hg debugnodemap --metadata && \
495 > hg debugnodemap --metadata && \
496 > sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-close sync-repo-read
496 > sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-close sync-repo-read
497 uid: ???????? (glob)
497 uid: ???????? (glob)
498 tip-rev: 5004
498 tip-rev: 5004
499 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
499 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
500 data-length: 121280 (pure !)
500 data-length: 121280 (pure !)
501 data-length: 121280 (rust !)
501 data-length: 121280 (rust !)
502 data-length: 121088 (no-pure no-rust !)
502 data-length: 121088 (no-pure no-rust !)
503 data-unused: 192 (pure !)
503 data-unused: 192 (pure !)
504 data-unused: 192 (rust !)
504 data-unused: 192 (rust !)
505 data-unused: 0 (no-pure no-rust !)
505 data-unused: 0 (no-pure no-rust !)
506 data-unused: 0.158% (pure !)
506 data-unused: 0.158% (pure !)
507 data-unused: 0.158% (rust !)
507 data-unused: 0.158% (rust !)
508 data-unused: 0.000% (no-pure no-rust !)
508 data-unused: 0.000% (no-pure no-rust !)
509 $ hg debugnodemap --metadata
509 $ hg debugnodemap --metadata
510 uid: ???????? (glob)
510 uid: ???????? (glob)
511 tip-rev: 5005
511 tip-rev: 5005
512 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
512 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
513 data-length: 121536 (pure !)
513 data-length: 121536 (pure !)
514 data-length: 121536 (rust !)
514 data-length: 121536 (rust !)
515 data-length: 121088 (no-pure no-rust !)
515 data-length: 121088 (no-pure no-rust !)
516 data-unused: 448 (pure !)
516 data-unused: 448 (pure !)
517 data-unused: 448 (rust !)
517 data-unused: 448 (rust !)
518 data-unused: 0 (no-pure no-rust !)
518 data-unused: 0 (no-pure no-rust !)
519 data-unused: 0.369% (pure !)
519 data-unused: 0.369% (pure !)
520 data-unused: 0.369% (rust !)
520 data-unused: 0.369% (rust !)
521 data-unused: 0.000% (no-pure no-rust !)
521 data-unused: 0.000% (no-pure no-rust !)
522
522
523 $ cat output.txt
523 $ cat output.txt
524
524
525 Check that a failing transaction will properly revert the data
525 Check that a failing transaction will properly revert the data
526
526
527 $ echo plakfe > a
527 $ echo plakfe > a
528 $ f --size --sha256 .hg/store/00changelog-*.nd
528 $ f --size --sha256 .hg/store/00changelog-*.nd
529 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
529 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
530 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
530 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
531 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
531 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
532 $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py"
532 $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py"
533 transaction abort!
533 transaction abort!
534 rollback completed
534 rollback completed
535 abort: This is a late abort
535 abort: This is a late abort
536 [255]
536 [255]
537 $ hg debugnodemap --metadata
537 $ hg debugnodemap --metadata
538 uid: ???????? (glob)
538 uid: ???????? (glob)
539 tip-rev: 5005
539 tip-rev: 5005
540 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
540 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
541 data-length: 121536 (pure !)
541 data-length: 121536 (pure !)
542 data-length: 121536 (rust !)
542 data-length: 121536 (rust !)
543 data-length: 121088 (no-pure no-rust !)
543 data-length: 121088 (no-pure no-rust !)
544 data-unused: 448 (pure !)
544 data-unused: 448 (pure !)
545 data-unused: 448 (rust !)
545 data-unused: 448 (rust !)
546 data-unused: 0 (no-pure no-rust !)
546 data-unused: 0 (no-pure no-rust !)
547 data-unused: 0.369% (pure !)
547 data-unused: 0.369% (pure !)
548 data-unused: 0.369% (rust !)
548 data-unused: 0.369% (rust !)
549 data-unused: 0.000% (no-pure no-rust !)
549 data-unused: 0.000% (no-pure no-rust !)
550 $ f --size --sha256 .hg/store/00changelog-*.nd
550 $ f --size --sha256 .hg/store/00changelog-*.nd
551 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
551 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
552 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
552 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
553 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
553 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
554
554
555 Check that removing content does not confuse the nodemap
555 Check that removing content does not confuse the nodemap
556 --------------------------------------------------------
556 --------------------------------------------------------
557
557
558 removing data with rollback
558 removing data with rollback
559
559
560 $ echo aso > a
560 $ echo aso > a
561 $ hg ci -m a4
561 $ hg ci -m a4
562 $ hg rollback
562 $ hg rollback
563 repository tip rolled back to revision 5005 (undo commit)
563 repository tip rolled back to revision 5005 (undo commit)
564 working directory now based on revision 5005
564 working directory now based on revision 5005
565 $ hg id -r .
565 $ hg id -r .
566 90d5d3ba2fc4 tip
566 90d5d3ba2fc4 tip
567
567
568 removing data with strip
568 removing data with strip
569
569
570 $ echo aso > a
570 $ echo aso > a
571 $ hg ci -m a4
571 $ hg ci -m a4
572 $ hg --config extensions.strip= strip -r . --no-backup
572 $ hg --config extensions.strip= strip -r . --no-backup
573 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
573 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
574 $ hg id -r . --traceback
574 $ hg id -r . --traceback
575 90d5d3ba2fc4 tip
575 90d5d3ba2fc4 tip
576
576
577 (be a good citizen and regenerate the nodemap)
577 (be a good citizen and regenerate the nodemap)
578 $ hg debugupdatecaches
578 $ hg debugupdatecaches
579 $ hg debugnodemap --metadata
579 $ hg debugnodemap --metadata
580 uid: * (glob)
580 uid: * (glob)
581 tip-rev: 5005
581 tip-rev: 5005
582 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
582 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
583 data-length: 121088
583 data-length: 121088
584 data-unused: 0
584 data-unused: 0
585 data-unused: 0.000%
585 data-unused: 0.000%
586
586
587 Check race condition when multiple process write new data to the repository
587 Check race condition when multiple process write new data to the repository
588 ---------------------------------------------------------------------------
588 ---------------------------------------------------------------------------
589
589
590 In this test, we check that two writers touching the repositories will not
590 In this test, we check that two writers touching the repositories will not
591 overwrite each other data. This test is prompted by the existent of issue6554.
591 overwrite each other data. This test is prompted by the existent of issue6554.
592 Where a writer ended up using and outdated docket to update the repository. See
592 Where a writer ended up using and outdated docket to update the repository. See
593 the dedicated extension for details on the race windows and read/write schedule
593 the dedicated extension for details on the race windows and read/write schedule
594 necessary to end up in this situation: testlib/persistent-nodemap-race-ext.py
594 necessary to end up in this situation: testlib/persistent-nodemap-race-ext.py
595
595
596 The issue was initially observed on a server with a high push trafic, but it
596 The issue was initially observed on a server with a high push trafic, but it
597 can be reproduced using a share and two commiting process which seems simpler.
597 can be reproduced using a share and two commiting process which seems simpler.
598
598
599 The test is Rust only as the other implementation does not use the same
599 The test is Rust only as the other implementation does not use the same
600 read/write patterns.
600 read/write patterns.
601
601
602 $ cd ..
602 $ cd ..
603
603
604 #if rust
604 #if rust
605
605
606 $ cp -R test-repo race-repo
606 $ cp -R test-repo race-repo
607 $ hg share race-repo ./other-wc --config format.use-share-safe=yes
607 $ hg share race-repo ./other-wc --config format.use-share-safe=yes
608 updating working directory
608 updating working directory
609 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
609 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
610 $ hg debugformat -R ./race-repo | egrep 'share-safe|persistent-nodemap'
610 $ hg debugformat -R ./race-repo | egrep 'share-safe|persistent-nodemap'
611 share-safe: yes
611 share-safe: yes
612 persistent-nodemap: yes
612 persistent-nodemap: yes
613 $ hg debugformat -R ./other-wc/ | egrep 'share-safe|persistent-nodemap'
613 $ hg debugformat -R ./other-wc/ | egrep 'share-safe|persistent-nodemap'
614 share-safe: yes
614 share-safe: yes
615 persistent-nodemap: yes
615 persistent-nodemap: yes
616 $ hg -R ./other-wc update 'min(head())'
616 $ hg -R ./other-wc update 'min(head())'
617 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
617 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
618 $ hg -R ./race-repo debugnodemap --metadata
618 $ hg -R ./race-repo debugnodemap --metadata
619 uid: 43c37dde
619 uid: 43c37dde
620 tip-rev: 5005
620 tip-rev: 5005
621 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
621 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
622 data-length: 121088
622 data-length: 121088
623 data-unused: 0
623 data-unused: 0
624 data-unused: 0.000%
624 data-unused: 0.000%
625 $ hg -R ./race-repo log -G -r 'head()'
625 $ hg -R ./race-repo log -G -r 'head()'
626 @ changeset: 5005:90d5d3ba2fc4
626 @ changeset: 5005:90d5d3ba2fc4
627 | tag: tip
627 | tag: tip
628 ~ user: test
628 ~ user: test
629 date: Thu Jan 01 00:00:00 1970 +0000
629 date: Thu Jan 01 00:00:00 1970 +0000
630 summary: a2
630 summary: a2
631
631
632 o changeset: 5001:16395c3cf7e2
632 o changeset: 5001:16395c3cf7e2
633 | user: test
633 | user: test
634 ~ date: Thu Jan 01 00:00:00 1970 +0000
634 ~ date: Thu Jan 01 00:00:00 1970 +0000
635 summary: foo
635 summary: foo
636
636
637 $ hg -R ./other-wc log -G -r 'head()'
637 $ hg -R ./other-wc log -G -r 'head()'
638 o changeset: 5005:90d5d3ba2fc4
638 o changeset: 5005:90d5d3ba2fc4
639 | tag: tip
639 | tag: tip
640 ~ user: test
640 ~ user: test
641 date: Thu Jan 01 00:00:00 1970 +0000
641 date: Thu Jan 01 00:00:00 1970 +0000
642 summary: a2
642 summary: a2
643
643
644 @ changeset: 5001:16395c3cf7e2
644 @ changeset: 5001:16395c3cf7e2
645 | user: test
645 | user: test
646 ~ date: Thu Jan 01 00:00:00 1970 +0000
646 ~ date: Thu Jan 01 00:00:00 1970 +0000
647 summary: foo
647 summary: foo
648
648
649 $ echo left-side-race > race-repo/left-side-race
649 $ echo left-side-race > race-repo/left-side-race
650 $ hg -R ./race-repo/ add race-repo/left-side-race
650 $ hg -R ./race-repo/ add race-repo/left-side-race
651
651
652 $ echo right-side-race > ./other-wc/right-side-race
652 $ echo right-side-race > ./other-wc/right-side-race
653 $ hg -R ./other-wc/ add ./other-wc/right-side-race
653 $ hg -R ./other-wc/ add ./other-wc/right-side-race
654
654
655 $ mkdir sync-files
655 $ mkdir sync-files
656 $ mkdir outputs
656 $ mkdir outputs
657 $ (
657 $ (
658 > hg -R ./race-repo/ commit -m left-side-commit \
658 > hg -R ./race-repo/ commit -m left-side-commit \
659 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
659 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
660 > --config 'devel.nodemap-race.role=left';
660 > --config 'devel.nodemap-race.role=left';
661 > touch sync-files/left-done
661 > touch sync-files/left-done
662 > ) > outputs/left.txt 2>&1 &
662 > ) > outputs/left.txt 2>&1 &
663 $ (
663 $ (
664 > hg -R ./other-wc/ commit -m right-side-commit \
664 > hg -R ./other-wc/ commit -m right-side-commit \
665 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
665 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
666 > --config 'devel.nodemap-race.role=right';
666 > --config 'devel.nodemap-race.role=right';
667 > touch sync-files/right-done
667 > touch sync-files/right-done
668 > ) > outputs/right.txt 2>&1 &
668 > ) > outputs/right.txt 2>&1 &
669 $ (
669 $ (
670 > hg -R ./race-repo/ check-nodemap-race \
670 > hg -R ./race-repo/ check-nodemap-race \
671 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
671 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
672 > --config 'devel.nodemap-race.role=reader';
672 > --config 'devel.nodemap-race.role=reader';
673 > touch sync-files/reader-done
673 > touch sync-files/reader-done
674 > ) > outputs/reader.txt 2>&1 &
674 > ) > outputs/reader.txt 2>&1 &
675 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/left-done
675 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/left-done
676 $ cat outputs/left.txt
676 $ cat outputs/left.txt
677 docket-details:
677 docket-details:
678 uid: 43c37dde
678 uid: 43c37dde
679 actual-tip: 5005
679 actual-tip: 5005
680 tip-rev: 5005
680 tip-rev: 5005
681 data-length: 121088
681 data-length: 121088
682 nodemap-race: left side locked and ready to commit
682 nodemap-race: left side locked and ready to commit
683 docket-details:
683 docket-details:
684 uid: 43c37dde
684 uid: 43c37dde
685 actual-tip: 5005
685 actual-tip: 5005
686 tip-rev: 5005
686 tip-rev: 5005
687 data-length: 121088
687 data-length: 121088
688 finalized changelog write
688 finalized changelog write
689 persisting changelog nodemap
689 persisting changelog nodemap
690 new data start at 121088
690 new data start at 121088
691 persisted changelog nodemap
691 persisted changelog nodemap
692 docket-details:
692 docket-details:
693 uid: 43c37dde
693 uid: 43c37dde
694 actual-tip: 5006
694 actual-tip: 5006
695 tip-rev: 5006
695 tip-rev: 5006
696 data-length: 121280
696 data-length: 121280
697 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/right-done
697 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/right-done
698 $ cat outputs/right.txt
698 $ cat outputs/right.txt
699 nodemap-race: right side start of the locking sequence
699 nodemap-race: right side start of the locking sequence
700 nodemap-race: right side reading changelog
700 nodemap-race: right side reading changelog
701 nodemap-race: right side reading of changelog is done
701 nodemap-race: right side reading of changelog is done
702 docket-details:
702 docket-details:
703 uid: 43c37dde
703 uid: 43c37dde
704 actual-tip: 5006
704 actual-tip: 5006
705 tip-rev: 5005
705 tip-rev: 5005
706 data-length: 121088
706 data-length: 121088
707 nodemap-race: right side ready to wait for the lock
707 nodemap-race: right side ready to wait for the lock
708 nodemap-race: right side locked and ready to commit
708 nodemap-race: right side locked and ready to commit
709 docket-details:
709 docket-details:
710 uid: 43c37dde
710 uid: 43c37dde
711 actual-tip: 5006
711 actual-tip: 5006
712 tip-rev: 5006
712 tip-rev: 5006
713 data-length: 121280
713 data-length: 121280
714 right ready to write, waiting for reader
714 right ready to write, waiting for reader
715 right proceeding with writing its changelog index and nodemap
715 right proceeding with writing its changelog index and nodemap
716 finalized changelog write
716 finalized changelog write
717 persisting changelog nodemap
717 persisting changelog nodemap
718 new data start at 121280
718 new data start at 121280
719 persisted changelog nodemap
719 persisted changelog nodemap
720 docket-details:
720 docket-details:
721 uid: 43c37dde
721 uid: 43c37dde
722 actual-tip: 5007
722 actual-tip: 5007
723 tip-rev: 5007
723 tip-rev: 5007
724 data-length: 121536
724 data-length: 121536
725 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/reader-done
725 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/reader-done
726 $ cat outputs/reader.txt
726 $ cat outputs/reader.txt
727 reader: reading changelog
727 reader: reading changelog
728 reader ready to read the changelog, waiting for right
728 reader ready to read the changelog, waiting for right
729 reader: nodemap docket read
729 reader: nodemap docket read
730 record-data-length: 121280
730 record-data-length: 121280
731 actual-data-length: 121280
731 actual-data-length: 121280
732 file-actual-length: 121536
732 file-actual-length: 121536
733 reader: changelog read
733 reader: changelog read
734 docket-details:
734 docket-details:
735 uid: 43c37dde
735 uid: 43c37dde
736 actual-tip: 5006
736 actual-tip: 5006
737 tip-rev: 5006
737 tip-rev: 5006
738 data-length: 121280
738 data-length: 121280
739 tip-rev: 5006
739 tip-rev: 5006
740 tip-node: 492901161367
740 tip-node: 492901161367
741 node-rev: 5006
741 node-rev: 5006
742
742
743 $ hg -R ./race-repo log -G -r 'head()'
743 $ hg -R ./race-repo log -G -r 'head()'
744 o changeset: 5007:ac4a2abde241
744 o changeset: 5007:ac4a2abde241
745 | tag: tip
745 | tag: tip
746 ~ parent: 5001:16395c3cf7e2
746 ~ parent: 5001:16395c3cf7e2
747 user: test
747 user: test
748 date: Thu Jan 01 00:00:00 1970 +0000
748 date: Thu Jan 01 00:00:00 1970 +0000
749 summary: right-side-commit
749 summary: right-side-commit
750
750
751 @ changeset: 5006:492901161367
751 @ changeset: 5006:492901161367
752 | user: test
752 | user: test
753 ~ date: Thu Jan 01 00:00:00 1970 +0000
753 ~ date: Thu Jan 01 00:00:00 1970 +0000
754 summary: left-side-commit
754 summary: left-side-commit
755
755
756 $ hg -R ./other-wc log -G -r 'head()'
756 $ hg -R ./other-wc log -G -r 'head()'
757 @ changeset: 5007:ac4a2abde241
757 @ changeset: 5007:ac4a2abde241
758 | tag: tip
758 | tag: tip
759 ~ parent: 5001:16395c3cf7e2
759 ~ parent: 5001:16395c3cf7e2
760 user: test
760 user: test
761 date: Thu Jan 01 00:00:00 1970 +0000
761 date: Thu Jan 01 00:00:00 1970 +0000
762 summary: right-side-commit
762 summary: right-side-commit
763
763
764 o changeset: 5006:492901161367
764 o changeset: 5006:492901161367
765 | user: test
765 | user: test
766 ~ date: Thu Jan 01 00:00:00 1970 +0000
766 ~ date: Thu Jan 01 00:00:00 1970 +0000
767 summary: left-side-commit
767 summary: left-side-commit
768
768
769 #endif
769 #endif
770
770
771 Test upgrade / downgrade
771 Test upgrade / downgrade
772 ========================
772 ========================
773
773
774 $ cd ./test-repo/
774 $ cd ./test-repo/
775
775
776 downgrading
776 downgrading
777
777
778 $ cat << EOF >> .hg/hgrc
778 $ cat << EOF >> .hg/hgrc
779 > [format]
779 > [format]
780 > use-persistent-nodemap=no
780 > use-persistent-nodemap=no
781 > EOF
781 > EOF
782 $ hg debugformat -v
782 $ hg debugformat -v
783 format-variant repo config default
783 format-variant repo config default
784 fncache: yes yes yes
784 fncache: yes yes yes
785 dirstate-v2: no no no
785 dirstate-v2: no no no
786 tracked-hint: no no no
786 tracked-hint: no no no
787 dotencode: yes yes yes
787 dotencode: yes yes yes
788 generaldelta: yes yes yes
788 generaldelta: yes yes yes
789 share-safe: yes yes yes
789 share-safe: yes yes yes
790 sparserevlog: yes yes yes
790 sparserevlog: yes yes yes
791 persistent-nodemap: yes no no
791 persistent-nodemap: yes no no
792 copies-sdc: no no no
792 copies-sdc: no no no
793 revlog-v2: no no no
793 revlog-v2: no no no
794 changelog-v2: no no no
794 changelog-v2: no no no
795 plain-cl-delta: yes yes yes
795 plain-cl-delta: yes yes yes
796 compression: zlib zlib zlib (no-zstd !)
796 compression: zlib zlib zlib (no-zstd !)
797 compression: zstd zstd zstd (zstd !)
797 compression: zstd zstd zstd (zstd !)
798 compression-level: default default default
798 compression-level: default default default
799 $ hg debugupgraderepo --run --no-backup --quiet
799 $ hg debugupgraderepo --run --no-backup --quiet
800 upgrade will perform the following actions:
800 upgrade will perform the following actions:
801
801
802 requirements
802 requirements
803 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
803 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
804 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
804 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
805 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
805 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
806 removed: persistent-nodemap
806 removed: persistent-nodemap
807
807
808 processed revlogs:
808 processed revlogs:
809 - all-filelogs
809 - all-filelogs
810 - changelog
810 - changelog
811 - manifest
811 - manifest
812
812
813 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
813 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
814 undo.backup.00changelog.n
814 [1]
815 undo.backup.00manifest.n
816 $ hg debugnodemap --metadata
815 $ hg debugnodemap --metadata
817
816
818
817
819 upgrading
818 upgrading
820
819
821 $ cat << EOF >> .hg/hgrc
820 $ cat << EOF >> .hg/hgrc
822 > [format]
821 > [format]
823 > use-persistent-nodemap=yes
822 > use-persistent-nodemap=yes
824 > EOF
823 > EOF
825 $ hg debugformat -v
824 $ hg debugformat -v
826 format-variant repo config default
825 format-variant repo config default
827 fncache: yes yes yes
826 fncache: yes yes yes
828 dirstate-v2: no no no
827 dirstate-v2: no no no
829 tracked-hint: no no no
828 tracked-hint: no no no
830 dotencode: yes yes yes
829 dotencode: yes yes yes
831 generaldelta: yes yes yes
830 generaldelta: yes yes yes
832 share-safe: yes yes yes
831 share-safe: yes yes yes
833 sparserevlog: yes yes yes
832 sparserevlog: yes yes yes
834 persistent-nodemap: no yes no
833 persistent-nodemap: no yes no
835 copies-sdc: no no no
834 copies-sdc: no no no
836 revlog-v2: no no no
835 revlog-v2: no no no
837 changelog-v2: no no no
836 changelog-v2: no no no
838 plain-cl-delta: yes yes yes
837 plain-cl-delta: yes yes yes
839 compression: zlib zlib zlib (no-zstd !)
838 compression: zlib zlib zlib (no-zstd !)
840 compression: zstd zstd zstd (zstd !)
839 compression: zstd zstd zstd (zstd !)
841 compression-level: default default default
840 compression-level: default default default
842 $ hg debugupgraderepo --run --no-backup --quiet
841 $ hg debugupgraderepo --run --no-backup --quiet
843 upgrade will perform the following actions:
842 upgrade will perform the following actions:
844
843
845 requirements
844 requirements
846 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
845 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
847 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
846 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
848 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
847 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
849 added: persistent-nodemap
848 added: persistent-nodemap
850
849
851 processed revlogs:
850 processed revlogs:
852 - all-filelogs
851 - all-filelogs
853 - changelog
852 - changelog
854 - manifest
853 - manifest
855
854
856 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
855 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
857 00changelog-*.nd (glob)
856 00changelog-*.nd (glob)
858 00changelog.n
857 00changelog.n
859 00manifest-*.nd (glob)
858 00manifest-*.nd (glob)
860 00manifest.n
859 00manifest.n
861 undo.backup.00changelog.n
862 undo.backup.00manifest.n
863
860
864 $ hg debugnodemap --metadata
861 $ hg debugnodemap --metadata
865 uid: * (glob)
862 uid: * (glob)
866 tip-rev: 5005
863 tip-rev: 5005
867 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
864 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
868 data-length: 121088
865 data-length: 121088
869 data-unused: 0
866 data-unused: 0
870 data-unused: 0.000%
867 data-unused: 0.000%
871
868
872 Running unrelated upgrade
869 Running unrelated upgrade
873
870
874 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
871 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
875 upgrade will perform the following actions:
872 upgrade will perform the following actions:
876
873
877 requirements
874 requirements
878 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
875 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
879 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
876 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
880 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
877 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
881
878
882 optimisations: re-delta-all
879 optimisations: re-delta-all
883
880
884 processed revlogs:
881 processed revlogs:
885 - all-filelogs
882 - all-filelogs
886 - changelog
883 - changelog
887 - manifest
884 - manifest
888
885
889 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
886 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
890 00changelog-*.nd (glob)
887 00changelog-*.nd (glob)
891 00changelog.n
888 00changelog.n
892 00manifest-*.nd (glob)
889 00manifest-*.nd (glob)
893 00manifest.n
890 00manifest.n
894
891
895 $ hg debugnodemap --metadata
892 $ hg debugnodemap --metadata
896 uid: * (glob)
893 uid: * (glob)
897 tip-rev: 5005
894 tip-rev: 5005
898 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
895 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
899 data-length: 121088
896 data-length: 121088
900 data-unused: 0
897 data-unused: 0
901 data-unused: 0.000%
898 data-unused: 0.000%
902
899
903 Persistent nodemap and local/streaming clone
900 Persistent nodemap and local/streaming clone
904 ============================================
901 ============================================
905
902
906 $ cd ..
903 $ cd ..
907
904
908 standard clone
905 standard clone
909 --------------
906 --------------
910
907
911 The persistent nodemap should exist after a streaming clone
908 The persistent nodemap should exist after a streaming clone
912
909
913 $ hg clone --pull --quiet -U test-repo standard-clone
910 $ hg clone --pull --quiet -U test-repo standard-clone
914 $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
911 $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
915 00changelog-*.nd (glob)
912 00changelog-*.nd (glob)
916 00changelog.n
913 00changelog.n
917 00manifest-*.nd (glob)
914 00manifest-*.nd (glob)
918 00manifest.n
915 00manifest.n
919 $ hg -R standard-clone debugnodemap --metadata
916 $ hg -R standard-clone debugnodemap --metadata
920 uid: * (glob)
917 uid: * (glob)
921 tip-rev: 5005
918 tip-rev: 5005
922 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
919 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
923 data-length: 121088
920 data-length: 121088
924 data-unused: 0
921 data-unused: 0
925 data-unused: 0.000%
922 data-unused: 0.000%
926
923
927
924
928 local clone
925 local clone
929 ------------
926 ------------
930
927
931 The persistent nodemap should exist after a streaming clone
928 The persistent nodemap should exist after a streaming clone
932
929
933 $ hg clone -U test-repo local-clone
930 $ hg clone -U test-repo local-clone
934 $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
931 $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
935 00changelog-*.nd (glob)
932 00changelog-*.nd (glob)
936 00changelog.n
933 00changelog.n
937 00manifest-*.nd (glob)
934 00manifest-*.nd (glob)
938 00manifest.n
935 00manifest.n
939 $ hg -R local-clone debugnodemap --metadata
936 $ hg -R local-clone debugnodemap --metadata
940 uid: * (glob)
937 uid: * (glob)
941 tip-rev: 5005
938 tip-rev: 5005
942 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
939 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
943 data-length: 121088
940 data-length: 121088
944 data-unused: 0
941 data-unused: 0
945 data-unused: 0.000%
942 data-unused: 0.000%
946
943
947 Test various corruption case
944 Test various corruption case
948 ============================
945 ============================
949
946
950 Missing datafile
947 Missing datafile
951 ----------------
948 ----------------
952
949
953 Test behavior with a missing datafile
950 Test behavior with a missing datafile
954
951
955 $ hg clone --quiet --pull test-repo corruption-test-repo
952 $ hg clone --quiet --pull test-repo corruption-test-repo
956 $ ls -1 corruption-test-repo/.hg/store/00changelog*
953 $ ls -1 corruption-test-repo/.hg/store/00changelog*
957 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
954 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
958 corruption-test-repo/.hg/store/00changelog.d
955 corruption-test-repo/.hg/store/00changelog.d
959 corruption-test-repo/.hg/store/00changelog.i
956 corruption-test-repo/.hg/store/00changelog.i
960 corruption-test-repo/.hg/store/00changelog.n
957 corruption-test-repo/.hg/store/00changelog.n
961 $ rm corruption-test-repo/.hg/store/00changelog*.nd
958 $ rm corruption-test-repo/.hg/store/00changelog*.nd
962 $ hg log -R corruption-test-repo -r .
959 $ hg log -R corruption-test-repo -r .
963 changeset: 5005:90d5d3ba2fc4
960 changeset: 5005:90d5d3ba2fc4
964 tag: tip
961 tag: tip
965 user: test
962 user: test
966 date: Thu Jan 01 00:00:00 1970 +0000
963 date: Thu Jan 01 00:00:00 1970 +0000
967 summary: a2
964 summary: a2
968
965
969 $ ls -1 corruption-test-repo/.hg/store/00changelog*
966 $ ls -1 corruption-test-repo/.hg/store/00changelog*
970 corruption-test-repo/.hg/store/00changelog.d
967 corruption-test-repo/.hg/store/00changelog.d
971 corruption-test-repo/.hg/store/00changelog.i
968 corruption-test-repo/.hg/store/00changelog.i
972 corruption-test-repo/.hg/store/00changelog.n
969 corruption-test-repo/.hg/store/00changelog.n
973
970
974 Truncated data file
971 Truncated data file
975 -------------------
972 -------------------
976
973
977 Test behavior with a too short datafile
974 Test behavior with a too short datafile
978
975
979 rebuild the missing data
976 rebuild the missing data
980 $ hg -R corruption-test-repo debugupdatecache
977 $ hg -R corruption-test-repo debugupdatecache
981 $ ls -1 corruption-test-repo/.hg/store/00changelog*
978 $ ls -1 corruption-test-repo/.hg/store/00changelog*
982 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
979 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
983 corruption-test-repo/.hg/store/00changelog.d
980 corruption-test-repo/.hg/store/00changelog.d
984 corruption-test-repo/.hg/store/00changelog.i
981 corruption-test-repo/.hg/store/00changelog.i
985 corruption-test-repo/.hg/store/00changelog.n
982 corruption-test-repo/.hg/store/00changelog.n
986
983
987 truncate the file
984 truncate the file
988
985
989 $ datafilepath=`ls corruption-test-repo/.hg/store/00changelog*.nd`
986 $ datafilepath=`ls corruption-test-repo/.hg/store/00changelog*.nd`
990 $ f -s $datafilepath
987 $ f -s $datafilepath
991 corruption-test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
988 corruption-test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
992 $ dd if=$datafilepath bs=1000 count=10 of=$datafilepath-tmp
989 $ dd if=$datafilepath bs=1000 count=10 of=$datafilepath-tmp
993 10+0 records in
990 10+0 records in
994 10+0 records out
991 10+0 records out
995 * bytes * (glob)
992 * bytes * (glob)
996 $ mv $datafilepath-tmp $datafilepath
993 $ mv $datafilepath-tmp $datafilepath
997 $ f -s $datafilepath
994 $ f -s $datafilepath
998 corruption-test-repo/.hg/store/00changelog-*.nd: size=10000 (glob)
995 corruption-test-repo/.hg/store/00changelog-*.nd: size=10000 (glob)
999
996
1000 Check that Mercurial reaction to this event
997 Check that Mercurial reaction to this event
1001
998
1002 $ hg -R corruption-test-repo log -r . --traceback
999 $ hg -R corruption-test-repo log -r . --traceback
1003 changeset: 5005:90d5d3ba2fc4
1000 changeset: 5005:90d5d3ba2fc4
1004 tag: tip
1001 tag: tip
1005 user: test
1002 user: test
1006 date: Thu Jan 01 00:00:00 1970 +0000
1003 date: Thu Jan 01 00:00:00 1970 +0000
1007 summary: a2
1004 summary: a2
1008
1005
1009
1006
1010
1007
1011 stream clone
1008 stream clone
1012 ============
1009 ============
1013
1010
1014 The persistent nodemap should exist after a streaming clone
1011 The persistent nodemap should exist after a streaming clone
1015
1012
1016 Simple case
1013 Simple case
1017 -----------
1014 -----------
1018
1015
1019 No race condition
1016 No race condition
1020
1017
1021 $ hg clone -U --stream ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)'
1018 $ hg clone -U --stream ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)'
1022 adding [s] 00manifest.n (62 bytes)
1019 adding [s] 00manifest.n (62 bytes)
1023 adding [s] 00manifest-*.nd (118 KB) (glob)
1020 adding [s] 00manifest-*.nd (118 KB) (glob)
1024 adding [s] 00changelog.n (62 bytes)
1021 adding [s] 00changelog.n (62 bytes)
1025 adding [s] 00changelog-*.nd (118 KB) (glob)
1022 adding [s] 00changelog-*.nd (118 KB) (glob)
1026 adding [s] 00manifest.d (452 KB) (no-zstd !)
1023 adding [s] 00manifest.d (452 KB) (no-zstd !)
1027 adding [s] 00manifest.d (491 KB) (zstd no-bigendian !)
1024 adding [s] 00manifest.d (491 KB) (zstd no-bigendian !)
1028 adding [s] 00manifest.d (492 KB) (zstd bigendian !)
1025 adding [s] 00manifest.d (492 KB) (zstd bigendian !)
1029 adding [s] 00changelog.d (360 KB) (no-zstd !)
1026 adding [s] 00changelog.d (360 KB) (no-zstd !)
1030 adding [s] 00changelog.d (368 KB) (zstd !)
1027 adding [s] 00changelog.d (368 KB) (zstd !)
1031 adding [s] 00manifest.i (313 KB)
1028 adding [s] 00manifest.i (313 KB)
1032 adding [s] 00changelog.i (313 KB)
1029 adding [s] 00changelog.i (313 KB)
1033 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
1030 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
1034 00changelog-*.nd (glob)
1031 00changelog-*.nd (glob)
1035 00changelog.n
1032 00changelog.n
1036 00manifest-*.nd (glob)
1033 00manifest-*.nd (glob)
1037 00manifest.n
1034 00manifest.n
1038 $ hg -R stream-clone debugnodemap --metadata
1035 $ hg -R stream-clone debugnodemap --metadata
1039 uid: * (glob)
1036 uid: * (glob)
1040 tip-rev: 5005
1037 tip-rev: 5005
1041 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1038 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1042 data-length: 121088
1039 data-length: 121088
1043 data-unused: 0
1040 data-unused: 0
1044 data-unused: 0.000%
1041 data-unused: 0.000%
1045
1042
1046 new data appened
1043 new data appened
1047 -----------------
1044 -----------------
1048
1045
1049 Other commit happening on the server during the stream clone
1046 Other commit happening on the server during the stream clone
1050
1047
1051 setup the step-by-step stream cloning
1048 setup the step-by-step stream cloning
1052
1049
1053 $ HG_TEST_STREAM_WALKED_FILE_1="$TESTTMP/sync_file_walked_1"
1050 $ HG_TEST_STREAM_WALKED_FILE_1="$TESTTMP/sync_file_walked_1"
1054 $ export HG_TEST_STREAM_WALKED_FILE_1
1051 $ export HG_TEST_STREAM_WALKED_FILE_1
1055 $ HG_TEST_STREAM_WALKED_FILE_2="$TESTTMP/sync_file_walked_2"
1052 $ HG_TEST_STREAM_WALKED_FILE_2="$TESTTMP/sync_file_walked_2"
1056 $ export HG_TEST_STREAM_WALKED_FILE_2
1053 $ export HG_TEST_STREAM_WALKED_FILE_2
1057 $ HG_TEST_STREAM_WALKED_FILE_3="$TESTTMP/sync_file_walked_3"
1054 $ HG_TEST_STREAM_WALKED_FILE_3="$TESTTMP/sync_file_walked_3"
1058 $ export HG_TEST_STREAM_WALKED_FILE_3
1055 $ export HG_TEST_STREAM_WALKED_FILE_3
1059 $ cat << EOF >> test-repo/.hg/hgrc
1056 $ cat << EOF >> test-repo/.hg/hgrc
1060 > [extensions]
1057 > [extensions]
1061 > steps=$RUNTESTDIR/testlib/ext-stream-clone-steps.py
1058 > steps=$RUNTESTDIR/testlib/ext-stream-clone-steps.py
1062 > EOF
1059 > EOF
1063
1060
1064 Check and record file state beforehand
1061 Check and record file state beforehand
1065
1062
1066 $ f --size test-repo/.hg/store/00changelog*
1063 $ f --size test-repo/.hg/store/00changelog*
1067 test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
1064 test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
1068 test-repo/.hg/store/00changelog.d: size=376891 (zstd no-bigendian !)
1065 test-repo/.hg/store/00changelog.d: size=376891 (zstd no-bigendian !)
1069 test-repo/.hg/store/00changelog.d: size=376889 (zstd bigendian !)
1066 test-repo/.hg/store/00changelog.d: size=376889 (zstd bigendian !)
1070 test-repo/.hg/store/00changelog.d: size=368890 (no-zstd !)
1067 test-repo/.hg/store/00changelog.d: size=368890 (no-zstd !)
1071 test-repo/.hg/store/00changelog.i: size=320384
1068 test-repo/.hg/store/00changelog.i: size=320384
1072 test-repo/.hg/store/00changelog.n: size=62
1069 test-repo/.hg/store/00changelog.n: size=62
1073 $ hg -R test-repo debugnodemap --metadata | tee server-metadata.txt
1070 $ hg -R test-repo debugnodemap --metadata | tee server-metadata.txt
1074 uid: * (glob)
1071 uid: * (glob)
1075 tip-rev: 5005
1072 tip-rev: 5005
1076 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1073 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1077 data-length: 121088
1074 data-length: 121088
1078 data-unused: 0
1075 data-unused: 0
1079 data-unused: 0.000%
1076 data-unused: 0.000%
1080
1077
1081 Prepare a commit
1078 Prepare a commit
1082
1079
1083 $ echo foo >> test-repo/foo
1080 $ echo foo >> test-repo/foo
1084 $ hg -R test-repo/ add test-repo/foo
1081 $ hg -R test-repo/ add test-repo/foo
1085
1082
1086 Do a mix of clone and commit at the same time so that the file listed on disk differ at actual transfer time.
1083 Do a mix of clone and commit at the same time so that the file listed on disk differ at actual transfer time.
1087
1084
1088 $ (hg clone -U --stream ssh://user@dummy/test-repo stream-clone-race-1 --debug 2>> clone-output | egrep '00(changelog|manifest)' >> clone-output; touch $HG_TEST_STREAM_WALKED_FILE_3) &
1085 $ (hg clone -U --stream ssh://user@dummy/test-repo stream-clone-race-1 --debug 2>> clone-output | egrep '00(changelog|manifest)' >> clone-output; touch $HG_TEST_STREAM_WALKED_FILE_3) &
1089 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
1086 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
1090 $ hg -R test-repo/ commit -m foo
1087 $ hg -R test-repo/ commit -m foo
1091 $ touch $HG_TEST_STREAM_WALKED_FILE_2
1088 $ touch $HG_TEST_STREAM_WALKED_FILE_2
1092 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
1089 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
1093 $ cat clone-output
1090 $ cat clone-output
1094 adding [s] 00manifest.n (62 bytes)
1091 adding [s] 00manifest.n (62 bytes)
1095 adding [s] 00manifest-*.nd (118 KB) (glob)
1092 adding [s] 00manifest-*.nd (118 KB) (glob)
1096 adding [s] 00changelog.n (62 bytes)
1093 adding [s] 00changelog.n (62 bytes)
1097 adding [s] 00changelog-*.nd (118 KB) (glob)
1094 adding [s] 00changelog-*.nd (118 KB) (glob)
1098 adding [s] 00manifest.d (452 KB) (no-zstd !)
1095 adding [s] 00manifest.d (452 KB) (no-zstd !)
1099 adding [s] 00manifest.d (491 KB) (zstd no-bigendian !)
1096 adding [s] 00manifest.d (491 KB) (zstd no-bigendian !)
1100 adding [s] 00manifest.d (492 KB) (zstd bigendian !)
1097 adding [s] 00manifest.d (492 KB) (zstd bigendian !)
1101 adding [s] 00changelog.d (360 KB) (no-zstd !)
1098 adding [s] 00changelog.d (360 KB) (no-zstd !)
1102 adding [s] 00changelog.d (368 KB) (zstd !)
1099 adding [s] 00changelog.d (368 KB) (zstd !)
1103 adding [s] 00manifest.i (313 KB)
1100 adding [s] 00manifest.i (313 KB)
1104 adding [s] 00changelog.i (313 KB)
1101 adding [s] 00changelog.i (313 KB)
1105
1102
1106 Check the result state
1103 Check the result state
1107
1104
1108 $ f --size stream-clone-race-1/.hg/store/00changelog*
1105 $ f --size stream-clone-race-1/.hg/store/00changelog*
1109 stream-clone-race-1/.hg/store/00changelog-*.nd: size=121088 (glob)
1106 stream-clone-race-1/.hg/store/00changelog-*.nd: size=121088 (glob)
1110 stream-clone-race-1/.hg/store/00changelog.d: size=368890 (no-zstd !)
1107 stream-clone-race-1/.hg/store/00changelog.d: size=368890 (no-zstd !)
1111 stream-clone-race-1/.hg/store/00changelog.d: size=376891 (zstd no-bigendian !)
1108 stream-clone-race-1/.hg/store/00changelog.d: size=376891 (zstd no-bigendian !)
1112 stream-clone-race-1/.hg/store/00changelog.d: size=376889 (zstd bigendian !)
1109 stream-clone-race-1/.hg/store/00changelog.d: size=376889 (zstd bigendian !)
1113 stream-clone-race-1/.hg/store/00changelog.i: size=320384
1110 stream-clone-race-1/.hg/store/00changelog.i: size=320384
1114 stream-clone-race-1/.hg/store/00changelog.n: size=62
1111 stream-clone-race-1/.hg/store/00changelog.n: size=62
1115
1112
1116 $ hg -R stream-clone-race-1 debugnodemap --metadata | tee client-metadata.txt
1113 $ hg -R stream-clone-race-1 debugnodemap --metadata | tee client-metadata.txt
1117 uid: * (glob)
1114 uid: * (glob)
1118 tip-rev: 5005
1115 tip-rev: 5005
1119 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1116 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1120 data-length: 121088
1117 data-length: 121088
1121 data-unused: 0
1118 data-unused: 0
1122 data-unused: 0.000%
1119 data-unused: 0.000%
1123
1120
1124 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1121 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1125 (ie: the following diff should be empty)
1122 (ie: the following diff should be empty)
1126
1123
1127 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
1124 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
1128
1125
1129 #if no-rust no-pure
1126 #if no-rust no-pure
1130 $ diff -u server-metadata.txt client-metadata.txt
1127 $ diff -u server-metadata.txt client-metadata.txt
1131 --- server-metadata.txt * (glob)
1128 --- server-metadata.txt * (glob)
1132 +++ client-metadata.txt * (glob)
1129 +++ client-metadata.txt * (glob)
1133 @@ -1,4 +1,4 @@
1130 @@ -1,4 +1,4 @@
1134 -uid: * (glob)
1131 -uid: * (glob)
1135 +uid: * (glob)
1132 +uid: * (glob)
1136 tip-rev: 5005
1133 tip-rev: 5005
1137 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1134 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1138 data-length: 121088
1135 data-length: 121088
1139 [1]
1136 [1]
1140 #else
1137 #else
1141 $ diff -u server-metadata.txt client-metadata.txt
1138 $ diff -u server-metadata.txt client-metadata.txt
1142 #endif
1139 #endif
1143
1140
1144
1141
1145 Clean up after the test.
1142 Clean up after the test.
1146
1143
1147 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_1"
1144 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_1"
1148 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_2"
1145 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_2"
1149 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_3"
1146 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_3"
1150
1147
1151 full regeneration
1148 full regeneration
1152 -----------------
1149 -----------------
1153
1150
1154 A full nodemap is generated
1151 A full nodemap is generated
1155
1152
1156 (ideally this test would append enough data to make sure the nodemap data file
1153 (ideally this test would append enough data to make sure the nodemap data file
1157 get changed, however to make thing simpler we will force the regeneration for
1154 get changed, however to make thing simpler we will force the regeneration for
1158 this test.
1155 this test.
1159
1156
1160 Check the initial state
1157 Check the initial state
1161
1158
1162 $ f --size test-repo/.hg/store/00changelog*
1159 $ f --size test-repo/.hg/store/00changelog*
1163 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1160 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1164 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1161 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1165 test-repo/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1162 test-repo/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1166 test-repo/.hg/store/00changelog.d: size=376950 (zstd no-bigendian !)
1163 test-repo/.hg/store/00changelog.d: size=376950 (zstd no-bigendian !)
1167 test-repo/.hg/store/00changelog.d: size=376948 (zstd bigendian !)
1164 test-repo/.hg/store/00changelog.d: size=376948 (zstd bigendian !)
1168 test-repo/.hg/store/00changelog.d: size=368949 (no-zstd !)
1165 test-repo/.hg/store/00changelog.d: size=368949 (no-zstd !)
1169 test-repo/.hg/store/00changelog.i: size=320448
1166 test-repo/.hg/store/00changelog.i: size=320448
1170 test-repo/.hg/store/00changelog.n: size=62
1167 test-repo/.hg/store/00changelog.n: size=62
1171 $ hg -R test-repo debugnodemap --metadata | tee server-metadata-2.txt
1168 $ hg -R test-repo debugnodemap --metadata | tee server-metadata-2.txt
1172 uid: * (glob)
1169 uid: * (glob)
1173 tip-rev: 5006
1170 tip-rev: 5006
1174 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1171 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1175 data-length: 121344 (rust !)
1172 data-length: 121344 (rust !)
1176 data-length: 121344 (pure !)
1173 data-length: 121344 (pure !)
1177 data-length: 121152 (no-rust no-pure !)
1174 data-length: 121152 (no-rust no-pure !)
1178 data-unused: 192 (rust !)
1175 data-unused: 192 (rust !)
1179 data-unused: 192 (pure !)
1176 data-unused: 192 (pure !)
1180 data-unused: 0 (no-rust no-pure !)
1177 data-unused: 0 (no-rust no-pure !)
1181 data-unused: 0.158% (rust !)
1178 data-unused: 0.158% (rust !)
1182 data-unused: 0.158% (pure !)
1179 data-unused: 0.158% (pure !)
1183 data-unused: 0.000% (no-rust no-pure !)
1180 data-unused: 0.000% (no-rust no-pure !)
1184
1181
1185 Performe the mix of clone and full refresh of the nodemap, so that the files
1182 Performe the mix of clone and full refresh of the nodemap, so that the files
1186 (and filenames) are different between listing time and actual transfer time.
1183 (and filenames) are different between listing time and actual transfer time.
1187
1184
1188 $ (hg clone -U --stream ssh://user@dummy/test-repo stream-clone-race-2 --debug 2>> clone-output-2 | egrep '00(changelog|manifest)' >> clone-output-2; touch $HG_TEST_STREAM_WALKED_FILE_3) &
1185 $ (hg clone -U --stream ssh://user@dummy/test-repo stream-clone-race-2 --debug 2>> clone-output-2 | egrep '00(changelog|manifest)' >> clone-output-2; touch $HG_TEST_STREAM_WALKED_FILE_3) &
1189 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
1186 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
1190 $ rm test-repo/.hg/store/00changelog.n
1187 $ rm test-repo/.hg/store/00changelog.n
1191 $ rm test-repo/.hg/store/00changelog-*.nd
1188 $ rm test-repo/.hg/store/00changelog-*.nd
1192 $ hg -R test-repo/ debugupdatecache
1189 $ hg -R test-repo/ debugupdatecache
1193 $ touch $HG_TEST_STREAM_WALKED_FILE_2
1190 $ touch $HG_TEST_STREAM_WALKED_FILE_2
1194 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
1191 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
1195
1192
1196 (note: the stream clone code wronly pick the `undo.` files)
1193 (note: the stream clone code wronly pick the `undo.` files)
1197
1194
1198 $ cat clone-output-2
1195 $ cat clone-output-2
1199 adding [s] undo.backup.00manifest.n (62 bytes) (known-bad-output !)
1196 adding [s] undo.backup.00manifest.n (62 bytes) (known-bad-output !)
1200 adding [s] undo.backup.00changelog.n (62 bytes) (known-bad-output !)
1197 adding [s] undo.backup.00changelog.n (62 bytes) (known-bad-output !)
1201 adding [s] 00manifest.n (62 bytes)
1198 adding [s] 00manifest.n (62 bytes)
1202 adding [s] 00manifest-*.nd (118 KB) (glob)
1199 adding [s] 00manifest-*.nd (118 KB) (glob)
1203 adding [s] 00changelog.n (62 bytes)
1200 adding [s] 00changelog.n (62 bytes)
1204 adding [s] 00changelog-*.nd (118 KB) (glob)
1201 adding [s] 00changelog-*.nd (118 KB) (glob)
1205 adding [s] 00manifest.d (492 KB) (zstd !)
1202 adding [s] 00manifest.d (492 KB) (zstd !)
1206 adding [s] 00manifest.d (452 KB) (no-zstd !)
1203 adding [s] 00manifest.d (452 KB) (no-zstd !)
1207 adding [s] 00changelog.d (360 KB) (no-zstd !)
1204 adding [s] 00changelog.d (360 KB) (no-zstd !)
1208 adding [s] 00changelog.d (368 KB) (zstd !)
1205 adding [s] 00changelog.d (368 KB) (zstd !)
1209 adding [s] 00manifest.i (313 KB)
1206 adding [s] 00manifest.i (313 KB)
1210 adding [s] 00changelog.i (313 KB)
1207 adding [s] 00changelog.i (313 KB)
1211
1208
1212 Check the result.
1209 Check the result.
1213
1210
1214 $ f --size stream-clone-race-2/.hg/store/00changelog*
1211 $ f --size stream-clone-race-2/.hg/store/00changelog*
1215 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1212 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1216 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1213 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1217 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1214 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1218 stream-clone-race-2/.hg/store/00changelog.d: size=376950 (zstd no-bigendian !)
1215 stream-clone-race-2/.hg/store/00changelog.d: size=376950 (zstd no-bigendian !)
1219 stream-clone-race-2/.hg/store/00changelog.d: size=376948 (zstd bigendian !)
1216 stream-clone-race-2/.hg/store/00changelog.d: size=376948 (zstd bigendian !)
1220 stream-clone-race-2/.hg/store/00changelog.d: size=368949 (no-zstd !)
1217 stream-clone-race-2/.hg/store/00changelog.d: size=368949 (no-zstd !)
1221 stream-clone-race-2/.hg/store/00changelog.i: size=320448
1218 stream-clone-race-2/.hg/store/00changelog.i: size=320448
1222 stream-clone-race-2/.hg/store/00changelog.n: size=62
1219 stream-clone-race-2/.hg/store/00changelog.n: size=62
1223
1220
1224 $ hg -R stream-clone-race-2 debugnodemap --metadata | tee client-metadata-2.txt
1221 $ hg -R stream-clone-race-2 debugnodemap --metadata | tee client-metadata-2.txt
1225 uid: * (glob)
1222 uid: * (glob)
1226 tip-rev: 5006
1223 tip-rev: 5006
1227 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1224 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1228 data-length: 121344 (rust !)
1225 data-length: 121344 (rust !)
1229 data-unused: 192 (rust !)
1226 data-unused: 192 (rust !)
1230 data-unused: 0.158% (rust !)
1227 data-unused: 0.158% (rust !)
1231 data-length: 121152 (no-rust no-pure !)
1228 data-length: 121152 (no-rust no-pure !)
1232 data-unused: 0 (no-rust no-pure !)
1229 data-unused: 0 (no-rust no-pure !)
1233 data-unused: 0.000% (no-rust no-pure !)
1230 data-unused: 0.000% (no-rust no-pure !)
1234 data-length: 121344 (pure !)
1231 data-length: 121344 (pure !)
1235 data-unused: 192 (pure !)
1232 data-unused: 192 (pure !)
1236 data-unused: 0.158% (pure !)
1233 data-unused: 0.158% (pure !)
1237
1234
1238 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1235 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1239 (ie: the following diff should be empty)
1236 (ie: the following diff should be empty)
1240
1237
1241 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
1238 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
1242
1239
1243 #if no-rust no-pure
1240 #if no-rust no-pure
1244 $ diff -u server-metadata-2.txt client-metadata-2.txt
1241 $ diff -u server-metadata-2.txt client-metadata-2.txt
1245 --- server-metadata-2.txt * (glob)
1242 --- server-metadata-2.txt * (glob)
1246 +++ client-metadata-2.txt * (glob)
1243 +++ client-metadata-2.txt * (glob)
1247 @@ -1,4 +1,4 @@
1244 @@ -1,4 +1,4 @@
1248 -uid: * (glob)
1245 -uid: * (glob)
1249 +uid: * (glob)
1246 +uid: * (glob)
1250 tip-rev: 5006
1247 tip-rev: 5006
1251 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1248 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1252 data-length: 121152
1249 data-length: 121152
1253 [1]
1250 [1]
1254 #else
1251 #else
1255 $ diff -u server-metadata-2.txt client-metadata-2.txt
1252 $ diff -u server-metadata-2.txt client-metadata-2.txt
1256 #endif
1253 #endif
1257
1254
1258 Clean up after the test
1255 Clean up after the test
1259
1256
1260 $ rm -f $HG_TEST_STREAM_WALKED_FILE_1
1257 $ rm -f $HG_TEST_STREAM_WALKED_FILE_1
1261 $ rm -f $HG_TEST_STREAM_WALKED_FILE_2
1258 $ rm -f $HG_TEST_STREAM_WALKED_FILE_2
1262 $ rm -f $HG_TEST_STREAM_WALKED_FILE_3
1259 $ rm -f $HG_TEST_STREAM_WALKED_FILE_3
1263
1260
General Comments 0
You need to be logged in to leave comments. Login now