##// END OF EJS Templates
rust-index: add support for `find_snapshots`
Raphaël Gomès -
r52105:9b06e7f3 default
parent child Browse files
Show More
@@ -1,3 +1,4 b''
1 use std::collections::HashSet;
1 use std::fmt::Debug;
2 use std::fmt::Debug;
2 use std::ops::Deref;
3 use std::ops::Deref;
3 use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
4 use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
@@ -10,7 +11,10 b' use crate::errors::HgError;'
10 use crate::node::{NODE_BYTES_LENGTH, NULL_NODE, STORED_NODE_ID_BYTES};
11 use crate::node::{NODE_BYTES_LENGTH, NULL_NODE, STORED_NODE_ID_BYTES};
11 use crate::revlog::node::Node;
12 use crate::revlog::node::Node;
12 use crate::revlog::{Revision, NULL_REVISION};
13 use crate::revlog::{Revision, NULL_REVISION};
13 use crate::{Graph, GraphError, RevlogError, RevlogIndex, UncheckedRevision};
14 use crate::{
15 BaseRevision, FastHashMap, Graph, GraphError, RevlogError, RevlogIndex,
16 UncheckedRevision,
17 };
14
18
15 pub const INDEX_ENTRY_SIZE: usize = 64;
19 pub const INDEX_ENTRY_SIZE: usize = 64;
16 pub const COMPRESSION_MODE_INLINE: u8 = 2;
20 pub const COMPRESSION_MODE_INLINE: u8 = 2;
@@ -283,6 +287,35 b' impl Graph for Index {'
283 }
287 }
284 }
288 }
285
289
290 /// A cache suitable for find_snapshots
291 ///
292 /// Logically equivalent to a mapping whose keys are [`BaseRevision`] and
293 /// values sets of [`BaseRevision`]
294 ///
295 /// TODO the dubious part is insisting that errors must be RevlogError
296 /// we would probably need to sprinkle some magic here, such as an associated
297 /// type that would be Into<RevlogError> but even that would not be
298 /// satisfactory, as errors potentially have nothing to do with the revlog.
299 pub trait SnapshotsCache {
300 fn insert_for(
301 &mut self,
302 rev: BaseRevision,
303 value: BaseRevision,
304 ) -> Result<(), RevlogError>;
305 }
306
307 impl SnapshotsCache for FastHashMap<BaseRevision, HashSet<BaseRevision>> {
308 fn insert_for(
309 &mut self,
310 rev: BaseRevision,
311 value: BaseRevision,
312 ) -> Result<(), RevlogError> {
313 let all_values = self.entry(rev).or_insert_with(HashSet::new);
314 all_values.insert(value);
315 Ok(())
316 }
317 }
318
286 impl Index {
319 impl Index {
287 /// Create an index from bytes.
320 /// Create an index from bytes.
288 /// Calculate the start of each entry when is_inline is true.
321 /// Calculate the start of each entry when is_inline is true.
@@ -479,6 +512,38 b' impl Index {'
479 }
512 }
480 }
513 }
481
514
515 pub fn find_snapshots(
516 &self,
517 start_rev: UncheckedRevision,
518 end_rev: UncheckedRevision,
519 cache: &mut impl SnapshotsCache,
520 ) -> Result<(), RevlogError> {
521 let mut start_rev = start_rev.0;
522 let mut end_rev = end_rev.0;
523 end_rev += 1;
524 let len = self.len().try_into().unwrap();
525 if end_rev > len {
526 end_rev = len;
527 }
528 if start_rev < 0 {
529 start_rev = 0;
530 }
531 for rev in start_rev..end_rev {
532 if !self.is_snapshot_unchecked(Revision(rev))? {
533 continue;
534 }
535 let mut base = self
536 .get_entry(Revision(rev))
537 .unwrap()
538 .base_revision_or_base_of_delta_chain();
539 if base.0 == rev {
540 base = NULL_REVISION.into();
541 }
542 cache.insert_for(base.0, rev)?;
543 }
544 Ok(())
545 }
546
482 /// TODO move this to the trait probably, along with other things
547 /// TODO move this to the trait probably, along with other things
483 pub fn append(
548 pub fn append(
484 &mut self,
549 &mut self,
@@ -14,12 +14,14 b' use cpython::{'
14 buffer::{Element, PyBuffer},
14 buffer::{Element, PyBuffer},
15 exc::{IndexError, ValueError},
15 exc::{IndexError, ValueError},
16 ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyInt, PyModule,
16 ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyInt, PyModule,
17 PyObject, PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
17 PyObject, PyResult, PySet, PyString, PyTuple, Python, PythonObject,
18 ToPyObject,
18 };
19 };
19 use hg::{
20 use hg::{
20 index::{IndexHeader, RevisionDataParams},
21 errors::HgError,
22 index::{IndexHeader, RevisionDataParams, SnapshotsCache},
21 nodemap::{Block, NodeMapError, NodeTree},
23 nodemap::{Block, NodeMapError, NodeTree},
22 revlog::{nodemap::NodeMap, NodePrefix, RevlogIndex},
24 revlog::{nodemap::NodeMap, NodePrefix, RevlogError, RevlogIndex},
23 BaseRevision, Revision, UncheckedRevision, NULL_REVISION,
25 BaseRevision, Revision, UncheckedRevision, NULL_REVISION,
24 };
26 };
25 use std::cell::RefCell;
27 use std::cell::RefCell;
@@ -271,7 +273,39 b' py_class!(pub class MixedIndex |py| {'
271
273
272 /// Gather snapshot data in a cache dict
274 /// Gather snapshot data in a cache dict
273 def findsnapshots(&self, *args, **kw) -> PyResult<PyObject> {
275 def findsnapshots(&self, *args, **kw) -> PyResult<PyObject> {
274 self.call_cindex(py, "findsnapshots", args, kw)
276 let index = self.index(py).borrow();
277 let cache: PyDict = args.get_item(py, 0).extract(py)?;
278 // this methods operates by setting new values in the cache,
279 // hence we will compare results by letting the C implementation
280 // operate over a deepcopy of the cache, and finally compare both
281 // caches.
282 let c_cache = PyDict::new(py);
283 for (k, v) in cache.items(py) {
284 c_cache.set_item(py, k, PySet::new(py, v)?)?;
285 }
286
287 let start_rev = UncheckedRevision(args.get_item(py, 1).extract(py)?);
288 let end_rev = UncheckedRevision(args.get_item(py, 2).extract(py)?);
289 let mut cache_wrapper = PySnapshotsCache{ py, dict: cache };
290 index.find_snapshots(
291 start_rev,
292 end_rev,
293 &mut cache_wrapper,
294 ).map_err(|_| revlog_error(py))?;
295
296 let c_args = PyTuple::new(
297 py,
298 &[
299 c_cache.clone_ref(py).into_object(),
300 args.get_item(py, 1),
301 args.get_item(py, 2)
302 ]
303 );
304 self.call_cindex(py, "findsnapshots", &c_args, kw)?;
305 assert_py_eq(py, "findsnapshots cache",
306 &cache_wrapper.into_object(),
307 &c_cache.into_object())?;
308 Ok(py.None())
275 }
309 }
276
310
277 /// determine revisions with deltas to reconstruct fulltext
311 /// determine revisions with deltas to reconstruct fulltext
@@ -487,6 +521,39 b' fn revision_data_params_to_py_tuple('
487 )
521 )
488 }
522 }
489
523
524 struct PySnapshotsCache<'p> {
525 py: Python<'p>,
526 dict: PyDict,
527 }
528
529 impl<'p> PySnapshotsCache<'p> {
530 fn into_object(self) -> PyObject {
531 self.dict.into_object()
532 }
533 }
534
535 impl<'p> SnapshotsCache for PySnapshotsCache<'p> {
536 fn insert_for(
537 &mut self,
538 rev: BaseRevision,
539 value: BaseRevision,
540 ) -> Result<(), RevlogError> {
541 let pyvalue = value.into_py_object(self.py).into_object();
542 match self.dict.get_item(self.py, rev) {
543 Some(obj) => obj
544 .extract::<PySet>(self.py)
545 .and_then(|set| set.add(self.py, pyvalue)),
546 None => PySet::new(self.py, vec![pyvalue])
547 .and_then(|set| self.dict.set_item(self.py, rev, set)),
548 }
549 .map_err(|_| {
550 RevlogError::Other(HgError::unsupported(
551 "Error in Python caches handling",
552 ))
553 })
554 }
555 }
556
490 impl MixedIndex {
557 impl MixedIndex {
491 fn new(
558 fn new(
492 py: Python,
559 py: Python,
General Comments 0
You need to be logged in to leave comments. Login now