comparison rust/hg-cpython/src/revlog.rs @ 44510:15febf99a9c6

rust-nodemap: add binding to `nodemap_update_data` Differential Revision: https://phab.mercurial-scm.org/D8160
author Georges Racinet <georges.racinet@octobus.net>
date Wed, 12 Feb 2020 10:53:19 +0100
parents 5bbf887275b0
children cadcc8c20860
comparison
equal deleted inserted replaced
44509:5bbf887275b0 44510:15febf99a9c6
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 exc::{IndexError, ValueError}, 14 exc::{IndexError, ValueError},
14 ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyModule, PyObject, 15 ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyModule, PyObject,
15 PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject, 16 PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
16 }; 17 };
17 use hg::{ 18 use hg::{
34 35
35 py_class!(pub class MixedIndex |py| { 36 py_class!(pub class MixedIndex |py| {
36 data cindex: RefCell<cindex::Index>; 37 data cindex: RefCell<cindex::Index>;
37 data nt: RefCell<Option<NodeTree>>; 38 data nt: RefCell<Option<NodeTree>>;
38 data docket: RefCell<Option<PyObject>>; 39 data docket: RefCell<Option<PyObject>>;
40 // Holds a reference to the mmap'ed persistent nodemap data
41 data mmap: RefCell<Option<PyBuffer>>;
39 42
40 def __new__(_cls, cindex: PyObject) -> PyResult<MixedIndex> { 43 def __new__(_cls, cindex: PyObject) -> PyResult<MixedIndex> {
41 Self::new(py, cindex) 44 Self::new(py, cindex)
42 } 45 }
43 46
266 } 269 }
267 270
268 def nodemap_data_incremental(&self) -> PyResult<PyObject> { 271 def nodemap_data_incremental(&self) -> PyResult<PyObject> {
269 self.inner_nodemap_data_incremental(py) 272 self.inner_nodemap_data_incremental(py)
270 } 273 }
274 def update_nodemap_data(
275 &self,
276 docket: PyObject,
277 nm_data: PyObject
278 ) -> PyResult<PyObject> {
279 self.inner_update_nodemap_data(py, docket, nm_data)
280 }
281
271 282
272 }); 283 });
273 284
274 impl MixedIndex { 285 impl MixedIndex {
275 fn new(py: Python, cindex: PyObject) -> PyResult<MixedIndex> { 286 fn new(py: Python, cindex: PyObject) -> PyResult<MixedIndex> {
276 Self::create_instance( 287 Self::create_instance(
277 py, 288 py,
278 RefCell::new(cindex::Index::new(py, cindex)?), 289 RefCell::new(cindex::Index::new(py, cindex)?),
290 RefCell::new(None),
279 RefCell::new(None), 291 RefCell::new(None),
280 RefCell::new(None), 292 RefCell::new(None),
281 ) 293 )
282 } 294 }
283 295
372 384
373 Ok((docket, changed, PyBytes::new(py, &data)) 385 Ok((docket, changed, PyBytes::new(py, &data))
374 .to_py_object(py) 386 .to_py_object(py)
375 .into_object()) 387 .into_object())
376 } 388 }
389
390 /// Update the nodemap from the new (mmaped) data.
391 /// The docket is kept as a reference for later incremental calls.
392 fn inner_update_nodemap_data(
393 &self,
394 py: Python,
395 docket: PyObject,
396 nm_data: PyObject,
397 ) -> PyResult<PyObject> {
398 let buf = PyBuffer::get(py, &nm_data)?;
399 let len = buf.item_count();
400
401 // Build a slice from the mmap'ed buffer data
402 let cbuf = buf.buf_ptr();
403 let bytes = if std::mem::size_of::<u8>() == buf.item_size()
404 && buf.is_c_contiguous()
405 && u8::is_compatible_format(buf.format())
406 {
407 unsafe { std::slice::from_raw_parts(cbuf as *const u8, len) }
408 } else {
409 return Err(PyErr::new::<ValueError, _>(
410 py,
411 "Nodemap data buffer has an invalid memory representation"
412 .to_string(),
413 ));
414 };
415
416 // Keep a reference to the mmap'ed buffer, otherwise we get a dangling
417 // pointer.
418 self.mmap(py).borrow_mut().replace(buf);
419
420 let mut nt = NodeTree::load_bytes(Box::new(bytes), len);
421
422 let data_tip =
423 docket.getattr(py, "tip_rev")?.extract::<Revision>(py)?;
424 self.docket(py).borrow_mut().replace(docket.clone_ref(py));
425 let idx = self.cindex(py).borrow();
426 let current_tip = idx.len();
427
428 for r in (data_tip + 1)..current_tip as Revision {
429 let rev = r as Revision;
430 // in this case node() won't ever return None
431 nt.insert(&*idx, idx.node(rev).unwrap(), rev)
432 .map_err(|e| nodemap_error(py, e))?
433 }
434
435 *self.nt(py).borrow_mut() = Some(nt);
436
437 Ok(py.None())
438 }
377 } 439 }
378 440
379 fn revlog_error(py: Python) -> PyErr { 441 fn revlog_error(py: Python) -> PyErr {
380 match py 442 match py
381 .import("mercurial.error") 443 .import("mercurial.error")