Compare commits
1 commit
main
...
querycache
Author | SHA1 | Date | |
---|---|---|---|
|
684cd7a46c |
6 changed files with 143 additions and 22 deletions
|
@ -160,6 +160,30 @@ impl OpSetInternal {
|
|||
self.length
|
||||
}
|
||||
|
||||
pub(crate) fn hint_clear(&mut self, obj: &ObjId) {
|
||||
if let Some(tree) = self.trees.get_mut(obj) {
|
||||
tree.internal.cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn hint_delete(&mut self, pos: usize, obj: &ObjId) {
|
||||
if let Some(tree) = self.trees.get_mut(obj) {
|
||||
tree.internal.cache.delete(pos);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn hint_shift(&mut self, index: Option<usize>, pos: usize, obj: &ObjId) {
|
||||
if let Some(tree) = self.trees.get_mut(obj) {
|
||||
tree.internal.cache.shift(index, pos);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn hint_insert(&mut self, index: usize, pos: usize, obj: &ObjId, element: &Op) {
|
||||
if let Some(tree) = self.trees.get_mut(obj) {
|
||||
tree.internal.cache.insert(index, pos, element);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, index: usize, obj: &ObjId, element: Op) {
|
||||
if let OpType::Make(typ) = element.action {
|
||||
self.trees.insert(
|
||||
|
@ -180,6 +204,8 @@ impl OpSetInternal {
|
|||
}
|
||||
|
||||
pub(crate) fn insert_op(&mut self, obj: &ObjId, op: Op) -> Op {
|
||||
self.hint_clear(obj);
|
||||
|
||||
let q = self.search(obj, query::SeekOp::new(&op));
|
||||
|
||||
let succ = q.succ;
|
||||
|
@ -201,6 +227,9 @@ impl OpSetInternal {
|
|||
op: Op,
|
||||
observer: &mut Obs,
|
||||
) -> Op {
|
||||
// FIXME
|
||||
self.hint_clear(obj);
|
||||
|
||||
let q = self.search(obj, query::SeekOpWithPatch::new(&op));
|
||||
|
||||
let query::SeekOpWithPatch {
|
||||
|
|
|
@ -11,16 +11,77 @@ use crate::{
|
|||
query::{self, Index, QueryResult, ReplaceArgs, TreeQuery},
|
||||
};
|
||||
use crate::{
|
||||
types::{ObjId, Op, OpId},
|
||||
types::{Key, ObjId, Op, OpId},
|
||||
ObjType,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashSet, VecDeque};
|
||||
|
||||
pub(crate) const B: usize = 16;
|
||||
|
||||
mod iter;
|
||||
pub(crate) use iter::OpTreeIter;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub(crate) struct ListCachePoint {
|
||||
pub(crate) index: usize, // list index
|
||||
pub(crate) pos: usize, // op tree position
|
||||
pub(crate) key: Key,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
pub(crate) struct QueryCache {
|
||||
index: VecDeque<ListCachePoint>,
|
||||
}
|
||||
|
||||
const CACHE_MAX: usize = 4;
|
||||
|
||||
impl QueryCache {
|
||||
pub(crate) fn find(&self, index: usize) -> Option<&ListCachePoint> {
|
||||
self.index.iter().find(|c| c.index == index)
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, index: usize, pos: usize, op: &Op) {
|
||||
for c in &mut self.index {
|
||||
if c.pos >= pos {
|
||||
c.pos += 1;
|
||||
c.index += 1;
|
||||
}
|
||||
}
|
||||
if self.index.len() >= CACHE_MAX {
|
||||
self.index.pop_front();
|
||||
}
|
||||
self.index.push_back(ListCachePoint {
|
||||
index,
|
||||
pos,
|
||||
key: op.elemid_or_key(),
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn clear(&mut self) {
|
||||
self.index.truncate(0)
|
||||
}
|
||||
|
||||
pub(crate) fn delete(&mut self, pos: usize) {
|
||||
for c in &mut self.index {
|
||||
if c.pos >= pos {
|
||||
c.index -= 1;
|
||||
}
|
||||
}
|
||||
self.index.retain(|c| c.pos + 1 != pos);
|
||||
}
|
||||
|
||||
pub(crate) fn shift(&mut self, index: Option<usize>, pos: usize) {
|
||||
for c in &mut self.index {
|
||||
if c.pos >= pos {
|
||||
c.pos += 1;
|
||||
}
|
||||
}
|
||||
if let Some(index) = index {
|
||||
self.index.retain(|c| c.index != index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub(crate) struct OpTree {
|
||||
pub(crate) internal: OpTreeInternal,
|
||||
|
@ -46,6 +107,7 @@ impl OpTree {
|
|||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct OpTreeInternal {
|
||||
pub(crate) root_node: Option<OpTreeNode>,
|
||||
pub(crate) cache: QueryCache,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -59,7 +121,10 @@ pub(crate) struct OpTreeNode {
|
|||
impl OpTreeInternal {
|
||||
/// Construct a new, empty, sequence.
|
||||
pub(crate) fn new() -> Self {
|
||||
Self { root_node: None }
|
||||
Self {
|
||||
root_node: None,
|
||||
cache: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the length of the sequence.
|
||||
|
@ -121,13 +186,15 @@ impl OpTreeInternal {
|
|||
where
|
||||
Q: TreeQuery<'a>,
|
||||
{
|
||||
self.root_node
|
||||
.as_ref()
|
||||
.map(|root| match query.query_node_with_metadata(root, m) {
|
||||
QueryResult::Descend => root.search(&mut query, m, None),
|
||||
QueryResult::Skip(skip) => root.search(&mut query, m, Some(skip)),
|
||||
_ => true,
|
||||
});
|
||||
if !query.read_cache(&self.cache) {
|
||||
self.root_node
|
||||
.as_ref()
|
||||
.map(|root| match query.query_node_with_metadata(root, m) {
|
||||
QueryResult::Descend => root.search(&mut query, m, None),
|
||||
QueryResult::Skip(skip) => root.search(&mut query, m, Some(skip)),
|
||||
_ => true,
|
||||
});
|
||||
}
|
||||
query
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::op_tree::{OpSetMetadata, OpTreeNode};
|
||||
use crate::op_tree::{OpSetMetadata, OpTreeNode, QueryCache};
|
||||
use crate::types::{Clock, Counter, Key, Op, OpId, OpType, ScalarValue};
|
||||
use fxhash::FxBuildHasher;
|
||||
use std::cmp::Ordering;
|
||||
|
@ -85,6 +85,12 @@ pub(crate) trait TreeQuery<'a> {
|
|||
fn query_element(&mut self, _element: &'a Op) -> QueryResult {
|
||||
panic!("invalid element query")
|
||||
}
|
||||
|
||||
fn read_cache(&mut self, _cache: &QueryCache) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn update_cache(&mut self, _cache: &mut QueryCache) {}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::error::AutomergeError;
|
||||
use crate::op_tree::OpTreeNode;
|
||||
use crate::query::{QueryResult, TreeQuery};
|
||||
use crate::query::{QueryCache, QueryResult, TreeQuery};
|
||||
use crate::types::{ElemId, Key, Op, HEAD};
|
||||
use std::fmt::Debug;
|
||||
|
||||
|
@ -46,16 +46,6 @@ impl InsertNth {
|
|||
pub(crate) fn key(&self) -> Result<Key, AutomergeError> {
|
||||
self.last_valid_insert
|
||||
.ok_or(AutomergeError::InvalidIndex(self.target))
|
||||
//if self.target == 0 {
|
||||
/*
|
||||
if self.last_insert.is_none() {
|
||||
Ok(HEAD.into())
|
||||
} else if self.seen == self.target && self.last_insert.is_some() {
|
||||
Ok(Key::Seq(self.last_insert.unwrap()))
|
||||
} else {
|
||||
Err(AutomergeError::InvalidIndex(self.target))
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,4 +100,18 @@ impl<'a> TreeQuery<'a> for InsertNth {
|
|||
self.n += 1;
|
||||
QueryResult::Next
|
||||
}
|
||||
|
||||
// AXIOM: ListCachePoint is only for single item inserts
|
||||
// remove cache points on update
|
||||
|
||||
fn read_cache(&mut self, cache: &QueryCache) -> bool {
|
||||
if self.target > 0 {
|
||||
if let Some(c) = cache.find(self.target - 1) {
|
||||
self.last_valid_insert = Some(c.key);
|
||||
self.valid = Some(c.pos + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ impl TransactionInner {
|
|||
let num = self.pending_ops();
|
||||
// remove in reverse order so sets are removed before makes etc...
|
||||
for (obj, _prop, op) in self.operations.into_iter().rev() {
|
||||
doc.ops.hint_clear(&obj);
|
||||
for pred_id in &op.pred {
|
||||
if let Some(p) = doc.ops.search(&obj, OpIdSearch::new(*pred_id)).index() {
|
||||
doc.ops.replace(&obj, p, |o| o.remove_succ(&op));
|
||||
|
@ -169,7 +170,10 @@ impl TransactionInner {
|
|||
}
|
||||
|
||||
if !op.is_delete() {
|
||||
doc.ops.hint_shift((&prop).into(), pos, &obj);
|
||||
doc.ops.insert(pos, &obj, op.clone());
|
||||
} else {
|
||||
doc.ops.hint_delete(pos, &obj)
|
||||
}
|
||||
|
||||
self.operations.push((obj, prop, op));
|
||||
|
@ -223,6 +227,8 @@ impl TransactionInner {
|
|||
insert: true,
|
||||
};
|
||||
|
||||
let pos = query.pos();
|
||||
doc.ops.hint_insert(index, pos, &obj, &op);
|
||||
doc.ops.insert(query.pos(), &obj, op.clone());
|
||||
self.operations.push((obj, Prop::Seq(index), op));
|
||||
|
||||
|
|
|
@ -575,3 +575,12 @@ impl From<Prop> for wasm_bindgen::JsValue {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Prop> for Option<usize> {
|
||||
fn from(prop: &Prop) -> Self {
|
||||
match prop {
|
||||
Prop::Map(_) => None,
|
||||
Prop::Seq(index) => Some(*index),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue