diff -r 3ea5bd40b8dc -r 42b219a1404a rust/hg-pyo3/src/revlog/mod.rs --- a/rust/hg-pyo3/src/revlog/mod.rs Wed Dec 25 12:43:45 2024 +0100 +++ b/rust/hg-pyo3/src/revlog/mod.rs Wed Dec 25 13:29:56 2024 +0100 @@ -6,16 +6,132 @@ // // This software may be used and distributed according to the terms of the // GNU General Public License version 2 or any later version. +use pyo3::buffer::PyBuffer; use pyo3::prelude::*; +use pyo3::types::{PyBytes, PyBytesMethods, PyList}; +use pyo3_sharedref::PyShareable; + +use std::sync::{atomic::AtomicUsize, RwLock}; -use crate::util::new_submodule; +use hg::{ + revlog::{ + index::Index, inner_revlog::InnerRevlog as CoreInnerRevlog, + nodemap::NodeTree as CoreNodeTree, options::RevlogOpenOptions, + RevlogType, + }, + utils::files::get_path_from_bytes, + vfs::FnCacheVfs, +}; + +use crate::{ + exceptions::revlog_error_from_msg, + store::PyFnCache, + util::{new_submodule, take_buffer_with_slice}, +}; mod config; +use config::*; + +#[pyclass] +#[allow(dead_code)] +struct InnerRevlog { + irl: PyShareable, + nt: RwLock>, + docket: Option, + // Holds a reference to the mmap'ed persistent nodemap data + nodemap_mmap: Option>, + // Holds a reference to the mmap'ed persistent index data + index_mmap: Option>, + revision_cache: Option, + head_revs_py_list: Option>, + head_node_ids_py_list: Option>, + use_persistent_nodemap: bool, + nodemap_queries: AtomicUsize, +} + +#[pymethods] +impl InnerRevlog { + #[new] + // The Python side has authority on this signature. + #[allow(clippy::too_many_arguments)] + fn new( + vfs_base: &Bound<'_, PyBytes>, + fncache: &Bound<'_, PyAny>, + vfs_is_readonly: bool, + index_data: &Bound<'_, PyAny>, + index_file: &Bound<'_, PyBytes>, + data_file: &Bound<'_, PyBytes>, + sidedata_file: &Bound<'_, PyAny>, + inline: bool, + data_config: &Bound<'_, PyAny>, + delta_config: &Bound<'_, PyAny>, + feature_config: &Bound<'_, PyAny>, + chunk_cache: &Bound<'_, PyAny>, + default_compression_header: &Bound<'_, PyAny>, + revlog_type: usize, + use_persistent_nodemap: bool, + ) -> PyResult { + // Let clippy accept the unused arguments. This is a bit better than + // a blank `allow` directive + let _ = sidedata_file; + let _ = chunk_cache; + let _ = default_compression_header; + + let index_file = get_path_from_bytes(index_file.as_bytes()).to_owned(); + let data_file = get_path_from_bytes(data_file.as_bytes()).to_owned(); + let revlog_type = RevlogType::try_from(revlog_type) + .map_err(revlog_error_from_msg)?; + let data_config = extract_data_config(data_config, revlog_type)?; + let delta_config = extract_delta_config(delta_config, revlog_type)?; + let feature_config = + extract_feature_config(feature_config, revlog_type)?; + let options = RevlogOpenOptions::new( + inline, + data_config, + delta_config, + feature_config, + ); + + // Safety: we keep the buffer around inside the returned instance as + // `index_mmap` + let (buf, bytes) = unsafe { take_buffer_with_slice(index_data)? }; + let index = Index::new(bytes, options.index_header()) + .map_err(revlog_error_from_msg)?; + + let base = get_path_from_bytes(vfs_base.as_bytes()).to_owned(); + let core = CoreInnerRevlog::new( + Box::new(FnCacheVfs::new( + base, + vfs_is_readonly, + Box::new(PyFnCache::new(fncache.clone().unbind())), + )), + index, + index_file, + data_file, + data_config, + delta_config, + feature_config, + ); + Ok(Self { + irl: core.into(), + nt: None.into(), + docket: None, + nodemap_mmap: None, + index_mmap: buf.into(), + head_revs_py_list: None, + head_node_ids_py_list: None, + revision_cache: None, + use_persistent_nodemap, + nodemap_queries: AtomicUsize::new(0), + }) + } +} pub fn init_module<'py>( py: Python<'py>, package: &str, ) -> PyResult> { let m = new_submodule(py, package, "revlog")?; + m.add_class::()?; Ok(m) }