|
|
… |
78 unchanged lines |
| 79 |
79 |
|
/// version 2 checkpoint, if any, and the edits of later changes in the |
| 80 |
80 |
|
/// order they were applied (spec §11). Building it later gives the same |
| 81 |
81 |
|
/// graph, since graph construction does not depend on order (§8). |
|
82 |
+ |
/// |
|
83 |
+ |
/// Read from a state index, it stays encoded until first used: a command |
|
84 |
+ |
/// that builds a few files decodes only their histories. |
| 82 |
85 |
|
#[derive(Clone, Default)] |
| 83 |
86 |
|
struct Deferred { |
|
87 |
+ |
body: std::sync::OnceLock<DeferredBody>, |
|
88 |
+ |
/// The body as the index encodes it, decoded into `body` on first use. |
|
89 |
+ |
raw: Option<(Arc<[u8]>, std::ops::Range<usize>)>, |
|
90 |
+ |
/// Its graph key, once worked out (or read from an index); reset by |
|
91 |
+ |
/// any edit added. |
|
92 |
+ |
key: std::sync::OnceLock<[u8; 32]>, |
|
93 |
+ |
} |
|
94 |
+ |
|
|
95 |
+ |
#[derive(Clone, Default)] |
|
96 |
+ |
struct DeferredBody { |
| 84 |
97 |
|
base: Option<DeferredBase>, |
| 85 |
98 |
|
edits: Vec<(ChangeHash, Vec<Edit>)>, |
| 86 |
99 |
|
/// The text blob and line count of each insert in `edits` left without |
| 87 |
100 |
|
/// its lines, in order: read when the graph is built. |
| 88 |
101 |
|
texts: Vec<TextRef>, |
| 89 |
|
- |
/// Its graph key, once worked out (or read from an index); reset by |
| 90 |
|
- |
/// any edit added. |
| 91 |
|
- |
key: std::sync::OnceLock<[u8; 32]>, |
|
102 |
+ |
} |
|
103 |
+ |
|
|
104 |
+ |
impl Deferred { |
|
105 |
+ |
fn from_body(body: DeferredBody) -> Deferred { |
|
106 |
+ |
Deferred { |
|
107 |
+ |
body: std::sync::OnceLock::from(body), |
|
108 |
+ |
..Deferred::default() |
|
109 |
+ |
} |
|
110 |
+ |
} |
|
111 |
+ |
|
|
112 |
+ |
fn body(&self) -> &DeferredBody { |
|
113 |
+ |
self.body.get_or_init(|| match &self.raw { |
|
114 |
+ |
// The index was checked against its hash when read, and was |
|
115 |
+ |
// written by `write_index`: it decodes. |
|
116 |
+ |
Some((bytes, range)) => State::read_deferred_body(&bytes[range.clone()]) |
|
117 |
+ |
.expect("a state index checked by its hash decodes"), |
|
118 |
+ |
None => DeferredBody::default(), |
|
119 |
+ |
}) |
|
120 |
+ |
} |
|
121 |
+ |
|
|
122 |
+ |
fn body_mut(&mut self) -> &mut DeferredBody { |
|
123 |
+ |
self.body(); |
|
124 |
+ |
self.raw = None; |
|
125 |
+ |
self.body.get_mut().expect("decoded above") |
|
126 |
+ |
} |
|
127 |
+ |
|
|
128 |
+ |
fn into_body(mut self) -> DeferredBody { |
|
129 |
+ |
self.body(); |
|
130 |
+ |
self.body.take().expect("decoded above") |
|
131 |
+ |
} |
| 92 |
132 |
|
} |
| 93 |
133 |
|
|
| 94 |
134 |
|
#[derive(Clone)] |
|
|
… |
8 unchanged lines |
| 103 |
143 |
|
/// command reads it rather than replaying history. Derived only: written |
| 104 |
144 |
|
/// from a state loaded the long way, and read back as the same state. |
| 105 |
145 |
|
impl State { |
| 106 |
|
- |
const INDEX_MAGIC: &'static [u8] = b"oxy state index 1\n"; |
|
146 |
+ |
const INDEX_MAGIC: &'static [u8] = b"oxy state index 2\n"; |
| 107 |
147 |
|
|
| 108 |
148 |
|
/// The index of this state, or `None` when it has anything an index |
| 109 |
149 |
|
/// does not hold: a built graph, or text in memory (a change added |
|
|
… |
58 unchanged lines |
| 168 |
208 |
|
w.count(nodes.len()); |
| 169 |
209 |
|
for (n, d) in nodes { |
| 170 |
210 |
|
w.fixed(&n.0); |
|
211 |
+ |
let mut h = blake3::Hasher::new(); |
|
212 |
+ |
h.update(b"oxy graph key 1\0"); |
|
213 |
+ |
h.update(&n.0); |
|
214 |
+ |
w.fixed(d.key.get_or_init(|| d.graph_key(h))); |
|
215 |
+ |
// Unchanged since read (a change clears `raw`): copied as it is. |
|
216 |
+ |
if let Some((bytes, range)) = &d.raw { |
|
217 |
+ |
w.bytes(&bytes[range.clone()]); |
|
218 |
+ |
continue; |
|
219 |
+ |
} |
|
220 |
+ |
let d = d.body(); |
|
221 |
+ |
let outer_w = std::mem::take(&mut w); |
| 171 |
222 |
|
match &d.base { |
| 172 |
223 |
|
None => w.u8(0), |
| 173 |
224 |
|
Some(DeferredBase::Blob(r)) => { |
|
|
… |
77 unchanged lines |
| 251 |
302 |
|
} |
| 252 |
303 |
|
} |
| 253 |
304 |
|
} |
| 254 |
|
- |
let mut h = blake3::Hasher::new(); |
| 255 |
|
- |
h.update(b"oxy graph key 1\0"); |
| 256 |
|
- |
h.update(&n.0); |
| 257 |
|
- |
w.fixed(d.key.get_or_init(|| d.graph_key(h))); |
|
305 |
+ |
let body = std::mem::replace(&mut w, outer_w); |
|
306 |
+ |
w.bytes(&body.0); |
| 258 |
307 |
|
} |
| 259 |
308 |
|
let mut outer = outer; |
| 260 |
309 |
|
outer.bytes(&w.0); |
|
|
… |
56 unchanged lines |
| 317 |
366 |
|
Ok(st) |
| 318 |
367 |
|
} |
| 319 |
368 |
|
|
|
369 |
+ |
/// The deferred block: each node with its graph key and its body, |
|
370 |
+ |
/// left encoded (see [`Deferred`]). |
| 320 |
371 |
|
fn read_deferred(bytes: &[u8]) -> Result<HashMap<NodeId, Arc<Deferred>>, ObjectError> { |
| 321 |
372 |
|
use crate::flat::Reader; |
| 322 |
373 |
|
let _t = crate::timing::phase("index: deferred"); |
|
374 |
+ |
let all: Arc<[u8]> = Arc::from(bytes); |
|
375 |
+ |
let mut r = Reader::new(bytes); |
|
376 |
+ |
let mut deferred: HashMap<NodeId, Arc<Deferred>> = HashMap::new(); |
|
377 |
+ |
let n = r.count()?; |
|
378 |
+ |
deferred.reserve(n); |
|
379 |
+ |
for _ in 0..n { |
|
380 |
+ |
let id = NodeId(r.fixed::<16>()?); |
|
381 |
+ |
let key = r.fixed::<32>()?; |
|
382 |
+ |
let body = r.bytes()?; |
|
383 |
+ |
let start = body.as_ptr() as usize - bytes.as_ptr() as usize; |
|
384 |
+ |
let d = Deferred { |
|
385 |
+ |
raw: Some((all.clone(), start..start + body.len())), |
|
386 |
+ |
key: std::sync::OnceLock::from(key), |
|
387 |
+ |
..Deferred::default() |
|
388 |
+ |
}; |
|
389 |
+ |
deferred.insert(id, Arc::new(d)); |
|
390 |
+ |
} |
|
391 |
+ |
if !r.at_end() { |
|
392 |
+ |
return Err(ObjectError::Schema("state index: trailing bytes".into())); |
|
393 |
+ |
} |
|
394 |
+ |
Ok(deferred) |
|
395 |
+ |
} |
|
396 |
+ |
|
|
397 |
+ |
/// One node's deferred history as the index encodes it. |
|
398 |
+ |
fn read_deferred_body(bytes: &[u8]) -> Result<DeferredBody, ObjectError> { |
|
399 |
+ |
use crate::flat::Reader; |
| 323 |
400 |
|
let bad = |what: &str| ObjectError::Schema(format!("state index: {what}")); |
| 324 |
401 |
|
let node = |r: &mut Reader| -> Result<NodeId, ObjectError> { Ok(NodeId(r.fixed::<16>()?)) }; |
| 325 |
402 |
|
let atom = |r: &mut Reader| -> Result<AtomRef, ObjectError> { |
|
|
… |
8 unchanged lines |
| 334 |
411 |
|
}) |
| 335 |
412 |
|
}; |
| 336 |
413 |
|
let mut r = Reader::new(bytes); |
| 337 |
|
- |
let mut deferred: HashMap<NodeId, Arc<Deferred>> = HashMap::new(); |
| 338 |
|
- |
let n = r.count()?; |
| 339 |
|
- |
deferred.reserve(n); |
| 340 |
|
- |
for _ in 0..n { |
| 341 |
|
- |
let id = node(&mut r)?; |
| 342 |
|
- |
let base = match r.u8()? { |
| 343 |
|
- |
0 => None, |
| 344 |
|
- |
1 => Some(DeferredBase::Blob(r.object()?)), |
| 345 |
|
- |
_ => Some(DeferredBase::Inline(cbor::decode(r.bytes()?)?)), |
| 346 |
|
- |
}; |
| 347 |
|
- |
let mut edits = Vec::new(); |
| 348 |
|
- |
for _ in 0..r.count()? { |
| 349 |
|
- |
let c = r.object()?; |
| 350 |
|
- |
let mut es = Vec::new(); |
| 351 |
|
- |
for _ in 0..r.count()? { |
| 352 |
|
- |
es.push(match r.u8()? { |
| 353 |
|
- |
0 => Edit::Insert { |
| 354 |
|
- |
node: node(&mut r)?, |
| 355 |
|
- |
after: atom(&mut r)?, |
| 356 |
|
- |
before: atom(&mut r)?, |
| 357 |
|
- |
lines: crate::lines::Lines::default(), |
| 358 |
|
- |
}, |
| 359 |
|
- |
1 => { |
| 360 |
|
- |
let node = node(&mut r)?; |
| 361 |
|
- |
let mut atoms = Vec::new(); |
| 362 |
|
- |
for _ in 0..r.count()? { |
| 363 |
|
- |
atoms.push(crate::objects::AtomRange { |
| 364 |
|
- |
change: r.object()?, |
| 365 |
|
- |
from: r.u32()?, |
| 366 |
|
- |
to: r.u32()?, |
| 367 |
|
- |
}); |
| 368 |
|
- |
} |
| 369 |
|
- |
Edit::Delete { node, atoms } |
| 370 |
|
- |
} |
| 371 |
|
- |
_ => return Err(bad("edit")), |
| 372 |
|
- |
}); |
| 373 |
|
- |
} |
| 374 |
|
- |
edits.push((c, es)); |
| 375 |
|
- |
} |
| 376 |
|
- |
let mut texts = Vec::new(); |
|
414 |
+ |
let base = match r.u8()? { |
|
415 |
+ |
0 => None, |
|
416 |
+ |
1 => Some(DeferredBase::Blob(r.object()?)), |
|
417 |
+ |
_ => Some(DeferredBase::Inline(cbor::decode(r.bytes()?)?)), |
|
418 |
+ |
}; |
|
419 |
+ |
let mut edits = Vec::new(); |
|
420 |
+ |
for _ in 0..r.count()? { |
|
421 |
+ |
let c = r.object()?; |
|
422 |
+ |
let mut es = Vec::new(); |
| 377 |
423 |
|
for _ in 0..r.count()? { |
| 378 |
|
- |
texts.push(match r.u8()? { |
| 379 |
|
- |
0 => TextRef::Blob( |
| 380 |
|
- |
r.object()?, |
| 381 |
|
- |
r.u32()?, |
| 382 |
|
- |
match r.u8()? { |
| 383 |
|
- |
0 => crate::objects::TextForm::Cbor, |
| 384 |
|
- |
1 => crate::objects::TextForm::Raw, |
| 385 |
|
- |
_ => crate::objects::TextForm::CborFallback, |
| 386 |
|
- |
}, |
| 387 |
|
- |
), |
| 388 |
|
- |
_ => TextRef::Inline { |
| 389 |
|
- |
change: r.object()?, |
| 390 |
|
- |
start: r.u32()?, |
| 391 |
|
- |
end: r.u32()?, |
|
424 |
+ |
es.push(match r.u8()? { |
|
425 |
+ |
0 => Edit::Insert { |
|
426 |
+ |
node: node(&mut r)?, |
|
427 |
+ |
after: atom(&mut r)?, |
|
428 |
+ |
before: atom(&mut r)?, |
|
429 |
+ |
lines: crate::lines::Lines::default(), |
| 392 |
430 |
|
}, |
|
431 |
+ |
1 => { |
|
432 |
+ |
let node = node(&mut r)?; |
|
433 |
+ |
let mut atoms = Vec::new(); |
|
434 |
+ |
for _ in 0..r.count()? { |
|
435 |
+ |
atoms.push(crate::objects::AtomRange { |
|
436 |
+ |
change: r.object()?, |
|
437 |
+ |
from: r.u32()?, |
|
438 |
+ |
to: r.u32()?, |
|
439 |
+ |
}); |
|
440 |
+ |
} |
|
441 |
+ |
Edit::Delete { node, atoms } |
|
442 |
+ |
} |
|
443 |
+ |
_ => return Err(bad("edit")), |
| 393 |
444 |
|
}); |
| 394 |
445 |
|
} |
| 395 |
|
- |
let d = Deferred { |
| 396 |
|
- |
base, |
| 397 |
|
- |
edits, |
| 398 |
|
- |
texts, |
| 399 |
|
- |
key: std::sync::OnceLock::from(r.fixed::<32>()?), |
| 400 |
|
- |
}; |
| 401 |
|
- |
deferred.insert(id, Arc::new(d)); |
|
446 |
+ |
edits.push((c, es)); |
|
447 |
+ |
} |
|
448 |
+ |
let mut texts = Vec::new(); |
|
449 |
+ |
for _ in 0..r.count()? { |
|
450 |
+ |
texts.push(match r.u8()? { |
|
451 |
+ |
0 => TextRef::Blob( |
|
452 |
+ |
r.object()?, |
|
453 |
+ |
r.u32()?, |
|
454 |
+ |
match r.u8()? { |
|
455 |
+ |
0 => crate::objects::TextForm::Cbor, |
|
456 |
+ |
1 => crate::objects::TextForm::Raw, |
|
457 |
+ |
_ => crate::objects::TextForm::CborFallback, |
|
458 |
+ |
}, |
|
459 |
+ |
), |
|
460 |
+ |
_ => TextRef::Inline { |
|
461 |
+ |
change: r.object()?, |
|
462 |
+ |
start: r.u32()?, |
|
463 |
+ |
end: r.u32()?, |
|
464 |
+ |
}, |
|
465 |
+ |
}); |
| 402 |
466 |
|
} |
| 403 |
467 |
|
if !r.at_end() { |
| 404 |
|
- |
return Err(bad("trailing bytes")); |
|
468 |
+ |
return Err(bad("trailing bytes in a file's history")); |
| 405 |
469 |
|
} |
| 406 |
|
- |
Ok(deferred) |
|
470 |
+ |
Ok(DeferredBody { base, edits, texts }) |
| 407 |
471 |
|
} |
| 408 |
472 |
|
} |
| 409 |
473 |
|
|
|
|
… |
137 unchanged lines |
| 547 |
611 |
|
/// texts of inserts read without their lines are loaded in one call, then |
| 548 |
612 |
|
/// the graphs are built in parallel (they are independent). |
| 549 |
613 |
|
fn build_deferred( |
| 550 |
|
- |
mut taken: Vec<(NodeId, Deferred)>, |
|
614 |
+ |
taken: Vec<(NodeId, Deferred)>, |
| 551 |
615 |
|
load: impl FnOnce(&[ObjectRef]) -> Result<Vec<Vec<u8>>, ObjectError>, |
| 552 |
616 |
|
read_change: impl Fn(&ChangeHash) -> Result<Arc<Vec<u8>>, ObjectError>, |
| 553 |
617 |
|
) -> Result<Vec<(NodeId, FileGraph)>, ObjectError> { |
|
618 |
+ |
let mut taken: Vec<(NodeId, DeferredBody)> = |
|
619 |
+ |
taken.into_iter().map(|(n, d)| (n, d.into_body())).collect(); |
| 554 |
620 |
|
let mut refs: Vec<ObjectRef> = taken |
| 555 |
621 |
|
.iter() |
| 556 |
622 |
|
.filter_map(|(_, d)| match &d.base { |
|
|
… |
31 unchanged lines |
| 588 |
654 |
|
let mut blobs = blobs.into_iter(); |
| 589 |
655 |
|
// Pair each graph with its blob, then build them all in parallel: |
| 590 |
656 |
|
// graphs are independent. |
| 591 |
|
- |
let mut work: Vec<(NodeId, Deferred, Option<Vec<u8>>)> = Vec::with_capacity(taken.len()); |
|
657 |
+ |
let mut work: Vec<(NodeId, DeferredBody, Option<Vec<u8>>)> = Vec::with_capacity(taken.len()); |
| 592 |
658 |
|
for (node, mut d) in taken.drain(..) { |
| 593 |
659 |
|
// Fill in the lines of inserts read without them, in order. |
| 594 |
660 |
|
let mut want = std::mem::take(&mut d.texts).into_iter(); |
|
|
… |
232 unchanged lines |
| 827 |
893 |
|
impl Deferred { |
| 828 |
894 |
|
/// See [`State::graph_key`]: `h` has taken the node already. |
| 829 |
895 |
|
fn graph_key(&self, mut h: blake3::Hasher) -> [u8; 32] { |
| 830 |
|
- |
let d = self; |
|
896 |
+ |
let d = self.body(); |
| 831 |
897 |
|
match &d.base { |
| 832 |
898 |
|
None => h.update(&[0]), |
| 833 |
899 |
|
Some(DeferredBase::Blob(r)) => h.update(&[1]).update(&r.0), |
|
|
… |
356 unchanged lines |
| 1190 |
1256 |
|
}; |
| 1191 |
1257 |
|
deferred.insert( |
| 1192 |
1258 |
|
node, |
| 1193 |
|
- |
Arc::new(Deferred { |
|
1259 |
+ |
Arc::new(Deferred::from_body(DeferredBody { |
| 1194 |
1260 |
|
base: Some(base), |
| 1195 |
|
- |
edits: Vec::new(), |
| 1196 |
|
- |
texts: Vec::new(), |
| 1197 |
|
- |
key: Default::default(), |
| 1198 |
|
- |
}), |
|
1261 |
+ |
..DeferredBody::default() |
|
1262 |
+ |
})), |
| 1199 |
1263 |
|
); |
| 1200 |
1264 |
|
} |
| 1201 |
1265 |
|
st.deferred = Some(deferred); |
|
|
… |
101 unchanged lines |
| 1303 |
1367 |
|
} |
| 1304 |
1368 |
|
None => { |
| 1305 |
1369 |
|
let d = Arc::make_mut(deferred.entry(node).or_default()); |
| 1306 |
|
- |
d.edits.push((h, edits)); |
| 1307 |
|
- |
d.texts.extend(node_texts); |
|
1370 |
+ |
let b = d.body_mut(); |
|
1371 |
+ |
b.edits.push((h, edits)); |
|
1372 |
+ |
b.texts.extend(node_texts); |
| 1308 |
1373 |
|
d.key = Default::default(); |
| 1309 |
1374 |
|
} |
| 1310 |
1375 |
|
} |
|
|
… |
1068 unchanged lines |