##// END OF EJS Templates
rust-nodemap: falling back to C impl as mitigation...
Georges Racinet -
r48600:3fffb485 stable
parent child Browse files
Show More
@@ -1,512 +1,529 b''
1 // revlog.rs
1 // revlog.rs
2 //
2 //
3 // Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
3 // Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 use crate::{
8 use crate::{
9 cindex,
9 cindex,
10 utils::{node_from_py_bytes, node_from_py_object},
10 utils::{node_from_py_bytes, node_from_py_object},
11 };
11 };
12 use cpython::{
12 use cpython::{
13 buffer::{Element, PyBuffer},
13 buffer::{Element, PyBuffer},
14 exc::{IndexError, ValueError},
14 exc::{IndexError, ValueError},
15 ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyInt, PyModule,
15 ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyInt, PyModule,
16 PyObject, PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
16 PyObject, PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
17 };
17 };
18 use hg::{
18 use hg::{
19 nodemap::{Block, NodeMapError, NodeTree},
19 nodemap::{Block, NodeMapError, NodeTree},
20 revlog::{nodemap::NodeMap, NodePrefix, RevlogIndex},
20 revlog::{nodemap::NodeMap, NodePrefix, RevlogIndex},
21 Revision,
21 Revision,
22 };
22 };
23 use std::cell::RefCell;
23 use std::cell::RefCell;
24
24
25 /// Return a Struct implementing the Graph trait
25 /// Return a Struct implementing the Graph trait
26 pub(crate) fn pyindex_to_graph(
26 pub(crate) fn pyindex_to_graph(
27 py: Python,
27 py: Python,
28 index: PyObject,
28 index: PyObject,
29 ) -> PyResult<cindex::Index> {
29 ) -> PyResult<cindex::Index> {
30 match index.extract::<MixedIndex>(py) {
30 match index.extract::<MixedIndex>(py) {
31 Ok(midx) => Ok(midx.clone_cindex(py)),
31 Ok(midx) => Ok(midx.clone_cindex(py)),
32 Err(_) => cindex::Index::new(py, index),
32 Err(_) => cindex::Index::new(py, index),
33 }
33 }
34 }
34 }
35
35
36 py_class!(pub class MixedIndex |py| {
36 py_class!(pub class MixedIndex |py| {
37 data cindex: RefCell<cindex::Index>;
37 data cindex: RefCell<cindex::Index>;
38 data nt: RefCell<Option<NodeTree>>;
38 data nt: RefCell<Option<NodeTree>>;
39 data docket: RefCell<Option<PyObject>>;
39 data docket: RefCell<Option<PyObject>>;
40 // Holds a reference to the mmap'ed persistent nodemap data
40 // Holds a reference to the mmap'ed persistent nodemap data
41 data mmap: RefCell<Option<PyBuffer>>;
41 data mmap: RefCell<Option<PyBuffer>>;
42
42
43 def __new__(_cls, cindex: PyObject) -> PyResult<MixedIndex> {
43 def __new__(_cls, cindex: PyObject) -> PyResult<MixedIndex> {
44 Self::new(py, cindex)
44 Self::new(py, cindex)
45 }
45 }
46
46
47 /// Compatibility layer used for Python consumers needing access to the C index
47 /// Compatibility layer used for Python consumers needing access to the C index
48 ///
48 ///
49 /// Only use case so far is `scmutil.shortesthexnodeidprefix`,
49 /// Only use case so far is `scmutil.shortesthexnodeidprefix`,
50 /// that may need to build a custom `nodetree`, based on a specified revset.
50 /// that may need to build a custom `nodetree`, based on a specified revset.
51 /// With a Rust implementation of the nodemap, we will be able to get rid of
51 /// With a Rust implementation of the nodemap, we will be able to get rid of
52 /// this, by exposing our own standalone nodemap class,
52 /// this, by exposing our own standalone nodemap class,
53 /// ready to accept `MixedIndex`.
53 /// ready to accept `MixedIndex`.
54 def get_cindex(&self) -> PyResult<PyObject> {
54 def get_cindex(&self) -> PyResult<PyObject> {
55 Ok(self.cindex(py).borrow().inner().clone_ref(py))
55 Ok(self.cindex(py).borrow().inner().clone_ref(py))
56 }
56 }
57
57
58 // Index API involving nodemap, as defined in mercurial/pure/parsers.py
58 // Index API involving nodemap, as defined in mercurial/pure/parsers.py
59
59
60 /// Return Revision if found, raises a bare `error.RevlogError`
60 /// Return Revision if found, raises a bare `error.RevlogError`
61 /// in case of ambiguity, same as C version does
61 /// in case of ambiguity, same as C version does
62 def get_rev(&self, node: PyBytes) -> PyResult<Option<Revision>> {
62 def get_rev(&self, pynode: PyBytes) -> PyResult<Option<Revision>> {
63 let opt = self.get_nodetree(py)?.borrow();
63 let opt = self.get_nodetree(py)?.borrow();
64 let nt = opt.as_ref().unwrap();
64 let nt = opt.as_ref().unwrap();
65 let idx = &*self.cindex(py).borrow();
65 let idx = &*self.cindex(py).borrow();
66 let node = node_from_py_bytes(py, &node)?;
66 let node = node_from_py_bytes(py, &pynode)?;
67 nt.find_bin(idx, node.into()).map_err(|e| nodemap_error(py, e))
67 match nt.find_bin(idx, node.into())
68 {
69 Ok(None) =>
70 // fallback to C implementation, remove once
71 // https://bz.mercurial-scm.org/show_bug.cgi?id=6554
72 // is fixed (a simple backout should do)
73 self.call_cindex(py, "get_rev", &PyTuple::new(py, &[pynode.into_object()]), None)?
74 .extract(py),
75 Ok(Some(rev)) => Ok(Some(rev)),
76 Err(e) => Err(nodemap_error(py, e)),
77 }
68 }
78 }
69
79
70 /// same as `get_rev()` but raises a bare `error.RevlogError` if node
80 /// same as `get_rev()` but raises a bare `error.RevlogError` if node
71 /// is not found.
81 /// is not found.
72 ///
82 ///
73 /// No need to repeat `node` in the exception, `mercurial/revlog.py`
83 /// No need to repeat `node` in the exception, `mercurial/revlog.py`
74 /// will catch and rewrap with it
84 /// will catch and rewrap with it
75 def rev(&self, node: PyBytes) -> PyResult<Revision> {
85 def rev(&self, node: PyBytes) -> PyResult<Revision> {
76 self.get_rev(py, node)?.ok_or_else(|| revlog_error(py))
86 self.get_rev(py, node)?.ok_or_else(|| revlog_error(py))
77 }
87 }
78
88
79 /// return True if the node exist in the index
89 /// return True if the node exist in the index
80 def has_node(&self, node: PyBytes) -> PyResult<bool> {
90 def has_node(&self, node: PyBytes) -> PyResult<bool> {
81 self.get_rev(py, node).map(|opt| opt.is_some())
91 self.get_rev(py, node).map(|opt| opt.is_some())
82 }
92 }
83
93
84 /// find length of shortest hex nodeid of a binary ID
94 /// find length of shortest hex nodeid of a binary ID
85 def shortest(&self, node: PyBytes) -> PyResult<usize> {
95 def shortest(&self, node: PyBytes) -> PyResult<usize> {
86 let opt = self.get_nodetree(py)?.borrow();
96 let opt = self.get_nodetree(py)?.borrow();
87 let nt = opt.as_ref().unwrap();
97 let nt = opt.as_ref().unwrap();
88 let idx = &*self.cindex(py).borrow();
98 let idx = &*self.cindex(py).borrow();
89 match nt.unique_prefix_len_node(idx, &node_from_py_bytes(py, &node)?)
99 match nt.unique_prefix_len_node(idx, &node_from_py_bytes(py, &node)?)
90 {
100 {
91 Ok(Some(l)) => Ok(l),
101 Ok(Some(l)) => Ok(l),
92 Ok(None) => Err(revlog_error(py)),
102 Ok(None) => Err(revlog_error(py)),
93 Err(e) => Err(nodemap_error(py, e)),
103 Err(e) => Err(nodemap_error(py, e)),
94 }
104 }
95 }
105 }
96
106
97 def partialmatch(&self, node: PyObject) -> PyResult<Option<PyBytes>> {
107 def partialmatch(&self, pynode: PyObject) -> PyResult<Option<PyBytes>> {
98 let opt = self.get_nodetree(py)?.borrow();
108 let opt = self.get_nodetree(py)?.borrow();
99 let nt = opt.as_ref().unwrap();
109 let nt = opt.as_ref().unwrap();
100 let idx = &*self.cindex(py).borrow();
110 let idx = &*self.cindex(py).borrow();
101
111
102 let node_as_string = if cfg!(feature = "python3-sys") {
112 let node_as_string = if cfg!(feature = "python3-sys") {
103 node.cast_as::<PyString>(py)?.to_string(py)?.to_string()
113 pynode.cast_as::<PyString>(py)?.to_string(py)?.to_string()
104 }
114 }
105 else {
115 else {
106 let node = node.extract::<PyBytes>(py)?;
116 let node = pynode.extract::<PyBytes>(py)?;
107 String::from_utf8_lossy(node.data(py)).to_string()
117 String::from_utf8_lossy(node.data(py)).to_string()
108 };
118 };
109
119
110 let prefix = NodePrefix::from_hex(&node_as_string).map_err(|_| PyErr::new::<ValueError, _>(py, "Invalid node or prefix"))?;
120 let prefix = NodePrefix::from_hex(&node_as_string).map_err(|_| PyErr::new::<ValueError, _>(py, "Invalid node or prefix"))?;
111
121
112 nt.find_bin(idx, prefix)
122 match nt.find_bin(idx, prefix) {
113 // TODO make an inner API returning the node directly
123 Ok(None) =>
114 .map(|opt| opt.map(
124 // fallback to C implementation, remove once
115 |rev| PyBytes::new(py, idx.node(rev).unwrap().as_bytes())))
125 // https://bz.mercurial-scm.org/show_bug.cgi?id=6554
116 .map_err(|e| nodemap_error(py, e))
126 // is fixed (a simple backout should do)
117
127 self.call_cindex(
128 py, "partialmatch",
129 &PyTuple::new(py, &[pynode]), None
130 )?.extract(py),
131 Ok(Some(rev)) =>
132 Ok(Some(PyBytes::new(py, idx.node(rev).unwrap().as_bytes()))),
133 Err(e) => Err(nodemap_error(py, e)),
134 }
118 }
135 }
119
136
120 /// append an index entry
137 /// append an index entry
121 def append(&self, tup: PyTuple) -> PyResult<PyObject> {
138 def append(&self, tup: PyTuple) -> PyResult<PyObject> {
122 if tup.len(py) < 8 {
139 if tup.len(py) < 8 {
123 // this is better than the panic promised by tup.get_item()
140 // this is better than the panic promised by tup.get_item()
124 return Err(
141 return Err(
125 PyErr::new::<IndexError, _>(py, "tuple index out of range"))
142 PyErr::new::<IndexError, _>(py, "tuple index out of range"))
126 }
143 }
127 let node_bytes = tup.get_item(py, 7).extract(py)?;
144 let node_bytes = tup.get_item(py, 7).extract(py)?;
128 let node = node_from_py_object(py, &node_bytes)?;
145 let node = node_from_py_object(py, &node_bytes)?;
129
146
130 let mut idx = self.cindex(py).borrow_mut();
147 let mut idx = self.cindex(py).borrow_mut();
131 let rev = idx.len() as Revision;
148 let rev = idx.len() as Revision;
132
149
133 idx.append(py, tup)?;
150 idx.append(py, tup)?;
134 self.get_nodetree(py)?.borrow_mut().as_mut().unwrap()
151 self.get_nodetree(py)?.borrow_mut().as_mut().unwrap()
135 .insert(&*idx, &node, rev)
152 .insert(&*idx, &node, rev)
136 .map_err(|e| nodemap_error(py, e))?;
153 .map_err(|e| nodemap_error(py, e))?;
137 Ok(py.None())
154 Ok(py.None())
138 }
155 }
139
156
140 def __delitem__(&self, key: PyObject) -> PyResult<()> {
157 def __delitem__(&self, key: PyObject) -> PyResult<()> {
141 // __delitem__ is both for `del idx[r]` and `del idx[r1:r2]`
158 // __delitem__ is both for `del idx[r]` and `del idx[r1:r2]`
142 self.cindex(py).borrow().inner().del_item(py, key)?;
159 self.cindex(py).borrow().inner().del_item(py, key)?;
143 let mut opt = self.get_nodetree(py)?.borrow_mut();
160 let mut opt = self.get_nodetree(py)?.borrow_mut();
144 let mut nt = opt.as_mut().unwrap();
161 let mut nt = opt.as_mut().unwrap();
145 nt.invalidate_all();
162 nt.invalidate_all();
146 self.fill_nodemap(py, &mut nt)?;
163 self.fill_nodemap(py, &mut nt)?;
147 Ok(())
164 Ok(())
148 }
165 }
149
166
150 //
167 //
151 // Reforwarded C index API
168 // Reforwarded C index API
152 //
169 //
153
170
154 // index_methods (tp_methods). Same ordering as in revlog.c
171 // index_methods (tp_methods). Same ordering as in revlog.c
155
172
156 /// return the gca set of the given revs
173 /// return the gca set of the given revs
157 def ancestors(&self, *args, **kw) -> PyResult<PyObject> {
174 def ancestors(&self, *args, **kw) -> PyResult<PyObject> {
158 self.call_cindex(py, "ancestors", args, kw)
175 self.call_cindex(py, "ancestors", args, kw)
159 }
176 }
160
177
161 /// return the heads of the common ancestors of the given revs
178 /// return the heads of the common ancestors of the given revs
162 def commonancestorsheads(&self, *args, **kw) -> PyResult<PyObject> {
179 def commonancestorsheads(&self, *args, **kw) -> PyResult<PyObject> {
163 self.call_cindex(py, "commonancestorsheads", args, kw)
180 self.call_cindex(py, "commonancestorsheads", args, kw)
164 }
181 }
165
182
166 /// Clear the index caches and inner py_class data.
183 /// Clear the index caches and inner py_class data.
167 /// It is Python's responsibility to call `update_nodemap_data` again.
184 /// It is Python's responsibility to call `update_nodemap_data` again.
168 def clearcaches(&self, *args, **kw) -> PyResult<PyObject> {
185 def clearcaches(&self, *args, **kw) -> PyResult<PyObject> {
169 self.nt(py).borrow_mut().take();
186 self.nt(py).borrow_mut().take();
170 self.docket(py).borrow_mut().take();
187 self.docket(py).borrow_mut().take();
171 self.mmap(py).borrow_mut().take();
188 self.mmap(py).borrow_mut().take();
172 self.call_cindex(py, "clearcaches", args, kw)
189 self.call_cindex(py, "clearcaches", args, kw)
173 }
190 }
174
191
175 /// return the raw binary string representing a revision
192 /// return the raw binary string representing a revision
176 def entry_binary(&self, *args, **kw) -> PyResult<PyObject> {
193 def entry_binary(&self, *args, **kw) -> PyResult<PyObject> {
177 self.call_cindex(py, "entry_binary", args, kw)
194 self.call_cindex(py, "entry_binary", args, kw)
178 }
195 }
179
196
180 /// return a binary packed version of the header
197 /// return a binary packed version of the header
181 def pack_header(&self, *args, **kw) -> PyResult<PyObject> {
198 def pack_header(&self, *args, **kw) -> PyResult<PyObject> {
182 self.call_cindex(py, "pack_header", args, kw)
199 self.call_cindex(py, "pack_header", args, kw)
183 }
200 }
184
201
185 /// get an index entry
202 /// get an index entry
186 def get(&self, *args, **kw) -> PyResult<PyObject> {
203 def get(&self, *args, **kw) -> PyResult<PyObject> {
187 self.call_cindex(py, "get", args, kw)
204 self.call_cindex(py, "get", args, kw)
188 }
205 }
189
206
190 /// compute phases
207 /// compute phases
191 def computephasesmapsets(&self, *args, **kw) -> PyResult<PyObject> {
208 def computephasesmapsets(&self, *args, **kw) -> PyResult<PyObject> {
192 self.call_cindex(py, "computephasesmapsets", args, kw)
209 self.call_cindex(py, "computephasesmapsets", args, kw)
193 }
210 }
194
211
195 /// reachableroots
212 /// reachableroots
196 def reachableroots2(&self, *args, **kw) -> PyResult<PyObject> {
213 def reachableroots2(&self, *args, **kw) -> PyResult<PyObject> {
197 self.call_cindex(py, "reachableroots2", args, kw)
214 self.call_cindex(py, "reachableroots2", args, kw)
198 }
215 }
199
216
200 /// get head revisions
217 /// get head revisions
201 def headrevs(&self, *args, **kw) -> PyResult<PyObject> {
218 def headrevs(&self, *args, **kw) -> PyResult<PyObject> {
202 self.call_cindex(py, "headrevs", args, kw)
219 self.call_cindex(py, "headrevs", args, kw)
203 }
220 }
204
221
205 /// get filtered head revisions
222 /// get filtered head revisions
206 def headrevsfiltered(&self, *args, **kw) -> PyResult<PyObject> {
223 def headrevsfiltered(&self, *args, **kw) -> PyResult<PyObject> {
207 self.call_cindex(py, "headrevsfiltered", args, kw)
224 self.call_cindex(py, "headrevsfiltered", args, kw)
208 }
225 }
209
226
210 /// True if the object is a snapshot
227 /// True if the object is a snapshot
211 def issnapshot(&self, *args, **kw) -> PyResult<PyObject> {
228 def issnapshot(&self, *args, **kw) -> PyResult<PyObject> {
212 self.call_cindex(py, "issnapshot", args, kw)
229 self.call_cindex(py, "issnapshot", args, kw)
213 }
230 }
214
231
215 /// Gather snapshot data in a cache dict
232 /// Gather snapshot data in a cache dict
216 def findsnapshots(&self, *args, **kw) -> PyResult<PyObject> {
233 def findsnapshots(&self, *args, **kw) -> PyResult<PyObject> {
217 self.call_cindex(py, "findsnapshots", args, kw)
234 self.call_cindex(py, "findsnapshots", args, kw)
218 }
235 }
219
236
220 /// determine revisions with deltas to reconstruct fulltext
237 /// determine revisions with deltas to reconstruct fulltext
221 def deltachain(&self, *args, **kw) -> PyResult<PyObject> {
238 def deltachain(&self, *args, **kw) -> PyResult<PyObject> {
222 self.call_cindex(py, "deltachain", args, kw)
239 self.call_cindex(py, "deltachain", args, kw)
223 }
240 }
224
241
225 /// slice planned chunk read to reach a density threshold
242 /// slice planned chunk read to reach a density threshold
226 def slicechunktodensity(&self, *args, **kw) -> PyResult<PyObject> {
243 def slicechunktodensity(&self, *args, **kw) -> PyResult<PyObject> {
227 self.call_cindex(py, "slicechunktodensity", args, kw)
244 self.call_cindex(py, "slicechunktodensity", args, kw)
228 }
245 }
229
246
230 /// stats for the index
247 /// stats for the index
231 def stats(&self, *args, **kw) -> PyResult<PyObject> {
248 def stats(&self, *args, **kw) -> PyResult<PyObject> {
232 self.call_cindex(py, "stats", args, kw)
249 self.call_cindex(py, "stats", args, kw)
233 }
250 }
234
251
235 // index_sequence_methods and index_mapping_methods.
252 // index_sequence_methods and index_mapping_methods.
236 //
253 //
237 // Since we call back through the high level Python API,
254 // Since we call back through the high level Python API,
238 // there's no point making a distinction between index_get
255 // there's no point making a distinction between index_get
239 // and index_getitem.
256 // and index_getitem.
240
257
241 def __len__(&self) -> PyResult<usize> {
258 def __len__(&self) -> PyResult<usize> {
242 self.cindex(py).borrow().inner().len(py)
259 self.cindex(py).borrow().inner().len(py)
243 }
260 }
244
261
245 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
262 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
246 // this conversion seems needless, but that's actually because
263 // this conversion seems needless, but that's actually because
247 // `index_getitem` does not handle conversion from PyLong,
264 // `index_getitem` does not handle conversion from PyLong,
248 // which expressions such as [e for e in index] internally use.
265 // which expressions such as [e for e in index] internally use.
249 // Note that we don't seem to have a direct way to call
266 // Note that we don't seem to have a direct way to call
250 // PySequence_GetItem (does the job), which would possibly be better
267 // PySequence_GetItem (does the job), which would possibly be better
251 // for performance
268 // for performance
252 let key = match key.extract::<Revision>(py) {
269 let key = match key.extract::<Revision>(py) {
253 Ok(rev) => rev.to_py_object(py).into_object(),
270 Ok(rev) => rev.to_py_object(py).into_object(),
254 Err(_) => key,
271 Err(_) => key,
255 };
272 };
256 self.cindex(py).borrow().inner().get_item(py, key)
273 self.cindex(py).borrow().inner().get_item(py, key)
257 }
274 }
258
275
259 def __setitem__(&self, key: PyObject, value: PyObject) -> PyResult<()> {
276 def __setitem__(&self, key: PyObject, value: PyObject) -> PyResult<()> {
260 self.cindex(py).borrow().inner().set_item(py, key, value)
277 self.cindex(py).borrow().inner().set_item(py, key, value)
261 }
278 }
262
279
263 def __contains__(&self, item: PyObject) -> PyResult<bool> {
280 def __contains__(&self, item: PyObject) -> PyResult<bool> {
264 // ObjectProtocol does not seem to provide contains(), so
281 // ObjectProtocol does not seem to provide contains(), so
265 // this is an equivalent implementation of the index_contains()
282 // this is an equivalent implementation of the index_contains()
266 // defined in revlog.c
283 // defined in revlog.c
267 let cindex = self.cindex(py).borrow();
284 let cindex = self.cindex(py).borrow();
268 match item.extract::<Revision>(py) {
285 match item.extract::<Revision>(py) {
269 Ok(rev) => {
286 Ok(rev) => {
270 Ok(rev >= -1 && rev < cindex.inner().len(py)? as Revision)
287 Ok(rev >= -1 && rev < cindex.inner().len(py)? as Revision)
271 }
288 }
272 Err(_) => {
289 Err(_) => {
273 cindex.inner().call_method(
290 cindex.inner().call_method(
274 py,
291 py,
275 "has_node",
292 "has_node",
276 PyTuple::new(py, &[item]),
293 PyTuple::new(py, &[item]),
277 None)?
294 None)?
278 .extract(py)
295 .extract(py)
279 }
296 }
280 }
297 }
281 }
298 }
282
299
283 def nodemap_data_all(&self) -> PyResult<PyBytes> {
300 def nodemap_data_all(&self) -> PyResult<PyBytes> {
284 self.inner_nodemap_data_all(py)
301 self.inner_nodemap_data_all(py)
285 }
302 }
286
303
287 def nodemap_data_incremental(&self) -> PyResult<PyObject> {
304 def nodemap_data_incremental(&self) -> PyResult<PyObject> {
288 self.inner_nodemap_data_incremental(py)
305 self.inner_nodemap_data_incremental(py)
289 }
306 }
290 def update_nodemap_data(
307 def update_nodemap_data(
291 &self,
308 &self,
292 docket: PyObject,
309 docket: PyObject,
293 nm_data: PyObject
310 nm_data: PyObject
294 ) -> PyResult<PyObject> {
311 ) -> PyResult<PyObject> {
295 self.inner_update_nodemap_data(py, docket, nm_data)
312 self.inner_update_nodemap_data(py, docket, nm_data)
296 }
313 }
297
314
298 @property
315 @property
299 def entry_size(&self) -> PyResult<PyInt> {
316 def entry_size(&self) -> PyResult<PyInt> {
300 self.cindex(py).borrow().inner().getattr(py, "entry_size")?.extract::<PyInt>(py)
317 self.cindex(py).borrow().inner().getattr(py, "entry_size")?.extract::<PyInt>(py)
301 }
318 }
302
319
303 @property
320 @property
304 def rust_ext_compat(&self) -> PyResult<PyInt> {
321 def rust_ext_compat(&self) -> PyResult<PyInt> {
305 self.cindex(py).borrow().inner().getattr(py, "rust_ext_compat")?.extract::<PyInt>(py)
322 self.cindex(py).borrow().inner().getattr(py, "rust_ext_compat")?.extract::<PyInt>(py)
306 }
323 }
307
324
308 });
325 });
309
326
310 impl MixedIndex {
327 impl MixedIndex {
311 fn new(py: Python, cindex: PyObject) -> PyResult<MixedIndex> {
328 fn new(py: Python, cindex: PyObject) -> PyResult<MixedIndex> {
312 Self::create_instance(
329 Self::create_instance(
313 py,
330 py,
314 RefCell::new(cindex::Index::new(py, cindex)?),
331 RefCell::new(cindex::Index::new(py, cindex)?),
315 RefCell::new(None),
332 RefCell::new(None),
316 RefCell::new(None),
333 RefCell::new(None),
317 RefCell::new(None),
334 RefCell::new(None),
318 )
335 )
319 }
336 }
320
337
321 /// This is scaffolding at this point, but it could also become
338 /// This is scaffolding at this point, but it could also become
322 /// a way to start a persistent nodemap or perform a
339 /// a way to start a persistent nodemap or perform a
323 /// vacuum / repack operation
340 /// vacuum / repack operation
324 fn fill_nodemap(
341 fn fill_nodemap(
325 &self,
342 &self,
326 py: Python,
343 py: Python,
327 nt: &mut NodeTree,
344 nt: &mut NodeTree,
328 ) -> PyResult<PyObject> {
345 ) -> PyResult<PyObject> {
329 let index = self.cindex(py).borrow();
346 let index = self.cindex(py).borrow();
330 for r in 0..index.len() {
347 for r in 0..index.len() {
331 let rev = r as Revision;
348 let rev = r as Revision;
332 // in this case node() won't ever return None
349 // in this case node() won't ever return None
333 nt.insert(&*index, index.node(rev).unwrap(), rev)
350 nt.insert(&*index, index.node(rev).unwrap(), rev)
334 .map_err(|e| nodemap_error(py, e))?
351 .map_err(|e| nodemap_error(py, e))?
335 }
352 }
336 Ok(py.None())
353 Ok(py.None())
337 }
354 }
338
355
339 fn get_nodetree<'a>(
356 fn get_nodetree<'a>(
340 &'a self,
357 &'a self,
341 py: Python<'a>,
358 py: Python<'a>,
342 ) -> PyResult<&'a RefCell<Option<NodeTree>>> {
359 ) -> PyResult<&'a RefCell<Option<NodeTree>>> {
343 if self.nt(py).borrow().is_none() {
360 if self.nt(py).borrow().is_none() {
344 let readonly = Box::new(Vec::new());
361 let readonly = Box::new(Vec::new());
345 let mut nt = NodeTree::load_bytes(readonly, 0);
362 let mut nt = NodeTree::load_bytes(readonly, 0);
346 self.fill_nodemap(py, &mut nt)?;
363 self.fill_nodemap(py, &mut nt)?;
347 self.nt(py).borrow_mut().replace(nt);
364 self.nt(py).borrow_mut().replace(nt);
348 }
365 }
349 Ok(self.nt(py))
366 Ok(self.nt(py))
350 }
367 }
351
368
352 /// forward a method call to the underlying C index
369 /// forward a method call to the underlying C index
353 fn call_cindex(
370 fn call_cindex(
354 &self,
371 &self,
355 py: Python,
372 py: Python,
356 name: &str,
373 name: &str,
357 args: &PyTuple,
374 args: &PyTuple,
358 kwargs: Option<&PyDict>,
375 kwargs: Option<&PyDict>,
359 ) -> PyResult<PyObject> {
376 ) -> PyResult<PyObject> {
360 self.cindex(py)
377 self.cindex(py)
361 .borrow()
378 .borrow()
362 .inner()
379 .inner()
363 .call_method(py, name, args, kwargs)
380 .call_method(py, name, args, kwargs)
364 }
381 }
365
382
366 pub fn clone_cindex(&self, py: Python) -> cindex::Index {
383 pub fn clone_cindex(&self, py: Python) -> cindex::Index {
367 self.cindex(py).borrow().clone_ref(py)
384 self.cindex(py).borrow().clone_ref(py)
368 }
385 }
369
386
370 /// Returns the full nodemap bytes to be written as-is to disk
387 /// Returns the full nodemap bytes to be written as-is to disk
371 fn inner_nodemap_data_all(&self, py: Python) -> PyResult<PyBytes> {
388 fn inner_nodemap_data_all(&self, py: Python) -> PyResult<PyBytes> {
372 let nodemap = self.get_nodetree(py)?.borrow_mut().take().unwrap();
389 let nodemap = self.get_nodetree(py)?.borrow_mut().take().unwrap();
373 let (readonly, bytes) = nodemap.into_readonly_and_added_bytes();
390 let (readonly, bytes) = nodemap.into_readonly_and_added_bytes();
374
391
375 // If there's anything readonly, we need to build the data again from
392 // If there's anything readonly, we need to build the data again from
376 // scratch
393 // scratch
377 let bytes = if readonly.len() > 0 {
394 let bytes = if readonly.len() > 0 {
378 let mut nt = NodeTree::load_bytes(Box::new(vec![]), 0);
395 let mut nt = NodeTree::load_bytes(Box::new(vec![]), 0);
379 self.fill_nodemap(py, &mut nt)?;
396 self.fill_nodemap(py, &mut nt)?;
380
397
381 let (readonly, bytes) = nt.into_readonly_and_added_bytes();
398 let (readonly, bytes) = nt.into_readonly_and_added_bytes();
382 assert_eq!(readonly.len(), 0);
399 assert_eq!(readonly.len(), 0);
383
400
384 bytes
401 bytes
385 } else {
402 } else {
386 bytes
403 bytes
387 };
404 };
388
405
389 let bytes = PyBytes::new(py, &bytes);
406 let bytes = PyBytes::new(py, &bytes);
390 Ok(bytes)
407 Ok(bytes)
391 }
408 }
392
409
393 /// Returns the last saved docket along with the size of any changed data
410 /// Returns the last saved docket along with the size of any changed data
394 /// (in number of blocks), and said data as bytes.
411 /// (in number of blocks), and said data as bytes.
395 fn inner_nodemap_data_incremental(
412 fn inner_nodemap_data_incremental(
396 &self,
413 &self,
397 py: Python,
414 py: Python,
398 ) -> PyResult<PyObject> {
415 ) -> PyResult<PyObject> {
399 let docket = self.docket(py).borrow();
416 let docket = self.docket(py).borrow();
400 let docket = match docket.as_ref() {
417 let docket = match docket.as_ref() {
401 Some(d) => d,
418 Some(d) => d,
402 None => return Ok(py.None()),
419 None => return Ok(py.None()),
403 };
420 };
404
421
405 let node_tree = self.get_nodetree(py)?.borrow_mut().take().unwrap();
422 let node_tree = self.get_nodetree(py)?.borrow_mut().take().unwrap();
406 let masked_blocks = node_tree.masked_readonly_blocks();
423 let masked_blocks = node_tree.masked_readonly_blocks();
407 let (_, data) = node_tree.into_readonly_and_added_bytes();
424 let (_, data) = node_tree.into_readonly_and_added_bytes();
408 let changed = masked_blocks * std::mem::size_of::<Block>();
425 let changed = masked_blocks * std::mem::size_of::<Block>();
409
426
410 Ok((docket, changed, PyBytes::new(py, &data))
427 Ok((docket, changed, PyBytes::new(py, &data))
411 .to_py_object(py)
428 .to_py_object(py)
412 .into_object())
429 .into_object())
413 }
430 }
414
431
415 /// Update the nodemap from the new (mmaped) data.
432 /// Update the nodemap from the new (mmaped) data.
416 /// The docket is kept as a reference for later incremental calls.
433 /// The docket is kept as a reference for later incremental calls.
417 fn inner_update_nodemap_data(
434 fn inner_update_nodemap_data(
418 &self,
435 &self,
419 py: Python,
436 py: Python,
420 docket: PyObject,
437 docket: PyObject,
421 nm_data: PyObject,
438 nm_data: PyObject,
422 ) -> PyResult<PyObject> {
439 ) -> PyResult<PyObject> {
423 let buf = PyBuffer::get(py, &nm_data)?;
440 let buf = PyBuffer::get(py, &nm_data)?;
424 let len = buf.item_count();
441 let len = buf.item_count();
425
442
426 // Build a slice from the mmap'ed buffer data
443 // Build a slice from the mmap'ed buffer data
427 let cbuf = buf.buf_ptr();
444 let cbuf = buf.buf_ptr();
428 let bytes = if std::mem::size_of::<u8>() == buf.item_size()
445 let bytes = if std::mem::size_of::<u8>() == buf.item_size()
429 && buf.is_c_contiguous()
446 && buf.is_c_contiguous()
430 && u8::is_compatible_format(buf.format())
447 && u8::is_compatible_format(buf.format())
431 {
448 {
432 unsafe { std::slice::from_raw_parts(cbuf as *const u8, len) }
449 unsafe { std::slice::from_raw_parts(cbuf as *const u8, len) }
433 } else {
450 } else {
434 return Err(PyErr::new::<ValueError, _>(
451 return Err(PyErr::new::<ValueError, _>(
435 py,
452 py,
436 "Nodemap data buffer has an invalid memory representation"
453 "Nodemap data buffer has an invalid memory representation"
437 .to_string(),
454 .to_string(),
438 ));
455 ));
439 };
456 };
440
457
441 // Keep a reference to the mmap'ed buffer, otherwise we get a dangling
458 // Keep a reference to the mmap'ed buffer, otherwise we get a dangling
442 // pointer.
459 // pointer.
443 self.mmap(py).borrow_mut().replace(buf);
460 self.mmap(py).borrow_mut().replace(buf);
444
461
445 let mut nt = NodeTree::load_bytes(Box::new(bytes), len);
462 let mut nt = NodeTree::load_bytes(Box::new(bytes), len);
446
463
447 let data_tip =
464 let data_tip =
448 docket.getattr(py, "tip_rev")?.extract::<Revision>(py)?;
465 docket.getattr(py, "tip_rev")?.extract::<Revision>(py)?;
449 self.docket(py).borrow_mut().replace(docket.clone_ref(py));
466 self.docket(py).borrow_mut().replace(docket.clone_ref(py));
450 let idx = self.cindex(py).borrow();
467 let idx = self.cindex(py).borrow();
451 let current_tip = idx.len();
468 let current_tip = idx.len();
452
469
453 for r in (data_tip + 1)..current_tip as Revision {
470 for r in (data_tip + 1)..current_tip as Revision {
454 let rev = r as Revision;
471 let rev = r as Revision;
455 // in this case node() won't ever return None
472 // in this case node() won't ever return None
456 nt.insert(&*idx, idx.node(rev).unwrap(), rev)
473 nt.insert(&*idx, idx.node(rev).unwrap(), rev)
457 .map_err(|e| nodemap_error(py, e))?
474 .map_err(|e| nodemap_error(py, e))?
458 }
475 }
459
476
460 *self.nt(py).borrow_mut() = Some(nt);
477 *self.nt(py).borrow_mut() = Some(nt);
461
478
462 Ok(py.None())
479 Ok(py.None())
463 }
480 }
464 }
481 }
465
482
466 fn revlog_error(py: Python) -> PyErr {
483 fn revlog_error(py: Python) -> PyErr {
467 match py
484 match py
468 .import("mercurial.error")
485 .import("mercurial.error")
469 .and_then(|m| m.get(py, "RevlogError"))
486 .and_then(|m| m.get(py, "RevlogError"))
470 {
487 {
471 Err(e) => e,
488 Err(e) => e,
472 Ok(cls) => PyErr::from_instance(
489 Ok(cls) => PyErr::from_instance(
473 py,
490 py,
474 cls.call(py, (py.None(),), None).ok().into_py_object(py),
491 cls.call(py, (py.None(),), None).ok().into_py_object(py),
475 ),
492 ),
476 }
493 }
477 }
494 }
478
495
479 fn rev_not_in_index(py: Python, rev: Revision) -> PyErr {
496 fn rev_not_in_index(py: Python, rev: Revision) -> PyErr {
480 PyErr::new::<ValueError, _>(
497 PyErr::new::<ValueError, _>(
481 py,
498 py,
482 format!(
499 format!(
483 "Inconsistency: Revision {} found in nodemap \
500 "Inconsistency: Revision {} found in nodemap \
484 is not in revlog index",
501 is not in revlog index",
485 rev
502 rev
486 ),
503 ),
487 )
504 )
488 }
505 }
489
506
490 /// Standard treatment of NodeMapError
507 /// Standard treatment of NodeMapError
491 fn nodemap_error(py: Python, err: NodeMapError) -> PyErr {
508 fn nodemap_error(py: Python, err: NodeMapError) -> PyErr {
492 match err {
509 match err {
493 NodeMapError::MultipleResults => revlog_error(py),
510 NodeMapError::MultipleResults => revlog_error(py),
494 NodeMapError::RevisionNotInIndex(r) => rev_not_in_index(py, r),
511 NodeMapError::RevisionNotInIndex(r) => rev_not_in_index(py, r),
495 }
512 }
496 }
513 }
497
514
498 /// Create the module, with __package__ given from parent
515 /// Create the module, with __package__ given from parent
499 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
516 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
500 let dotted_name = &format!("{}.revlog", package);
517 let dotted_name = &format!("{}.revlog", package);
501 let m = PyModule::new(py, dotted_name)?;
518 let m = PyModule::new(py, dotted_name)?;
502 m.add(py, "__package__", package)?;
519 m.add(py, "__package__", package)?;
503 m.add(py, "__doc__", "RevLog - Rust implementations")?;
520 m.add(py, "__doc__", "RevLog - Rust implementations")?;
504
521
505 m.add_class::<MixedIndex>(py)?;
522 m.add_class::<MixedIndex>(py)?;
506
523
507 let sys = PyModule::import(py, "sys")?;
524 let sys = PyModule::import(py, "sys")?;
508 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
525 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
509 sys_modules.set_item(py, dotted_name, &m)?;
526 sys_modules.set_item(py, dotted_name, &m)?;
510
527
511 Ok(m)
528 Ok(m)
512 }
529 }
@@ -1,1067 +1,1107 b''
1 ===================================
1 ===================================
2 Test the persistent on-disk nodemap
2 Test the persistent on-disk nodemap
3 ===================================
3 ===================================
4
4
5
5
6 #if no-rust
6 #if no-rust
7
7
8 $ cat << EOF >> $HGRCPATH
8 $ cat << EOF >> $HGRCPATH
9 > [format]
9 > [format]
10 > use-persistent-nodemap=yes
10 > use-persistent-nodemap=yes
11 > [devel]
11 > [devel]
12 > persistent-nodemap=yes
12 > persistent-nodemap=yes
13 > EOF
13 > EOF
14
14
15 #endif
15 #endif
16
16
17 $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow
17 $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow
18 $ cd test-repo
18 $ cd test-repo
19
19
20 Check handling of the default slow-path value
20 Check handling of the default slow-path value
21
21
22 #if no-pure no-rust
22 #if no-pure no-rust
23
23
24 $ hg id
24 $ hg id
25 abort: accessing `persistent-nodemap` repository without associated fast implementation.
25 abort: accessing `persistent-nodemap` repository without associated fast implementation.
26 (check `hg help config.format.use-persistent-nodemap` for details)
26 (check `hg help config.format.use-persistent-nodemap` for details)
27 [255]
27 [255]
28
28
29 Unlock further check (we are here to test the feature)
29 Unlock further check (we are here to test the feature)
30
30
31 $ cat << EOF >> $HGRCPATH
31 $ cat << EOF >> $HGRCPATH
32 > [storage]
32 > [storage]
33 > # to avoid spamming the test
33 > # to avoid spamming the test
34 > revlog.persistent-nodemap.slow-path=allow
34 > revlog.persistent-nodemap.slow-path=allow
35 > EOF
35 > EOF
36
36
37 #endif
37 #endif
38
38
39 #if rust
39 #if rust
40
40
41 Regression test for a previous bug in Rust/C FFI for the `Revlog_CAPI` capsule:
41 Regression test for a previous bug in Rust/C FFI for the `Revlog_CAPI` capsule:
42 in places where `mercurial/cext/revlog.c` function signatures use `Py_ssize_t`
42 in places where `mercurial/cext/revlog.c` function signatures use `Py_ssize_t`
43 (64 bits on Linux x86_64), corresponding declarations in `rust/hg-cpython/src/cindex.rs`
43 (64 bits on Linux x86_64), corresponding declarations in `rust/hg-cpython/src/cindex.rs`
44 incorrectly used `libc::c_int` (32 bits).
44 incorrectly used `libc::c_int` (32 bits).
45 As a result, -1 passed from Rust for the null revision became 4294967295 in C.
45 As a result, -1 passed from Rust for the null revision became 4294967295 in C.
46
46
47 $ hg log -r 00000000
47 $ hg log -r 00000000
48 changeset: -1:000000000000
48 changeset: -1:000000000000
49 tag: tip
49 tag: tip
50 user:
50 user:
51 date: Thu Jan 01 00:00:00 1970 +0000
51 date: Thu Jan 01 00:00:00 1970 +0000
52
52
53
53
54 #endif
54 #endif
55
55
56
56
57 $ hg debugformat
57 $ hg debugformat
58 format-variant repo
58 format-variant repo
59 fncache: yes
59 fncache: yes
60 dirstate-v2: no
60 dirstate-v2: no
61 dotencode: yes
61 dotencode: yes
62 generaldelta: yes
62 generaldelta: yes
63 share-safe: no
63 share-safe: no
64 sparserevlog: yes
64 sparserevlog: yes
65 persistent-nodemap: yes
65 persistent-nodemap: yes
66 copies-sdc: no
66 copies-sdc: no
67 revlog-v2: no
67 revlog-v2: no
68 changelog-v2: no
68 changelog-v2: no
69 plain-cl-delta: yes
69 plain-cl-delta: yes
70 compression: zlib (no-zstd !)
70 compression: zlib (no-zstd !)
71 compression: zstd (zstd !)
71 compression: zstd (zstd !)
72 compression-level: default
72 compression-level: default
73 $ hg debugbuilddag .+5000 --new-file
73 $ hg debugbuilddag .+5000 --new-file
74
74
75 $ hg debugnodemap --metadata
75 $ hg debugnodemap --metadata
76 uid: ???????? (glob)
76 uid: ???????? (glob)
77 tip-rev: 5000
77 tip-rev: 5000
78 tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c
78 tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c
79 data-length: 121088
79 data-length: 121088
80 data-unused: 0
80 data-unused: 0
81 data-unused: 0.000%
81 data-unused: 0.000%
82 $ f --size .hg/store/00changelog.n
82 $ f --size .hg/store/00changelog.n
83 .hg/store/00changelog.n: size=62
83 .hg/store/00changelog.n: size=62
84
84
85 Simple lookup works
85 Simple lookup works
86
86
87 $ ANYNODE=`hg log --template '{node|short}\n' --rev tip`
87 $ ANYNODE=`hg log --template '{node|short}\n' --rev tip`
88 $ hg log -r "$ANYNODE" --template '{rev}\n'
88 $ hg log -r "$ANYNODE" --template '{rev}\n'
89 5000
89 5000
90
90
91
91
92 #if rust
92 #if rust
93
93
94 $ f --sha256 .hg/store/00changelog-*.nd
94 $ f --sha256 .hg/store/00changelog-*.nd
95 .hg/store/00changelog-????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob)
95 .hg/store/00changelog-????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob)
96
96
97 $ f --sha256 .hg/store/00manifest-*.nd
97 $ f --sha256 .hg/store/00manifest-*.nd
98 .hg/store/00manifest-????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob)
98 .hg/store/00manifest-????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob)
99 $ hg debugnodemap --dump-new | f --sha256 --size
99 $ hg debugnodemap --dump-new | f --sha256 --size
100 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
100 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
101 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
101 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
102 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
102 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
103 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........|
103 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........|
104 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."|
104 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."|
105 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^|
105 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^|
106 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....|
106 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....|
107 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8|
107 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8|
108 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i|
108 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i|
109 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....|
109 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....|
110 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........|
110 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........|
111 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....|
111 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....|
112 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................|
112 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................|
113 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+|
113 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+|
114 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................|
114 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................|
115 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5|
115 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5|
116 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U|
116 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U|
117 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................|
117 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................|
118 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................|
118 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................|
119
119
120
120
121 #else
121 #else
122
122
123 $ f --sha256 .hg/store/00changelog-*.nd
123 $ f --sha256 .hg/store/00changelog-*.nd
124 .hg/store/00changelog-????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob)
124 .hg/store/00changelog-????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob)
125 $ hg debugnodemap --dump-new | f --sha256 --size
125 $ hg debugnodemap --dump-new | f --sha256 --size
126 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
126 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
127 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
127 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
128 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
128 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
129 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
129 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
130 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
130 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
131 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................|
131 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................|
132 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................|
132 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................|
133 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
133 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
134 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................|
134 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................|
135 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............|
135 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............|
136 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
136 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
137 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
137 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
138 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................|
138 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................|
139 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........|
139 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........|
140 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
140 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
141 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
141 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
142 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
142 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
143 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................|
143 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................|
144 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................|
144 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................|
145
145
146 #endif
146 #endif
147
147
148 $ hg debugnodemap --check
148 $ hg debugnodemap --check
149 revision in index: 5001
149 revision in index: 5001
150 revision in nodemap: 5001
150 revision in nodemap: 5001
151
151
152 add a new commit
152 add a new commit
153
153
154 $ hg up
154 $ hg up
155 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
156 $ echo foo > foo
156 $ echo foo > foo
157 $ hg add foo
157 $ hg add foo
158
158
159
159
160 Check slow-path config value handling
160 Check slow-path config value handling
161 -------------------------------------
161 -------------------------------------
162
162
163 #if no-pure no-rust
163 #if no-pure no-rust
164
164
165 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
165 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
166 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
166 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
167 falling back to default value: abort
167 falling back to default value: abort
168 abort: accessing `persistent-nodemap` repository without associated fast implementation.
168 abort: accessing `persistent-nodemap` repository without associated fast implementation.
169 (check `hg help config.format.use-persistent-nodemap` for details)
169 (check `hg help config.format.use-persistent-nodemap` for details)
170 [255]
170 [255]
171
171
172 $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn"
172 $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn"
173 warning: accessing `persistent-nodemap` repository without associated fast implementation.
173 warning: accessing `persistent-nodemap` repository without associated fast implementation.
174 (check `hg help config.format.use-persistent-nodemap` for details)
174 (check `hg help config.format.use-persistent-nodemap` for details)
175 changeset: 5000:6b02b8c7b966
175 changeset: 5000:6b02b8c7b966
176 tag: tip
176 tag: tip
177 user: debugbuilddag
177 user: debugbuilddag
178 date: Thu Jan 01 01:23:20 1970 +0000
178 date: Thu Jan 01 01:23:20 1970 +0000
179 summary: r5000
179 summary: r5000
180
180
181 $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort"
181 $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort"
182 abort: accessing `persistent-nodemap` repository without associated fast implementation.
182 abort: accessing `persistent-nodemap` repository without associated fast implementation.
183 (check `hg help config.format.use-persistent-nodemap` for details)
183 (check `hg help config.format.use-persistent-nodemap` for details)
184 [255]
184 [255]
185
185
186 #else
186 #else
187
187
188 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
188 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
189 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
189 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
190 falling back to default value: abort
190 falling back to default value: abort
191 6b02b8c7b966+ tip
191 6b02b8c7b966+ tip
192
192
193 #endif
193 #endif
194
194
195 $ hg ci -m 'foo'
195 $ hg ci -m 'foo'
196
196
197 #if no-pure no-rust
197 #if no-pure no-rust
198 $ hg debugnodemap --metadata
198 $ hg debugnodemap --metadata
199 uid: ???????? (glob)
199 uid: ???????? (glob)
200 tip-rev: 5001
200 tip-rev: 5001
201 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
201 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
202 data-length: 121088
202 data-length: 121088
203 data-unused: 0
203 data-unused: 0
204 data-unused: 0.000%
204 data-unused: 0.000%
205 #else
205 #else
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: 121344
210 data-length: 121344
211 data-unused: 256
211 data-unused: 256
212 data-unused: 0.211%
212 data-unused: 0.211%
213 #endif
213 #endif
214
214
215 $ f --size .hg/store/00changelog.n
215 $ f --size .hg/store/00changelog.n
216 .hg/store/00changelog.n: size=62
216 .hg/store/00changelog.n: size=62
217
217
218 (The pure code use the debug code that perform incremental update, the C code reencode from scratch)
218 (The pure code use the debug code that perform incremental update, the C code reencode from scratch)
219
219
220 #if pure
220 #if pure
221 $ f --sha256 .hg/store/00changelog-*.nd --size
221 $ f --sha256 .hg/store/00changelog-*.nd --size
222 .hg/store/00changelog-????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob)
222 .hg/store/00changelog-????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob)
223 #endif
223 #endif
224
224
225 #if rust
225 #if rust
226 $ f --sha256 .hg/store/00changelog-*.nd --size
226 $ f --sha256 .hg/store/00changelog-*.nd --size
227 .hg/store/00changelog-????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob)
227 .hg/store/00changelog-????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob)
228 #endif
228 #endif
229
229
230 #if no-pure no-rust
230 #if no-pure no-rust
231 $ f --sha256 .hg/store/00changelog-*.nd --size
231 $ f --sha256 .hg/store/00changelog-*.nd --size
232 .hg/store/00changelog-????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob)
232 .hg/store/00changelog-????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob)
233 #endif
233 #endif
234
234
235 $ hg debugnodemap --check
235 $ hg debugnodemap --check
236 revision in index: 5002
236 revision in index: 5002
237 revision in nodemap: 5002
237 revision in nodemap: 5002
238
238
239 Test code path without mmap
239 Test code path without mmap
240 ---------------------------
240 ---------------------------
241
241
242 $ echo bar > bar
242 $ echo bar > bar
243 $ hg add bar
243 $ hg add bar
244 $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no
244 $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no
245
245
246 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes
246 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes
247 revision in index: 5003
247 revision in index: 5003
248 revision in nodemap: 5003
248 revision in nodemap: 5003
249 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no
249 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no
250 revision in index: 5003
250 revision in index: 5003
251 revision in nodemap: 5003
251 revision in nodemap: 5003
252
252
253
253
254 #if pure
254 #if pure
255 $ hg debugnodemap --metadata
255 $ hg debugnodemap --metadata
256 uid: ???????? (glob)
256 uid: ???????? (glob)
257 tip-rev: 5002
257 tip-rev: 5002
258 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
258 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
259 data-length: 121600
259 data-length: 121600
260 data-unused: 512
260 data-unused: 512
261 data-unused: 0.421%
261 data-unused: 0.421%
262 $ f --sha256 .hg/store/00changelog-*.nd --size
262 $ f --sha256 .hg/store/00changelog-*.nd --size
263 .hg/store/00changelog-????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob)
263 .hg/store/00changelog-????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob)
264 #endif
264 #endif
265 #if rust
265 #if rust
266 $ hg debugnodemap --metadata
266 $ hg debugnodemap --metadata
267 uid: ???????? (glob)
267 uid: ???????? (glob)
268 tip-rev: 5002
268 tip-rev: 5002
269 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
269 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
270 data-length: 121600
270 data-length: 121600
271 data-unused: 512
271 data-unused: 512
272 data-unused: 0.421%
272 data-unused: 0.421%
273 $ f --sha256 .hg/store/00changelog-*.nd --size
273 $ f --sha256 .hg/store/00changelog-*.nd --size
274 .hg/store/00changelog-????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob)
274 .hg/store/00changelog-????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob)
275 #endif
275 #endif
276 #if no-pure no-rust
276 #if no-pure no-rust
277 $ hg debugnodemap --metadata
277 $ hg debugnodemap --metadata
278 uid: ???????? (glob)
278 uid: ???????? (glob)
279 tip-rev: 5002
279 tip-rev: 5002
280 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
280 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
281 data-length: 121088
281 data-length: 121088
282 data-unused: 0
282 data-unused: 0
283 data-unused: 0.000%
283 data-unused: 0.000%
284 $ f --sha256 .hg/store/00changelog-*.nd --size
284 $ f --sha256 .hg/store/00changelog-*.nd --size
285 .hg/store/00changelog-????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob)
285 .hg/store/00changelog-????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob)
286 #endif
286 #endif
287
287
288 Test force warming the cache
288 Test force warming the cache
289
289
290 $ rm .hg/store/00changelog.n
290 $ rm .hg/store/00changelog.n
291 $ hg debugnodemap --metadata
291 $ hg debugnodemap --metadata
292 $ hg debugupdatecache
292 $ hg debugupdatecache
293 #if pure
293 #if pure
294 $ hg debugnodemap --metadata
294 $ hg debugnodemap --metadata
295 uid: ???????? (glob)
295 uid: ???????? (glob)
296 tip-rev: 5002
296 tip-rev: 5002
297 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
297 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
298 data-length: 121088
298 data-length: 121088
299 data-unused: 0
299 data-unused: 0
300 data-unused: 0.000%
300 data-unused: 0.000%
301 #else
301 #else
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 #endif
309 #endif
310
310
311 Check out of sync nodemap
311 Check out of sync nodemap
312 =========================
312 =========================
313
313
314 First copy old data on the side.
314 First copy old data on the side.
315
315
316 $ mkdir ../tmp-copies
316 $ mkdir ../tmp-copies
317 $ cp .hg/store/00changelog-????????.nd .hg/store/00changelog.n ../tmp-copies
317 $ cp .hg/store/00changelog-????????.nd .hg/store/00changelog.n ../tmp-copies
318
318
319 Nodemap lagging behind
319 Nodemap lagging behind
320 ----------------------
320 ----------------------
321
321
322 make a new commit
322 make a new commit
323
323
324 $ echo bar2 > bar
324 $ echo bar2 > bar
325 $ hg ci -m 'bar2'
325 $ hg ci -m 'bar2'
326 $ NODE=`hg log -r tip -T '{node}\n'`
326 $ NODE=`hg log -r tip -T '{node}\n'`
327 $ hg log -r "$NODE" -T '{rev}\n'
327 $ hg log -r "$NODE" -T '{rev}\n'
328 5003
328 5003
329
329
330 If the nodemap is lagging behind, it can catch up fine
330 If the nodemap is lagging behind, it can catch up fine
331
331
332 $ hg debugnodemap --metadata
332 $ hg debugnodemap --metadata
333 uid: ???????? (glob)
333 uid: ???????? (glob)
334 tip-rev: 5003
334 tip-rev: 5003
335 tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3
335 tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3
336 data-length: 121344 (pure !)
336 data-length: 121344 (pure !)
337 data-length: 121344 (rust !)
337 data-length: 121344 (rust !)
338 data-length: 121152 (no-rust no-pure !)
338 data-length: 121152 (no-rust no-pure !)
339 data-unused: 192 (pure !)
339 data-unused: 192 (pure !)
340 data-unused: 192 (rust !)
340 data-unused: 192 (rust !)
341 data-unused: 0 (no-rust no-pure !)
341 data-unused: 0 (no-rust no-pure !)
342 data-unused: 0.158% (pure !)
342 data-unused: 0.158% (pure !)
343 data-unused: 0.158% (rust !)
343 data-unused: 0.158% (rust !)
344 data-unused: 0.000% (no-rust no-pure !)
344 data-unused: 0.000% (no-rust no-pure !)
345 $ cp -f ../tmp-copies/* .hg/store/
345 $ cp -f ../tmp-copies/* .hg/store/
346 $ hg debugnodemap --metadata
346 $ hg debugnodemap --metadata
347 uid: ???????? (glob)
347 uid: ???????? (glob)
348 tip-rev: 5002
348 tip-rev: 5002
349 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
349 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
350 data-length: 121088
350 data-length: 121088
351 data-unused: 0
351 data-unused: 0
352 data-unused: 0.000%
352 data-unused: 0.000%
353 $ hg log -r "$NODE" -T '{rev}\n'
353 $ hg log -r "$NODE" -T '{rev}\n'
354 5003
354 5003
355
355
356 changelog altered
356 changelog altered
357 -----------------
357 -----------------
358
358
359 If the nodemap is not gated behind a requirements, an unaware client can alter
359 If the nodemap is not gated behind a requirements, an unaware client can alter
360 the repository so the revlog used to generate the nodemap is not longer
360 the repository so the revlog used to generate the nodemap is not longer
361 compatible with the persistent nodemap. We need to detect that.
361 compatible with the persistent nodemap. We need to detect that.
362
362
363 $ hg up "$NODE~5"
363 $ hg up "$NODE~5"
364 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
364 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
365 $ echo bar > babar
365 $ echo bar > babar
366 $ hg add babar
366 $ hg add babar
367 $ hg ci -m 'babar'
367 $ hg ci -m 'babar'
368 created new head
368 created new head
369 $ OTHERNODE=`hg log -r tip -T '{node}\n'`
369 $ OTHERNODE=`hg log -r tip -T '{node}\n'`
370 $ hg log -r "$OTHERNODE" -T '{rev}\n'
370 $ hg log -r "$OTHERNODE" -T '{rev}\n'
371 5004
371 5004
372
372
373 $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup
373 $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup
374
374
375 the nodemap should detect the changelog have been tampered with and recover.
375 the nodemap should detect the changelog have been tampered with and recover.
376
376
377 $ hg debugnodemap --metadata
377 $ hg debugnodemap --metadata
378 uid: ???????? (glob)
378 uid: ???????? (glob)
379 tip-rev: 5002
379 tip-rev: 5002
380 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
380 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
381 data-length: 121536 (pure !)
381 data-length: 121536 (pure !)
382 data-length: 121088 (rust !)
382 data-length: 121088 (rust !)
383 data-length: 121088 (no-pure no-rust !)
383 data-length: 121088 (no-pure no-rust !)
384 data-unused: 448 (pure !)
384 data-unused: 448 (pure !)
385 data-unused: 0 (rust !)
385 data-unused: 0 (rust !)
386 data-unused: 0 (no-pure no-rust !)
386 data-unused: 0 (no-pure no-rust !)
387 data-unused: 0.000% (rust !)
387 data-unused: 0.000% (rust !)
388 data-unused: 0.369% (pure !)
388 data-unused: 0.369% (pure !)
389 data-unused: 0.000% (no-pure no-rust !)
389 data-unused: 0.000% (no-pure no-rust !)
390
390
391 $ cp -f ../tmp-copies/* .hg/store/
391 $ cp -f ../tmp-copies/* .hg/store/
392 $ hg debugnodemap --metadata
392 $ hg debugnodemap --metadata
393 uid: ???????? (glob)
393 uid: ???????? (glob)
394 tip-rev: 5002
394 tip-rev: 5002
395 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
395 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
396 data-length: 121088
396 data-length: 121088
397 data-unused: 0
397 data-unused: 0
398 data-unused: 0.000%
398 data-unused: 0.000%
399 $ hg log -r "$OTHERNODE" -T '{rev}\n'
399 $ hg log -r "$OTHERNODE" -T '{rev}\n'
400 5002
400 5002
401
401
402 missing data file
402 missing data file
403 -----------------
403 -----------------
404
404
405 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
405 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
406 > sed 's/uid: //'`
406 > sed 's/uid: //'`
407 $ FILE=.hg/store/00changelog-"${UUID}".nd
407 $ FILE=.hg/store/00changelog-"${UUID}".nd
408 $ mv $FILE ../tmp-data-file
408 $ mv $FILE ../tmp-data-file
409 $ cp .hg/store/00changelog.n ../tmp-docket
409 $ cp .hg/store/00changelog.n ../tmp-docket
410
410
411 mercurial don't crash
411 mercurial don't crash
412
412
413 $ hg log -r .
413 $ hg log -r .
414 changeset: 5002:b355ef8adce0
414 changeset: 5002:b355ef8adce0
415 tag: tip
415 tag: tip
416 parent: 4998:d918ad6d18d3
416 parent: 4998:d918ad6d18d3
417 user: test
417 user: test
418 date: Thu Jan 01 00:00:00 1970 +0000
418 date: Thu Jan 01 00:00:00 1970 +0000
419 summary: babar
419 summary: babar
420
420
421 $ hg debugnodemap --metadata
421 $ hg debugnodemap --metadata
422
422
423 $ hg debugupdatecache
423 $ hg debugupdatecache
424 $ hg debugnodemap --metadata
424 $ hg debugnodemap --metadata
425 uid: * (glob)
425 uid: * (glob)
426 tip-rev: 5002
426 tip-rev: 5002
427 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
427 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
428 data-length: 121088
428 data-length: 121088
429 data-unused: 0
429 data-unused: 0
430 data-unused: 0.000%
430 data-unused: 0.000%
431
432 Sub-case: fallback for corrupted data file
433 ------------------------------------------
434
435 Sabotaging the data file so that nodemap resolutions fail, triggering fallback to
436 (non-persistent) C implementation.
437
438
439 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
440 > sed 's/uid: //'`
441 $ FILE=.hg/store/00changelog-"${UUID}".nd
442 $ python -c "fobj = open('$FILE', 'r+b'); fobj.write(b'\xff' * 121088); fobj.close()"
443
444 The nodemap data file is still considered in sync with the docket. This
445 would fail without the fallback to the (non-persistent) C implementation:
446
447 $ hg log -r b355ef8adce0949b8bdf6afc72ca853740d65944 -T '{rev}\n' --traceback
448 5002
449
450 The nodemap data file hasn't been fixed, more tests can be inserted:
451
452 $ hg debugnodemap --dump-disk | f --bytes=256 --hexdump --size
453 size=121088
454 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
455 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
456 0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
457 0030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
458 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
459 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
460 0060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
461 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
462 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
463 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
464 00a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
465 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
466 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
467 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
468 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
469 00f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
470
431 $ mv ../tmp-data-file $FILE
471 $ mv ../tmp-data-file $FILE
432 $ mv ../tmp-docket .hg/store/00changelog.n
472 $ mv ../tmp-docket .hg/store/00changelog.n
433
473
434 Check transaction related property
474 Check transaction related property
435 ==================================
475 ==================================
436
476
437 An up to date nodemap should be available to shell hooks,
477 An up to date nodemap should be available to shell hooks,
438
478
439 $ echo dsljfl > a
479 $ echo dsljfl > a
440 $ hg add a
480 $ hg add a
441 $ hg ci -m a
481 $ hg ci -m a
442 $ hg debugnodemap --metadata
482 $ hg debugnodemap --metadata
443 uid: ???????? (glob)
483 uid: ???????? (glob)
444 tip-rev: 5003
484 tip-rev: 5003
445 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
485 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
446 data-length: 121088
486 data-length: 121088
447 data-unused: 0
487 data-unused: 0
448 data-unused: 0.000%
488 data-unused: 0.000%
449 $ echo babar2 > babar
489 $ echo babar2 > babar
450 $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata"
490 $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata"
451 uid: ???????? (glob)
491 uid: ???????? (glob)
452 tip-rev: 5004
492 tip-rev: 5004
453 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
493 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
454 data-length: 121280 (pure !)
494 data-length: 121280 (pure !)
455 data-length: 121280 (rust !)
495 data-length: 121280 (rust !)
456 data-length: 121088 (no-pure no-rust !)
496 data-length: 121088 (no-pure no-rust !)
457 data-unused: 192 (pure !)
497 data-unused: 192 (pure !)
458 data-unused: 192 (rust !)
498 data-unused: 192 (rust !)
459 data-unused: 0 (no-pure no-rust !)
499 data-unused: 0 (no-pure no-rust !)
460 data-unused: 0.158% (pure !)
500 data-unused: 0.158% (pure !)
461 data-unused: 0.158% (rust !)
501 data-unused: 0.158% (rust !)
462 data-unused: 0.000% (no-pure no-rust !)
502 data-unused: 0.000% (no-pure no-rust !)
463 $ hg debugnodemap --metadata
503 $ hg debugnodemap --metadata
464 uid: ???????? (glob)
504 uid: ???????? (glob)
465 tip-rev: 5004
505 tip-rev: 5004
466 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
506 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
467 data-length: 121280 (pure !)
507 data-length: 121280 (pure !)
468 data-length: 121280 (rust !)
508 data-length: 121280 (rust !)
469 data-length: 121088 (no-pure no-rust !)
509 data-length: 121088 (no-pure no-rust !)
470 data-unused: 192 (pure !)
510 data-unused: 192 (pure !)
471 data-unused: 192 (rust !)
511 data-unused: 192 (rust !)
472 data-unused: 0 (no-pure no-rust !)
512 data-unused: 0 (no-pure no-rust !)
473 data-unused: 0.158% (pure !)
513 data-unused: 0.158% (pure !)
474 data-unused: 0.158% (rust !)
514 data-unused: 0.158% (rust !)
475 data-unused: 0.000% (no-pure no-rust !)
515 data-unused: 0.000% (no-pure no-rust !)
476
516
477 Another process does not see the pending nodemap content during run.
517 Another process does not see the pending nodemap content during run.
478
518
479 $ echo qpoasp > a
519 $ echo qpoasp > a
480 $ hg ci -m a2 \
520 $ hg ci -m a2 \
481 > --config "hooks.pretxnclose=sh \"$RUNTESTDIR/testlib/wait-on-file\" 20 sync-repo-read sync-txn-pending" \
521 > --config "hooks.pretxnclose=sh \"$RUNTESTDIR/testlib/wait-on-file\" 20 sync-repo-read sync-txn-pending" \
482 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
522 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
483
523
484 (read the repository while the commit transaction is pending)
524 (read the repository while the commit transaction is pending)
485
525
486 $ sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-pending && \
526 $ sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-pending && \
487 > hg debugnodemap --metadata && \
527 > hg debugnodemap --metadata && \
488 > sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-close sync-repo-read
528 > sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-close sync-repo-read
489 uid: ???????? (glob)
529 uid: ???????? (glob)
490 tip-rev: 5004
530 tip-rev: 5004
491 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
531 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
492 data-length: 121280 (pure !)
532 data-length: 121280 (pure !)
493 data-length: 121280 (rust !)
533 data-length: 121280 (rust !)
494 data-length: 121088 (no-pure no-rust !)
534 data-length: 121088 (no-pure no-rust !)
495 data-unused: 192 (pure !)
535 data-unused: 192 (pure !)
496 data-unused: 192 (rust !)
536 data-unused: 192 (rust !)
497 data-unused: 0 (no-pure no-rust !)
537 data-unused: 0 (no-pure no-rust !)
498 data-unused: 0.158% (pure !)
538 data-unused: 0.158% (pure !)
499 data-unused: 0.158% (rust !)
539 data-unused: 0.158% (rust !)
500 data-unused: 0.000% (no-pure no-rust !)
540 data-unused: 0.000% (no-pure no-rust !)
501 $ hg debugnodemap --metadata
541 $ hg debugnodemap --metadata
502 uid: ???????? (glob)
542 uid: ???????? (glob)
503 tip-rev: 5005
543 tip-rev: 5005
504 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
544 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
505 data-length: 121536 (pure !)
545 data-length: 121536 (pure !)
506 data-length: 121536 (rust !)
546 data-length: 121536 (rust !)
507 data-length: 121088 (no-pure no-rust !)
547 data-length: 121088 (no-pure no-rust !)
508 data-unused: 448 (pure !)
548 data-unused: 448 (pure !)
509 data-unused: 448 (rust !)
549 data-unused: 448 (rust !)
510 data-unused: 0 (no-pure no-rust !)
550 data-unused: 0 (no-pure no-rust !)
511 data-unused: 0.369% (pure !)
551 data-unused: 0.369% (pure !)
512 data-unused: 0.369% (rust !)
552 data-unused: 0.369% (rust !)
513 data-unused: 0.000% (no-pure no-rust !)
553 data-unused: 0.000% (no-pure no-rust !)
514
554
515 $ cat output.txt
555 $ cat output.txt
516
556
517 Check that a failing transaction will properly revert the data
557 Check that a failing transaction will properly revert the data
518
558
519 $ echo plakfe > a
559 $ echo plakfe > a
520 $ f --size --sha256 .hg/store/00changelog-*.nd
560 $ f --size --sha256 .hg/store/00changelog-*.nd
521 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
561 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
522 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
562 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
523 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
563 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
524 $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py"
564 $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py"
525 transaction abort!
565 transaction abort!
526 rollback completed
566 rollback completed
527 abort: This is a late abort
567 abort: This is a late abort
528 [255]
568 [255]
529 $ hg debugnodemap --metadata
569 $ hg debugnodemap --metadata
530 uid: ???????? (glob)
570 uid: ???????? (glob)
531 tip-rev: 5005
571 tip-rev: 5005
532 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
572 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
533 data-length: 121536 (pure !)
573 data-length: 121536 (pure !)
534 data-length: 121536 (rust !)
574 data-length: 121536 (rust !)
535 data-length: 121088 (no-pure no-rust !)
575 data-length: 121088 (no-pure no-rust !)
536 data-unused: 448 (pure !)
576 data-unused: 448 (pure !)
537 data-unused: 448 (rust !)
577 data-unused: 448 (rust !)
538 data-unused: 0 (no-pure no-rust !)
578 data-unused: 0 (no-pure no-rust !)
539 data-unused: 0.369% (pure !)
579 data-unused: 0.369% (pure !)
540 data-unused: 0.369% (rust !)
580 data-unused: 0.369% (rust !)
541 data-unused: 0.000% (no-pure no-rust !)
581 data-unused: 0.000% (no-pure no-rust !)
542 $ f --size --sha256 .hg/store/00changelog-*.nd
582 $ f --size --sha256 .hg/store/00changelog-*.nd
543 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
583 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
544 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
584 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
545 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
585 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
546
586
547 Check that removing content does not confuse the nodemap
587 Check that removing content does not confuse the nodemap
548 --------------------------------------------------------
588 --------------------------------------------------------
549
589
550 removing data with rollback
590 removing data with rollback
551
591
552 $ echo aso > a
592 $ echo aso > a
553 $ hg ci -m a4
593 $ hg ci -m a4
554 $ hg rollback
594 $ hg rollback
555 repository tip rolled back to revision 5005 (undo commit)
595 repository tip rolled back to revision 5005 (undo commit)
556 working directory now based on revision 5005
596 working directory now based on revision 5005
557 $ hg id -r .
597 $ hg id -r .
558 90d5d3ba2fc4 tip
598 90d5d3ba2fc4 tip
559
599
560 roming data with strip
600 roming data with strip
561
601
562 $ echo aso > a
602 $ echo aso > a
563 $ hg ci -m a4
603 $ hg ci -m a4
564 $ hg --config extensions.strip= strip -r . --no-backup
604 $ hg --config extensions.strip= strip -r . --no-backup
565 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
605 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
566 $ hg id -r . --traceback
606 $ hg id -r . --traceback
567 90d5d3ba2fc4 tip
607 90d5d3ba2fc4 tip
568
608
569 Test upgrade / downgrade
609 Test upgrade / downgrade
570 ========================
610 ========================
571
611
572 downgrading
612 downgrading
573
613
574 $ cat << EOF >> .hg/hgrc
614 $ cat << EOF >> .hg/hgrc
575 > [format]
615 > [format]
576 > use-persistent-nodemap=no
616 > use-persistent-nodemap=no
577 > EOF
617 > EOF
578 $ hg debugformat -v
618 $ hg debugformat -v
579 format-variant repo config default
619 format-variant repo config default
580 fncache: yes yes yes
620 fncache: yes yes yes
581 dirstate-v2: no no no
621 dirstate-v2: no no no
582 dotencode: yes yes yes
622 dotencode: yes yes yes
583 generaldelta: yes yes yes
623 generaldelta: yes yes yes
584 share-safe: no no no
624 share-safe: no no no
585 sparserevlog: yes yes yes
625 sparserevlog: yes yes yes
586 persistent-nodemap: yes no no
626 persistent-nodemap: yes no no
587 copies-sdc: no no no
627 copies-sdc: no no no
588 revlog-v2: no no no
628 revlog-v2: no no no
589 changelog-v2: no no no
629 changelog-v2: no no no
590 plain-cl-delta: yes yes yes
630 plain-cl-delta: yes yes yes
591 compression: zlib zlib zlib (no-zstd !)
631 compression: zlib zlib zlib (no-zstd !)
592 compression: zstd zstd zstd (zstd !)
632 compression: zstd zstd zstd (zstd !)
593 compression-level: default default default
633 compression-level: default default default
594 $ hg debugupgraderepo --run --no-backup
634 $ hg debugupgraderepo --run --no-backup
595 upgrade will perform the following actions:
635 upgrade will perform the following actions:
596
636
597 requirements
637 requirements
598 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !)
638 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !)
599 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !)
639 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !)
600 preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !)
640 preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !)
601 removed: persistent-nodemap
641 removed: persistent-nodemap
602
642
603 processed revlogs:
643 processed revlogs:
604 - all-filelogs
644 - all-filelogs
605 - changelog
645 - changelog
606 - manifest
646 - manifest
607
647
608 beginning upgrade...
648 beginning upgrade...
609 repository locked and read-only
649 repository locked and read-only
610 creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob)
650 creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob)
611 (it is safe to interrupt this process any time before data migration completes)
651 (it is safe to interrupt this process any time before data migration completes)
612 downgrading repository to not use persistent nodemap feature
652 downgrading repository to not use persistent nodemap feature
613 removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob)
653 removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob)
614 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
654 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
615 00changelog-*.nd (glob)
655 00changelog-*.nd (glob)
616 00manifest-*.nd (glob)
656 00manifest-*.nd (glob)
617 undo.backup.00changelog.n
657 undo.backup.00changelog.n
618 undo.backup.00manifest.n
658 undo.backup.00manifest.n
619 $ hg debugnodemap --metadata
659 $ hg debugnodemap --metadata
620
660
621
661
622 upgrading
662 upgrading
623
663
624 $ cat << EOF >> .hg/hgrc
664 $ cat << EOF >> .hg/hgrc
625 > [format]
665 > [format]
626 > use-persistent-nodemap=yes
666 > use-persistent-nodemap=yes
627 > EOF
667 > EOF
628 $ hg debugformat -v
668 $ hg debugformat -v
629 format-variant repo config default
669 format-variant repo config default
630 fncache: yes yes yes
670 fncache: yes yes yes
631 dirstate-v2: no no no
671 dirstate-v2: no no no
632 dotencode: yes yes yes
672 dotencode: yes yes yes
633 generaldelta: yes yes yes
673 generaldelta: yes yes yes
634 share-safe: no no no
674 share-safe: no no no
635 sparserevlog: yes yes yes
675 sparserevlog: yes yes yes
636 persistent-nodemap: no yes no
676 persistent-nodemap: no yes no
637 copies-sdc: no no no
677 copies-sdc: no no no
638 revlog-v2: no no no
678 revlog-v2: no no no
639 changelog-v2: no no no
679 changelog-v2: no no no
640 plain-cl-delta: yes yes yes
680 plain-cl-delta: yes yes yes
641 compression: zlib zlib zlib (no-zstd !)
681 compression: zlib zlib zlib (no-zstd !)
642 compression: zstd zstd zstd (zstd !)
682 compression: zstd zstd zstd (zstd !)
643 compression-level: default default default
683 compression-level: default default default
644 $ hg debugupgraderepo --run --no-backup
684 $ hg debugupgraderepo --run --no-backup
645 upgrade will perform the following actions:
685 upgrade will perform the following actions:
646
686
647 requirements
687 requirements
648 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !)
688 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !)
649 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !)
689 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !)
650 preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !)
690 preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !)
651 added: persistent-nodemap
691 added: persistent-nodemap
652
692
653 persistent-nodemap
693 persistent-nodemap
654 Speedup revision lookup by node id.
694 Speedup revision lookup by node id.
655
695
656 processed revlogs:
696 processed revlogs:
657 - all-filelogs
697 - all-filelogs
658 - changelog
698 - changelog
659 - manifest
699 - manifest
660
700
661 beginning upgrade...
701 beginning upgrade...
662 repository locked and read-only
702 repository locked and read-only
663 creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob)
703 creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob)
664 (it is safe to interrupt this process any time before data migration completes)
704 (it is safe to interrupt this process any time before data migration completes)
665 upgrading repository to use persistent nodemap feature
705 upgrading repository to use persistent nodemap feature
666 removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob)
706 removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob)
667 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
707 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
668 00changelog-*.nd (glob)
708 00changelog-*.nd (glob)
669 00changelog.n
709 00changelog.n
670 00manifest-*.nd (glob)
710 00manifest-*.nd (glob)
671 00manifest.n
711 00manifest.n
672 undo.backup.00changelog.n
712 undo.backup.00changelog.n
673 undo.backup.00manifest.n
713 undo.backup.00manifest.n
674
714
675 $ hg debugnodemap --metadata
715 $ hg debugnodemap --metadata
676 uid: * (glob)
716 uid: * (glob)
677 tip-rev: 5005
717 tip-rev: 5005
678 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
718 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
679 data-length: 121088
719 data-length: 121088
680 data-unused: 0
720 data-unused: 0
681 data-unused: 0.000%
721 data-unused: 0.000%
682
722
683 Running unrelated upgrade
723 Running unrelated upgrade
684
724
685 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
725 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
686 upgrade will perform the following actions:
726 upgrade will perform the following actions:
687
727
688 requirements
728 requirements
689 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !)
729 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !)
690 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !)
730 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !)
691 preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !)
731 preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !)
692
732
693 optimisations: re-delta-all
733 optimisations: re-delta-all
694
734
695 processed revlogs:
735 processed revlogs:
696 - all-filelogs
736 - all-filelogs
697 - changelog
737 - changelog
698 - manifest
738 - manifest
699
739
700 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
740 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
701 00changelog-*.nd (glob)
741 00changelog-*.nd (glob)
702 00changelog.n
742 00changelog.n
703 00manifest-*.nd (glob)
743 00manifest-*.nd (glob)
704 00manifest.n
744 00manifest.n
705
745
706 $ hg debugnodemap --metadata
746 $ hg debugnodemap --metadata
707 uid: * (glob)
747 uid: * (glob)
708 tip-rev: 5005
748 tip-rev: 5005
709 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
749 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
710 data-length: 121088
750 data-length: 121088
711 data-unused: 0
751 data-unused: 0
712 data-unused: 0.000%
752 data-unused: 0.000%
713
753
714 Persistent nodemap and local/streaming clone
754 Persistent nodemap and local/streaming clone
715 ============================================
755 ============================================
716
756
717 $ cd ..
757 $ cd ..
718
758
719 standard clone
759 standard clone
720 --------------
760 --------------
721
761
722 The persistent nodemap should exist after a streaming clone
762 The persistent nodemap should exist after a streaming clone
723
763
724 $ hg clone --pull --quiet -U test-repo standard-clone
764 $ hg clone --pull --quiet -U test-repo standard-clone
725 $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
765 $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
726 00changelog-*.nd (glob)
766 00changelog-*.nd (glob)
727 00changelog.n
767 00changelog.n
728 00manifest-*.nd (glob)
768 00manifest-*.nd (glob)
729 00manifest.n
769 00manifest.n
730 $ hg -R standard-clone debugnodemap --metadata
770 $ hg -R standard-clone debugnodemap --metadata
731 uid: * (glob)
771 uid: * (glob)
732 tip-rev: 5005
772 tip-rev: 5005
733 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
773 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
734 data-length: 121088
774 data-length: 121088
735 data-unused: 0
775 data-unused: 0
736 data-unused: 0.000%
776 data-unused: 0.000%
737
777
738
778
739 local clone
779 local clone
740 ------------
780 ------------
741
781
742 The persistent nodemap should exist after a streaming clone
782 The persistent nodemap should exist after a streaming clone
743
783
744 $ hg clone -U test-repo local-clone
784 $ hg clone -U test-repo local-clone
745 $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
785 $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
746 00changelog-*.nd (glob)
786 00changelog-*.nd (glob)
747 00changelog.n
787 00changelog.n
748 00manifest-*.nd (glob)
788 00manifest-*.nd (glob)
749 00manifest.n
789 00manifest.n
750 $ hg -R local-clone debugnodemap --metadata
790 $ hg -R local-clone debugnodemap --metadata
751 uid: * (glob)
791 uid: * (glob)
752 tip-rev: 5005
792 tip-rev: 5005
753 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
793 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
754 data-length: 121088
794 data-length: 121088
755 data-unused: 0
795 data-unused: 0
756 data-unused: 0.000%
796 data-unused: 0.000%
757
797
758 Test various corruption case
798 Test various corruption case
759 ============================
799 ============================
760
800
761 Missing datafile
801 Missing datafile
762 ----------------
802 ----------------
763
803
764 Test behavior with a missing datafile
804 Test behavior with a missing datafile
765
805
766 $ hg clone --quiet --pull test-repo corruption-test-repo
806 $ hg clone --quiet --pull test-repo corruption-test-repo
767 $ ls -1 corruption-test-repo/.hg/store/00changelog*
807 $ ls -1 corruption-test-repo/.hg/store/00changelog*
768 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
808 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
769 corruption-test-repo/.hg/store/00changelog.d
809 corruption-test-repo/.hg/store/00changelog.d
770 corruption-test-repo/.hg/store/00changelog.i
810 corruption-test-repo/.hg/store/00changelog.i
771 corruption-test-repo/.hg/store/00changelog.n
811 corruption-test-repo/.hg/store/00changelog.n
772 $ rm corruption-test-repo/.hg/store/00changelog*.nd
812 $ rm corruption-test-repo/.hg/store/00changelog*.nd
773 $ hg log -R corruption-test-repo -r .
813 $ hg log -R corruption-test-repo -r .
774 changeset: 5005:90d5d3ba2fc4
814 changeset: 5005:90d5d3ba2fc4
775 tag: tip
815 tag: tip
776 user: test
816 user: test
777 date: Thu Jan 01 00:00:00 1970 +0000
817 date: Thu Jan 01 00:00:00 1970 +0000
778 summary: a2
818 summary: a2
779
819
780 $ ls -1 corruption-test-repo/.hg/store/00changelog*
820 $ ls -1 corruption-test-repo/.hg/store/00changelog*
781 corruption-test-repo/.hg/store/00changelog.d
821 corruption-test-repo/.hg/store/00changelog.d
782 corruption-test-repo/.hg/store/00changelog.i
822 corruption-test-repo/.hg/store/00changelog.i
783 corruption-test-repo/.hg/store/00changelog.n
823 corruption-test-repo/.hg/store/00changelog.n
784
824
785 Truncated data file
825 Truncated data file
786 -------------------
826 -------------------
787
827
788 Test behavior with a too short datafile
828 Test behavior with a too short datafile
789
829
790 rebuild the missing data
830 rebuild the missing data
791 $ hg -R corruption-test-repo debugupdatecache
831 $ hg -R corruption-test-repo debugupdatecache
792 $ ls -1 corruption-test-repo/.hg/store/00changelog*
832 $ ls -1 corruption-test-repo/.hg/store/00changelog*
793 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
833 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
794 corruption-test-repo/.hg/store/00changelog.d
834 corruption-test-repo/.hg/store/00changelog.d
795 corruption-test-repo/.hg/store/00changelog.i
835 corruption-test-repo/.hg/store/00changelog.i
796 corruption-test-repo/.hg/store/00changelog.n
836 corruption-test-repo/.hg/store/00changelog.n
797
837
798 truncate the file
838 truncate the file
799
839
800 $ datafilepath=`ls corruption-test-repo/.hg/store/00changelog*.nd`
840 $ datafilepath=`ls corruption-test-repo/.hg/store/00changelog*.nd`
801 $ f -s $datafilepath
841 $ f -s $datafilepath
802 corruption-test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
842 corruption-test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
803 $ dd if=$datafilepath bs=1000 count=10 of=$datafilepath-tmp status=noxfer
843 $ dd if=$datafilepath bs=1000 count=10 of=$datafilepath-tmp status=noxfer
804 10+0 records in
844 10+0 records in
805 10+0 records out
845 10+0 records out
806 $ mv $datafilepath-tmp $datafilepath
846 $ mv $datafilepath-tmp $datafilepath
807 $ f -s $datafilepath
847 $ f -s $datafilepath
808 corruption-test-repo/.hg/store/00changelog-*.nd: size=10000 (glob)
848 corruption-test-repo/.hg/store/00changelog-*.nd: size=10000 (glob)
809
849
810 Check that Mercurial reaction to this event
850 Check that Mercurial reaction to this event
811
851
812 $ hg -R corruption-test-repo log -r . --traceback
852 $ hg -R corruption-test-repo log -r . --traceback
813 changeset: 5005:90d5d3ba2fc4
853 changeset: 5005:90d5d3ba2fc4
814 tag: tip
854 tag: tip
815 user: test
855 user: test
816 date: Thu Jan 01 00:00:00 1970 +0000
856 date: Thu Jan 01 00:00:00 1970 +0000
817 summary: a2
857 summary: a2
818
858
819
859
820
860
821 stream clone
861 stream clone
822 ============
862 ============
823
863
824 The persistent nodemap should exist after a streaming clone
864 The persistent nodemap should exist after a streaming clone
825
865
826 Simple case
866 Simple case
827 -----------
867 -----------
828
868
829 No race condition
869 No race condition
830
870
831 $ hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)'
871 $ hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)'
832 adding [s] 00manifest.n (62 bytes)
872 adding [s] 00manifest.n (62 bytes)
833 adding [s] 00manifest-*.nd (118 KB) (glob)
873 adding [s] 00manifest-*.nd (118 KB) (glob)
834 adding [s] 00changelog.n (62 bytes)
874 adding [s] 00changelog.n (62 bytes)
835 adding [s] 00changelog-*.nd (118 KB) (glob)
875 adding [s] 00changelog-*.nd (118 KB) (glob)
836 adding [s] 00manifest.d (452 KB) (no-zstd !)
876 adding [s] 00manifest.d (452 KB) (no-zstd !)
837 adding [s] 00manifest.d (491 KB) (zstd !)
877 adding [s] 00manifest.d (491 KB) (zstd !)
838 adding [s] 00changelog.d (360 KB) (no-zstd !)
878 adding [s] 00changelog.d (360 KB) (no-zstd !)
839 adding [s] 00changelog.d (368 KB) (zstd !)
879 adding [s] 00changelog.d (368 KB) (zstd !)
840 adding [s] 00manifest.i (313 KB)
880 adding [s] 00manifest.i (313 KB)
841 adding [s] 00changelog.i (313 KB)
881 adding [s] 00changelog.i (313 KB)
842 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
882 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
843 00changelog-*.nd (glob)
883 00changelog-*.nd (glob)
844 00changelog.n
884 00changelog.n
845 00manifest-*.nd (glob)
885 00manifest-*.nd (glob)
846 00manifest.n
886 00manifest.n
847 $ hg -R stream-clone debugnodemap --metadata
887 $ hg -R stream-clone debugnodemap --metadata
848 uid: * (glob)
888 uid: * (glob)
849 tip-rev: 5005
889 tip-rev: 5005
850 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
890 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
851 data-length: 121088
891 data-length: 121088
852 data-unused: 0
892 data-unused: 0
853 data-unused: 0.000%
893 data-unused: 0.000%
854
894
855 new data appened
895 new data appened
856 -----------------
896 -----------------
857
897
858 Other commit happening on the server during the stream clone
898 Other commit happening on the server during the stream clone
859
899
860 setup the step-by-step stream cloning
900 setup the step-by-step stream cloning
861
901
862 $ HG_TEST_STREAM_WALKED_FILE_1="$TESTTMP/sync_file_walked_1"
902 $ HG_TEST_STREAM_WALKED_FILE_1="$TESTTMP/sync_file_walked_1"
863 $ export HG_TEST_STREAM_WALKED_FILE_1
903 $ export HG_TEST_STREAM_WALKED_FILE_1
864 $ HG_TEST_STREAM_WALKED_FILE_2="$TESTTMP/sync_file_walked_2"
904 $ HG_TEST_STREAM_WALKED_FILE_2="$TESTTMP/sync_file_walked_2"
865 $ export HG_TEST_STREAM_WALKED_FILE_2
905 $ export HG_TEST_STREAM_WALKED_FILE_2
866 $ HG_TEST_STREAM_WALKED_FILE_3="$TESTTMP/sync_file_walked_3"
906 $ HG_TEST_STREAM_WALKED_FILE_3="$TESTTMP/sync_file_walked_3"
867 $ export HG_TEST_STREAM_WALKED_FILE_3
907 $ export HG_TEST_STREAM_WALKED_FILE_3
868 $ cat << EOF >> test-repo/.hg/hgrc
908 $ cat << EOF >> test-repo/.hg/hgrc
869 > [extensions]
909 > [extensions]
870 > steps=$RUNTESTDIR/testlib/ext-stream-clone-steps.py
910 > steps=$RUNTESTDIR/testlib/ext-stream-clone-steps.py
871 > EOF
911 > EOF
872
912
873 Check and record file state beforehand
913 Check and record file state beforehand
874
914
875 $ f --size test-repo/.hg/store/00changelog*
915 $ f --size test-repo/.hg/store/00changelog*
876 test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
916 test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
877 test-repo/.hg/store/00changelog.d: size=376891 (zstd !)
917 test-repo/.hg/store/00changelog.d: size=376891 (zstd !)
878 test-repo/.hg/store/00changelog.d: size=368890 (no-zstd !)
918 test-repo/.hg/store/00changelog.d: size=368890 (no-zstd !)
879 test-repo/.hg/store/00changelog.i: size=320384
919 test-repo/.hg/store/00changelog.i: size=320384
880 test-repo/.hg/store/00changelog.n: size=62
920 test-repo/.hg/store/00changelog.n: size=62
881 $ hg -R test-repo debugnodemap --metadata | tee server-metadata.txt
921 $ hg -R test-repo debugnodemap --metadata | tee server-metadata.txt
882 uid: * (glob)
922 uid: * (glob)
883 tip-rev: 5005
923 tip-rev: 5005
884 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
924 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
885 data-length: 121088
925 data-length: 121088
886 data-unused: 0
926 data-unused: 0
887 data-unused: 0.000%
927 data-unused: 0.000%
888
928
889 Prepare a commit
929 Prepare a commit
890
930
891 $ echo foo >> test-repo/foo
931 $ echo foo >> test-repo/foo
892 $ hg -R test-repo/ add test-repo/foo
932 $ hg -R test-repo/ add test-repo/foo
893
933
894 Do a mix of clone and commit at the same time so that the file listed on disk differ at actual transfer time.
934 Do a mix of clone and commit at the same time so that the file listed on disk differ at actual transfer time.
895
935
896 $ (hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" 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) &
936 $ (hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" 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) &
897 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
937 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
898 $ hg -R test-repo/ commit -m foo
938 $ hg -R test-repo/ commit -m foo
899 $ touch $HG_TEST_STREAM_WALKED_FILE_2
939 $ touch $HG_TEST_STREAM_WALKED_FILE_2
900 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
940 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
901 $ cat clone-output
941 $ cat clone-output
902 adding [s] 00manifest.n (62 bytes)
942 adding [s] 00manifest.n (62 bytes)
903 adding [s] 00manifest-*.nd (118 KB) (glob)
943 adding [s] 00manifest-*.nd (118 KB) (glob)
904 adding [s] 00changelog.n (62 bytes)
944 adding [s] 00changelog.n (62 bytes)
905 adding [s] 00changelog-*.nd (118 KB) (glob)
945 adding [s] 00changelog-*.nd (118 KB) (glob)
906 adding [s] 00manifest.d (452 KB) (no-zstd !)
946 adding [s] 00manifest.d (452 KB) (no-zstd !)
907 adding [s] 00manifest.d (491 KB) (zstd !)
947 adding [s] 00manifest.d (491 KB) (zstd !)
908 adding [s] 00changelog.d (360 KB) (no-zstd !)
948 adding [s] 00changelog.d (360 KB) (no-zstd !)
909 adding [s] 00changelog.d (368 KB) (zstd !)
949 adding [s] 00changelog.d (368 KB) (zstd !)
910 adding [s] 00manifest.i (313 KB)
950 adding [s] 00manifest.i (313 KB)
911 adding [s] 00changelog.i (313 KB)
951 adding [s] 00changelog.i (313 KB)
912
952
913 Check the result state
953 Check the result state
914
954
915 $ f --size stream-clone-race-1/.hg/store/00changelog*
955 $ f --size stream-clone-race-1/.hg/store/00changelog*
916 stream-clone-race-1/.hg/store/00changelog-*.nd: size=121088 (glob)
956 stream-clone-race-1/.hg/store/00changelog-*.nd: size=121088 (glob)
917 stream-clone-race-1/.hg/store/00changelog.d: size=368890 (no-zstd !)
957 stream-clone-race-1/.hg/store/00changelog.d: size=368890 (no-zstd !)
918 stream-clone-race-1/.hg/store/00changelog.d: size=376891 (zstd !)
958 stream-clone-race-1/.hg/store/00changelog.d: size=376891 (zstd !)
919 stream-clone-race-1/.hg/store/00changelog.i: size=320384
959 stream-clone-race-1/.hg/store/00changelog.i: size=320384
920 stream-clone-race-1/.hg/store/00changelog.n: size=62
960 stream-clone-race-1/.hg/store/00changelog.n: size=62
921
961
922 $ hg -R stream-clone-race-1 debugnodemap --metadata | tee client-metadata.txt
962 $ hg -R stream-clone-race-1 debugnodemap --metadata | tee client-metadata.txt
923 uid: * (glob)
963 uid: * (glob)
924 tip-rev: 5005
964 tip-rev: 5005
925 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
965 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
926 data-length: 121088
966 data-length: 121088
927 data-unused: 0
967 data-unused: 0
928 data-unused: 0.000%
968 data-unused: 0.000%
929
969
930 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
970 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
931 (ie: the following diff should be empty)
971 (ie: the following diff should be empty)
932
972
933 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".
973 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".
934
974
935 #if no-rust no-pure
975 #if no-rust no-pure
936 $ diff -u server-metadata.txt client-metadata.txt
976 $ diff -u server-metadata.txt client-metadata.txt
937 --- server-metadata.txt * (glob)
977 --- server-metadata.txt * (glob)
938 +++ client-metadata.txt * (glob)
978 +++ client-metadata.txt * (glob)
939 @@ -1,4 +1,4 @@
979 @@ -1,4 +1,4 @@
940 -uid: * (glob)
980 -uid: * (glob)
941 +uid: * (glob)
981 +uid: * (glob)
942 tip-rev: 5005
982 tip-rev: 5005
943 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
983 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
944 data-length: 121088
984 data-length: 121088
945 [1]
985 [1]
946 #else
986 #else
947 $ diff -u server-metadata.txt client-metadata.txt
987 $ diff -u server-metadata.txt client-metadata.txt
948 #endif
988 #endif
949
989
950
990
951 Clean up after the test.
991 Clean up after the test.
952
992
953 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_1"
993 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_1"
954 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_2"
994 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_2"
955 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_3"
995 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_3"
956
996
957 full regeneration
997 full regeneration
958 -----------------
998 -----------------
959
999
960 A full nodemap is generated
1000 A full nodemap is generated
961
1001
962 (ideally this test would append enough data to make sure the nodemap data file
1002 (ideally this test would append enough data to make sure the nodemap data file
963 get changed, however to make thing simpler we will force the regeneration for
1003 get changed, however to make thing simpler we will force the regeneration for
964 this test.
1004 this test.
965
1005
966 Check the initial state
1006 Check the initial state
967
1007
968 $ f --size test-repo/.hg/store/00changelog*
1008 $ f --size test-repo/.hg/store/00changelog*
969 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1009 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
970 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1010 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
971 test-repo/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1011 test-repo/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
972 test-repo/.hg/store/00changelog.d: size=376950 (zstd !)
1012 test-repo/.hg/store/00changelog.d: size=376950 (zstd !)
973 test-repo/.hg/store/00changelog.d: size=368949 (no-zstd !)
1013 test-repo/.hg/store/00changelog.d: size=368949 (no-zstd !)
974 test-repo/.hg/store/00changelog.i: size=320448
1014 test-repo/.hg/store/00changelog.i: size=320448
975 test-repo/.hg/store/00changelog.n: size=62
1015 test-repo/.hg/store/00changelog.n: size=62
976 $ hg -R test-repo debugnodemap --metadata | tee server-metadata-2.txt
1016 $ hg -R test-repo debugnodemap --metadata | tee server-metadata-2.txt
977 uid: * (glob)
1017 uid: * (glob)
978 tip-rev: 5006
1018 tip-rev: 5006
979 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1019 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
980 data-length: 121344 (rust !)
1020 data-length: 121344 (rust !)
981 data-length: 121344 (pure !)
1021 data-length: 121344 (pure !)
982 data-length: 121152 (no-rust no-pure !)
1022 data-length: 121152 (no-rust no-pure !)
983 data-unused: 192 (rust !)
1023 data-unused: 192 (rust !)
984 data-unused: 192 (pure !)
1024 data-unused: 192 (pure !)
985 data-unused: 0 (no-rust no-pure !)
1025 data-unused: 0 (no-rust no-pure !)
986 data-unused: 0.158% (rust !)
1026 data-unused: 0.158% (rust !)
987 data-unused: 0.158% (pure !)
1027 data-unused: 0.158% (pure !)
988 data-unused: 0.000% (no-rust no-pure !)
1028 data-unused: 0.000% (no-rust no-pure !)
989
1029
990 Performe the mix of clone and full refresh of the nodemap, so that the files
1030 Performe the mix of clone and full refresh of the nodemap, so that the files
991 (and filenames) are different between listing time and actual transfer time.
1031 (and filenames) are different between listing time and actual transfer time.
992
1032
993 $ (hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" 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) &
1033 $ (hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" 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) &
994 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
1034 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
995 $ rm test-repo/.hg/store/00changelog.n
1035 $ rm test-repo/.hg/store/00changelog.n
996 $ rm test-repo/.hg/store/00changelog-*.nd
1036 $ rm test-repo/.hg/store/00changelog-*.nd
997 $ hg -R test-repo/ debugupdatecache
1037 $ hg -R test-repo/ debugupdatecache
998 $ touch $HG_TEST_STREAM_WALKED_FILE_2
1038 $ touch $HG_TEST_STREAM_WALKED_FILE_2
999 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
1039 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
1000
1040
1001 (note: the stream clone code wronly pick the `undo.` files)
1041 (note: the stream clone code wronly pick the `undo.` files)
1002
1042
1003 $ cat clone-output-2
1043 $ cat clone-output-2
1004 adding [s] undo.backup.00manifest.n (62 bytes) (known-bad-output !)
1044 adding [s] undo.backup.00manifest.n (62 bytes) (known-bad-output !)
1005 adding [s] undo.backup.00changelog.n (62 bytes) (known-bad-output !)
1045 adding [s] undo.backup.00changelog.n (62 bytes) (known-bad-output !)
1006 adding [s] 00manifest.n (62 bytes)
1046 adding [s] 00manifest.n (62 bytes)
1007 adding [s] 00manifest-*.nd (118 KB) (glob)
1047 adding [s] 00manifest-*.nd (118 KB) (glob)
1008 adding [s] 00changelog.n (62 bytes)
1048 adding [s] 00changelog.n (62 bytes)
1009 adding [s] 00changelog-*.nd (118 KB) (glob)
1049 adding [s] 00changelog-*.nd (118 KB) (glob)
1010 adding [s] 00manifest.d (492 KB) (zstd !)
1050 adding [s] 00manifest.d (492 KB) (zstd !)
1011 adding [s] 00manifest.d (452 KB) (no-zstd !)
1051 adding [s] 00manifest.d (452 KB) (no-zstd !)
1012 adding [s] 00changelog.d (360 KB) (no-zstd !)
1052 adding [s] 00changelog.d (360 KB) (no-zstd !)
1013 adding [s] 00changelog.d (368 KB) (zstd !)
1053 adding [s] 00changelog.d (368 KB) (zstd !)
1014 adding [s] 00manifest.i (313 KB)
1054 adding [s] 00manifest.i (313 KB)
1015 adding [s] 00changelog.i (313 KB)
1055 adding [s] 00changelog.i (313 KB)
1016
1056
1017 Check the result.
1057 Check the result.
1018
1058
1019 $ f --size stream-clone-race-2/.hg/store/00changelog*
1059 $ f --size stream-clone-race-2/.hg/store/00changelog*
1020 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1060 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1021 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1061 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1022 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1062 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1023 stream-clone-race-2/.hg/store/00changelog.d: size=376950 (zstd !)
1063 stream-clone-race-2/.hg/store/00changelog.d: size=376950 (zstd !)
1024 stream-clone-race-2/.hg/store/00changelog.d: size=368949 (no-zstd !)
1064 stream-clone-race-2/.hg/store/00changelog.d: size=368949 (no-zstd !)
1025 stream-clone-race-2/.hg/store/00changelog.i: size=320448
1065 stream-clone-race-2/.hg/store/00changelog.i: size=320448
1026 stream-clone-race-2/.hg/store/00changelog.n: size=62
1066 stream-clone-race-2/.hg/store/00changelog.n: size=62
1027
1067
1028 $ hg -R stream-clone-race-2 debugnodemap --metadata | tee client-metadata-2.txt
1068 $ hg -R stream-clone-race-2 debugnodemap --metadata | tee client-metadata-2.txt
1029 uid: * (glob)
1069 uid: * (glob)
1030 tip-rev: 5006
1070 tip-rev: 5006
1031 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1071 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1032 data-length: 121344 (rust !)
1072 data-length: 121344 (rust !)
1033 data-unused: 192 (rust !)
1073 data-unused: 192 (rust !)
1034 data-unused: 0.158% (rust !)
1074 data-unused: 0.158% (rust !)
1035 data-length: 121152 (no-rust no-pure !)
1075 data-length: 121152 (no-rust no-pure !)
1036 data-unused: 0 (no-rust no-pure !)
1076 data-unused: 0 (no-rust no-pure !)
1037 data-unused: 0.000% (no-rust no-pure !)
1077 data-unused: 0.000% (no-rust no-pure !)
1038 data-length: 121344 (pure !)
1078 data-length: 121344 (pure !)
1039 data-unused: 192 (pure !)
1079 data-unused: 192 (pure !)
1040 data-unused: 0.158% (pure !)
1080 data-unused: 0.158% (pure !)
1041
1081
1042 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1082 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1043 (ie: the following diff should be empty)
1083 (ie: the following diff should be empty)
1044
1084
1045 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".
1085 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".
1046
1086
1047 #if no-rust no-pure
1087 #if no-rust no-pure
1048 $ diff -u server-metadata-2.txt client-metadata-2.txt
1088 $ diff -u server-metadata-2.txt client-metadata-2.txt
1049 --- server-metadata-2.txt * (glob)
1089 --- server-metadata-2.txt * (glob)
1050 +++ client-metadata-2.txt * (glob)
1090 +++ client-metadata-2.txt * (glob)
1051 @@ -1,4 +1,4 @@
1091 @@ -1,4 +1,4 @@
1052 -uid: * (glob)
1092 -uid: * (glob)
1053 +uid: * (glob)
1093 +uid: * (glob)
1054 tip-rev: 5006
1094 tip-rev: 5006
1055 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1095 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1056 data-length: 121152
1096 data-length: 121152
1057 [1]
1097 [1]
1058 #else
1098 #else
1059 $ diff -u server-metadata-2.txt client-metadata-2.txt
1099 $ diff -u server-metadata-2.txt client-metadata-2.txt
1060 #endif
1100 #endif
1061
1101
1062 Clean up after the test
1102 Clean up after the test
1063
1103
1064 $ rm -f $HG_TEST_STREAM_WALKED_FILE_1
1104 $ rm -f $HG_TEST_STREAM_WALKED_FILE_1
1065 $ rm -f $HG_TEST_STREAM_WALKED_FILE_2
1105 $ rm -f $HG_TEST_STREAM_WALKED_FILE_2
1066 $ rm -f $HG_TEST_STREAM_WALKED_FILE_3
1106 $ rm -f $HG_TEST_STREAM_WALKED_FILE_3
1067
1107
General Comments 0
You need to be logged in to leave comments. Login now