rust/hg-pyo3/src/revlog/mod.rs
changeset 52786 4e34e8fd46d4
parent 52784 5e3e8876fd9e
child 52787 e5f89bd1a5ee
equal deleted inserted replaced
52785:71ebe880f24a 52786:4e34e8fd46d4
     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| {
   212     /// will need to take the lock and unwrap with `expect()`.
   305     /// will need to take the lock and unwrap with `expect()`.
   213     ///
   306     ///
   214     /// # Python exceptions
   307     /// # Python exceptions
   215     /// The case mentioned in [`Self::fill_nodemap()`] cannot happen, as the
   308     /// The case mentioned in [`Self::fill_nodemap()`] cannot happen, as the
   216     /// NodeTree is empty when it is called.
   309     /// NodeTree is empty when it is called.
   217     #[allow(dead_code)]
       
   218     fn get_nodetree(
   310     fn get_nodetree(
   219         &self,
   311         &self,
   220         idx: &Index,
   312         idx: &Index,
   221     ) -> PyResult<&RwLock<Option<CoreNodeTree>>> {
   313     ) -> PyResult<&RwLock<Option<CoreNodeTree>>> {
   222         if self.nt.read().map_err(map_lock_error)?.is_none() {
   314         if self.nt.read().map_err(map_lock_error)?.is_none() {