##// END OF EJS Templates
censor: extract the part about creating and opening new files in a function...
marmoute -
r48262:d6afe147 default
parent child Browse files
Show More
@@ -1,436 +1,461 b''
1 # censor code related to censoring revision
1 # censor code related to censoring revision
2 # coding: utf8
2 # coding: utf8
3 #
3 #
4 # Copyright 2021 Pierre-Yves David <pierre-yves.david@octobus.net>
4 # Copyright 2021 Pierre-Yves David <pierre-yves.david@octobus.net>
5 # Copyright 2015 Google, Inc <martinvonz@google.com>
5 # Copyright 2015 Google, Inc <martinvonz@google.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 import contextlib
10 import contextlib
11 import os
11 import os
12
12
13 from ..node import (
13 from ..node import (
14 nullrev,
14 nullrev,
15 )
15 )
16 from .constants import (
16 from .constants import (
17 COMP_MODE_PLAIN,
17 COMP_MODE_PLAIN,
18 ENTRY_DATA_COMPRESSED_LENGTH,
18 ENTRY_DATA_COMPRESSED_LENGTH,
19 ENTRY_DATA_COMPRESSION_MODE,
19 ENTRY_DATA_COMPRESSION_MODE,
20 ENTRY_DATA_OFFSET,
20 ENTRY_DATA_OFFSET,
21 ENTRY_DATA_UNCOMPRESSED_LENGTH,
21 ENTRY_DATA_UNCOMPRESSED_LENGTH,
22 ENTRY_DELTA_BASE,
22 ENTRY_DELTA_BASE,
23 ENTRY_LINK_REV,
23 ENTRY_LINK_REV,
24 ENTRY_NODE_ID,
24 ENTRY_NODE_ID,
25 ENTRY_PARENT_1,
25 ENTRY_PARENT_1,
26 ENTRY_PARENT_2,
26 ENTRY_PARENT_2,
27 ENTRY_SIDEDATA_COMPRESSED_LENGTH,
27 ENTRY_SIDEDATA_COMPRESSED_LENGTH,
28 ENTRY_SIDEDATA_COMPRESSION_MODE,
28 ENTRY_SIDEDATA_COMPRESSION_MODE,
29 ENTRY_SIDEDATA_OFFSET,
29 ENTRY_SIDEDATA_OFFSET,
30 REVLOGV0,
30 REVLOGV0,
31 REVLOGV1,
31 REVLOGV1,
32 )
32 )
33 from ..i18n import _
33 from ..i18n import _
34
34
35 from .. import (
35 from .. import (
36 error,
36 error,
37 pycompat,
37 pycompat,
38 revlogutils,
38 revlogutils,
39 util,
39 util,
40 )
40 )
41 from ..utils import (
41 from ..utils import (
42 storageutil,
42 storageutil,
43 )
43 )
44 from . import (
44 from . import (
45 constants,
45 constants,
46 deltas,
46 deltas,
47 )
47 )
48
48
49
49
50 def v1_censor(rl, tr, censornode, tombstone=b''):
50 def v1_censor(rl, tr, censornode, tombstone=b''):
51 """censors a revision in a "version 1" revlog"""
51 """censors a revision in a "version 1" revlog"""
52 assert rl._format_version == constants.REVLOGV1, rl._format_version
52 assert rl._format_version == constants.REVLOGV1, rl._format_version
53
53
54 # avoid cycle
54 # avoid cycle
55 from .. import revlog
55 from .. import revlog
56
56
57 censorrev = rl.rev(censornode)
57 censorrev = rl.rev(censornode)
58 tombstone = storageutil.packmeta({b'censored': tombstone}, b'')
58 tombstone = storageutil.packmeta({b'censored': tombstone}, b'')
59
59
60 # Rewriting the revlog in place is hard. Our strategy for censoring is
60 # Rewriting the revlog in place is hard. Our strategy for censoring is
61 # to create a new revlog, copy all revisions to it, then replace the
61 # to create a new revlog, copy all revisions to it, then replace the
62 # revlogs on transaction close.
62 # revlogs on transaction close.
63 #
63 #
64 # This is a bit dangerous. We could easily have a mismatch of state.
64 # This is a bit dangerous. We could easily have a mismatch of state.
65 newrl = revlog.revlog(
65 newrl = revlog.revlog(
66 rl.opener,
66 rl.opener,
67 target=rl.target,
67 target=rl.target,
68 radix=rl.radix,
68 radix=rl.radix,
69 postfix=b'tmpcensored',
69 postfix=b'tmpcensored',
70 censorable=True,
70 censorable=True,
71 )
71 )
72 newrl._format_version = rl._format_version
72 newrl._format_version = rl._format_version
73 newrl._format_flags = rl._format_flags
73 newrl._format_flags = rl._format_flags
74 newrl._generaldelta = rl._generaldelta
74 newrl._generaldelta = rl._generaldelta
75 newrl._parse_index = rl._parse_index
75 newrl._parse_index = rl._parse_index
76
76
77 for rev in rl.revs():
77 for rev in rl.revs():
78 node = rl.node(rev)
78 node = rl.node(rev)
79 p1, p2 = rl.parents(node)
79 p1, p2 = rl.parents(node)
80
80
81 if rev == censorrev:
81 if rev == censorrev:
82 newrl.addrawrevision(
82 newrl.addrawrevision(
83 tombstone,
83 tombstone,
84 tr,
84 tr,
85 rl.linkrev(censorrev),
85 rl.linkrev(censorrev),
86 p1,
86 p1,
87 p2,
87 p2,
88 censornode,
88 censornode,
89 constants.REVIDX_ISCENSORED,
89 constants.REVIDX_ISCENSORED,
90 )
90 )
91
91
92 if newrl.deltaparent(rev) != nullrev:
92 if newrl.deltaparent(rev) != nullrev:
93 m = _(b'censored revision stored as delta; cannot censor')
93 m = _(b'censored revision stored as delta; cannot censor')
94 h = _(
94 h = _(
95 b'censoring of revlogs is not fully implemented;'
95 b'censoring of revlogs is not fully implemented;'
96 b' please report this bug'
96 b' please report this bug'
97 )
97 )
98 raise error.Abort(m, hint=h)
98 raise error.Abort(m, hint=h)
99 continue
99 continue
100
100
101 if rl.iscensored(rev):
101 if rl.iscensored(rev):
102 if rl.deltaparent(rev) != nullrev:
102 if rl.deltaparent(rev) != nullrev:
103 m = _(
103 m = _(
104 b'cannot censor due to censored '
104 b'cannot censor due to censored '
105 b'revision having delta stored'
105 b'revision having delta stored'
106 )
106 )
107 raise error.Abort(m)
107 raise error.Abort(m)
108 rawtext = rl._chunk(rev)
108 rawtext = rl._chunk(rev)
109 else:
109 else:
110 rawtext = rl.rawdata(rev)
110 rawtext = rl.rawdata(rev)
111
111
112 newrl.addrawrevision(
112 newrl.addrawrevision(
113 rawtext, tr, rl.linkrev(rev), p1, p2, node, rl.flags(rev)
113 rawtext, tr, rl.linkrev(rev), p1, p2, node, rl.flags(rev)
114 )
114 )
115
115
116 tr.addbackup(rl._indexfile, location=b'store')
116 tr.addbackup(rl._indexfile, location=b'store')
117 if not rl._inline:
117 if not rl._inline:
118 tr.addbackup(rl._datafile, location=b'store')
118 tr.addbackup(rl._datafile, location=b'store')
119
119
120 rl.opener.rename(newrl._indexfile, rl._indexfile)
120 rl.opener.rename(newrl._indexfile, rl._indexfile)
121 if not rl._inline:
121 if not rl._inline:
122 rl.opener.rename(newrl._datafile, rl._datafile)
122 rl.opener.rename(newrl._datafile, rl._datafile)
123
123
124 rl.clearcaches()
124 rl.clearcaches()
125 rl._loadindex()
125 rl._loadindex()
126
126
127
127
128 def v2_censor(rl, tr, censornode, tombstone=b''):
128 def v2_censor(rl, tr, censornode, tombstone=b''):
129 """censors a revision in a "version 2" revlog"""
129 """censors a revision in a "version 2" revlog"""
130 # General principle
130 # General principle
131 #
131 #
132 # We create new revlog files (index/data/sidedata) to copy the content of
132 # We create new revlog files (index/data/sidedata) to copy the content of
133 # the existing data without the censored data.
133 # the existing data without the censored data.
134 #
134 #
135 # We need to recompute new delta for any revision that used the censored
135 # We need to recompute new delta for any revision that used the censored
136 # revision as delta base. As the cumulative size of the new delta may be
136 # revision as delta base. As the cumulative size of the new delta may be
137 # large, we store them in a temporary file until they are stored in their
137 # large, we store them in a temporary file until they are stored in their
138 # final destination.
138 # final destination.
139 #
139 #
140 # All data before the censored data can be blindly copied. The rest needs
140 # All data before the censored data can be blindly copied. The rest needs
141 # to be copied as we go and the associated index entry needs adjustement.
141 # to be copied as we go and the associated index entry needs adjustement.
142
142
143 assert rl._format_version != REVLOGV0, rl._format_version
143 assert rl._format_version != REVLOGV0, rl._format_version
144 assert rl._format_version != REVLOGV1, rl._format_version
144 assert rl._format_version != REVLOGV1, rl._format_version
145
145
146 old_index = rl.index
146 old_index = rl.index
147 docket = rl._docket
147 docket = rl._docket
148
148
149 censor_rev = rl.rev(censornode)
149 censor_rev = rl.rev(censornode)
150 tombstone = storageutil.packmeta({b'censored': tombstone}, b'')
150 tombstone = storageutil.packmeta({b'censored': tombstone}, b'')
151
151
152 censored_entry = rl.index[censor_rev]
152 censored_entry = rl.index[censor_rev]
153 index_cutoff = rl.index.entry_size * censor_rev
153 index_cutoff = rl.index.entry_size * censor_rev
154 data_cutoff = censored_entry[ENTRY_DATA_OFFSET] >> 16
154 data_cutoff = censored_entry[ENTRY_DATA_OFFSET] >> 16
155 sidedata_cutoff = rl.sidedata_cut_off(censor_rev)
155 sidedata_cutoff = rl.sidedata_cut_off(censor_rev)
156
156
157 with pycompat.unnamedtempfile(mode=b"w+b") as tmp_storage:
157 with pycompat.unnamedtempfile(mode=b"w+b") as tmp_storage:
158 # rev β†’ (new_base, data_start, data_end, compression_mode)
158 # rev β†’ (new_base, data_start, data_end, compression_mode)
159 rewritten_entries = _precompute_rewritten_delta(
159 rewritten_entries = _precompute_rewritten_delta(
160 rl,
160 rl,
161 old_index,
161 old_index,
162 {censor_rev},
162 {censor_rev},
163 tmp_storage,
163 tmp_storage,
164 )
164 )
165
165
166 old_index_filepath = rl.opener.join(docket.index_filepath())
166 all_files = _setup_new_files(
167 old_data_filepath = rl.opener.join(docket.data_filepath())
167 rl,
168 old_sidedata_filepath = rl.opener.join(docket.sidedata_filepath())
168 index_cutoff,
169
169 data_cutoff,
170 new_index_filepath = rl.opener.join(docket.new_index_file())
170 sidedata_cutoff,
171 new_data_filepath = rl.opener.join(docket.new_data_file())
172 new_sidedata_filepath = rl.opener.join(docket.new_sidedata_file())
173
174 util.copyfile(
175 old_index_filepath, new_index_filepath, nb_bytes=index_cutoff
176 )
177 util.copyfile(
178 old_data_filepath, new_data_filepath, nb_bytes=data_cutoff
179 )
180 util.copyfile(
181 old_sidedata_filepath,
182 new_sidedata_filepath,
183 nb_bytes=sidedata_cutoff,
184 )
171 )
185 rl.opener.register_file(docket.index_filepath())
186 rl.opener.register_file(docket.data_filepath())
187 rl.opener.register_file(docket.sidedata_filepath())
188
189 docket.index_end = index_cutoff
190 docket.data_end = data_cutoff
191 docket.sidedata_end = sidedata_cutoff
192
193 # reload the revlog internal information
194 rl.clearcaches()
195 rl._loadindex(docket=docket)
196
197 @contextlib.contextmanager
198 def all_files():
199 # hide opening in an helper function to please check-code, black
200 # and various python ersion at the same time
201 with open(old_data_filepath, 'rb') as old_data_file:
202 with open(old_sidedata_filepath, 'rb') as old_sidedata_file:
203 with open(new_index_filepath, 'r+b') as new_index_file:
204 with open(new_data_filepath, 'r+b') as new_data_file:
205 with open(
206 new_sidedata_filepath, 'r+b'
207 ) as new_sidedata_file:
208 yield (
209 old_data_file,
210 old_sidedata_file,
211 new_index_file,
212 new_data_file,
213 new_sidedata_file,
214 )
215
172
216 # we dont need to open the old index file since its content already
173 # we dont need to open the old index file since its content already
217 # exist in a usable form in `old_index`.
174 # exist in a usable form in `old_index`.
218 with all_files() as open_files:
175 with all_files() as open_files:
219 (
176 (
220 old_data_file,
177 old_data_file,
221 old_sidedata_file,
178 old_sidedata_file,
222 new_index_file,
179 new_index_file,
223 new_data_file,
180 new_data_file,
224 new_sidedata_file,
181 new_sidedata_file,
225 ) = open_files
182 ) = open_files
226 new_index_file.seek(0, os.SEEK_END)
227 assert new_index_file.tell() == index_cutoff
228 new_data_file.seek(0, os.SEEK_END)
229 assert new_data_file.tell() == data_cutoff
230 new_sidedata_file.seek(0, os.SEEK_END)
231 assert new_sidedata_file.tell() == sidedata_cutoff
232
183
233 # writing the censored revision
184 # writing the censored revision
234 _rewrite_censor(
185 _rewrite_censor(
235 rl,
186 rl,
236 old_index,
187 old_index,
237 open_files,
188 open_files,
238 censor_rev,
189 censor_rev,
239 tombstone,
190 tombstone,
240 )
191 )
241
192
242 # Writing all subsequent revisions
193 # Writing all subsequent revisions
243 for rev in range(censor_rev + 1, len(old_index)):
194 for rev in range(censor_rev + 1, len(old_index)):
244 _rewrite_simple(
195 _rewrite_simple(
245 rl,
196 rl,
246 old_index,
197 old_index,
247 open_files,
198 open_files,
248 rev,
199 rev,
249 rewritten_entries,
200 rewritten_entries,
250 tmp_storage,
201 tmp_storage,
251 )
202 )
252 docket.write(transaction=None, stripping=True)
203 docket.write(transaction=None, stripping=True)
253
204
254
205
255 def _precompute_rewritten_delta(
206 def _precompute_rewritten_delta(
256 revlog,
207 revlog,
257 old_index,
208 old_index,
258 excluded_revs,
209 excluded_revs,
259 tmp_storage,
210 tmp_storage,
260 ):
211 ):
261 """Compute new delta for revisions whose delta is based on revision that
212 """Compute new delta for revisions whose delta is based on revision that
262 will not survive as is.
213 will not survive as is.
263
214
264 Return a mapping: {rev β†’ (new_base, data_start, data_end, compression_mode)}
215 Return a mapping: {rev β†’ (new_base, data_start, data_end, compression_mode)}
265 """
216 """
266 dc = deltas.deltacomputer(revlog)
217 dc = deltas.deltacomputer(revlog)
267 rewritten_entries = {}
218 rewritten_entries = {}
268 first_excl_rev = min(excluded_revs)
219 first_excl_rev = min(excluded_revs)
269 with revlog._segmentfile._open_read() as dfh:
220 with revlog._segmentfile._open_read() as dfh:
270 for rev in range(first_excl_rev, len(old_index)):
221 for rev in range(first_excl_rev, len(old_index)):
271 if rev in excluded_revs:
222 if rev in excluded_revs:
272 # this revision will be preserved as is, so we don't need to
223 # this revision will be preserved as is, so we don't need to
273 # consider recomputing a delta.
224 # consider recomputing a delta.
274 continue
225 continue
275 entry = old_index[rev]
226 entry = old_index[rev]
276 if entry[ENTRY_DELTA_BASE] not in excluded_revs:
227 if entry[ENTRY_DELTA_BASE] not in excluded_revs:
277 continue
228 continue
278 # This is a revision that use the censored revision as the base
229 # This is a revision that use the censored revision as the base
279 # for its delta. We need a need new deltas
230 # for its delta. We need a need new deltas
280 if entry[ENTRY_DATA_UNCOMPRESSED_LENGTH] == 0:
231 if entry[ENTRY_DATA_UNCOMPRESSED_LENGTH] == 0:
281 # this revision is empty, we can delta against nullrev
232 # this revision is empty, we can delta against nullrev
282 rewritten_entries[rev] = (nullrev, 0, 0, COMP_MODE_PLAIN)
233 rewritten_entries[rev] = (nullrev, 0, 0, COMP_MODE_PLAIN)
283 else:
234 else:
284
235
285 text = revlog.rawdata(rev, _df=dfh)
236 text = revlog.rawdata(rev, _df=dfh)
286 info = revlogutils.revisioninfo(
237 info = revlogutils.revisioninfo(
287 node=entry[ENTRY_NODE_ID],
238 node=entry[ENTRY_NODE_ID],
288 p1=revlog.node(entry[ENTRY_PARENT_1]),
239 p1=revlog.node(entry[ENTRY_PARENT_1]),
289 p2=revlog.node(entry[ENTRY_PARENT_2]),
240 p2=revlog.node(entry[ENTRY_PARENT_2]),
290 btext=[text],
241 btext=[text],
291 textlen=len(text),
242 textlen=len(text),
292 cachedelta=None,
243 cachedelta=None,
293 flags=entry[ENTRY_DATA_OFFSET] & 0xFFFF,
244 flags=entry[ENTRY_DATA_OFFSET] & 0xFFFF,
294 )
245 )
295 d = dc.finddeltainfo(
246 d = dc.finddeltainfo(
296 info, dfh, excluded_bases=excluded_revs, target_rev=rev
247 info, dfh, excluded_bases=excluded_revs, target_rev=rev
297 )
248 )
298 default_comp = revlog._docket.default_compression_header
249 default_comp = revlog._docket.default_compression_header
299 comp_mode, d = deltas.delta_compression(default_comp, d)
250 comp_mode, d = deltas.delta_compression(default_comp, d)
300 # using `tell` is a bit lazy, but we are not here for speed
251 # using `tell` is a bit lazy, but we are not here for speed
301 start = tmp_storage.tell()
252 start = tmp_storage.tell()
302 tmp_storage.write(d.data[1])
253 tmp_storage.write(d.data[1])
303 end = tmp_storage.tell()
254 end = tmp_storage.tell()
304 rewritten_entries[rev] = (d.base, start, end, comp_mode)
255 rewritten_entries[rev] = (d.base, start, end, comp_mode)
305 return rewritten_entries
256 return rewritten_entries
306
257
307
258
259 def _setup_new_files(
260 revlog,
261 index_cutoff,
262 data_cutoff,
263 sidedata_cutoff,
264 ):
265 """
266
267 return a context manager to open all the relevant files:
268 - old_data_file,
269 - old_sidedata_file,
270 - new_index_file,
271 - new_data_file,
272 - new_sidedata_file,
273
274 The old_index_file is not here because it is accessed through the
275 `old_index` object if the caller function.
276 """
277 docket = revlog._docket
278 old_index_filepath = revlog.opener.join(docket.index_filepath())
279 old_data_filepath = revlog.opener.join(docket.data_filepath())
280 old_sidedata_filepath = revlog.opener.join(docket.sidedata_filepath())
281
282 new_index_filepath = revlog.opener.join(docket.new_index_file())
283 new_data_filepath = revlog.opener.join(docket.new_data_file())
284 new_sidedata_filepath = revlog.opener.join(docket.new_sidedata_file())
285
286 util.copyfile(old_index_filepath, new_index_filepath, nb_bytes=index_cutoff)
287 util.copyfile(old_data_filepath, new_data_filepath, nb_bytes=data_cutoff)
288 util.copyfile(
289 old_sidedata_filepath,
290 new_sidedata_filepath,
291 nb_bytes=sidedata_cutoff,
292 )
293 revlog.opener.register_file(docket.index_filepath())
294 revlog.opener.register_file(docket.data_filepath())
295 revlog.opener.register_file(docket.sidedata_filepath())
296
297 docket.index_end = index_cutoff
298 docket.data_end = data_cutoff
299 docket.sidedata_end = sidedata_cutoff
300
301 # reload the revlog internal information
302 revlog.clearcaches()
303 revlog._loadindex(docket=docket)
304
305 @contextlib.contextmanager
306 def all_files_opener():
307 # hide opening in an helper function to please check-code, black
308 # and various python version at the same time
309 with open(old_data_filepath, 'rb') as old_data_file:
310 with open(old_sidedata_filepath, 'rb') as old_sidedata_file:
311 with open(new_index_filepath, 'r+b') as new_index_file:
312 with open(new_data_filepath, 'r+b') as new_data_file:
313 with open(
314 new_sidedata_filepath, 'r+b'
315 ) as new_sidedata_file:
316 new_index_file.seek(0, os.SEEK_END)
317 assert new_index_file.tell() == index_cutoff
318 new_data_file.seek(0, os.SEEK_END)
319 assert new_data_file.tell() == data_cutoff
320 new_sidedata_file.seek(0, os.SEEK_END)
321 assert new_sidedata_file.tell() == sidedata_cutoff
322 yield (
323 old_data_file,
324 old_sidedata_file,
325 new_index_file,
326 new_data_file,
327 new_sidedata_file,
328 )
329
330 return all_files_opener
331
332
308 def _rewrite_simple(
333 def _rewrite_simple(
309 revlog,
334 revlog,
310 old_index,
335 old_index,
311 all_files,
336 all_files,
312 rev,
337 rev,
313 rewritten_entries,
338 rewritten_entries,
314 tmp_storage,
339 tmp_storage,
315 ):
340 ):
316 """append a normal revision to the index after the rewritten one(s)"""
341 """append a normal revision to the index after the rewritten one(s)"""
317 (
342 (
318 old_data_file,
343 old_data_file,
319 old_sidedata_file,
344 old_sidedata_file,
320 new_index_file,
345 new_index_file,
321 new_data_file,
346 new_data_file,
322 new_sidedata_file,
347 new_sidedata_file,
323 ) = all_files
348 ) = all_files
324 entry = old_index[rev]
349 entry = old_index[rev]
325 flags = entry[ENTRY_DATA_OFFSET] & 0xFFFF
350 flags = entry[ENTRY_DATA_OFFSET] & 0xFFFF
326 old_data_offset = entry[ENTRY_DATA_OFFSET] >> 16
351 old_data_offset = entry[ENTRY_DATA_OFFSET] >> 16
327
352
328 if rev not in rewritten_entries:
353 if rev not in rewritten_entries:
329 old_data_file.seek(old_data_offset)
354 old_data_file.seek(old_data_offset)
330 new_data_size = entry[ENTRY_DATA_COMPRESSED_LENGTH]
355 new_data_size = entry[ENTRY_DATA_COMPRESSED_LENGTH]
331 new_data = old_data_file.read(new_data_size)
356 new_data = old_data_file.read(new_data_size)
332 data_delta_base = entry[ENTRY_DELTA_BASE]
357 data_delta_base = entry[ENTRY_DELTA_BASE]
333 d_comp_mode = entry[ENTRY_DATA_COMPRESSION_MODE]
358 d_comp_mode = entry[ENTRY_DATA_COMPRESSION_MODE]
334 else:
359 else:
335 (
360 (
336 data_delta_base,
361 data_delta_base,
337 start,
362 start,
338 end,
363 end,
339 d_comp_mode,
364 d_comp_mode,
340 ) = rewritten_entries[rev]
365 ) = rewritten_entries[rev]
341 new_data_size = end - start
366 new_data_size = end - start
342 tmp_storage.seek(start)
367 tmp_storage.seek(start)
343 new_data = tmp_storage.read(new_data_size)
368 new_data = tmp_storage.read(new_data_size)
344
369
345 # It might be faster to group continuous read/write operation,
370 # It might be faster to group continuous read/write operation,
346 # however, this is censor, an operation that is not focussed
371 # however, this is censor, an operation that is not focussed
347 # around stellar performance. So I have not written this
372 # around stellar performance. So I have not written this
348 # optimisation yet.
373 # optimisation yet.
349 new_data_offset = new_data_file.tell()
374 new_data_offset = new_data_file.tell()
350 new_data_file.write(new_data)
375 new_data_file.write(new_data)
351
376
352 sidedata_size = entry[ENTRY_SIDEDATA_COMPRESSED_LENGTH]
377 sidedata_size = entry[ENTRY_SIDEDATA_COMPRESSED_LENGTH]
353 new_sidedata_offset = new_sidedata_file.tell()
378 new_sidedata_offset = new_sidedata_file.tell()
354 if 0 < sidedata_size:
379 if 0 < sidedata_size:
355 old_sidedata_offset = entry[ENTRY_SIDEDATA_OFFSET]
380 old_sidedata_offset = entry[ENTRY_SIDEDATA_OFFSET]
356 old_sidedata_file.seek(old_sidedata_offset)
381 old_sidedata_file.seek(old_sidedata_offset)
357 new_sidedata = old_sidedata_file.read(sidedata_size)
382 new_sidedata = old_sidedata_file.read(sidedata_size)
358 new_sidedata_file.write(new_sidedata)
383 new_sidedata_file.write(new_sidedata)
359
384
360 data_uncompressed_length = entry[ENTRY_DATA_UNCOMPRESSED_LENGTH]
385 data_uncompressed_length = entry[ENTRY_DATA_UNCOMPRESSED_LENGTH]
361 sd_com_mode = entry[ENTRY_SIDEDATA_COMPRESSION_MODE]
386 sd_com_mode = entry[ENTRY_SIDEDATA_COMPRESSION_MODE]
362 assert data_delta_base <= rev, (data_delta_base, rev)
387 assert data_delta_base <= rev, (data_delta_base, rev)
363
388
364 new_entry = revlogutils.entry(
389 new_entry = revlogutils.entry(
365 flags=flags,
390 flags=flags,
366 data_offset=new_data_offset,
391 data_offset=new_data_offset,
367 data_compressed_length=new_data_size,
392 data_compressed_length=new_data_size,
368 data_uncompressed_length=data_uncompressed_length,
393 data_uncompressed_length=data_uncompressed_length,
369 data_delta_base=data_delta_base,
394 data_delta_base=data_delta_base,
370 link_rev=entry[ENTRY_LINK_REV],
395 link_rev=entry[ENTRY_LINK_REV],
371 parent_rev_1=entry[ENTRY_PARENT_1],
396 parent_rev_1=entry[ENTRY_PARENT_1],
372 parent_rev_2=entry[ENTRY_PARENT_2],
397 parent_rev_2=entry[ENTRY_PARENT_2],
373 node_id=entry[ENTRY_NODE_ID],
398 node_id=entry[ENTRY_NODE_ID],
374 sidedata_offset=new_sidedata_offset,
399 sidedata_offset=new_sidedata_offset,
375 sidedata_compressed_length=sidedata_size,
400 sidedata_compressed_length=sidedata_size,
376 data_compression_mode=d_comp_mode,
401 data_compression_mode=d_comp_mode,
377 sidedata_compression_mode=sd_com_mode,
402 sidedata_compression_mode=sd_com_mode,
378 )
403 )
379 revlog.index.append(new_entry)
404 revlog.index.append(new_entry)
380 entry_bin = revlog.index.entry_binary(rev)
405 entry_bin = revlog.index.entry_binary(rev)
381 new_index_file.write(entry_bin)
406 new_index_file.write(entry_bin)
382
407
383 revlog._docket.index_end = new_index_file.tell()
408 revlog._docket.index_end = new_index_file.tell()
384 revlog._docket.data_end = new_data_file.tell()
409 revlog._docket.data_end = new_data_file.tell()
385 revlog._docket.sidedata_end = new_sidedata_file.tell()
410 revlog._docket.sidedata_end = new_sidedata_file.tell()
386
411
387
412
388 def _rewrite_censor(
413 def _rewrite_censor(
389 revlog,
414 revlog,
390 old_index,
415 old_index,
391 all_files,
416 all_files,
392 rev,
417 rev,
393 tombstone,
418 tombstone,
394 ):
419 ):
395 """rewrite and append a censored revision"""
420 """rewrite and append a censored revision"""
396 (
421 (
397 old_data_file,
422 old_data_file,
398 old_sidedata_file,
423 old_sidedata_file,
399 new_index_file,
424 new_index_file,
400 new_data_file,
425 new_data_file,
401 new_sidedata_file,
426 new_sidedata_file,
402 ) = all_files
427 ) = all_files
403 entry = old_index[rev]
428 entry = old_index[rev]
404
429
405 # XXX consider trying the default compression too
430 # XXX consider trying the default compression too
406 new_data_size = len(tombstone)
431 new_data_size = len(tombstone)
407 new_data_offset = new_data_file.tell()
432 new_data_offset = new_data_file.tell()
408 new_data_file.write(tombstone)
433 new_data_file.write(tombstone)
409
434
410 # we are not adding any sidedata as they might leak info about the censored version
435 # we are not adding any sidedata as they might leak info about the censored version
411
436
412 link_rev = entry[ENTRY_LINK_REV]
437 link_rev = entry[ENTRY_LINK_REV]
413
438
414 p1 = entry[ENTRY_PARENT_1]
439 p1 = entry[ENTRY_PARENT_1]
415 p2 = entry[ENTRY_PARENT_2]
440 p2 = entry[ENTRY_PARENT_2]
416
441
417 new_entry = revlogutils.entry(
442 new_entry = revlogutils.entry(
418 flags=constants.REVIDX_ISCENSORED,
443 flags=constants.REVIDX_ISCENSORED,
419 data_offset=new_data_offset,
444 data_offset=new_data_offset,
420 data_compressed_length=new_data_size,
445 data_compressed_length=new_data_size,
421 data_uncompressed_length=new_data_size,
446 data_uncompressed_length=new_data_size,
422 data_delta_base=rev,
447 data_delta_base=rev,
423 link_rev=link_rev,
448 link_rev=link_rev,
424 parent_rev_1=p1,
449 parent_rev_1=p1,
425 parent_rev_2=p2,
450 parent_rev_2=p2,
426 node_id=entry[ENTRY_NODE_ID],
451 node_id=entry[ENTRY_NODE_ID],
427 sidedata_offset=0,
452 sidedata_offset=0,
428 sidedata_compressed_length=0,
453 sidedata_compressed_length=0,
429 data_compression_mode=COMP_MODE_PLAIN,
454 data_compression_mode=COMP_MODE_PLAIN,
430 sidedata_compression_mode=COMP_MODE_PLAIN,
455 sidedata_compression_mode=COMP_MODE_PLAIN,
431 )
456 )
432 revlog.index.append(new_entry)
457 revlog.index.append(new_entry)
433 entry_bin = revlog.index.entry_binary(rev)
458 entry_bin = revlog.index.entry_binary(rev)
434 new_index_file.write(entry_bin)
459 new_index_file.write(entry_bin)
435 revlog._docket.index_end = new_index_file.tell()
460 revlog._docket.index_end = new_index_file.tell()
436 revlog._docket.data_end = new_data_file.tell()
461 revlog._docket.data_end = new_data_file.tell()
General Comments 0
You need to be logged in to leave comments. Login now