9 use pyo3::buffer::PyBuffer; |
9 use pyo3::buffer::PyBuffer; |
10 use pyo3::prelude::*; |
10 use pyo3::prelude::*; |
11 use pyo3::types::{PyBytes, PyBytesMethods, PyList}; |
11 use pyo3::types::{PyBytes, PyBytesMethods, PyList}; |
12 use pyo3_sharedref::PyShareable; |
12 use pyo3_sharedref::PyShareable; |
13 |
13 |
14 use std::sync::{atomic::AtomicUsize, RwLock, RwLockReadGuard}; |
14 use std::sync::{ |
|
15 atomic::{AtomicUsize, Ordering}, |
|
16 RwLock, RwLockReadGuard, |
|
17 }; |
15 |
18 |
16 use hg::{ |
19 use hg::{ |
17 revlog::{ |
20 revlog::{ |
18 index::Index, inner_revlog::InnerRevlog as CoreInnerRevlog, |
21 index::Index, |
19 nodemap::NodeTree as CoreNodeTree, options::RevlogOpenOptions, |
22 inner_revlog::InnerRevlog as CoreInnerRevlog, |
|
23 nodemap::{NodeMap, NodeTree as CoreNodeTree}, |
|
24 options::RevlogOpenOptions, |
20 RevlogIndex, RevlogType, |
25 RevlogIndex, RevlogType, |
21 }, |
26 }, |
22 utils::files::get_path_from_bytes, |
27 utils::files::get_path_from_bytes, |
23 vfs::FnCacheVfs, |
28 vfs::FnCacheVfs, |
24 BaseRevision, Revision, |
29 BaseRevision, Revision, |
25 }; |
30 }; |
26 |
31 |
27 use crate::{ |
32 use crate::{ |
28 exceptions::{ |
33 exceptions::{ |
29 map_lock_error, map_try_lock_error, nodemap_error, |
34 map_lock_error, map_try_lock_error, nodemap_error, revlog_error_bare, |
30 revlog_error_from_msg, |
35 revlog_error_from_msg, |
31 }, |
36 }, |
|
37 node::{node_from_py_bytes, node_prefix_from_py_bytes, py_node_for_rev}, |
|
38 revision::PyRevision, |
32 store::PyFnCache, |
39 store::PyFnCache, |
33 util::{new_submodule, take_buffer_with_slice}, |
40 util::{new_submodule, take_buffer_with_slice}, |
34 }; |
41 }; |
35 |
42 |
36 mod config; |
43 mod config; |
127 revision_cache: None, |
134 revision_cache: None, |
128 use_persistent_nodemap, |
135 use_persistent_nodemap, |
129 nodemap_queries: AtomicUsize::new(0), |
136 nodemap_queries: AtomicUsize::new(0), |
130 }) |
137 }) |
131 } |
138 } |
|
139 |
|
140 // |
|
141 // -- forwarded index methods -- |
|
142 // |
|
143 |
|
144 fn _index_get_rev( |
|
145 slf: &Bound<'_, Self>, |
|
146 node: &Bound<'_, PyBytes>, |
|
147 ) -> PyResult<Option<PyRevision>> { |
|
148 let node = node_from_py_bytes(node)?; |
|
149 |
|
150 // Do not rewrite this with `Self::with_index_nt_read`: it makes |
|
151 // inconditionally a volatile nodetree, and that is not the intent |
|
152 // here: the code below specifically avoids that. |
|
153 Self::with_core_read(slf, |self_ref, irl| { |
|
154 let idx = &irl.index; |
|
155 |
|
156 let prev_queries = |
|
157 self_ref.nodemap_queries.fetch_add(1, Ordering::Relaxed); |
|
158 // Filelogs have no persistent nodemaps and are often small, |
|
159 // use a brute force lookup from the end |
|
160 // backwards. If there is a very large filelog |
|
161 // (automation file that changes every |
|
162 // commit etc.), it also seems to work quite well for |
|
163 // all measured purposes so far. |
|
164 if !self_ref.use_persistent_nodemap && prev_queries <= 3 { |
|
165 return Ok(idx |
|
166 .rev_from_node_no_persistent_nodemap(node.into()) |
|
167 .ok() |
|
168 .map(Into::into)); |
|
169 } |
|
170 |
|
171 let opt = |
|
172 self_ref.get_nodetree(idx)?.read().map_err(map_lock_error)?; |
|
173 let nt = opt.as_ref().expect("nodetree should be set"); |
|
174 |
|
175 let rust_rev = |
|
176 nt.find_bin(idx, node.into()).map_err(nodemap_error)?; |
|
177 Ok(rust_rev.map(Into::into)) |
|
178 }) |
|
179 } |
|
180 |
|
181 /// same as `_index_get_rev()` but raises a bare `error.RevlogError` if |
|
182 /// node is not found. |
|
183 /// |
|
184 /// No need to repeat `node` in the exception, `mercurial/revlog.py` |
|
185 /// will catch and rewrap with it |
|
186 fn _index_rev( |
|
187 slf: &Bound<'_, Self>, |
|
188 node: &Bound<'_, PyBytes>, |
|
189 ) -> PyResult<PyRevision> { |
|
190 Self::_index_get_rev(slf, node)?.ok_or_else(revlog_error_bare) |
|
191 } |
|
192 |
|
193 /// return True if the node exist in the index |
|
194 fn _index_has_node( |
|
195 slf: &Bound<'_, Self>, |
|
196 node: &Bound<'_, PyBytes>, |
|
197 ) -> PyResult<bool> { |
|
198 Self::_index_get_rev(slf, node).map(|opt| opt.is_some()) |
|
199 } |
|
200 |
|
201 /// find length of shortest hex nodeid of a binary ID |
|
202 fn _index_shortest( |
|
203 slf: &Bound<'_, Self>, |
|
204 node: &Bound<'_, PyBytes>, |
|
205 ) -> PyResult<usize> { |
|
206 Self::with_index_nt_read(slf, |idx, nt| { |
|
207 match nt.unique_prefix_len_node(idx, &node_from_py_bytes(node)?) { |
|
208 Ok(Some(l)) => Ok(l), |
|
209 Ok(None) => Err(revlog_error_bare()), |
|
210 Err(e) => Err(nodemap_error(e)), |
|
211 } |
|
212 }) |
|
213 } |
|
214 |
|
215 fn _index_partialmatch<'py>( |
|
216 slf: &Bound<'py, Self>, |
|
217 node: &Bound<'py, PyBytes>, |
|
218 ) -> PyResult<Option<Bound<'py, PyBytes>>> { |
|
219 Self::with_index_nt_read(slf, |idx, nt| { |
|
220 Ok(nt |
|
221 .find_bin(idx, node_prefix_from_py_bytes(node)?) |
|
222 .map_err(nodemap_error)? |
|
223 .map(|rev| py_node_for_rev(slf.py(), idx, rev))) |
|
224 }) |
|
225 } |
132 } |
226 } |
133 |
227 |
134 impl InnerRevlog { |
228 impl InnerRevlog { |
135 /// Take the lock on `slf.irl` for reading and call a closure. |
229 /// Take the lock on `slf.irl` for reading and call a closure. |
136 /// |
230 /// |
169 |
263 |
170 /// Lock `slf` for reading and execute a closure on its [`Index`] and |
264 /// Lock `slf` for reading and execute a closure on its [`Index`] and |
171 /// [`NodeTree`] |
265 /// [`NodeTree`] |
172 /// |
266 /// |
173 /// The [`NodeTree`] is initialized an filled before hand if needed. |
267 /// The [`NodeTree`] is initialized an filled before hand if needed. |
174 #[allow(dead_code)] |
|
175 fn with_index_nt_read<T>( |
268 fn with_index_nt_read<T>( |
176 slf: &Bound<'_, Self>, |
269 slf: &Bound<'_, Self>, |
177 f: impl FnOnce(&Index, &CoreNodeTree) -> PyResult<T>, |
270 f: impl FnOnce(&Index, &CoreNodeTree) -> PyResult<T>, |
178 ) -> PyResult<T> { |
271 ) -> PyResult<T> { |
179 Self::with_core_read(slf, |self_ref, guard| { |
272 Self::with_core_read(slf, |self_ref, guard| { |