ff0af1ee unknown 1 month ago
1
2
3
4
5
6
0bdc3f91 Andy McCall 1 month ago ↶
7
use crate :: fasthash:: { FastMap as HashMap, FastSet as HashSet} ;
ff0af1ee unknown 1 month ago
8
use crate :: hash:: ChangeHash;
01a47cd7 Andy McCall 1 month ago ↶
9
use crate :: lines:: { LineRef, Lines} ;
ff0af1ee unknown 1 month ago
10
use crate :: objects:: AtomRange;
0bdc3f91 Andy McCall 1 month ago ↶
11
use std:: collections:: { BTreeMap, BTreeSet} ;
ff0af1ee unknown 1 month ago
12
13
14
pub type AtomKey = ( ChangeHash, u32 ) ;
15
16
# [ derive ( Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug ) ]
17
pub enum Vertex {
18
Start,
19
Atom( AtomKey) ,
20
End,
21
}
22
23
24
pub trait DepOracle {
25
fn depends_on ( & self , a : & ChangeHash, b : & ChangeHash) -> bool ;
26
}
27
aedfe465 Andy McCall 25 days ago ↶
28
29
30
31
32
struct MemoDeps < 'a > {
33
inner : & 'a dyn DepOracle,
34
known : std:: cell:: RefCell< crate:: fasthash:: FastMap< ( ChangeHash, ChangeHash) , bool > > ,
35
}
36
37
impl DepOracle for MemoDeps < '_ > {
38
fn depends_on ( & self , a : & ChangeHash, b : & ChangeHash) -> bool {
39
if let Some ( v) = self .known.borrow ( ) .get ( & ( * a, * b) ) {
40
return * v;
41
}
42
let v = self .inner.depends_on ( a, b) ;
43
self .known.borrow_mut ( ) .insert ( ( * a, * b) , v) ;
44
v
45
}
46
}
47
ff0af1ee unknown 1 month ago
48
49
pub struct NoDeps ;
50
impl DepOracle for NoDeps {
51
fn depends_on ( & self , a : & ChangeHash, b : & ChangeHash) -> bool {
52
a = = b
53
}
54
}
55
56
# [ derive ( Default, Clone, Debug ) ]
57
struct AtomInfo {
01a47cd7 Andy McCall 1 month ago ↶
58
59
60
content : Option< LineRef> ,
ff0af1ee unknown 1 month ago
61
deleted_by : BTreeSet< ChangeHash> ,
62
}
63
64
# [ derive ( Clone, Debug ) ]
65
pub struct FileGraph {
66
atoms : HashMap< AtomKey, AtomInfo> ,
0bdc3f91 Andy McCall 1 month ago ↶
67
68
succ : HashMap< Vertex, Edges> ,
dbf06d34 Andy McCall 1 month ago ↶
69
70
order : OrderSlot,
0bdc3f91 Andy McCall 1 month ago ↶
71
}
dbf06d34 Andy McCall 1 month ago ↶
72
73
74
75
76
77
78
# [ derive ( Debug ) ]
79
pub struct Order {
80
atoms : Vec< AtomKey> ,
81
82
83
84
unchecked : Vec< AtomKey> ,
85
confirmed : std:: sync:: atomic:: AtomicBool,
86
}
87
88
89
90
# [ derive ( Debug, Default ) ]
91
struct OrderSlot ( std:: sync:: Mutex< Option< std:: sync:: Arc< Order> > > ) ;
92
93
impl OrderSlot {
94
fn get ( & self ) -> Option< std:: sync:: Arc< Order> > {
95
self .0. lock ( ) .unwrap_or_else ( | e | e.into_inner ( ) ) .clone ( )
96
}
97
fn set ( & self , o : Option< std:: sync:: Arc< Order> > ) {
98
* self .0. lock ( ) .unwrap_or_else ( | e | e.into_inner ( ) ) = o;
99
}
100
fn take ( & mut self ) -> Option< std:: sync:: Arc< Order> > {
101
self .0. get_mut ( ) .unwrap_or_else ( | e | e.into_inner ( ) ) .take ( )
102
}
103
}
104
105
impl Clone for OrderSlot {
106
fn clone ( & self ) -> Self {
107
OrderSlot( std:: sync:: Mutex:: new( self .get ( ) ) )
108
}
109
}
110
111
impl Order {
112
fn known ( atoms : Vec< AtomKey> ) -> Order {
113
Order {
114
atoms,
115
unchecked: Vec :: new( ) ,
116
confirmed: std:: sync:: atomic:: AtomicBool:: new( true ) ,
117
}
118
}
0bdc3f91 Andy McCall 1 month ago ↶
119
dbf06d34 Andy McCall 1 month ago ↶
120
121
122
123
124
7eac74ab Andy McCall 1 month ago ↶
125
fn splice (
dbf06d34 Andy McCall 1 month ago ↶
126
& self ,
127
h : ChangeHash,
128
inserts : & [( Vertex , Vertex , u32 , u32 ) ],
129
deleted : & [AtomKey],
130
) -> Option< std:: sync:: Arc< Order> > {
131
let mut want: HashSet< AtomKey> = deleted.iter ( ) .copied ( ) .collect ( ) ;
132
for ( a, b, _ , _ ) in inserts {
133
for v in [ a, b] {
134
if let Vertex:: Atom( k) = v {
135
want.insert ( * k) ;
136
}
137
}
138
}
139
let mut pos: HashMap< AtomKey, usize > = HashMap:: default( ) ;
140
for ( i, k) in self .atoms.iter ( ) .enumerate ( ) {
141
if want.contains ( k) {
142
pos.insert ( * k, i) ;
143
}
144
}
145
let len = self .atoms.len ( ) ;
146
let mut gone = vec! [ false ; len] ;
147
let mut unchecked = if self .confirmed.load ( std:: sync:: atomic:: Ordering:: Relaxed) {
148
Vec :: new( )
149
} else {
150
self .unchecked.clone ( )
151
} ;
152
for k in deleted {
153
if k.0 = = h {
154
return None ;
155
}
156
if let Some ( & i) = pos.get ( k) {
157
if ! gone[ i] {
158
gone[ i] = true ;
159
unchecked.push ( * k) ;
160
}
161
}
162
}
163
164
165
let mut slots: Vec< ( usize , usize , u32 , u32 ) > = Vec :: with_capacity( inserts.len ( ) ) ;
166
for & ( a, b, first, count) in inserts {
167
let from = match a {
168
Vertex:: Start => 0 ,
169
Vertex:: Atom( k) => pos.get ( & k) ? + 1 ,
170
Vertex:: End => return None ,
171
} ;
172
let to = match b {
173
Vertex:: End => len,
174
Vertex:: Atom( k) => * pos.get ( & k) ? ,
175
Vertex:: Start => return None ,
176
} ;
177
if from > to | | gone[ from.. to] .iter ( ) .any ( | g | ! g) {
178
return None ;
179
}
180
slots.push ( ( from, to, first, count) ) ;
181
}
182
183
184
slots.sort_unstable ( ) ;
185
for w in slots.windows ( 2 ) {
186
let ( end, next) = ( w[ 0 ] .1 , w[ 1 ] .0 ) ;
187
if end > = next | | ! gone[ end.. next] .iter ( ) .any ( | g | ! g) {
188
return None ;
189
}
190
}
191
let added: usize = slots.iter ( ) .map ( | s | s.3 as usize ) .sum ( ) ;
192
let mut atoms = Vec :: with_capacity( len + added) ;
193
let mut slots = slots.into_iter ( ) .peekable ( ) ;
194
let mut runs_at = | i : usize , atoms : & mut Vec< AtomKey> | {
195
while let Some ( & ( from, _ , first, count) ) = slots.peek ( ) {
196
if from ! = i {
197
break ;
198
}
199
atoms.extend ( ( first.. first + count) .map ( | j | ( h, j) ) ) ;
200
slots.next ( ) ;
201
}
202
} ;
203
for ( i, ( k, g) ) in self .atoms.iter ( ) .zip ( & gone) .enumerate ( ) {
204
runs_at ( i, & mut atoms) ;
205
if ! g {
206
atoms.push ( * k) ;
207
}
208
}
209
runs_at ( len, & mut atoms) ;
210
let confirmed = unchecked.is_empty ( ) ;
211
Some ( std:: sync:: Arc:: new( Order {
212
atoms,
213
unchecked,
214
confirmed: std:: sync:: atomic:: AtomicBool:: new( confirmed) ,
215
} ) )
216
}
217
}
218
0bdc3f91 Andy McCall 1 month ago ↶
219
220
221
# [ derive ( Clone, Debug, Default, PartialEq, Eq ) ]
222
enum Edges {
223
# [ default ]
224
None ,
225
One( Vertex) ,
226
Many( Vec< Vertex> ) ,
ff0af1ee unknown 1 month ago
227
}
228
0bdc3f91 Andy McCall 1 month ago ↶
229
impl Edges {
230
fn insert ( & mut self , v : Vertex) {
231
match self {
232
Edges:: None => * self = Edges:: One( v) ,
233
Edges:: One( a) if * a = = v => { }
234
Edges:: One( a) => {
235
let a = * a;
236
* self = Edges:: Many( if a < v { vec! [ a, v] } else { vec! [ v, a] } ) ;
237
}
238
Edges:: Many( list) => {
239
if let Err ( i) = list.binary_search ( & v) {
240
list.insert ( i, v) ;
241
}
242
}
243
}
244
}
245
246
fn as_slice ( & self ) -> & [ Vertex] {
247
match self {
248
Edges:: None => & [ ] ,
249
Edges:: One( v) => std:: slice:: from_ref( v) ,
250
Edges:: Many( list) => list,
251
}
252
}
253
254
fn iter ( & self ) -> std:: slice:: Iter< '_ , Vertex> {
255
self .as_slice ( ) .iter ( )
256
}
257
}
258
ff0af1ee unknown 1 month ago
259
impl Default for FileGraph {
260
fn default ( ) -> Self {
261
Self :: new( )
262
}
263
}
264
265
266
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
267
pub enum Segment {
268
Lines( Vec< AtomKey> ) ,
269
270
Conflict( Vec< Vec< AtomKey> > ) ,
271
272
75167672 Andy McCall 1 month ago
273
Zombie {
274
deleted: Vec< AtomKey> ,
275
inserted: Vec< AtomKey> ,
276
} ,
ff0af1ee unknown 1 month ago
277
}
278
279
# [ derive ( Clone, Debug, PartialEq, Eq, Default ) ]
280
pub struct Materialized {
281
pub segments : Vec< Segment> ,
282
}
283
284
impl Materialized {
285
pub fn is_conflicted ( & self ) -> bool {
75167672 Andy McCall 1 month ago
286
self .segments
287
.iter ( )
288
.any ( | s | ! matches! ( s, Segment:: Lines( _ ) ) )
ff0af1ee unknown 1 month ago
289
}
290
pub fn conflict_count ( & self ) -> usize {
75167672 Andy McCall 1 month ago
291
self .segments
292
.iter ( )
293
.filter ( | s | ! matches! ( s, Segment:: Lines( _ ) ) )
294
.count ( )
ff0af1ee unknown 1 month ago
295
}
296
297
pub fn live_atoms ( & self ) -> Vec< AtomKey> {
298
let mut out = Vec :: new( ) ;
299
for s in & self .segments {
300
match s {
301
Segment:: Lines( a) => out.extend ( a) ,
302
Segment:: Conflict( sides) => sides.iter ( ) .for_each ( | x | out.extend ( x) ) ,
303
Segment:: Zombie { inserted, .. } => out.extend ( inserted) ,
304
}
305
}
306
out
307
}
308
}
309
310
impl FileGraph {
311
pub fn new ( ) -> Self {
75167672 Andy McCall 1 month ago
312
let mut g = FileGraph {
0bdc3f91 Andy McCall 1 month ago ↶
313
atoms: HashMap:: default( ) ,
314
succ: HashMap:: default( ) ,
dbf06d34 Andy McCall 1 month ago ↶
315
order: OrderSlot:: default( ) ,
75167672 Andy McCall 1 month ago
316
} ;
ff0af1ee unknown 1 month ago
317
g.edge ( Vertex:: Start, Vertex:: End) ;
318
g
319
}
320
321
fn edge ( & mut self , a : Vertex, b : Vertex) {
322
self .succ.entry ( a) .or_default ( ) .insert ( b) ;
323
self .succ.entry ( b) .or_default ( ) ;
324
}
325
326
75167672 Andy McCall 1 month ago
327
pub fn insert (
328
& mut self ,
329
change : ChangeHash,
330
first_index : u32 ,
331
after : Vertex,
332
before : Vertex,
01a47cd7 Andy McCall 1 month ago ↶
333
lines : & Lines,
0bdc3f91 Andy McCall 1 month ago ↶
334
) {
01a47cd7 Andy McCall 1 month ago ↶
335
self .insert_owned ( change, first_index, after, before, lines.clone ( ) ) ;
0bdc3f91 Andy McCall 1 month ago ↶
336
}
337
338
339
340
341
pub fn insert_owned (
342
& mut self ,
343
change : ChangeHash,
344
first_index : u32 ,
345
after : Vertex,
346
before : Vertex,
01a47cd7 Andy McCall 1 month ago ↶
347
lines : Lines,
75167672 Andy McCall 1 month ago
348
) {
dbf06d34 Andy McCall 1 month ago ↶
349
self .order.take ( ) ;
0bdc3f91 Andy McCall 1 month ago ↶
350
self .atoms.reserve ( lines.len ( ) ) ;
351
self .succ.reserve ( lines.len ( ) + 1 ) ;
ff0af1ee unknown 1 month ago
352
let mut prev = after;
01a47cd7 Andy McCall 1 month ago ↶
353
for i in 0 .. lines.len ( ) {
ff0af1ee unknown 1 month ago
354
let key = ( change, first_index + i as u32 ) ;
01a47cd7 Andy McCall 1 month ago ↶
355
self .atoms.entry ( key) .or_default ( ) .content =
356
Some ( LineRef:: new( lines.clone ( ) , i as u32 ) ) ;
ff0af1ee unknown 1 month ago
357
let v = Vertex:: Atom( key) ;
0bdc3f91 Andy McCall 1 month ago ↶
358
self .succ.entry ( prev) .or_default ( ) .insert ( v) ;
ff0af1ee unknown 1 month ago
359
prev = v;
360
}
0bdc3f91 Andy McCall 1 month ago ↶
361
self .succ.entry ( prev) .or_default ( ) .insert ( before) ;
362
self .succ.entry ( before) .or_default ( ) ;
ff0af1ee unknown 1 month ago
363
}
364
365
366
pub fn delete ( & mut self , by : ChangeHash, range : & AtomRange) {
dbf06d34 Andy McCall 1 month ago ↶
367
self .order.take ( ) ;
ff0af1ee unknown 1 month ago
368
for i in range.from.. range.to {
75167672 Andy McCall 1 month ago
369
self .atoms
370
.entry ( ( range.change, i) )
371
.or_default ( )
372
.deleted_by
373
.insert ( by) ;
ff0af1ee unknown 1 month ago
374
}
375
}
376
377
pub fn is_live ( & self , k : & AtomKey) -> bool {
75167672 Andy McCall 1 month ago
378
self .atoms
379
.get ( k)
380
.is_some_and ( | a | a.content.is_some ( ) & & a.deleted_by.is_empty ( ) )
ff0af1ee unknown 1 month ago
381
}
382
383
pub fn content ( & self , k : & AtomKey) -> Option< & [ u8 ] > {
01a47cd7 Andy McCall 1 month ago ↶
384
self .atoms
385
.get ( k)
386
.and_then ( | a | a.content.as_ref ( ) .map ( LineRef:: bytes) )
ff0af1ee unknown 1 month ago
387
}
388
389
pub fn deleters ( & self , k : & AtomKey) -> impl Iterator< Item = & ChangeHash> {
75167672 Andy McCall 1 month ago
390
self .atoms
391
.get ( k)
392
.into_iter ( )
393
.flat_map ( | a | a.deleted_by.iter ( ) )
ff0af1ee unknown 1 month ago
394
}
395
9bd98cfb Andy McCall 9 days ago ↶
396
397
398
399
400
401
402
403
pub fn adjacent_insertion ( & self , m : & Materialized, i : usize , deps : & dyn DepOracle) -> bool {
404
let Some ( Segment:: Conflict( sides) ) = m.segments.get ( i) else {
405
return false ;
406
} ;
407
let before = match i.checked_sub ( 1 ) .map ( | j | & m.segments[ j] ) {
408
None => Vertex:: Start,
409
Some ( Segment:: Lines( a) ) => match a.last ( ) {
410
Some ( k) => Vertex:: Atom( * k) ,
411
None => return false ,
412
} ,
413
Some ( _ ) => return false ,
414
} ;
415
let on_side: HashSet< AtomKey> = sides.iter ( ) .flatten ( ) .copied ( ) .collect ( ) ;
416
let side_changes: Vec< BTreeSet< ChangeHash> > = sides
417
.iter ( )
418
.map ( | s | s.iter ( ) .map ( | a | a.0 ) .collect ( ) )
419
.collect ( ) ;
420
let shared = | d : & ChangeHash| {
421
side_changes
422
.iter ( )
423
.all ( | s | s.iter ( ) .any ( | c | deps.depends_on ( c, d) ) )
424
} ;
425
426
427
let mut seen: HashSet< AtomKey> = HashSet:: default( ) ;
428
let mut todo = vec! [ before] ;
429
while let Some ( v) = todo.pop ( ) {
430
for & w in self .succ.get ( & v) .map ( Edges:: as_slice) .unwrap_or ( & [ ] ) {
431
let Vertex:: Atom( k) = w else { continue } ;
432
if ! seen.insert ( k) {
433
continue ;
434
}
435
if ! on_side.contains ( & k) {
436
if self .is_live ( & k) {
437
continue ;
438
}
439
if self .deleters ( & k) .any ( | d | ! shared ( d) ) {
440
return false ;
441
}
442
}
443
todo.push ( w) ;
444
}
445
}
446
true
447
}
448
ff0af1ee unknown 1 month ago
449
450
pub fn atom_count ( & self ) -> usize {
451
self .atoms.len ( )
452
}
453
62794ecc Andy McCall 1 month ago ↶
454
455
456
83d61e80 Andy McCall 1 month ago ↶
457
458
459
460
461
pub fn between ( & self , first : & AtomKey, last : & AtomKey) -> Vec< AtomKey> {
462
let ( from, to) = ( Vertex:: Atom( * first) , Vertex:: Atom( * last) ) ;
463
let mut ahead: HashSet< Vertex> = HashSet:: default( ) ;
464
let mut stack = vec! [ from] ;
465
while let Some ( v) = stack.pop ( ) {
466
if ahead.insert ( v) {
467
stack.extend (
468
self .succ
469
.get ( & v)
470
.map ( | e | e.as_slice ( ) )
471
.unwrap_or ( & [ ] )
472
.iter ( )
473
.copied ( ) ,
474
) ;
475
}
476
}
477
if ! ahead.contains ( & to) {
478
return vec! [ ] ;
479
}
480
let mut pred: HashMap< Vertex, Vec< Vertex> > = HashMap:: default( ) ;
481
for ( u, es) in & self .succ {
482
if ahead.contains ( u) {
483
for w in es.iter ( ) {
484
pred.entry ( * w) .or_default ( ) .push ( * u) ;
485
}
486
}
487
}
488
let mut behind: HashSet< Vertex> = HashSet:: default( ) ;
489
let mut stack = vec! [ to] ;
490
while let Some ( v) = stack.pop ( ) {
491
if behind.insert ( v) {
492
stack.extend ( pred.get ( & v) .into_iter ( ) .flatten ( ) .copied ( ) ) ;
493
}
494
}
495
let mut out: Vec< AtomKey> = ahead
496
.intersection ( & behind)
497
.filter_map ( | v | match v {
498
Vertex:: Atom( k) if self .atoms.contains_key ( k) => Some ( * k) ,
499
_ => None ,
500
} )
501
.collect ( ) ;
502
out.sort ( ) ;
503
out
504
}
505
506
507
pub fn touching ( & self , atoms : & [AtomKey]) -> BTreeSet< ChangeHash> {
508
let mut out = BTreeSet:: new( ) ;
509
for k in atoms {
510
out.insert ( k.0 ) ;
511
if let Some ( info) = self .atoms.get ( k) {
512
out.extend ( info.deleted_by.iter ( ) .copied ( ) ) ;
513
}
514
}
515
out
516
}
517
62794ecc Andy McCall 1 month ago ↶
518
pub fn live_successor_changes ( & self , k : & AtomKey) -> Vec< ChangeHash> {
519
self .succ
520
.get ( & Vertex:: Atom( * k) )
521
.map ( | ss | {
522
ss.iter ( )
523
.filter_map ( | s | match s {
524
Vertex:: Atom( y) if self .is_live ( y) => Some ( y.0 ) ,
525
_ => None ,
526
} )
527
.collect ( )
528
} )
529
.unwrap_or_default ( )
530
}
531
ff0af1ee unknown 1 month ago
532
fn is_ghost ( & self , k : & AtomKey, info : & AtomInfo, deps : & dyn DepOracle) -> bool {
23b217d7 Andy McCall 1 month ago ↶
533
534
535
536
ff0af1ee unknown 1 month ago
537
self .succ.get ( & Vertex:: Atom( * k) ) .is_some_and ( | ss | {
538
ss.iter ( ) .any ( | s | match s {
75167672 Andy McCall 1 month ago
539
Vertex:: Atom( y) if self .is_live ( y) => ! info
540
.deleted_by
541
.iter ( )
542
.any ( | d | deps.depends_on ( d, & y.0 ) | | deps.depends_on ( & y.0 , d) ) ,
ff0af1ee unknown 1 month ago
543
_ => false ,
544
} )
545
} )
546
}
547
548
75167672 Andy McCall 1 month ago
549
fn reduced_succ (
550
& self ,
551
v : Vertex,
552
kept : & HashSet< Vertex> ,
553
memo : & mut HashMap< Vertex, BTreeSet< Vertex> > ,
554
) -> BTreeSet< Vertex> {
598009a7 Andy McCall 1 month ago ↶
555
let direct = self .succ.get ( & v) .map ( Edges:: as_slice) .unwrap_or_default ( ) ;
556
557
558
if direct.iter ( ) .all ( | s | kept.contains ( s) ) {
559
return direct.iter ( ) .copied ( ) .collect ( ) ;
560
}
ff0af1ee unknown 1 month ago
561
let mut out = BTreeSet:: new( ) ;
598009a7 Andy McCall 1 month ago ↶
562
let mut stack: Vec< Vertex> = direct.to_vec ( ) ;
0bdc3f91 Andy McCall 1 month ago ↶
563
let mut seen = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
564
while let Some ( s) = stack.pop ( ) {
565
if kept.contains ( & s) {
566
out.insert ( s) ;
567
} else if seen.insert ( s) {
568
if let Some ( m) = memo.get ( & s) {
569
out.extend ( m.iter ( ) .copied ( ) ) ;
570
} else if let Some ( next) = self .succ.get ( & s) {
571
stack.extend ( next.iter ( ) .copied ( ) ) ;
572
}
573
}
574
}
575
out
598009a7 Andy McCall 1 month ago ↶
576
}
577
578
579
580
581
582
583
fn as_chain ( & self ) -> Option< Vec< AtomKey> > {
584
if self
585
.atoms
586
.values ( )
587
.any ( | a | a.content.is_none ( ) | | ! a.deleted_by.is_empty ( ) )
588
{
589
return None ;
590
}
591
let mut order = Vec :: with_capacity( self .atoms.len ( ) ) ;
592
let mut v = Vertex:: Start;
593
loop {
594
let succ = self .succ.get ( & v) ? .as_slice ( ) ;
595
let mut atoms = succ.iter ( ) .filter ( | s | * * s ! = Vertex:: End) ;
596
match ( atoms.next ( ) , atoms.next ( ) ) {
597
( None , _ ) if succ.contains ( & Vertex:: End) => break ,
598
( Some ( Vertex:: Atom( k) ) , None ) if order.len ( ) < self .atoms.len ( ) => {
599
order.push ( * k) ;
600
v = Vertex:: Atom( * k) ;
601
}
602
_ => return None ,
603
}
604
}
605
( order.len ( ) = = self .atoms.len ( ) ) .then_some ( order)
ff0af1ee unknown 1 month ago
606
}
607
608
609
pub fn materialize ( & self , deps : & dyn DepOracle) -> Materialized {
aedfe465 Andy McCall 25 days ago ↶
610
let deps = & MemoDeps {
611
inner: deps,
612
known: Default :: default( ) ,
613
} ;
dbf06d34 Andy McCall 1 month ago ↶
614
let lines = | order : Vec< AtomKey> | Materialized {
615
segments: if order.is_empty ( ) {
616
vec! [ ]
617
} else {
618
vec! [ Segment:: Lines( order) ]
619
} ,
620
} ;
621
use std:: sync:: atomic:: Ordering:: Relaxed;
40a40bb7 Andy McCall 1 month ago ↶
622
623
let started = crate :: timing:: enabled( ) .then ( std:: time:: Instant:: now) ;
624
let took = | name : & 'static str | {
625
if let Some ( t) = started {
626
crate :: timing:: add( name, t.elapsed ( ) ) ;
627
}
628
} ;
dbf06d34 Andy McCall 1 month ago ↶
629
if let Some ( o) = self .order.get ( ) {
630
let holds = o.confirmed.load ( Relaxed)
631
| | o.unchecked.iter ( ) .all ( | k | {
632
self .atoms
633
.get ( k)
634
.is_none_or ( | info | ! self .is_ghost ( k, info, deps) )
635
} ) ;
636
if holds {
637
o.confirmed.store ( true , Relaxed) ;
40a40bb7 Andy McCall 1 month ago ↶
638
took ( " graph: kept order" ) ;
dbf06d34 Andy McCall 1 month ago ↶
639
return lines ( o.atoms.clone ( ) ) ;
640
}
641
self .order.set ( None ) ;
642
}
643
644
645
if let Some ( order) = self .as_chain ( ) {
40a40bb7 Andy McCall 1 month ago ↶
646
took ( " graph: chain" ) ;
dbf06d34 Andy McCall 1 month ago ↶
647
return lines ( order) ;
598009a7 Andy McCall 1 month ago ↶
648
}
dbf06d34 Andy McCall 1 month ago ↶
649
if let Some ( order) = self .as_order ( deps) {
650
self .order
651
.set ( Some ( std:: sync:: Arc:: new( Order:: known( order.clone ( ) ) ) ) ) ;
40a40bb7 Andy McCall 1 month ago ↶
652
took ( " graph: single order" ) ;
dbf06d34 Andy McCall 1 month ago ↶
653
return lines ( order) ;
654
}
40a40bb7 Andy McCall 1 month ago ↶
655
let m = self .materialize_general ( deps) ;
656
took ( " graph: general" ) ;
657
m
dbf06d34 Andy McCall 1 month ago ↶
658
}
659
660
661
662
pub fn take_order ( & mut self ) -> Option< std:: sync:: Arc< Order> > {
663
self .order.take ( )
664
}
665
7eac74ab Andy McCall 1 month ago ↶
666
667
668
669
670
pub fn keep_spliced (
671
& mut self ,
672
order : std:: sync:: Arc< Order> ,
673
h : ChangeHash,
674
inserts : & [( Vertex , Vertex , u32 , u32 ) ],
675
deleted : & [AtomKey],
676
) {
677
let live = inserts
678
.iter ( )
679
.all ( | & ( _, _, first , count ) | ( first.. first + count) .all ( | i | self .is_live ( & ( h, i) ) ) ) ;
680
let spliced = if live {
681
order.splice ( h, inserts, deleted)
682
} else {
683
None
684
} ;
685
* self .order.0. get_mut ( ) .unwrap_or_else ( | e | e.into_inner ( ) ) = spliced;
598009a7 Andy McCall 1 month ago ↶
686
}
687
e83354cd Andy McCall 1 month ago ↶
688
689
690
691
692
693
694
fn as_order ( & self , deps : & dyn DepOracle) -> Option< Vec< AtomKey> > {
695
696
let mut index: HashMap< Vertex, u32 > =
697
HashMap:: with_capacity_and_hasher( self .atoms.len ( ) + 2 , Default :: default( ) ) ;
698
let mut verts: Vec< Vertex> = Vec :: with_capacity( self .atoms.len ( ) + 2 ) ;
699
verts.extend ( [ Vertex:: Start, Vertex:: End] ) ;
700
index.insert ( Vertex:: Start, 0 ) ;
701
index.insert ( Vertex:: End, 1 ) ;
702
for ( k, info) in & self .atoms {
703
if info.content.is_none ( ) {
704
continue ;
705
}
706
if info.deleted_by.is_empty ( ) {
707
index.insert ( Vertex:: Atom( * k) , verts.len ( ) as u32 ) ;
708
verts.push ( Vertex:: Atom( * k) ) ;
709
} else if self .is_ghost ( k, info, deps) {
710
return None ;
711
}
712
}
713
714
715
let mut reach: HashMap< Vertex, Vec< u32 > > = HashMap:: default( ) ;
716
let contracted = | v : Vertex, reach : & mut HashMap< Vertex, Vec< u32 > > | {
717
let mut stack: Vec< ( Vertex, bool ) > = vec! [ ( v, false ) ] ;
718
while let Some ( ( x, done) ) = stack.pop ( ) {
719
if reach.contains_key ( & x) {
720
continue ;
721
}
722
let next = self .succ.get ( & x) .map ( Edges:: as_slice) .unwrap_or_default ( ) ;
723
if ! done {
724
stack.push ( ( x, true ) ) ;
725
for s in next {
726
if ! index.contains_key ( s) & & ! reach.contains_key ( s) {
727
stack.push ( ( * s, false ) ) ;
728
}
729
}
730
continue ;
731
}
732
let mut out: Vec< u32 > = Vec :: new( ) ;
733
for s in next {
734
match index.get ( s) {
735
Some ( i) => out.push ( * i) ,
736
None => out.extend ( reach.get ( s) .into_iter ( ) .flatten ( ) ) ,
737
}
738
}
739
out.sort_unstable ( ) ;
740
out.dedup ( ) ;
741
reach.insert ( x, out) ;
742
}
743
} ;
744
745
let mut succ: Vec< u32 > = Vec :: with_capacity( verts.len ( ) * 2 ) ;
746
let mut starts: Vec< usize > = Vec :: with_capacity( verts.len ( ) + 1 ) ;
747
let mut indeg: Vec< u32 > = vec! [ 0 ; verts.len ( ) ] ;
748
for v in & verts {
749
let from = succ.len ( ) ;
750
starts.push ( from) ;
751
for s in self .succ.get ( v) .map ( Edges:: as_slice) .unwrap_or_default ( ) {
752
match index.get ( s) {
753
Some ( i) => succ.push ( * i) ,
754
None => {
755
contracted ( * s, & mut reach) ;
756
succ.extend ( reach.get ( s) .into_iter ( ) .flatten ( ) ) ;
757
}
758
}
759
}
760
if succ.len ( ) - from > 1 {
761
succ[ from.. ] .sort_unstable ( ) ;
762
let mut kept = from;
763
for i in from.. succ.len ( ) {
764
if i = = from | | succ[ i] ! = succ[ kept - 1 ] {
765
succ[ kept] = succ[ i] ;
766
kept + = 1 ;
767
}
768
}
769
succ.truncate ( kept) ;
770
}
771
for & w in & succ[ from.. ] {
772
indeg[ w as usize ] + = 1 ;
773
}
774
}
775
starts.push ( succ.len ( ) ) ;
776
777
let mut ready: Vec< u32 > = ( 0 .. verts.len ( ) as u32 )
778
.filter ( | & i | indeg[ i as usize ] = = 0 )
779
.collect ( ) ;
780
let mut order: Vec< AtomKey> = Vec :: with_capacity( verts.len ( ) ) ;
781
let mut seen = 0 ;
782
while let Some ( v) = ready.pop ( ) {
783
if ! ready.is_empty ( ) {
784
return None ;
785
}
786
seen + = 1 ;
787
if let Vertex:: Atom( k) = verts[ v as usize ] {
788
order.push ( k) ;
789
}
790
for & w in & succ[ starts[ v as usize ] .. starts[ v as usize + 1 ] ] {
791
indeg[ w as usize ] - = 1 ;
792
if indeg[ w as usize ] = = 0 {
793
ready.push ( w) ;
794
}
795
}
796
if ready.len ( ) > 1 {
797
return None ;
798
}
799
}
800
( seen = = verts.len ( ) ) .then_some ( order)
801
}
802
598009a7 Andy McCall 1 month ago ↶
803
804
805
fn materialize_general ( & self , deps : & dyn DepOracle) -> Materialized {
ff0af1ee unknown 1 month ago
806
0bdc3f91 Andy McCall 1 month ago ↶
807
let mut kept: HashSet< Vertex> = HashSet:: default( ) ;
808
let mut ghosts: HashSet< AtomKey> = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
809
kept.insert ( Vertex:: Start) ;
810
kept.insert ( Vertex:: End) ;
811
for ( k, info) in & self .atoms {
812
if info.content.is_none ( ) {
813
continue ;
814
}
815
if info.deleted_by.is_empty ( ) {
816
kept.insert ( Vertex:: Atom( * k) ) ;
817
} else if self .is_ghost ( k, info, deps) {
818
kept.insert ( Vertex:: Atom( * k) ) ;
819
ghosts.insert ( * k) ;
820
}
821
}
822
823
0bdc3f91 Andy McCall 1 month ago ↶
824
let mut memo = HashMap:: default( ) ;
825
let mut rsucc: HashMap< Vertex, BTreeSet< Vertex> > = HashMap:: default( ) ;
826
let mut indeg: HashMap< Vertex, usize > = HashMap:: default( ) ;
ff0af1ee unknown 1 month ago
827
for & u in & kept {
828
indeg.entry ( u) .or_insert ( 0 ) ;
829
let rs = self .reduced_succ ( u, & kept, & mut memo) ;
830
for & w in & rs {
831
* indeg.entry ( w) .or_insert ( 0 ) + = 1 ;
832
}
833
rsucc.insert ( u, rs) ;
834
}
835
836
75167672 Andy McCall 1 month ago
837
let mut ready: BTreeSet< Vertex> = indeg
838
.iter ( )
839
.filter ( | ( _, &d ) | d = = 0 )
840
.map ( | ( v , _) | * v)
841
.collect ( ) ;
0bdc3f91 Andy McCall 1 month ago ↶
842
let mut side: HashMap< Vertex, u32 > = HashMap:: default( ) ;
843
let mut joins: HashSet< Vertex> = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
844
let mut next_side = 0 u32 ;
845
let mut plain: Vec< Vertex> = Vec :: new( ) ;
846
let mut conflict: Option< BTreeMap< u32 , Vec< Vertex> > > = None ;
847
let mut segments: Vec< Segment> = Vec :: new( ) ;
848
849
let flush_plain = | plain : & mut Vec< Vertex> , segments : & mut Vec< Segment> | {
75167672 Andy McCall 1 month ago
850
let atoms: Vec< AtomKey> = plain
851
.iter ( )
852
.filter_map ( | v | {
853
if let Vertex:: Atom( k) = v {
854
Some ( * k)
855
} else {
856
None
857
}
858
} )
859
.collect ( ) ;
ff0af1ee unknown 1 month ago
860
plain.clear ( ) ;
861
if ! atoms.is_empty ( ) {
862
segments.extend ( split_zombies ( atoms, & ghosts) ) ;
863
}
864
} ;
865
let finish_conflict = | c : BTreeMap< u32 , Vec< Vertex> > , segments : & mut Vec< Segment> | {
866
let sides: Vec< Vec< AtomKey> > = c
867
.into_values ( )
868
.map ( | vs | {
869
vs.into_iter ( )
870
.filter_map ( | v | match v {
871
Vertex:: Atom( k) if ! ghosts.contains ( & k) => Some ( k) ,
872
_ => None ,
873
} )
874
.collect:: < Vec< _ > > ( )
875
} )
876
.filter ( | s | ! s.is_empty ( ) )
877
.collect ( ) ;
878
match sides.len ( ) {
879
0 => { }
880
1 => segments.push ( Segment:: Lines( sides.into_iter ( ) .next ( ) .unwrap ( ) ) ) ,
881
_ => segments.push ( Segment:: Conflict( sides) ) ,
882
}
883
} ;
884
885
while ! ready.is_empty ( ) {
886
if ready.len ( ) > = 2 {
887
if conflict.is_none ( ) {
888
flush_plain ( & mut plain, & mut segments) ;
889
conflict = Some ( BTreeMap:: new( ) ) ;
890
}
891
for r in & ready {
892
if ! side.contains_key ( r) {
893
side.insert ( * r, next_side) ;
894
next_side + = 1 ;
895
}
896
}
897
}
898
let v = ready.pop_first ( ) .unwrap ( ) ;
899
let my_side = side.get ( & v) .copied ( ) ;
900
match ( & mut conflict, my_side) {
901
( Some ( c) , Some ( s) ) => c.entry ( s) .or_default ( ) .push ( v) ,
902
( Some ( _ ) , None ) => {
903
let c = conflict.take ( ) .unwrap ( ) ;
904
finish_conflict ( c, & mut segments) ;
905
plain.push ( v) ;
906
}
907
( None , _ ) => plain.push ( v) ,
908
}
909
for & w in & rsucc[ & v] {
910
let d = indeg.get_mut ( & w) .unwrap ( ) ;
911
* d - = 1 ;
912
if conflict.is_some ( ) & & ! joins.contains ( & w) {
913
match ( my_side, side.get ( & w) .copied ( ) ) {
914
( Some ( s) , None ) => {
915
side.insert ( w, s) ;
916
}
917
( Some ( s) , Some ( t) ) if s ! = t => {
918
side.remove ( & w) ;
919
joins.insert ( w) ;
920
}
921
( None , Some ( _ ) ) => {
922
side.remove ( & w) ;
923
joins.insert ( w) ;
924
}
925
_ => { }
926
}
927
}
928
if * d = = 0 {
929
ready.insert ( w) ;
930
}
931
}
932
}
933
if let Some ( c) = conflict.take ( ) {
934
finish_conflict ( c, & mut segments) ;
935
}
936
flush_plain ( & mut plain, & mut segments) ;
937
Materialized { segments }
938
}
939
940
941
942
pub fn render ( & self , m : & Materialized, label : & dyn Fn( &ChangeHash ) -> String) -> Vec< u8 > {
943
let total = m.conflict_count ( ) ;
944
let mut n = 0 ;
945
let mut out: Vec< u8 > = Vec :: new( ) ;
946
let push_atoms = | out : & mut Vec< u8 > , atoms : & [AtomKey]| {
947
for a in atoms {
948
if let Some ( c) = self .content ( a) {
949
out.extend_from_slice ( c) ;
950
}
951
}
952
} ;
953
let newline_if_needed = | out : & mut Vec< u8 > | {
954
if ! out.is_empty ( ) & & * out.last ( ) .unwrap ( ) ! = b ' \n ' {
955
out.push ( b ' \n ' ) ;
956
}
957
} ;
958
for seg in & m.segments {
959
match seg {
960
Segment:: Lines( a) => push_atoms ( & mut out, a) ,
961
Segment:: Conflict( sides) => {
962
n + = 1 ;
963
let k = sides.len ( ) ;
964
for ( i, s) in sides.iter ( ) .enumerate ( ) {
965
newline_if_needed ( & mut out) ;
966
let who = s.first ( ) .map ( | a | label ( & a.0 ) ) .unwrap_or_default ( ) ;
967
let marker = if i = = 0 { " <<<<<<<" } else { " =======" } ;
968
out.extend_from_slice (
969
format! ( " {marker} oxy conflict {n} of {total} , side {} of {k} : change {who} \n " , i + 1 ) .as_bytes ( ) ,
970
) ;
971
push_atoms ( & mut out, s) ;
972
}
973
newline_if_needed ( & mut out) ;
75167672 Andy McCall 1 month ago
974
out.extend_from_slice (
975
format! ( " >>>>>>> oxy conflict {n} of {total} end\n " ) .as_bytes ( ) ,
976
) ;
ff0af1ee unknown 1 month ago
977
}
978
Segment:: Zombie { deleted, inserted } => {
979
n + = 1 ;
980
newline_if_needed ( & mut out) ;
981
let deleter = deleted
982
.first ( )
983
.and_then ( | a | self .deleters ( a) .next ( ) .copied ( ) )
984
.map ( | d | label ( & d) )
985
.unwrap_or_default ( ) ;
986
let inserter = inserted.first ( ) .map ( | a | label ( & a.0 ) ) .unwrap_or_default ( ) ;
987
out.extend_from_slice (
988
format! ( " <<<<<<< oxy conflict {n} of {total} , side 1 of 2: deleted by change {deleter} \n -------\n " ) .as_bytes ( ) ,
989
) ;
990
push_atoms ( & mut out, deleted) ;
991
newline_if_needed ( & mut out) ;
75167672 Andy McCall 1 month ago
992
out.extend_from_slice (
993
format! (
994
" ======= oxy conflict {n} of {total} , side 2 of 2: change {inserter} \n "
995
)
996
.as_bytes ( ) ,
997
) ;
ff0af1ee unknown 1 month ago
998
push_atoms ( & mut out, inserted) ;
999
newline_if_needed ( & mut out) ;
75167672 Andy McCall 1 month ago
1000
out.extend_from_slice (
1001
format! ( " >>>>>>> oxy conflict {n} of {total} end\n " ) .as_bytes ( ) ,
1002
) ;
ff0af1ee unknown 1 month ago
1003
}
1004
}
1005
}
1006
out
1007
}
1008
}
1009
252e8cb2 Andy McCall 1 month ago ↶
1010
fn vertex_value ( v : & Vertex) -> crate:: cbor:: Value {
1011
use crate :: cbor:: Value;
1012
match v {
1013
Vertex:: Start => Value:: Uint( 0 ) ,
1014
Vertex:: End => Value:: Uint( 1 ) ,
75167672 Andy McCall 1 month ago
1015
Vertex:: Atom( ( c, i) ) => {
1016
Value:: Array( vec! [ Value:: Bytes( c.0. to_vec ( ) ) , Value:: Uint( * i as u64 ) ] )
1017
}
252e8cb2 Andy McCall 1 month ago ↶
1018
}
1019
}
1020
1021
fn vertex_from ( v : & crate:: cbor:: Value) -> Result< Vertex, crate:: objects:: ObjectError> {
1022
use crate :: cbor:: Value;
1023
use crate :: objects:: ObjectError;
1024
match v {
1025
Value:: Uint( 0 ) => Ok ( Vertex:: Start) ,
1026
Value:: Uint( 1 ) => Ok ( Vertex:: End) ,
75167672 Andy McCall 1 month ago
1027
Value:: Array( a) if a.len ( ) = = 2 => Ok ( Vertex:: Atom( (
1028
crate :: objects:: oref( & a[ 0 ] , " vertex" ) ? ,
1029
crate :: objects:: u32_( & a[ 1 ] , " vertex" ) ? ,
1030
) ) ) ,
1031
_ => Err ( ObjectError:: Schema(
1032
" vertex: expected 0, 1, or [hash, index]" .into ( ) ,
1033
) ) ,
252e8cb2 Andy McCall 1 month ago ↶
1034
}
1035
}
1036
1037
impl FileGraph {
1038
1039
pub fn to_value ( & self ) -> crate:: cbor:: Value {
1040
use crate :: cbor:: Value;
1041
let mut atoms: Vec< ( & AtomKey, & AtomInfo) > = self .atoms.iter ( ) .collect ( ) ;
1042
atoms.sort_by_key ( | ( k , _) | * * k) ;
75167672 Andy McCall 1 month ago
1043
let mut edges: Vec< ( Vertex, Vertex) > = self
1044
.succ
1045
.iter ( )
1046
.flat_map ( | ( a , bs ) | bs.iter ( ) .map ( move | b| ( * a, * b) ) )
1047
.collect ( ) ;
252e8cb2 Andy McCall 1 month ago ↶
1048
edges.sort ( ) ;
1049
Value:: map( [
1050
(
1051
0 ,
1052
Value:: Array(
1053
atoms
1054
.into_iter ( )
1055
.map ( | ( (c , i ) , info) | {
1056
Value:: Array( vec! [
1057
Value:: Bytes( c.0. to_vec ( ) ) ,
1058
Value:: Uint( * i as u64 ) ,
75167672 Andy McCall 1 month ago
1059
info.content
1060
.as_ref ( )
01a47cd7 Andy McCall 1 month ago ↶
1061
.map ( | b | Value:: Bytes( b.bytes ( ) .to_vec ( ) ) )
75167672 Andy McCall 1 month ago
1062
.unwrap_or ( Value:: Null) ,
1063
Value:: Array(
1064
info.deleted_by
1065
.iter ( )
1066
.map ( | d | Value:: Bytes( d.0. to_vec ( ) ) )
1067
.collect ( ) ,
1068
) ,
252e8cb2 Andy McCall 1 month ago ↶
1069
] )
1070
} )
1071
.collect ( ) ,
1072
) ,
1073
),
75167672 Andy McCall 1 month ago
1074
(
1075
1 ,
1076
Value:: Array(
1077
edges
1078
.iter ( )
1079
.map ( | ( a , b ) | Value:: Array( vec! [ vertex_value ( a) , vertex_value ( b) ] ) )
1080
.collect ( ) ,
1081
) ,
1082
) ,
252e8cb2 Andy McCall 1 month ago ↶
1083
] )
1084
}
1085
1086
pub fn from_value ( v : & crate:: cbor:: Value) -> Result< FileGraph, crate:: objects:: ObjectError> {
1087
use crate :: objects:: { array, bytes, field, map, oref, u32_, ObjectError} ;
1088
let m = map ( v, " file graph" ) ? ;
75167672 Andy McCall 1 month ago
1089
let mut g = FileGraph {
0bdc3f91 Andy McCall 1 month ago ↶
1090
atoms: HashMap:: default( ) ,
1091
succ: HashMap:: default( ) ,
dbf06d34 Andy McCall 1 month ago ↶
1092
order: OrderSlot:: default( ) ,
75167672 Andy McCall 1 month ago
1093
} ;
01a47cd7 Andy McCall 1 month ago ↶
1094
let atoms = array ( field ( m, 0 , " atoms" ) ? , " atoms" ) ? ;
1095
1096
let mut texts: Vec< & [ u8 ] > = Vec :: new( ) ;
1097
for a in atoms {
1098
let e = array ( a, " atom" ) ? ;
1099
if e.len ( ) = = 4 & & ! e[ 2 ] .is_null ( ) {
1100
texts.push ( bytes ( & e[ 2 ] , " atom content" ) ? ) ;
1101
}
1102
}
1103
let all: Lines = texts.into_iter ( ) .collect ( ) ;
1104
let mut next = 0 u32 ;
1105
for a in atoms {
252e8cb2 Andy McCall 1 month ago ↶
1106
let e = array ( a, " atom" ) ? ;
1107
if e.len ( ) ! = 4 {
1108
return Err ( ObjectError:: Schema( " atom: expected 4 fields" .into ( ) ) ) ;
1109
}
1110
let key = ( oref ( & e[ 0 ] , " atom change" ) ? , u32_ ( & e[ 1 ] , " atom index" ) ? ) ;
75167672 Andy McCall 1 month ago
1111
let content = if e[ 2 ] .is_null ( ) {
1112
None
1113
} else {
01a47cd7 Andy McCall 1 month ago ↶
1114
next + = 1 ;
1115
Some ( LineRef:: new( all.clone ( ) , next - 1 ) )
75167672 Andy McCall 1 month ago
1116
} ;
1117
let deleted_by = array ( & e[ 3 ] , " deleters" ) ?
1118
.iter ( )
1119
.map ( | d | oref ( d, " deleter" ) )
1120
.collect:: < Result< BTreeSet< _ > , _ > > ( ) ? ;
1121
g.atoms.insert (
1122
key,
1123
AtomInfo {
1124
content,
1125
deleted_by,
1126
} ,
1127
) ;
252e8cb2 Andy McCall 1 month ago ↶
1128
}
1129
for e in array ( field ( m, 1 , " edges" ) ? , " edges" ) ? {
1130
let pair = array ( e, " edge" ) ? ;
1131
if pair.len ( ) ! = 2 {
1132
return Err ( ObjectError:: Schema( " edge: expected [from, to]" .into ( ) ) ) ;
1133
}
1134
g.edge ( vertex_from ( & pair[ 0 ] ) ? , vertex_from ( & pair[ 1 ] ) ? ) ;
1135
}
1136
Ok ( g)
1137
}
1138
}
1139
ff0af1ee unknown 1 month ago
1140
1141
fn split_zombies ( atoms : Vec< AtomKey> , ghosts : & HashSet< AtomKey> ) -> Vec< Segment> {
1142
let mut out = Vec :: new( ) ;
1143
let mut lines: Vec< AtomKey> = Vec :: new( ) ;
1144
let mut i = 0 ;
1145
while i < atoms.len ( ) {
1146
if ! ghosts.contains ( & atoms[ i] ) {
1147
lines.push ( atoms[ i] ) ;
1148
i + = 1 ;
1149
continue ;
1150
}
1151
if ! lines.is_empty ( ) {
1152
out.push ( Segment:: Lines( std:: mem:: take( & mut lines) ) ) ;
1153
}
1154
let mut deleted = Vec :: new( ) ;
1155
while i < atoms.len ( ) & & ghosts.contains ( & atoms[ i] ) {
1156
deleted.push ( atoms[ i] ) ;
1157
i + = 1 ;
1158
}
1159
let mut inserted = Vec :: new( ) ;
1160
if i < atoms.len ( ) {
1161
let ch = atoms[ i] .0 ;
1162
while i < atoms.len ( ) & & atoms[ i] .0 = = ch & & ! ghosts.contains ( & atoms[ i] ) {
1163
inserted.push ( atoms[ i] ) ;
1164
i + = 1 ;
1165
}
1166
}
1167
out.push ( Segment:: Zombie { deleted, inserted } ) ;
1168
}
1169
if ! lines.is_empty ( ) {
1170
out.push ( Segment:: Lines( lines) ) ;
1171
}
1172
out
1173
}
1174
1175
# [ cfg ( test ) ]
1176
mod tests {
1177
use super :: * ;
1178
use crate :: hash:: ObjectRef;
1179
1180
fn h ( n : u8 ) -> ChangeHash {
1181
ObjectRef( [ n; 32 ] )
1182
}
01a47cd7 Andy McCall 1 month ago ↶
1183
fn lines ( v : & [& str ]) -> Lines {
1184
v.iter ( ) .map ( | s | s.as_bytes ( ) ) .collect ( )
ff0af1ee unknown 1 month ago
1185
}
1186
fn text ( g : & FileGraph, m : & Materialized) -> String {
1187
String :: from_utf8( g.render ( m, & | c| c.short ( 4 ) ) ) .unwrap ( )
1188
}
1189
1190
struct Deps ( HashMap< ChangeHash, Vec< ChangeHash> > ) ;
1191
impl DepOracle for Deps {
1192
fn depends_on ( & self , a : & ChangeHash, b : & ChangeHash) -> bool {
1193
if a = = b {
1194
return true ;
1195
}
1196
let mut stack = vec! [ * a] ;
0bdc3f91 Andy McCall 1 month ago ↶
1197
let mut seen = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
1198
while let Some ( x) = stack.pop ( ) {
1199
if let Some ( ds) = self .0. get ( & x) {
1200
for d in ds {
1201
if d = = b {
1202
return true ;
1203
}
1204
if seen.insert ( * d) {
1205
stack.push ( * d) ;
1206
}
1207
}
1208
}
1209
}
1210
false
e83354cd Andy McCall 1 month ago ↶
1211
}
1212
}
1213
1214
1215
struct Linear ;
1216
impl DepOracle for Linear {
1217
fn depends_on ( & self , a : & ChangeHash, b : & ChangeHash) -> bool {
1218
a.0 [ .. 2 ] > = b.0 [ .. 2 ]
1219
}
1220
}
1221
1222
1223
1224
fn edited_file ( n : usize , revs : usize , per : usize ) -> FileGraph {
1225
let hn = | i : usize | {
1226
let mut b = [ 0 u8 ; 32 ] ;
1227
b[ .. 2 ] .copy_from_slice ( & ( i as u16 ) .to_be_bytes ( ) ) ;
1228
ObjectRef( b)
1229
} ;
1230
let mut g = FileGraph:: new( ) ;
1231
let first: Vec< String> = ( 0 .. n) .map ( | i | format! ( " line {i} \n " ) ) .collect ( ) ;
1232
let first: Vec< & str > = first.iter ( ) .map ( String :: as_str) .collect ( ) ;
1233
g.insert ( hn ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & first) ) ;
1234
for r in 2 .. revs + 2 {
1235
let order = g.materialize ( & Linear) .live_atoms ( ) ;
1236
let step = order.len ( ) / per;
1237
for j in 0 .. per {
1238
let at = j * step + ( r % step.max ( 1 ) ) ;
1239
let k = order[ at] ;
1240
g.delete (
1241
hn ( r) ,
1242
& AtomRange {
1243
change: k.0 ,
1244
from: k.1 ,
1245
to: k.1 + 1 ,
1246
} ,
1247
) ;
1248
let after = if at = = 0 {
1249
Vertex:: Start
1250
} else {
1251
Vertex:: Atom( order[ at - 1 ] )
1252
} ;
1253
let before = order
1254
.get ( at + 1 )
1255
.map ( | k | Vertex:: Atom( * k) )
1256
.unwrap_or ( Vertex:: End) ;
1257
g.insert ( hn ( r) , j as u32 , after, before, & lines ( & [ " new\n " ] ) ) ;
1258
}
ff0af1ee unknown 1 month ago
1259
}
e83354cd Andy McCall 1 month ago ↶
1260
g
1261
}
1262
1263
1264
# [ test ]
1265
fn the_order_shortcut_agrees_with_the_general_order ( ) {
1266
let g = edited_file ( 500 , 10 , 20 ) ;
1267
assert! ( g.as_chain ( ) .is_none ( ) ) ;
1268
let fast = g.as_order ( & Linear) .expect ( " a single order" ) ;
1269
assert_eq! (
1270
Materialized {
1271
segments: vec! [ Segment:: Lines( fast) ]
1272
} ,
1273
g.materialize_general ( & Linear)
1274
) ;
1275
1276
1277
let mut g = FileGraph:: new( ) ;
1278
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " ] ) ) ;
1279
let a = Vertex:: Atom( ( h ( 1 ) , 0 ) ) ;
1280
g.insert ( h ( 2 ) , 0 , a, Vertex:: End, & lines ( & [ " b\n " ] ) ) ;
1281
g.insert ( h ( 3 ) , 0 , a, Vertex:: End, & lines ( & [ " c\n " ] ) ) ;
1282
assert! ( g.as_order ( & NoDeps) .is_none ( ) ) ;
1283
assert! ( g.materialize ( & NoDeps) .is_conflicted ( ) ) ;
dbf06d34 Andy McCall 1 month ago ↶
1284
}
1285
1286
1287
1288
fn apply_spliced (
1289
g : & mut FileGraph,
1290
h : ChangeHash,
1291
inserts : & [( Vertex , Vertex , usize ) ],
1292
deleted : & [AtomKey],
1293
) {
1294
let order = g.take_order ( ) ;
1295
let mut runs = Vec :: new( ) ;
1296
let mut next = 0 u32 ;
1297
for ( i, & ( a, b, n) ) in inserts.iter ( ) .enumerate ( ) {
1298
let text: Vec< String> = ( 0 .. n) .map ( | j | format! ( " {i} .{j} \n " ) ) .collect ( ) ;
1299
let text: Vec< & str > = text.iter ( ) .map ( String :: as_str) .collect ( ) ;
1300
g.insert ( h, next, a, b, & lines ( & text) ) ;
1301
runs.push ( ( a, b, next, n as u32 ) ) ;
1302
next + = n as u32 ;
1303
}
1304
for k in deleted {
1305
g.delete (
1306
h,
1307
& AtomRange {
1308
change: k.0 ,
1309
from: k.1 ,
1310
to: k.1 + 1 ,
1311
} ,
1312
) ;
1313
}
1314
if let Some ( o) = order {
7eac74ab Andy McCall 1 month ago ↶
1315
g.keep_spliced ( o, h, & runs, deleted) ;
dbf06d34 Andy McCall 1 month ago ↶
1316
}
1317
}
1318
1319
1320
1321
fn random_edits (
1322
l : & [AtomKey],
1323
rnd : & mut impl FnMut( usize ) -> usize ,
1324
) -> ( Vec< ( Vertex, Vertex, usize ) > , Vec< AtomKey> ) {
1325
let ( mut inserts, mut deleted) = ( Vec :: new( ) , Vec :: new( ) ) ;
1326
let mut i = rnd ( 3 ) ;
1327
while i < = l.len ( ) {
1328
let del = rnd ( 3 ) .min ( l.len ( ) - i) ;
1329
let add = rnd ( 3 ) ;
1330
let after = if i = = 0 {
1331
Vertex:: Start
1332
} else {
1333
Vertex:: Atom( l[ i - 1 ] )
1334
} ;
1335
let before = l.get ( i) .map ( | k | Vertex:: Atom( * k) ) .unwrap_or ( Vertex:: End) ;
1336
deleted.extend ( & l[ i.. i + del] ) ;
1337
if add > 0 {
1338
inserts.push ( ( after, before, add) ) ;
1339
}
1340
i + = del + 1 + rnd ( 6 ) ;
1341
}
1342
( inserts, deleted)
1343
}
1344
1345
1346
1347
1348
# [ test ]
1349
fn the_kept_order_follows_edits ( ) {
1350
let hn = | i : usize | {
1351
let mut b = [ 0 u8 ; 32 ] ;
1352
b[ .. 2 ] .copy_from_slice ( & ( i as u16 ) .to_be_bytes ( ) ) ;
1353
ObjectRef( b)
1354
} ;
1355
let mut seed = 7 u64 ;
1356
let mut rnd = move | n: usize | {
1357
seed = seed
1358
.wrapping_mul ( 6364136223846793005 )
1359
.wrapping_add ( 1442695040888963407 ) ;
1360
( ( seed > > 33 ) as usize ) % n.max ( 1 )
1361
} ;
1362
let mut deps = Deps( HashMap:: default( ) ) ;
1363
let mut g = FileGraph:: new( ) ;
1364
let first: Vec< String> = ( 0 .. 40 ) .map ( | i | format! ( " {i} \n " ) ) .collect ( ) ;
1365
let first: Vec< & str > = first.iter ( ) .map ( String :: as_str) .collect ( ) ;
1366
g.insert ( hn ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & first) ) ;
1367
let mut known: Vec< ChangeHash> = vec! [ hn ( 1 ) ] ;
1368
let mut c = 2 ;
1369
let ( mut spliced, mut conflicted) = ( 0 , 0 ) ;
1370
for step in 0 .. 400 {
1371
let l = g.materialize ( & deps) .live_atoms ( ) ;
1372
1373
1374
let pair = step % 7 = = 3 ;
1375
let base = known.clone ( ) ;
1376
for _ in 0 .. if pair { 2 } else { 1 } {
1377
let h = hn ( c) ;
1378
c + = 1 ;
1379
let ( inserts, deleted) = random_edits ( & l, & mut rnd) ;
1380
deps.0. insert ( h, base.clone ( ) ) ;
1381
apply_spliced ( & mut g, h, & inserts, & deleted) ;
1382
known.push ( h) ;
1383
if g.order.get ( ) .is_some ( ) {
1384
spliced + = 1 ;
1385
}
1386
let m = g.materialize ( & deps) ;
1387
assert_eq! ( m, g.materialize_general ( & deps) , " step {step}" ) ;
1388
if m.is_conflicted ( ) {
1389
conflicted + = 1 ;
1390
}
1391
}
1392
1393
1394
if g.materialize ( & deps) .is_conflicted ( ) {
1395
let h = hn ( c) ;
1396
c + = 1 ;
1397
let all = g.materialize ( & deps) .live_atoms ( ) ;
1398
deps.0. insert ( h, known.clone ( ) ) ;
1399
apply_spliced ( & mut g, h, & [ ( Vertex:: Start, Vertex:: End, 5 ) ] , & all) ;
1400
known.push ( h) ;
1401
assert_eq! ( g.materialize ( & deps) , g.materialize_general ( & deps) ) ;
1402
}
1403
}
1404
assert! (
1405
spliced > 100 & & conflicted > 0 ,
1406
" {spliced} spliced, {conflicted} conflicted"
1407
) ;
7eac74ab Andy McCall 1 month ago ↶
1408
}
1409
1410
1411
1412
1413
# [ test ]
1414
fn the_kept_order_takes_no_line_that_arrives_deleted ( ) {
1415
let mut deps = Deps( HashMap:: default( ) ) ;
1416
let mut g = FileGraph:: new( ) ;
1417
g.insert (
1418
h ( 1 ) ,
1419
0 ,
1420
Vertex:: Start,
1421
Vertex:: End,
1422
& lines ( & [ " a\n " , " b\n " , " c\n " ] ) ,
1423
) ;
1424
1425
apply_spliced ( & mut g, h ( 2 ) , & [ ] , & [ ( h ( 1 ) , 2 ) ] ) ;
1426
deps.0. insert ( h ( 2 ) , vec! [ h ( 1 ) ] ) ;
1427
let _ = g.materialize ( & deps) ;
1428
assert! ( g.order.get ( ) .is_some ( ) ) ;
1429
let ( a, b) = ( Vertex:: Atom( ( h ( 1 ) , 0 ) ) , Vertex:: Atom( ( h ( 1 ) , 1 ) ) ) ;
1430
1431
deps.0. insert ( h ( 3 ) , vec! [ h ( 2 ) ] ) ;
1432
deps.0. insert ( h ( 4 ) , vec! [ h ( 3 ) ] ) ;
1433
apply_spliced ( & mut g, h ( 4 ) , & [ ] , & [ ( h ( 3 ) , 0 ) ] ) ;
1434
apply_spliced ( & mut g, h ( 3 ) , & [ ( a, b, 1 ) ] , & [ ] ) ;
1435
let m = g.materialize ( & deps) ;
1436
assert_eq! ( m, g.materialize_general ( & deps) ) ;
1437
assert_eq! ( text ( & g, & m) , " a\n b\n " ) ;
e83354cd Andy McCall 1 month ago ↶
1438
}
1439
1440
1441
# [ test ]
1442
# [ ignore ]
1443
fn bench_materialize_edited_file ( ) {
1444
let g = edited_file ( 20_000 , 50 , 100 ) ;
1445
let t = std:: time:: Instant:: now( ) ;
1446
let mut n = 0 ;
1447
for _ in 0 .. 20 {
1448
n + = g.materialize ( & Linear) .live_atoms ( ) .len ( ) ;
1449
}
1450
eprintln! (
1451
" materialize: {:.2} ms each ({n} atoms)" ,
1452
t.elapsed ( ) .as_secs_f64 ( ) * 1000. 0 / 20. 0
1453
) ;
598009a7 Andy McCall 1 month ago ↶
1454
}
1455
1456
1457
1458
# [ test ]
1459
fn the_chain_shortcut_agrees_with_the_general_order ( ) {
1460
let mut g = FileGraph:: new( ) ;
1461
g.insert (
1462
h ( 1 ) ,
1463
0 ,
1464
Vertex:: Start,
1465
Vertex:: End,
1466
& lines ( & [ " a\n " , " b\n " , " c\n " ] ) ,
1467
) ;
1468
assert! ( g.as_chain ( ) .is_some ( ) ) ;
1469
assert_eq! ( g.materialize ( & NoDeps) , g.materialize_general ( & NoDeps) ) ;
1470
1471
g.insert (
1472
h ( 2 ) ,
1473
0 ,
1474
Vertex:: Atom( ( h ( 1 ) , 2 ) ) ,
1475
Vertex:: End,
1476
& lines ( & [ " d\n " ] ) ,
1477
) ;
1478
assert! ( g.as_chain ( ) .is_some ( ) ) ;
1479
assert_eq! ( g.materialize ( & NoDeps) , g.materialize_general ( & NoDeps) ) ;
1480
1481
g.insert (
1482
h ( 4 ) ,
1483
0 ,
1484
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1485
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1486
& lines ( & [ " x\n " ] ) ,
1487
) ;
1488
assert! ( g.as_chain ( ) .is_none ( ) ) ;
1489
assert_eq! ( text ( & g, & g.materialize ( & NoDeps) ) , " a\n x\n b\n c\n d\n " ) ;
1490
1491
let mut c = FileGraph:: new( ) ;
1492
c.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " ] ) ) ;
1493
c.insert ( h ( 2 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " b\n " ] ) ) ;
1494
assert! ( c.as_chain ( ) .is_none ( ) ) ;
1495
assert! ( c.materialize ( & NoDeps) .is_conflicted ( ) ) ;
1496
1497
let mut d = FileGraph:: new( ) ;
1498
d.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
1499
d.delete (
1500
h ( 3 ) ,
1501
& AtomRange {
1502
change: h ( 1 ) ,
1503
from: 0 ,
1504
to: 1 ,
1505
} ,
1506
) ;
1507
assert! ( d.as_chain ( ) .is_none ( ) ) ;
1508
assert_eq! ( d.materialize ( & NoDeps) , d.materialize_general ( & NoDeps) ) ;
1509
1510
let e = FileGraph:: new( ) ;
1511
assert_eq! ( e.materialize ( & NoDeps) , e.materialize_general ( & NoDeps) ) ;
ff0af1ee unknown 1 month ago
1512
}
1513
1514
# [ test ]
1515
fn sequential_inserts_and_deletes ( ) {
1516
let mut g = FileGraph:: new( ) ;
75167672 Andy McCall 1 month ago
1517
g.insert (
1518
h ( 1 ) ,
1519
0 ,
1520
Vertex:: Start,
1521
Vertex:: End,
1522
& lines ( & [ " a\n " , " b\n " , " c\n " ] ) ,
1523
) ;
ff0af1ee unknown 1 month ago
1524
let m = g.materialize ( & NoDeps) ;
1525
assert! ( ! m.is_conflicted ( ) ) ;
1526
assert_eq! ( text ( & g, & m) , " a\n b\n c\n " ) ;
1527
1528
75167672 Andy McCall 1 month ago
1529
g.insert (
1530
h ( 2 ) ,
1531
0 ,
1532
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1533
Vertex:: Atom( ( h ( 1 ) , 2 ) ) ,
1534
& lines ( & [ " x\n " ] ) ,
1535
) ;
1536
g.delete (
1537
h ( 2 ) ,
1538
& AtomRange {
1539
change: h ( 1 ) ,
1540
from: 0 ,
1541
to: 1 ,
1542
} ,
1543
) ;
ff0af1ee unknown 1 month ago
1544
let deps = Deps( [ ( h ( 2 ) , vec! [ h ( 1 ) ] ) ] .into_iter ( ) .collect ( ) ) ;
1545
let m = g.materialize ( & deps) ;
1546
assert! ( ! m.is_conflicted ( ) ) ;
1547
assert_eq! ( text ( & g, & m) , " b\n x\n c\n " ) ;
1548
assert_eq! ( m.live_atoms ( ) , vec! [ ( h ( 1 ) , 1 ) , ( h ( 2 ) , 0 ) , ( h ( 1 ) , 2 ) ] ) ;
1549
}
1550
1551
# [ test ]
1552
fn concurrent_inserts_at_same_anchor_conflict ( ) {
1553
let mut g = FileGraph:: new( ) ;
1554
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1555
g.insert (
1556
h ( 2 ) ,
1557
0 ,
1558
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1559
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1560
& lines ( & [ " from-2\n " ] ) ,
1561
) ;
1562
g.insert (
1563
h ( 3 ) ,
1564
0 ,
1565
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1566
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1567
& lines ( & [ " from-3\n " , " more-3\n " ] ) ,
1568
) ;
1569
let deps = Deps(
1570
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1571
.into_iter ( )
1572
.collect ( ) ,
1573
) ;
ff0af1ee unknown 1 month ago
1574
let m = g.materialize ( & deps) ;
1575
assert! ( m.is_conflicted ( ) ) ;
1576
assert_eq! ( m.conflict_count ( ) , 1 ) ;
1577
assert_eq! (
1578
m.segments,
1579
vec! [
1580
Segment:: Lines( vec! [ ( h ( 1 ) , 0 ) ] ) ,
1581
Segment:: Conflict( vec! [ vec! [ ( h ( 2 ) , 0 ) ] , vec! [ ( h ( 3 ) , 0 ) , ( h ( 3 ) , 1 ) ] ] ) ,
1582
Segment:: Lines( vec! [ ( h ( 1 ) , 1 ) ] ) ,
1583
]
1584
) ;
1585
let t = text ( & g, & m) ;
1586
assert! ( t.starts_with ( " a\n <<<<<<< oxy conflict 1 of 1, side 1 of 2: change 0202\n from-2\n ======= oxy conflict 1 of 1, side 2 of 2: change 0303\n from-3\n more-3\n >>>>>>> oxy conflict 1 of 1 end\n b\n " ) , " {t}" ) ;
1587
}
1588
1589
# [ test ]
1590
fn concurrent_inserts_at_different_anchors_do_not_conflict ( ) {
1591
let mut g = FileGraph:: new( ) ;
75167672 Andy McCall 1 month ago
1592
g.insert (
1593
h ( 1 ) ,
1594
0 ,
1595
Vertex:: Start,
1596
Vertex:: End,
1597
& lines ( & [ " a\n " , " b\n " , " c\n " ] ) ,
1598
) ;
1599
g.insert (
1600
h ( 2 ) ,
1601
0 ,
1602
Vertex:: Start,
1603
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1604
& lines ( & [ " top\n " ] ) ,
1605
) ;
1606
g.insert (
1607
h ( 3 ) ,
1608
0 ,
1609
Vertex:: Atom( ( h ( 1 ) , 2 ) ) ,
1610
Vertex:: End,
1611
& lines ( & [ " bottom\n " ] ) ,
1612
) ;
1613
let deps = Deps(
1614
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1615
.into_iter ( )
1616
.collect ( ) ,
1617
) ;
ff0af1ee unknown 1 month ago
1618
let m = g.materialize ( & deps) ;
1619
assert! ( ! m.is_conflicted ( ) ) ;
1620
assert_eq! ( text ( & g, & m) , " top\n a\n b\n c\n bottom\n " ) ;
1621
}
1622
1623
# [ test ]
1624
fn concurrent_deletes_of_the_same_line_agree ( ) {
1625
let mut g = FileGraph:: new( ) ;
1626
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1627
g.delete (
1628
h ( 2 ) ,
1629
& AtomRange {
1630
change: h ( 1 ) ,
1631
from: 0 ,
1632
to: 1 ,
1633
} ,
1634
) ;
1635
g.delete (
1636
h ( 3 ) ,
1637
& AtomRange {
1638
change: h ( 1 ) ,
1639
from: 0 ,
1640
to: 1 ,
1641
} ,
1642
) ;
1643
let deps = Deps(
1644
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1645
.into_iter ( )
1646
.collect ( ) ,
1647
) ;
ff0af1ee unknown 1 month ago
1648
let m = g.materialize ( & deps) ;
1649
assert! ( ! m.is_conflicted ( ) ) ;
1650
assert_eq! ( text ( & g, & m) , " b\n " ) ;
1651
}
1652
1653
# [ test ]
1654
fn delete_insert_conflict_is_a_zombie ( ) {
1655
let mut g = FileGraph:: new( ) ;
1656
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
1657
75167672 Andy McCall 1 month ago
1658
g.delete (
1659
h ( 2 ) ,
1660
& AtomRange {
1661
change: h ( 1 ) ,
1662
from: 0 ,
1663
to: 1 ,
1664
} ,
1665
) ;
1666
g.insert (
1667
h ( 3 ) ,
1668
0 ,
1669
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1670
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1671
& lines ( & [ " after-a\n " ] ) ,
1672
) ;
1673
let deps = Deps(
1674
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1675
.into_iter ( )
1676
.collect ( ) ,
1677
) ;
ff0af1ee unknown 1 month ago
1678
let m = g.materialize ( & deps) ;
1679
assert! ( m.is_conflicted ( ) ) ;
1680
assert_eq! (
1681
m.segments,
1682
vec! [
75167672 Andy McCall 1 month ago
1683
Segment:: Zombie {
1684
deleted: vec! [ ( h ( 1 ) , 0 ) ] ,
1685
inserted: vec! [ ( h ( 3 ) , 0 ) ]
1686
} ,
ff0af1ee unknown 1 month ago
1687
Segment:: Lines( vec! [ ( h ( 1 ) , 1 ) ] ) ,
1688
]
1689
) ;
1690
let t = text ( & g, & m) ;
1691
assert! ( t.contains ( " -------\n a\n =======" ) , " {t}" ) ;
1692
assert! ( t.contains ( " after-a\n >>>>>>>" ) , " {t}" ) ;
1693
1694
75167672 Andy McCall 1 month ago
1695
let deps = Deps(
1696
[ ( h ( 2 ) , vec! [ h ( 1 ) , h ( 3 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1697
.into_iter ( )
1698
.collect ( ) ,
1699
) ;
ff0af1ee unknown 1 month ago
1700
let m = g.materialize ( & deps) ;
1701
assert! ( ! m.is_conflicted ( ) ) ;
1702
assert_eq! ( text ( & g, & m) , " after-a\n b\n " ) ;
1703
}
1704
1705
# [ test ]
23b217d7 Andy McCall 1 month ago ↶
1706
fn insert_after_a_line_deleted_by_a_dependency_is_not_a_conflict ( ) {
1707
1708
1709
let mut g = FileGraph:: new( ) ;
1710
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1711
g.delete (
1712
h ( 2 ) ,
1713
& AtomRange {
1714
change: h ( 1 ) ,
1715
from: 1 ,
1716
to: 2 ,
1717
} ,
1718
) ;
1719
g.insert (
1720
h ( 3 ) ,
1721
0 ,
1722
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1723
Vertex:: End,
1724
& lines ( & [ " c\n " ] ) ,
1725
) ;
1726
let deps = Deps(
1727
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 2 ) ] ) ]
1728
.into_iter ( )
1729
.collect ( ) ,
1730
) ;
23b217d7 Andy McCall 1 month ago ↶
1731
let m = g.materialize ( & deps) ;
1732
assert! ( ! m.is_conflicted ( ) , " {:?}" , m.segments) ;
1733
assert_eq! ( text ( & g, & m) , " a\n c\n " ) ;
1734
1735
1736
let mut g = FileGraph:: new( ) ;
1737
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " x\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1738
g.delete (
1739
h ( 1 ) ,
1740
& AtomRange {
1741
change: h ( 1 ) ,
1742
from: 0 ,
1743
to: 1 ,
1744
} ,
1745
) ;
1746
g.insert (
1747
h ( 2 ) ,
1748
0 ,
1749
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1750
Vertex:: End,
1751
& lines ( & [ " y\n " ] ) ,
1752
) ;
23b217d7 Andy McCall 1 month ago ↶
1753
let deps = Deps( [ ( h ( 2 ) , vec! [ h ( 1 ) ] ) ] .into_iter ( ) .collect ( ) ) ;
1754
let m = g.materialize ( & deps) ;
1755
assert! ( ! m.is_conflicted ( ) ) ;
1756
assert_eq! ( text ( & g, & m) , " y\n " ) ;
1757
}
1758
1759
# [ test ]
ff0af1ee unknown 1 month ago
1760
fn resolution_collapses_a_conflict ( ) {
1761
let mut g = FileGraph:: new( ) ;
1762
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1763
g.insert (
1764
h ( 2 ) ,
1765
0 ,
1766
Vertex:: Start,
1767
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1768
& lines ( & [ " x\n " ] ) ,
1769
) ;
1770
g.insert (
1771
h ( 3 ) ,
1772
0 ,
1773
Vertex:: Start,
1774
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1775
& lines ( & [ " y\n " ] ) ,
1776
) ;
1777
let mut deps: HashMap< _ , _ > = [ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1778
.into_iter ( )
1779
.collect ( ) ;
ff0af1ee unknown 1 month ago
1780
assert! ( g.materialize ( & Deps( deps.clone ( ) ) ) .is_conflicted ( ) ) ;
1781
75167672 Andy McCall 1 month ago
1782
g.delete (
1783
h ( 4 ) ,
1784
& AtomRange {
1785
change: h ( 2 ) ,
1786
from: 0 ,
1787
to: 1 ,
1788
} ,
1789
) ;
ff0af1ee unknown 1 month ago
1790
deps.insert ( h ( 4 ) , vec! [ h ( 2 ) , h ( 3 ) ] ) ;
1791
let m = g.materialize ( & Deps( deps) ) ;
1792
assert! ( ! m.is_conflicted ( ) ) ;
1793
assert_eq! ( text ( & g, & m) , " y\n a\n " ) ;
1794
}
1795
1796
# [ test ]
1797
fn empty_and_unterminated_files ( ) {
1798
let g = FileGraph:: new( ) ;
1799
let m = g.materialize ( & NoDeps) ;
1800
assert_eq! ( m.segments, vec! [ ] ) ;
1801
assert_eq! ( text ( & g, & m) , " " ) ;
1802
let mut g = FileGraph:: new( ) ;
1803
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " no newline" ] ) ) ;
1804
assert_eq! ( text ( & g, & g.materialize ( & NoDeps) ) , " no newline" ) ;
1805
}
1806
252e8cb2 Andy McCall 1 month ago ↶
1807
# [ test ]
1808
fn serialization_round_trip ( ) {
1809
let mut g = FileGraph:: new( ) ;
1810
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1811
g.insert (
1812
h ( 2 ) ,
1813
0 ,
1814
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1815
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1816
& lines ( & [ " x\n " ] ) ,
1817
) ;
1818
g.delete (
1819
h ( 3 ) ,
1820
& AtomRange {
1821
change: h ( 1 ) ,
1822
from: 1 ,
1823
to: 2 ,
1824
} ,
1825
) ;
252e8cb2 Andy McCall 1 month ago ↶
1826
let v = g.to_value ( ) ;
1827
let bytes = crate :: cbor:: encode( & v) ;
1828
let back = FileGraph:: from_value( & crate :: cbor:: decode( & bytes) .unwrap ( ) ) .unwrap ( ) ;
75167672 Andy McCall 1 month ago
1829
let deps = Deps(
1830
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1831
.into_iter ( )
1832
.collect ( ) ,
1833
) ;
252e8cb2 Andy McCall 1 month ago ↶
1834
assert_eq! ( back.materialize ( & deps) , g.materialize ( & deps) ) ;
1835
assert_eq! ( text ( & back, & back.materialize ( & deps) ) , " a\n x\n " ) ;
75167672 Andy McCall 1 month ago
1836
assert_eq! (
1837
crate :: cbor:: encode( & back.to_value ( ) ) ,
1838
bytes,
1839
" deterministic"
1840
) ;
252e8cb2 Andy McCall 1 month ago ↶
1841
}
1842
ff0af1ee unknown 1 month ago
1843
1844
# [ test ]
1845
fn application_order_is_irrelevant ( ) {
1846
use rand:: seq:: SliceRandom;
75167672 Andy McCall 1 month ago
1847
type Op = (
1848
ChangeHash,
01a47cd7 Andy McCall 1 month ago ↶
1849
Vec< ( u32 , Vertex, Vertex, Lines) > ,
75167672 Andy McCall 1 month ago
1850
Vec< AtomRange> ,
1851
) ;
ff0af1ee unknown 1 month ago
1852
let ops: Vec< Op> = vec! [
75167672 Andy McCall 1 month ago
1853
(
1854
h ( 1 ) ,
1855
vec! [ ( 0 , Vertex:: Start, Vertex:: End, lines ( & [ " a\n " , " b\n " , " c\n " ] ) ) ] ,
1856
vec! [ ] ,
1857
) ,
1858
(
1859
h ( 2 ) ,
1860
vec! [ (
1861
0 ,
1862
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1863
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1864
lines ( & [ " p\n " ] ) ,
1865
) ] ,
1866
vec! [ ] ,
1867
) ,
1868
(
1869
h ( 3 ) ,
1870
vec! [ (
1871
0 ,
1872
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1873
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1874
lines ( & [ " q\n " , " r\n " ] ) ,
1875
) ] ,
1876
vec! [ AtomRange {
1877
change: h ( 1 ) ,
1878
from: 2 ,
1879
to: 3 ,
1880
} ] ,
1881
) ,
1882
(
1883
h ( 4 ) ,
1884
vec! [ (
1885
0 ,
1886
Vertex:: Atom( ( h ( 3 ) , 1 ) ) ,
1887
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1888
lines ( & [ " s\n " ] ) ,
1889
) ] ,
1890
vec! [ AtomRange {
1891
change: h ( 1 ) ,
1892
from: 1 ,
1893
to: 2 ,
1894
} ] ,
1895
) ,
1896
(
1897
h ( 5 ) ,
1898
vec! [ ( 0 , Vertex:: Atom( ( h ( 1 ) , 2 ) ) , Vertex:: End, lines ( & [ " z\n " ] ) ) ] ,
1899
vec! [ ] ,
1900
) ,
ff0af1ee unknown 1 month ago
1901
] ;
1902
let deps = Deps(
75167672 Andy McCall 1 month ago
1903
[
1904
( h ( 2 ) , vec! [ h ( 1 ) ] ) ,
1905
( h ( 3 ) , vec! [ h ( 1 ) ] ) ,
1906
( h ( 4 ) , vec! [ h ( 3 ) , h ( 1 ) ] ) ,
1907
( h ( 5 ) , vec! [ h ( 1 ) ] ) ,
1908
]
1909
.into_iter ( )
1910
.collect ( ) ,
ff0af1ee unknown 1 month ago
1911
) ;
1912
let build = | order : & [usize ]| {
1913
let mut g = FileGraph:: new( ) ;
1914
for & i in order {
1915
let ( c, ins, dels) = & ops[ i] ;
1916
for ( idx, a, b, l) in ins {
1917
g.insert ( * c, * idx, * a, * b, l) ;
1918
}
1919
for d in dels {
1920
g.delete ( * c, d) ;
1921
}
1922
}
1923
let m = g.materialize ( & deps) ;
1924
( m.clone ( ) , text ( & g, & m) )
1925
} ;
1926
let reference = build ( & [ 0 , 1 , 2 , 3 , 4 ] ) ;
1927
assert! ( reference.0. is_conflicted ( ) ) ;
1928
let mut rng = rand:: thread_rng( ) ;
1929
let mut order: Vec< usize > = ( 0 .. ops.len ( ) ) .collect ( ) ;
1930
for _ in 0 .. 50 {
1931
order.shuffle ( & mut rng) ;
1932
assert_eq! ( build ( & order) , reference, " order {order:?}" ) ;
1933
}
1934
}
1935
}