mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-02 06:46:50 -06:00
The server's fixes for a refused batch walked every deleted layer's whole subtree again and compared each document-level fix with all the earlier ones, so a batch deleting a deep chain took quadratic time on the hub thread. Each subtree walk now stops at a layer already restored, and document-level fixes are looked up and sent once per target. The fixes are unchanged. A refused batch deleting a 20,000-deep chain plus 40,000 comment puts: 27.2 s before, 0.14 s after (debug build). Fixes #1063
This commit is contained in:
+18
-13
@@ -557,6 +557,7 @@ impl Server {
|
||||
let doc = self.state.document();
|
||||
let mut props: BTreeMap<NodeId, BTreeSet<Prop>> = BTreeMap::new();
|
||||
let mut gone: BTreeSet<NodeId> = BTreeSet::new();
|
||||
let (mut asked, mut sent) = (BTreeSet::new(), BTreeSet::new());
|
||||
let mut out = Vec::new();
|
||||
for c in changes {
|
||||
match c {
|
||||
@@ -569,9 +570,11 @@ impl Server {
|
||||
Change::Delete { id } => {
|
||||
gone.insert(*id);
|
||||
}
|
||||
// The same target has the same fix: look each one up once, and send each fix once.
|
||||
other => {
|
||||
if let Some(fix) = docprops::current(doc, other)?
|
||||
&& !out.contains(&fix)
|
||||
if Target::of(other).is_some_and(|t| asked.insert(t))
|
||||
&& let Some(fix) = docprops::current(doc, other)?
|
||||
&& Target::of(&fix).is_some_and(|t| sent.insert(t))
|
||||
{
|
||||
out.push(fix);
|
||||
}
|
||||
@@ -589,19 +592,21 @@ impl Server {
|
||||
nodes.extend(t.write(self.state.value(&t)?.as_ref()));
|
||||
}
|
||||
}
|
||||
let mut restored = std::collections::BTreeSet::new();
|
||||
// Each deleted node's subtree, pre-order, every node once: a restored node's whole subtree
|
||||
// went out with it, so the walk stops there (deleting a deep chain stays linear).
|
||||
let mut restored = BTreeSet::new();
|
||||
for id in gone {
|
||||
match doc.node(id) {
|
||||
Some(_) => {
|
||||
for d in doc.subtree(id) {
|
||||
if restored.insert(d)
|
||||
&& let Some(n) = doc.node(d)
|
||||
{
|
||||
nodes.push(create_change(n, self.state.key(d))?);
|
||||
}
|
||||
}
|
||||
if !doc.contains(id) {
|
||||
nodes.push(Change::Delete { id });
|
||||
continue;
|
||||
}
|
||||
let mut stack = vec![id];
|
||||
while let Some(d) = stack.pop() {
|
||||
let Some(n) = doc.node(d) else { continue };
|
||||
if restored.insert(d) {
|
||||
nodes.push(create_change(n, self.state.key(d))?);
|
||||
stack.extend(n.children.iter().rev());
|
||||
}
|
||||
None => nodes.push(Change::Delete { id }),
|
||||
}
|
||||
}
|
||||
nodes.extend(out);
|
||||
|
||||
Reference in New Issue
Block a user