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
396
397
pub fn atom_count ( & self ) -> usize {
398
self .atoms.len ( )
399
}
400
62794ecc Andy McCall 1 month ago ↶
401
402
403
83d61e80 Andy McCall 1 month ago ↶
404
405
406
407
408
pub fn between ( & self , first : & AtomKey, last : & AtomKey) -> Vec< AtomKey> {
409
let ( from, to) = ( Vertex:: Atom( * first) , Vertex:: Atom( * last) ) ;
410
let mut ahead: HashSet< Vertex> = HashSet:: default( ) ;
411
let mut stack = vec! [ from] ;
412
while let Some ( v) = stack.pop ( ) {
413
if ahead.insert ( v) {
414
stack.extend (
415
self .succ
416
.get ( & v)
417
.map ( | e | e.as_slice ( ) )
418
.unwrap_or ( & [ ] )
419
.iter ( )
420
.copied ( ) ,
421
) ;
422
}
423
}
424
if ! ahead.contains ( & to) {
425
return vec! [ ] ;
426
}
427
let mut pred: HashMap< Vertex, Vec< Vertex> > = HashMap:: default( ) ;
428
for ( u, es) in & self .succ {
429
if ahead.contains ( u) {
430
for w in es.iter ( ) {
431
pred.entry ( * w) .or_default ( ) .push ( * u) ;
432
}
433
}
434
}
435
let mut behind: HashSet< Vertex> = HashSet:: default( ) ;
436
let mut stack = vec! [ to] ;
437
while let Some ( v) = stack.pop ( ) {
438
if behind.insert ( v) {
439
stack.extend ( pred.get ( & v) .into_iter ( ) .flatten ( ) .copied ( ) ) ;
440
}
441
}
442
let mut out: Vec< AtomKey> = ahead
443
.intersection ( & behind)
444
.filter_map ( | v | match v {
445
Vertex:: Atom( k) if self .atoms.contains_key ( k) => Some ( * k) ,
446
_ => None ,
447
} )
448
.collect ( ) ;
449
out.sort ( ) ;
450
out
451
}
452
453
454
pub fn touching ( & self , atoms : & [AtomKey]) -> BTreeSet< ChangeHash> {
455
let mut out = BTreeSet:: new( ) ;
456
for k in atoms {
457
out.insert ( k.0 ) ;
458
if let Some ( info) = self .atoms.get ( k) {
459
out.extend ( info.deleted_by.iter ( ) .copied ( ) ) ;
460
}
461
}
462
out
463
}
464
62794ecc Andy McCall 1 month ago ↶
465
pub fn live_successor_changes ( & self , k : & AtomKey) -> Vec< ChangeHash> {
466
self .succ
467
.get ( & Vertex:: Atom( * k) )
468
.map ( | ss | {
469
ss.iter ( )
470
.filter_map ( | s | match s {
471
Vertex:: Atom( y) if self .is_live ( y) => Some ( y.0 ) ,
472
_ => None ,
473
} )
474
.collect ( )
475
} )
476
.unwrap_or_default ( )
477
}
478
ff0af1ee unknown 1 month ago
479
fn is_ghost ( & self , k : & AtomKey, info : & AtomInfo, deps : & dyn DepOracle) -> bool {
23b217d7 Andy McCall 1 month ago ↶
480
481
482
483
ff0af1ee unknown 1 month ago
484
self .succ.get ( & Vertex:: Atom( * k) ) .is_some_and ( | ss | {
485
ss.iter ( ) .any ( | s | match s {
75167672 Andy McCall 1 month ago
486
Vertex:: Atom( y) if self .is_live ( y) => ! info
487
.deleted_by
488
.iter ( )
489
.any ( | d | deps.depends_on ( d, & y.0 ) | | deps.depends_on ( & y.0 , d) ) ,
ff0af1ee unknown 1 month ago
490
_ => false ,
491
} )
492
} )
493
}
494
495
75167672 Andy McCall 1 month ago
496
fn reduced_succ (
497
& self ,
498
v : Vertex,
499
kept : & HashSet< Vertex> ,
500
memo : & mut HashMap< Vertex, BTreeSet< Vertex> > ,
501
) -> BTreeSet< Vertex> {
598009a7 Andy McCall 1 month ago ↶
502
let direct = self .succ.get ( & v) .map ( Edges:: as_slice) .unwrap_or_default ( ) ;
503
504
505
if direct.iter ( ) .all ( | s | kept.contains ( s) ) {
506
return direct.iter ( ) .copied ( ) .collect ( ) ;
507
}
ff0af1ee unknown 1 month ago
508
let mut out = BTreeSet:: new( ) ;
598009a7 Andy McCall 1 month ago ↶
509
let mut stack: Vec< Vertex> = direct.to_vec ( ) ;
0bdc3f91 Andy McCall 1 month ago ↶
510
let mut seen = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
511
while let Some ( s) = stack.pop ( ) {
512
if kept.contains ( & s) {
513
out.insert ( s) ;
514
} else if seen.insert ( s) {
515
if let Some ( m) = memo.get ( & s) {
516
out.extend ( m.iter ( ) .copied ( ) ) ;
517
} else if let Some ( next) = self .succ.get ( & s) {
518
stack.extend ( next.iter ( ) .copied ( ) ) ;
519
}
520
}
521
}
522
out
598009a7 Andy McCall 1 month ago ↶
523
}
524
525
526
527
528
529
530
fn as_chain ( & self ) -> Option< Vec< AtomKey> > {
531
if self
532
.atoms
533
.values ( )
534
.any ( | a | a.content.is_none ( ) | | ! a.deleted_by.is_empty ( ) )
535
{
536
return None ;
537
}
538
let mut order = Vec :: with_capacity( self .atoms.len ( ) ) ;
539
let mut v = Vertex:: Start;
540
loop {
541
let succ = self .succ.get ( & v) ? .as_slice ( ) ;
542
let mut atoms = succ.iter ( ) .filter ( | s | * * s ! = Vertex:: End) ;
543
match ( atoms.next ( ) , atoms.next ( ) ) {
544
( None , _ ) if succ.contains ( & Vertex:: End) => break ,
545
( Some ( Vertex:: Atom( k) ) , None ) if order.len ( ) < self .atoms.len ( ) => {
546
order.push ( * k) ;
547
v = Vertex:: Atom( * k) ;
548
}
549
_ => return None ,
550
}
551
}
552
( order.len ( ) = = self .atoms.len ( ) ) .then_some ( order)
ff0af1ee unknown 1 month ago
553
}
554
555
556
pub fn materialize ( & self , deps : & dyn DepOracle) -> Materialized {
aedfe465 Andy McCall 25 days ago ↶
557
let deps = & MemoDeps {
558
inner: deps,
559
known: Default :: default( ) ,
560
} ;
dbf06d34 Andy McCall 1 month ago ↶
561
let lines = | order : Vec< AtomKey> | Materialized {
562
segments: if order.is_empty ( ) {
563
vec! [ ]
564
} else {
565
vec! [ Segment:: Lines( order) ]
566
} ,
567
} ;
568
use std:: sync:: atomic:: Ordering:: Relaxed;
40a40bb7 Andy McCall 1 month ago ↶
569
570
let started = crate :: timing:: enabled( ) .then ( std:: time:: Instant:: now) ;
571
let took = | name : & 'static str | {
572
if let Some ( t) = started {
573
crate :: timing:: add( name, t.elapsed ( ) ) ;
574
}
575
} ;
dbf06d34 Andy McCall 1 month ago ↶
576
if let Some ( o) = self .order.get ( ) {
577
let holds = o.confirmed.load ( Relaxed)
578
| | o.unchecked.iter ( ) .all ( | k | {
579
self .atoms
580
.get ( k)
581
.is_none_or ( | info | ! self .is_ghost ( k, info, deps) )
582
} ) ;
583
if holds {
584
o.confirmed.store ( true , Relaxed) ;
40a40bb7 Andy McCall 1 month ago ↶
585
took ( " graph: kept order" ) ;
dbf06d34 Andy McCall 1 month ago ↶
586
return lines ( o.atoms.clone ( ) ) ;
587
}
588
self .order.set ( None ) ;
589
}
590
591
592
if let Some ( order) = self .as_chain ( ) {
40a40bb7 Andy McCall 1 month ago ↶
593
took ( " graph: chain" ) ;
dbf06d34 Andy McCall 1 month ago ↶
594
return lines ( order) ;
598009a7 Andy McCall 1 month ago ↶
595
}
dbf06d34 Andy McCall 1 month ago ↶
596
if let Some ( order) = self .as_order ( deps) {
597
self .order
598
.set ( Some ( std:: sync:: Arc:: new( Order:: known( order.clone ( ) ) ) ) ) ;
40a40bb7 Andy McCall 1 month ago ↶
599
took ( " graph: single order" ) ;
dbf06d34 Andy McCall 1 month ago ↶
600
return lines ( order) ;
601
}
40a40bb7 Andy McCall 1 month ago ↶
602
let m = self .materialize_general ( deps) ;
603
took ( " graph: general" ) ;
604
m
dbf06d34 Andy McCall 1 month ago ↶
605
}
606
607
608
609
pub fn take_order ( & mut self ) -> Option< std:: sync:: Arc< Order> > {
610
self .order.take ( )
611
}
612
7eac74ab Andy McCall 1 month ago ↶
613
614
615
616
617
pub fn keep_spliced (
618
& mut self ,
619
order : std:: sync:: Arc< Order> ,
620
h : ChangeHash,
621
inserts : & [( Vertex , Vertex , u32 , u32 ) ],
622
deleted : & [AtomKey],
623
) {
624
let live = inserts
625
.iter ( )
626
.all ( | & ( _, _, first , count ) | ( first.. first + count) .all ( | i | self .is_live ( & ( h, i) ) ) ) ;
627
let spliced = if live {
628
order.splice ( h, inserts, deleted)
629
} else {
630
None
631
} ;
632
* self .order.0. get_mut ( ) .unwrap_or_else ( | e | e.into_inner ( ) ) = spliced;
598009a7 Andy McCall 1 month ago ↶
633
}
634
e83354cd Andy McCall 1 month ago ↶
635
636
637
638
639
640
641
fn as_order ( & self , deps : & dyn DepOracle) -> Option< Vec< AtomKey> > {
642
643
let mut index: HashMap< Vertex, u32 > =
644
HashMap:: with_capacity_and_hasher( self .atoms.len ( ) + 2 , Default :: default( ) ) ;
645
let mut verts: Vec< Vertex> = Vec :: with_capacity( self .atoms.len ( ) + 2 ) ;
646
verts.extend ( [ Vertex:: Start, Vertex:: End] ) ;
647
index.insert ( Vertex:: Start, 0 ) ;
648
index.insert ( Vertex:: End, 1 ) ;
649
for ( k, info) in & self .atoms {
650
if info.content.is_none ( ) {
651
continue ;
652
}
653
if info.deleted_by.is_empty ( ) {
654
index.insert ( Vertex:: Atom( * k) , verts.len ( ) as u32 ) ;
655
verts.push ( Vertex:: Atom( * k) ) ;
656
} else if self .is_ghost ( k, info, deps) {
657
return None ;
658
}
659
}
660
661
662
let mut reach: HashMap< Vertex, Vec< u32 > > = HashMap:: default( ) ;
663
let contracted = | v : Vertex, reach : & mut HashMap< Vertex, Vec< u32 > > | {
664
let mut stack: Vec< ( Vertex, bool ) > = vec! [ ( v, false ) ] ;
665
while let Some ( ( x, done) ) = stack.pop ( ) {
666
if reach.contains_key ( & x) {
667
continue ;
668
}
669
let next = self .succ.get ( & x) .map ( Edges:: as_slice) .unwrap_or_default ( ) ;
670
if ! done {
671
stack.push ( ( x, true ) ) ;
672
for s in next {
673
if ! index.contains_key ( s) & & ! reach.contains_key ( s) {
674
stack.push ( ( * s, false ) ) ;
675
}
676
}
677
continue ;
678
}
679
let mut out: Vec< u32 > = Vec :: new( ) ;
680
for s in next {
681
match index.get ( s) {
682
Some ( i) => out.push ( * i) ,
683
None => out.extend ( reach.get ( s) .into_iter ( ) .flatten ( ) ) ,
684
}
685
}
686
out.sort_unstable ( ) ;
687
out.dedup ( ) ;
688
reach.insert ( x, out) ;
689
}
690
} ;
691
692
let mut succ: Vec< u32 > = Vec :: with_capacity( verts.len ( ) * 2 ) ;
693
let mut starts: Vec< usize > = Vec :: with_capacity( verts.len ( ) + 1 ) ;
694
let mut indeg: Vec< u32 > = vec! [ 0 ; verts.len ( ) ] ;
695
for v in & verts {
696
let from = succ.len ( ) ;
697
starts.push ( from) ;
698
for s in self .succ.get ( v) .map ( Edges:: as_slice) .unwrap_or_default ( ) {
699
match index.get ( s) {
700
Some ( i) => succ.push ( * i) ,
701
None => {
702
contracted ( * s, & mut reach) ;
703
succ.extend ( reach.get ( s) .into_iter ( ) .flatten ( ) ) ;
704
}
705
}
706
}
707
if succ.len ( ) - from > 1 {
708
succ[ from.. ] .sort_unstable ( ) ;
709
let mut kept = from;
710
for i in from.. succ.len ( ) {
711
if i = = from | | succ[ i] ! = succ[ kept - 1 ] {
712
succ[ kept] = succ[ i] ;
713
kept + = 1 ;
714
}
715
}
716
succ.truncate ( kept) ;
717
}
718
for & w in & succ[ from.. ] {
719
indeg[ w as usize ] + = 1 ;
720
}
721
}
722
starts.push ( succ.len ( ) ) ;
723
724
let mut ready: Vec< u32 > = ( 0 .. verts.len ( ) as u32 )
725
.filter ( | & i | indeg[ i as usize ] = = 0 )
726
.collect ( ) ;
727
let mut order: Vec< AtomKey> = Vec :: with_capacity( verts.len ( ) ) ;
728
let mut seen = 0 ;
729
while let Some ( v) = ready.pop ( ) {
730
if ! ready.is_empty ( ) {
731
return None ;
732
}
733
seen + = 1 ;
734
if let Vertex:: Atom( k) = verts[ v as usize ] {
735
order.push ( k) ;
736
}
737
for & w in & succ[ starts[ v as usize ] .. starts[ v as usize + 1 ] ] {
738
indeg[ w as usize ] - = 1 ;
739
if indeg[ w as usize ] = = 0 {
740
ready.push ( w) ;
741
}
742
}
743
if ready.len ( ) > 1 {
744
return None ;
745
}
746
}
747
( seen = = verts.len ( ) ) .then_some ( order)
748
}
749
598009a7 Andy McCall 1 month ago ↶
750
751
752
fn materialize_general ( & self , deps : & dyn DepOracle) -> Materialized {
ff0af1ee unknown 1 month ago
753
0bdc3f91 Andy McCall 1 month ago ↶
754
let mut kept: HashSet< Vertex> = HashSet:: default( ) ;
755
let mut ghosts: HashSet< AtomKey> = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
756
kept.insert ( Vertex:: Start) ;
757
kept.insert ( Vertex:: End) ;
758
for ( k, info) in & self .atoms {
759
if info.content.is_none ( ) {
760
continue ;
761
}
762
if info.deleted_by.is_empty ( ) {
763
kept.insert ( Vertex:: Atom( * k) ) ;
764
} else if self .is_ghost ( k, info, deps) {
765
kept.insert ( Vertex:: Atom( * k) ) ;
766
ghosts.insert ( * k) ;
767
}
768
}
769
770
0bdc3f91 Andy McCall 1 month ago ↶
771
let mut memo = HashMap:: default( ) ;
772
let mut rsucc: HashMap< Vertex, BTreeSet< Vertex> > = HashMap:: default( ) ;
773
let mut indeg: HashMap< Vertex, usize > = HashMap:: default( ) ;
ff0af1ee unknown 1 month ago
774
for & u in & kept {
775
indeg.entry ( u) .or_insert ( 0 ) ;
776
let rs = self .reduced_succ ( u, & kept, & mut memo) ;
777
for & w in & rs {
778
* indeg.entry ( w) .or_insert ( 0 ) + = 1 ;
779
}
780
rsucc.insert ( u, rs) ;
781
}
782
783
75167672 Andy McCall 1 month ago
784
let mut ready: BTreeSet< Vertex> = indeg
785
.iter ( )
786
.filter ( | ( _, &d ) | d = = 0 )
787
.map ( | ( v , _) | * v)
788
.collect ( ) ;
0bdc3f91 Andy McCall 1 month ago ↶
789
let mut side: HashMap< Vertex, u32 > = HashMap:: default( ) ;
790
let mut joins: HashSet< Vertex> = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
791
let mut next_side = 0 u32 ;
792
let mut plain: Vec< Vertex> = Vec :: new( ) ;
793
let mut conflict: Option< BTreeMap< u32 , Vec< Vertex> > > = None ;
794
let mut segments: Vec< Segment> = Vec :: new( ) ;
795
796
let flush_plain = | plain : & mut Vec< Vertex> , segments : & mut Vec< Segment> | {
75167672 Andy McCall 1 month ago
797
let atoms: Vec< AtomKey> = plain
798
.iter ( )
799
.filter_map ( | v | {
800
if let Vertex:: Atom( k) = v {
801
Some ( * k)
802
} else {
803
None
804
}
805
} )
806
.collect ( ) ;
ff0af1ee unknown 1 month ago
807
plain.clear ( ) ;
808
if ! atoms.is_empty ( ) {
809
segments.extend ( split_zombies ( atoms, & ghosts) ) ;
810
}
811
} ;
812
let finish_conflict = | c : BTreeMap< u32 , Vec< Vertex> > , segments : & mut Vec< Segment> | {
813
let sides: Vec< Vec< AtomKey> > = c
814
.into_values ( )
815
.map ( | vs | {
816
vs.into_iter ( )
817
.filter_map ( | v | match v {
818
Vertex:: Atom( k) if ! ghosts.contains ( & k) => Some ( k) ,
819
_ => None ,
820
} )
821
.collect:: < Vec< _ > > ( )
822
} )
823
.filter ( | s | ! s.is_empty ( ) )
824
.collect ( ) ;
825
match sides.len ( ) {
826
0 => { }
827
1 => segments.push ( Segment:: Lines( sides.into_iter ( ) .next ( ) .unwrap ( ) ) ) ,
828
_ => segments.push ( Segment:: Conflict( sides) ) ,
829
}
830
} ;
831
832
while ! ready.is_empty ( ) {
833
if ready.len ( ) > = 2 {
834
if conflict.is_none ( ) {
835
flush_plain ( & mut plain, & mut segments) ;
836
conflict = Some ( BTreeMap:: new( ) ) ;
837
}
838
for r in & ready {
839
if ! side.contains_key ( r) {
840
side.insert ( * r, next_side) ;
841
next_side + = 1 ;
842
}
843
}
844
}
845
let v = ready.pop_first ( ) .unwrap ( ) ;
846
let my_side = side.get ( & v) .copied ( ) ;
847
match ( & mut conflict, my_side) {
848
( Some ( c) , Some ( s) ) => c.entry ( s) .or_default ( ) .push ( v) ,
849
( Some ( _ ) , None ) => {
850
let c = conflict.take ( ) .unwrap ( ) ;
851
finish_conflict ( c, & mut segments) ;
852
plain.push ( v) ;
853
}
854
( None , _ ) => plain.push ( v) ,
855
}
856
for & w in & rsucc[ & v] {
857
let d = indeg.get_mut ( & w) .unwrap ( ) ;
858
* d - = 1 ;
859
if conflict.is_some ( ) & & ! joins.contains ( & w) {
860
match ( my_side, side.get ( & w) .copied ( ) ) {
861
( Some ( s) , None ) => {
862
side.insert ( w, s) ;
863
}
864
( Some ( s) , Some ( t) ) if s ! = t => {
865
side.remove ( & w) ;
866
joins.insert ( w) ;
867
}
868
( None , Some ( _ ) ) => {
869
side.remove ( & w) ;
870
joins.insert ( w) ;
871
}
872
_ => { }
873
}
874
}
875
if * d = = 0 {
876
ready.insert ( w) ;
877
}
878
}
879
}
880
if let Some ( c) = conflict.take ( ) {
881
finish_conflict ( c, & mut segments) ;
882
}
883
flush_plain ( & mut plain, & mut segments) ;
884
Materialized { segments }
885
}
886
887
888
889
pub fn render ( & self , m : & Materialized, label : & dyn Fn( &ChangeHash ) -> String) -> Vec< u8 > {
890
let total = m.conflict_count ( ) ;
891
let mut n = 0 ;
892
let mut out: Vec< u8 > = Vec :: new( ) ;
893
let push_atoms = | out : & mut Vec< u8 > , atoms : & [AtomKey]| {
894
for a in atoms {
895
if let Some ( c) = self .content ( a) {
896
out.extend_from_slice ( c) ;
897
}
898
}
899
} ;
900
let newline_if_needed = | out : & mut Vec< u8 > | {
901
if ! out.is_empty ( ) & & * out.last ( ) .unwrap ( ) ! = b ' \n ' {
902
out.push ( b ' \n ' ) ;
903
}
904
} ;
905
for seg in & m.segments {
906
match seg {
907
Segment:: Lines( a) => push_atoms ( & mut out, a) ,
908
Segment:: Conflict( sides) => {
909
n + = 1 ;
910
let k = sides.len ( ) ;
911
for ( i, s) in sides.iter ( ) .enumerate ( ) {
912
newline_if_needed ( & mut out) ;
913
let who = s.first ( ) .map ( | a | label ( & a.0 ) ) .unwrap_or_default ( ) ;
914
let marker = if i = = 0 { " <<<<<<<" } else { " =======" } ;
915
out.extend_from_slice (
916
format! ( " {marker} oxy conflict {n} of {total} , side {} of {k} : change {who} \n " , i + 1 ) .as_bytes ( ) ,
917
) ;
918
push_atoms ( & mut out, s) ;
919
}
920
newline_if_needed ( & mut out) ;
75167672 Andy McCall 1 month ago
921
out.extend_from_slice (
922
format! ( " >>>>>>> oxy conflict {n} of {total} end\n " ) .as_bytes ( ) ,
923
) ;
ff0af1ee unknown 1 month ago
924
}
925
Segment:: Zombie { deleted, inserted } => {
926
n + = 1 ;
927
newline_if_needed ( & mut out) ;
928
let deleter = deleted
929
.first ( )
930
.and_then ( | a | self .deleters ( a) .next ( ) .copied ( ) )
931
.map ( | d | label ( & d) )
932
.unwrap_or_default ( ) ;
933
let inserter = inserted.first ( ) .map ( | a | label ( & a.0 ) ) .unwrap_or_default ( ) ;
934
out.extend_from_slice (
935
format! ( " <<<<<<< oxy conflict {n} of {total} , side 1 of 2: deleted by change {deleter} \n -------\n " ) .as_bytes ( ) ,
936
) ;
937
push_atoms ( & mut out, deleted) ;
938
newline_if_needed ( & mut out) ;
75167672 Andy McCall 1 month ago
939
out.extend_from_slice (
940
format! (
941
" ======= oxy conflict {n} of {total} , side 2 of 2: change {inserter} \n "
942
)
943
.as_bytes ( ) ,
944
) ;
ff0af1ee unknown 1 month ago
945
push_atoms ( & mut out, inserted) ;
946
newline_if_needed ( & mut out) ;
75167672 Andy McCall 1 month ago
947
out.extend_from_slice (
948
format! ( " >>>>>>> oxy conflict {n} of {total} end\n " ) .as_bytes ( ) ,
949
) ;
ff0af1ee unknown 1 month ago
950
}
951
}
952
}
953
out
954
}
955
}
956
252e8cb2 Andy McCall 1 month ago ↶
957
fn vertex_value ( v : & Vertex) -> crate:: cbor:: Value {
958
use crate :: cbor:: Value;
959
match v {
960
Vertex:: Start => Value:: Uint( 0 ) ,
961
Vertex:: End => Value:: Uint( 1 ) ,
75167672 Andy McCall 1 month ago
962
Vertex:: Atom( ( c, i) ) => {
963
Value:: Array( vec! [ Value:: Bytes( c.0. to_vec ( ) ) , Value:: Uint( * i as u64 ) ] )
964
}
252e8cb2 Andy McCall 1 month ago ↶
965
}
966
}
967
968
fn vertex_from ( v : & crate:: cbor:: Value) -> Result< Vertex, crate:: objects:: ObjectError> {
969
use crate :: cbor:: Value;
970
use crate :: objects:: ObjectError;
971
match v {
972
Value:: Uint( 0 ) => Ok ( Vertex:: Start) ,
973
Value:: Uint( 1 ) => Ok ( Vertex:: End) ,
75167672 Andy McCall 1 month ago
974
Value:: Array( a) if a.len ( ) = = 2 => Ok ( Vertex:: Atom( (
975
crate :: objects:: oref( & a[ 0 ] , " vertex" ) ? ,
976
crate :: objects:: u32_( & a[ 1 ] , " vertex" ) ? ,
977
) ) ) ,
978
_ => Err ( ObjectError:: Schema(
979
" vertex: expected 0, 1, or [hash, index]" .into ( ) ,
980
) ) ,
252e8cb2 Andy McCall 1 month ago ↶
981
}
982
}
983
984
impl FileGraph {
985
986
pub fn to_value ( & self ) -> crate:: cbor:: Value {
987
use crate :: cbor:: Value;
988
let mut atoms: Vec< ( & AtomKey, & AtomInfo) > = self .atoms.iter ( ) .collect ( ) ;
989
atoms.sort_by_key ( | ( k , _) | * * k) ;
75167672 Andy McCall 1 month ago
990
let mut edges: Vec< ( Vertex, Vertex) > = self
991
.succ
992
.iter ( )
993
.flat_map ( | ( a , bs ) | bs.iter ( ) .map ( move | b| ( * a, * b) ) )
994
.collect ( ) ;
252e8cb2 Andy McCall 1 month ago ↶
995
edges.sort ( ) ;
996
Value:: map( [
997
(
998
0 ,
999
Value:: Array(
1000
atoms
1001
.into_iter ( )
1002
.map ( | ( (c , i ) , info) | {
1003
Value:: Array( vec! [
1004
Value:: Bytes( c.0. to_vec ( ) ) ,
1005
Value:: Uint( * i as u64 ) ,
75167672 Andy McCall 1 month ago
1006
info.content
1007
.as_ref ( )
01a47cd7 Andy McCall 1 month ago ↶
1008
.map ( | b | Value:: Bytes( b.bytes ( ) .to_vec ( ) ) )
75167672 Andy McCall 1 month ago
1009
.unwrap_or ( Value:: Null) ,
1010
Value:: Array(
1011
info.deleted_by
1012
.iter ( )
1013
.map ( | d | Value:: Bytes( d.0. to_vec ( ) ) )
1014
.collect ( ) ,
1015
) ,
252e8cb2 Andy McCall 1 month ago ↶
1016
] )
1017
} )
1018
.collect ( ) ,
1019
) ,
1020
),
75167672 Andy McCall 1 month ago
1021
(
1022
1 ,
1023
Value:: Array(
1024
edges
1025
.iter ( )
1026
.map ( | ( a , b ) | Value:: Array( vec! [ vertex_value ( a) , vertex_value ( b) ] ) )
1027
.collect ( ) ,
1028
) ,
1029
) ,
252e8cb2 Andy McCall 1 month ago ↶
1030
] )
1031
}
1032
1033
pub fn from_value ( v : & crate:: cbor:: Value) -> Result< FileGraph, crate:: objects:: ObjectError> {
1034
use crate :: objects:: { array, bytes, field, map, oref, u32_, ObjectError} ;
1035
let m = map ( v, " file graph" ) ? ;
75167672 Andy McCall 1 month ago
1036
let mut g = FileGraph {
0bdc3f91 Andy McCall 1 month ago ↶
1037
atoms: HashMap:: default( ) ,
1038
succ: HashMap:: default( ) ,
dbf06d34 Andy McCall 1 month ago ↶
1039
order: OrderSlot:: default( ) ,
75167672 Andy McCall 1 month ago
1040
} ;
01a47cd7 Andy McCall 1 month ago ↶
1041
let atoms = array ( field ( m, 0 , " atoms" ) ? , " atoms" ) ? ;
1042
1043
let mut texts: Vec< & [ u8 ] > = Vec :: new( ) ;
1044
for a in atoms {
1045
let e = array ( a, " atom" ) ? ;
1046
if e.len ( ) = = 4 & & ! e[ 2 ] .is_null ( ) {
1047
texts.push ( bytes ( & e[ 2 ] , " atom content" ) ? ) ;
1048
}
1049
}
1050
let all: Lines = texts.into_iter ( ) .collect ( ) ;
1051
let mut next = 0 u32 ;
1052
for a in atoms {
252e8cb2 Andy McCall 1 month ago ↶
1053
let e = array ( a, " atom" ) ? ;
1054
if e.len ( ) ! = 4 {
1055
return Err ( ObjectError:: Schema( " atom: expected 4 fields" .into ( ) ) ) ;
1056
}
1057
let key = ( oref ( & e[ 0 ] , " atom change" ) ? , u32_ ( & e[ 1 ] , " atom index" ) ? ) ;
75167672 Andy McCall 1 month ago
1058
let content = if e[ 2 ] .is_null ( ) {
1059
None
1060
} else {
01a47cd7 Andy McCall 1 month ago ↶
1061
next + = 1 ;
1062
Some ( LineRef:: new( all.clone ( ) , next - 1 ) )
75167672 Andy McCall 1 month ago
1063
} ;
1064
let deleted_by = array ( & e[ 3 ] , " deleters" ) ?
1065
.iter ( )
1066
.map ( | d | oref ( d, " deleter" ) )
1067
.collect:: < Result< BTreeSet< _ > , _ > > ( ) ? ;
1068
g.atoms.insert (
1069
key,
1070
AtomInfo {
1071
content,
1072
deleted_by,
1073
} ,
1074
) ;
252e8cb2 Andy McCall 1 month ago ↶
1075
}
1076
for e in array ( field ( m, 1 , " edges" ) ? , " edges" ) ? {
1077
let pair = array ( e, " edge" ) ? ;
1078
if pair.len ( ) ! = 2 {
1079
return Err ( ObjectError:: Schema( " edge: expected [from, to]" .into ( ) ) ) ;
1080
}
1081
g.edge ( vertex_from ( & pair[ 0 ] ) ? , vertex_from ( & pair[ 1 ] ) ? ) ;
1082
}
1083
Ok ( g)
1084
}
1085
}
1086
ff0af1ee unknown 1 month ago
1087
1088
fn split_zombies ( atoms : Vec< AtomKey> , ghosts : & HashSet< AtomKey> ) -> Vec< Segment> {
1089
let mut out = Vec :: new( ) ;
1090
let mut lines: Vec< AtomKey> = Vec :: new( ) ;
1091
let mut i = 0 ;
1092
while i < atoms.len ( ) {
1093
if ! ghosts.contains ( & atoms[ i] ) {
1094
lines.push ( atoms[ i] ) ;
1095
i + = 1 ;
1096
continue ;
1097
}
1098
if ! lines.is_empty ( ) {
1099
out.push ( Segment:: Lines( std:: mem:: take( & mut lines) ) ) ;
1100
}
1101
let mut deleted = Vec :: new( ) ;
1102
while i < atoms.len ( ) & & ghosts.contains ( & atoms[ i] ) {
1103
deleted.push ( atoms[ i] ) ;
1104
i + = 1 ;
1105
}
1106
let mut inserted = Vec :: new( ) ;
1107
if i < atoms.len ( ) {
1108
let ch = atoms[ i] .0 ;
1109
while i < atoms.len ( ) & & atoms[ i] .0 = = ch & & ! ghosts.contains ( & atoms[ i] ) {
1110
inserted.push ( atoms[ i] ) ;
1111
i + = 1 ;
1112
}
1113
}
1114
out.push ( Segment:: Zombie { deleted, inserted } ) ;
1115
}
1116
if ! lines.is_empty ( ) {
1117
out.push ( Segment:: Lines( lines) ) ;
1118
}
1119
out
1120
}
1121
1122
# [ cfg ( test ) ]
1123
mod tests {
1124
use super :: * ;
1125
use crate :: hash:: ObjectRef;
1126
1127
fn h ( n : u8 ) -> ChangeHash {
1128
ObjectRef( [ n; 32 ] )
1129
}
01a47cd7 Andy McCall 1 month ago ↶
1130
fn lines ( v : & [& str ]) -> Lines {
1131
v.iter ( ) .map ( | s | s.as_bytes ( ) ) .collect ( )
ff0af1ee unknown 1 month ago
1132
}
1133
fn text ( g : & FileGraph, m : & Materialized) -> String {
1134
String :: from_utf8( g.render ( m, & | c| c.short ( 4 ) ) ) .unwrap ( )
1135
}
1136
1137
struct Deps ( HashMap< ChangeHash, Vec< ChangeHash> > ) ;
1138
impl DepOracle for Deps {
1139
fn depends_on ( & self , a : & ChangeHash, b : & ChangeHash) -> bool {
1140
if a = = b {
1141
return true ;
1142
}
1143
let mut stack = vec! [ * a] ;
0bdc3f91 Andy McCall 1 month ago ↶
1144
let mut seen = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
1145
while let Some ( x) = stack.pop ( ) {
1146
if let Some ( ds) = self .0. get ( & x) {
1147
for d in ds {
1148
if d = = b {
1149
return true ;
1150
}
1151
if seen.insert ( * d) {
1152
stack.push ( * d) ;
1153
}
1154
}
1155
}
1156
}
1157
false
e83354cd Andy McCall 1 month ago ↶
1158
}
1159
}
1160
1161
1162
struct Linear ;
1163
impl DepOracle for Linear {
1164
fn depends_on ( & self , a : & ChangeHash, b : & ChangeHash) -> bool {
1165
a.0 [ .. 2 ] > = b.0 [ .. 2 ]
1166
}
1167
}
1168
1169
1170
1171
fn edited_file ( n : usize , revs : usize , per : usize ) -> FileGraph {
1172
let hn = | i : usize | {
1173
let mut b = [ 0 u8 ; 32 ] ;
1174
b[ .. 2 ] .copy_from_slice ( & ( i as u16 ) .to_be_bytes ( ) ) ;
1175
ObjectRef( b)
1176
} ;
1177
let mut g = FileGraph:: new( ) ;
1178
let first: Vec< String> = ( 0 .. n) .map ( | i | format! ( " line {i} \n " ) ) .collect ( ) ;
1179
let first: Vec< & str > = first.iter ( ) .map ( String :: as_str) .collect ( ) ;
1180
g.insert ( hn ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & first) ) ;
1181
for r in 2 .. revs + 2 {
1182
let order = g.materialize ( & Linear) .live_atoms ( ) ;
1183
let step = order.len ( ) / per;
1184
for j in 0 .. per {
1185
let at = j * step + ( r % step.max ( 1 ) ) ;
1186
let k = order[ at] ;
1187
g.delete (
1188
hn ( r) ,
1189
& AtomRange {
1190
change: k.0 ,
1191
from: k.1 ,
1192
to: k.1 + 1 ,
1193
} ,
1194
) ;
1195
let after = if at = = 0 {
1196
Vertex:: Start
1197
} else {
1198
Vertex:: Atom( order[ at - 1 ] )
1199
} ;
1200
let before = order
1201
.get ( at + 1 )
1202
.map ( | k | Vertex:: Atom( * k) )
1203
.unwrap_or ( Vertex:: End) ;
1204
g.insert ( hn ( r) , j as u32 , after, before, & lines ( & [ " new\n " ] ) ) ;
1205
}
ff0af1ee unknown 1 month ago
1206
}
e83354cd Andy McCall 1 month ago ↶
1207
g
1208
}
1209
1210
1211
# [ test ]
1212
fn the_order_shortcut_agrees_with_the_general_order ( ) {
1213
let g = edited_file ( 500 , 10 , 20 ) ;
1214
assert! ( g.as_chain ( ) .is_none ( ) ) ;
1215
let fast = g.as_order ( & Linear) .expect ( " a single order" ) ;
1216
assert_eq! (
1217
Materialized {
1218
segments: vec! [ Segment:: Lines( fast) ]
1219
} ,
1220
g.materialize_general ( & Linear)
1221
) ;
1222
1223
1224
let mut g = FileGraph:: new( ) ;
1225
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " ] ) ) ;
1226
let a = Vertex:: Atom( ( h ( 1 ) , 0 ) ) ;
1227
g.insert ( h ( 2 ) , 0 , a, Vertex:: End, & lines ( & [ " b\n " ] ) ) ;
1228
g.insert ( h ( 3 ) , 0 , a, Vertex:: End, & lines ( & [ " c\n " ] ) ) ;
1229
assert! ( g.as_order ( & NoDeps) .is_none ( ) ) ;
1230
assert! ( g.materialize ( & NoDeps) .is_conflicted ( ) ) ;
dbf06d34 Andy McCall 1 month ago ↶
1231
}
1232
1233
1234
1235
fn apply_spliced (
1236
g : & mut FileGraph,
1237
h : ChangeHash,
1238
inserts : & [( Vertex , Vertex , usize ) ],
1239
deleted : & [AtomKey],
1240
) {
1241
let order = g.take_order ( ) ;
1242
let mut runs = Vec :: new( ) ;
1243
let mut next = 0 u32 ;
1244
for ( i, & ( a, b, n) ) in inserts.iter ( ) .enumerate ( ) {
1245
let text: Vec< String> = ( 0 .. n) .map ( | j | format! ( " {i} .{j} \n " ) ) .collect ( ) ;
1246
let text: Vec< & str > = text.iter ( ) .map ( String :: as_str) .collect ( ) ;
1247
g.insert ( h, next, a, b, & lines ( & text) ) ;
1248
runs.push ( ( a, b, next, n as u32 ) ) ;
1249
next + = n as u32 ;
1250
}
1251
for k in deleted {
1252
g.delete (
1253
h,
1254
& AtomRange {
1255
change: k.0 ,
1256
from: k.1 ,
1257
to: k.1 + 1 ,
1258
} ,
1259
) ;
1260
}
1261
if let Some ( o) = order {
7eac74ab Andy McCall 1 month ago ↶
1262
g.keep_spliced ( o, h, & runs, deleted) ;
dbf06d34 Andy McCall 1 month ago ↶
1263
}
1264
}
1265
1266
1267
1268
fn random_edits (
1269
l : & [AtomKey],
1270
rnd : & mut impl FnMut( usize ) -> usize ,
1271
) -> ( Vec< ( Vertex, Vertex, usize ) > , Vec< AtomKey> ) {
1272
let ( mut inserts, mut deleted) = ( Vec :: new( ) , Vec :: new( ) ) ;
1273
let mut i = rnd ( 3 ) ;
1274
while i < = l.len ( ) {
1275
let del = rnd ( 3 ) .min ( l.len ( ) - i) ;
1276
let add = rnd ( 3 ) ;
1277
let after = if i = = 0 {
1278
Vertex:: Start
1279
} else {
1280
Vertex:: Atom( l[ i - 1 ] )
1281
} ;
1282
let before = l.get ( i) .map ( | k | Vertex:: Atom( * k) ) .unwrap_or ( Vertex:: End) ;
1283
deleted.extend ( & l[ i.. i + del] ) ;
1284
if add > 0 {
1285
inserts.push ( ( after, before, add) ) ;
1286
}
1287
i + = del + 1 + rnd ( 6 ) ;
1288
}
1289
( inserts, deleted)
1290
}
1291
1292
1293
1294
1295
# [ test ]
1296
fn the_kept_order_follows_edits ( ) {
1297
let hn = | i : usize | {
1298
let mut b = [ 0 u8 ; 32 ] ;
1299
b[ .. 2 ] .copy_from_slice ( & ( i as u16 ) .to_be_bytes ( ) ) ;
1300
ObjectRef( b)
1301
} ;
1302
let mut seed = 7 u64 ;
1303
let mut rnd = move | n: usize | {
1304
seed = seed
1305
.wrapping_mul ( 6364136223846793005 )
1306
.wrapping_add ( 1442695040888963407 ) ;
1307
( ( seed > > 33 ) as usize ) % n.max ( 1 )
1308
} ;
1309
let mut deps = Deps( HashMap:: default( ) ) ;
1310
let mut g = FileGraph:: new( ) ;
1311
let first: Vec< String> = ( 0 .. 40 ) .map ( | i | format! ( " {i} \n " ) ) .collect ( ) ;
1312
let first: Vec< & str > = first.iter ( ) .map ( String :: as_str) .collect ( ) ;
1313
g.insert ( hn ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & first) ) ;
1314
let mut known: Vec< ChangeHash> = vec! [ hn ( 1 ) ] ;
1315
let mut c = 2 ;
1316
let ( mut spliced, mut conflicted) = ( 0 , 0 ) ;
1317
for step in 0 .. 400 {
1318
let l = g.materialize ( & deps) .live_atoms ( ) ;
1319
1320
1321
let pair = step % 7 = = 3 ;
1322
let base = known.clone ( ) ;
1323
for _ in 0 .. if pair { 2 } else { 1 } {
1324
let h = hn ( c) ;
1325
c + = 1 ;
1326
let ( inserts, deleted) = random_edits ( & l, & mut rnd) ;
1327
deps.0. insert ( h, base.clone ( ) ) ;
1328
apply_spliced ( & mut g, h, & inserts, & deleted) ;
1329
known.push ( h) ;
1330
if g.order.get ( ) .is_some ( ) {
1331
spliced + = 1 ;
1332
}
1333
let m = g.materialize ( & deps) ;
1334
assert_eq! ( m, g.materialize_general ( & deps) , " step {step}" ) ;
1335
if m.is_conflicted ( ) {
1336
conflicted + = 1 ;
1337
}
1338
}
1339
1340
1341
if g.materialize ( & deps) .is_conflicted ( ) {
1342
let h = hn ( c) ;
1343
c + = 1 ;
1344
let all = g.materialize ( & deps) .live_atoms ( ) ;
1345
deps.0. insert ( h, known.clone ( ) ) ;
1346
apply_spliced ( & mut g, h, & [ ( Vertex:: Start, Vertex:: End, 5 ) ] , & all) ;
1347
known.push ( h) ;
1348
assert_eq! ( g.materialize ( & deps) , g.materialize_general ( & deps) ) ;
1349
}
1350
}
1351
assert! (
1352
spliced > 100 & & conflicted > 0 ,
1353
" {spliced} spliced, {conflicted} conflicted"
1354
) ;
7eac74ab Andy McCall 1 month ago ↶
1355
}
1356
1357
1358
1359
1360
# [ test ]
1361
fn the_kept_order_takes_no_line_that_arrives_deleted ( ) {
1362
let mut deps = Deps( HashMap:: default( ) ) ;
1363
let mut g = FileGraph:: new( ) ;
1364
g.insert (
1365
h ( 1 ) ,
1366
0 ,
1367
Vertex:: Start,
1368
Vertex:: End,
1369
& lines ( & [ " a\n " , " b\n " , " c\n " ] ) ,
1370
) ;
1371
1372
apply_spliced ( & mut g, h ( 2 ) , & [ ] , & [ ( h ( 1 ) , 2 ) ] ) ;
1373
deps.0. insert ( h ( 2 ) , vec! [ h ( 1 ) ] ) ;
1374
let _ = g.materialize ( & deps) ;
1375
assert! ( g.order.get ( ) .is_some ( ) ) ;
1376
let ( a, b) = ( Vertex:: Atom( ( h ( 1 ) , 0 ) ) , Vertex:: Atom( ( h ( 1 ) , 1 ) ) ) ;
1377
1378
deps.0. insert ( h ( 3 ) , vec! [ h ( 2 ) ] ) ;
1379
deps.0. insert ( h ( 4 ) , vec! [ h ( 3 ) ] ) ;
1380
apply_spliced ( & mut g, h ( 4 ) , & [ ] , & [ ( h ( 3 ) , 0 ) ] ) ;
1381
apply_spliced ( & mut g, h ( 3 ) , & [ ( a, b, 1 ) ] , & [ ] ) ;
1382
let m = g.materialize ( & deps) ;
1383
assert_eq! ( m, g.materialize_general ( & deps) ) ;
1384
assert_eq! ( text ( & g, & m) , " a\n b\n " ) ;
e83354cd Andy McCall 1 month ago ↶
1385
}
1386
1387
1388
# [ test ]
1389
# [ ignore ]
1390
fn bench_materialize_edited_file ( ) {
1391
let g = edited_file ( 20_000 , 50 , 100 ) ;
1392
let t = std:: time:: Instant:: now( ) ;
1393
let mut n = 0 ;
1394
for _ in 0 .. 20 {
1395
n + = g.materialize ( & Linear) .live_atoms ( ) .len ( ) ;
1396
}
1397
eprintln! (
1398
" materialize: {:.2} ms each ({n} atoms)" ,
1399
t.elapsed ( ) .as_secs_f64 ( ) * 1000. 0 / 20. 0
1400
) ;
598009a7 Andy McCall 1 month ago ↶
1401
}
1402
1403
1404
1405
# [ test ]
1406
fn the_chain_shortcut_agrees_with_the_general_order ( ) {
1407
let mut g = FileGraph:: new( ) ;
1408
g.insert (
1409
h ( 1 ) ,
1410
0 ,
1411
Vertex:: Start,
1412
Vertex:: End,
1413
& lines ( & [ " a\n " , " b\n " , " c\n " ] ) ,
1414
) ;
1415
assert! ( g.as_chain ( ) .is_some ( ) ) ;
1416
assert_eq! ( g.materialize ( & NoDeps) , g.materialize_general ( & NoDeps) ) ;
1417
1418
g.insert (
1419
h ( 2 ) ,
1420
0 ,
1421
Vertex:: Atom( ( h ( 1 ) , 2 ) ) ,
1422
Vertex:: End,
1423
& lines ( & [ " d\n " ] ) ,
1424
) ;
1425
assert! ( g.as_chain ( ) .is_some ( ) ) ;
1426
assert_eq! ( g.materialize ( & NoDeps) , g.materialize_general ( & NoDeps) ) ;
1427
1428
g.insert (
1429
h ( 4 ) ,
1430
0 ,
1431
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1432
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1433
& lines ( & [ " x\n " ] ) ,
1434
) ;
1435
assert! ( g.as_chain ( ) .is_none ( ) ) ;
1436
assert_eq! ( text ( & g, & g.materialize ( & NoDeps) ) , " a\n x\n b\n c\n d\n " ) ;
1437
1438
let mut c = FileGraph:: new( ) ;
1439
c.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " ] ) ) ;
1440
c.insert ( h ( 2 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " b\n " ] ) ) ;
1441
assert! ( c.as_chain ( ) .is_none ( ) ) ;
1442
assert! ( c.materialize ( & NoDeps) .is_conflicted ( ) ) ;
1443
1444
let mut d = FileGraph:: new( ) ;
1445
d.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
1446
d.delete (
1447
h ( 3 ) ,
1448
& AtomRange {
1449
change: h ( 1 ) ,
1450
from: 0 ,
1451
to: 1 ,
1452
} ,
1453
) ;
1454
assert! ( d.as_chain ( ) .is_none ( ) ) ;
1455
assert_eq! ( d.materialize ( & NoDeps) , d.materialize_general ( & NoDeps) ) ;
1456
1457
let e = FileGraph:: new( ) ;
1458
assert_eq! ( e.materialize ( & NoDeps) , e.materialize_general ( & NoDeps) ) ;
ff0af1ee unknown 1 month ago
1459
}
1460
1461
# [ test ]
1462
fn sequential_inserts_and_deletes ( ) {
1463
let mut g = FileGraph:: new( ) ;
75167672 Andy McCall 1 month ago
1464
g.insert (
1465
h ( 1 ) ,
1466
0 ,
1467
Vertex:: Start,
1468
Vertex:: End,
1469
& lines ( & [ " a\n " , " b\n " , " c\n " ] ) ,
1470
) ;
ff0af1ee unknown 1 month ago
1471
let m = g.materialize ( & NoDeps) ;
1472
assert! ( ! m.is_conflicted ( ) ) ;
1473
assert_eq! ( text ( & g, & m) , " a\n b\n c\n " ) ;
1474
1475
75167672 Andy McCall 1 month ago
1476
g.insert (
1477
h ( 2 ) ,
1478
0 ,
1479
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1480
Vertex:: Atom( ( h ( 1 ) , 2 ) ) ,
1481
& lines ( & [ " x\n " ] ) ,
1482
) ;
1483
g.delete (
1484
h ( 2 ) ,
1485
& AtomRange {
1486
change: h ( 1 ) ,
1487
from: 0 ,
1488
to: 1 ,
1489
} ,
1490
) ;
ff0af1ee unknown 1 month ago
1491
let deps = Deps( [ ( h ( 2 ) , vec! [ h ( 1 ) ] ) ] .into_iter ( ) .collect ( ) ) ;
1492
let m = g.materialize ( & deps) ;
1493
assert! ( ! m.is_conflicted ( ) ) ;
1494
assert_eq! ( text ( & g, & m) , " b\n x\n c\n " ) ;
1495
assert_eq! ( m.live_atoms ( ) , vec! [ ( h ( 1 ) , 1 ) , ( h ( 2 ) , 0 ) , ( h ( 1 ) , 2 ) ] ) ;
1496
}
1497
1498
# [ test ]
1499
fn concurrent_inserts_at_same_anchor_conflict ( ) {
1500
let mut g = FileGraph:: new( ) ;
1501
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1502
g.insert (
1503
h ( 2 ) ,
1504
0 ,
1505
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1506
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1507
& lines ( & [ " from-2\n " ] ) ,
1508
) ;
1509
g.insert (
1510
h ( 3 ) ,
1511
0 ,
1512
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1513
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1514
& lines ( & [ " from-3\n " , " more-3\n " ] ) ,
1515
) ;
1516
let deps = Deps(
1517
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1518
.into_iter ( )
1519
.collect ( ) ,
1520
) ;
ff0af1ee unknown 1 month ago
1521
let m = g.materialize ( & deps) ;
1522
assert! ( m.is_conflicted ( ) ) ;
1523
assert_eq! ( m.conflict_count ( ) , 1 ) ;
1524
assert_eq! (
1525
m.segments,
1526
vec! [
1527
Segment:: Lines( vec! [ ( h ( 1 ) , 0 ) ] ) ,
1528
Segment:: Conflict( vec! [ vec! [ ( h ( 2 ) , 0 ) ] , vec! [ ( h ( 3 ) , 0 ) , ( h ( 3 ) , 1 ) ] ] ) ,
1529
Segment:: Lines( vec! [ ( h ( 1 ) , 1 ) ] ) ,
1530
]
1531
) ;
1532
let t = text ( & g, & m) ;
1533
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}" ) ;
1534
}
1535
1536
# [ test ]
1537
fn concurrent_inserts_at_different_anchors_do_not_conflict ( ) {
1538
let mut g = FileGraph:: new( ) ;
75167672 Andy McCall 1 month ago
1539
g.insert (
1540
h ( 1 ) ,
1541
0 ,
1542
Vertex:: Start,
1543
Vertex:: End,
1544
& lines ( & [ " a\n " , " b\n " , " c\n " ] ) ,
1545
) ;
1546
g.insert (
1547
h ( 2 ) ,
1548
0 ,
1549
Vertex:: Start,
1550
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1551
& lines ( & [ " top\n " ] ) ,
1552
) ;
1553
g.insert (
1554
h ( 3 ) ,
1555
0 ,
1556
Vertex:: Atom( ( h ( 1 ) , 2 ) ) ,
1557
Vertex:: End,
1558
& lines ( & [ " bottom\n " ] ) ,
1559
) ;
1560
let deps = Deps(
1561
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1562
.into_iter ( )
1563
.collect ( ) ,
1564
) ;
ff0af1ee unknown 1 month ago
1565
let m = g.materialize ( & deps) ;
1566
assert! ( ! m.is_conflicted ( ) ) ;
1567
assert_eq! ( text ( & g, & m) , " top\n a\n b\n c\n bottom\n " ) ;
1568
}
1569
1570
# [ test ]
1571
fn concurrent_deletes_of_the_same_line_agree ( ) {
1572
let mut g = FileGraph:: new( ) ;
1573
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1574
g.delete (
1575
h ( 2 ) ,
1576
& AtomRange {
1577
change: h ( 1 ) ,
1578
from: 0 ,
1579
to: 1 ,
1580
} ,
1581
) ;
1582
g.delete (
1583
h ( 3 ) ,
1584
& AtomRange {
1585
change: h ( 1 ) ,
1586
from: 0 ,
1587
to: 1 ,
1588
} ,
1589
) ;
1590
let deps = Deps(
1591
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1592
.into_iter ( )
1593
.collect ( ) ,
1594
) ;
ff0af1ee unknown 1 month ago
1595
let m = g.materialize ( & deps) ;
1596
assert! ( ! m.is_conflicted ( ) ) ;
1597
assert_eq! ( text ( & g, & m) , " b\n " ) ;
1598
}
1599
1600
# [ test ]
1601
fn delete_insert_conflict_is_a_zombie ( ) {
1602
let mut g = FileGraph:: new( ) ;
1603
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
1604
75167672 Andy McCall 1 month ago
1605
g.delete (
1606
h ( 2 ) ,
1607
& AtomRange {
1608
change: h ( 1 ) ,
1609
from: 0 ,
1610
to: 1 ,
1611
} ,
1612
) ;
1613
g.insert (
1614
h ( 3 ) ,
1615
0 ,
1616
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1617
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1618
& lines ( & [ " after-a\n " ] ) ,
1619
) ;
1620
let deps = Deps(
1621
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1622
.into_iter ( )
1623
.collect ( ) ,
1624
) ;
ff0af1ee unknown 1 month ago
1625
let m = g.materialize ( & deps) ;
1626
assert! ( m.is_conflicted ( ) ) ;
1627
assert_eq! (
1628
m.segments,
1629
vec! [
75167672 Andy McCall 1 month ago
1630
Segment:: Zombie {
1631
deleted: vec! [ ( h ( 1 ) , 0 ) ] ,
1632
inserted: vec! [ ( h ( 3 ) , 0 ) ]
1633
} ,
ff0af1ee unknown 1 month ago
1634
Segment:: Lines( vec! [ ( h ( 1 ) , 1 ) ] ) ,
1635
]
1636
) ;
1637
let t = text ( & g, & m) ;
1638
assert! ( t.contains ( " -------\n a\n =======" ) , " {t}" ) ;
1639
assert! ( t.contains ( " after-a\n >>>>>>>" ) , " {t}" ) ;
1640
1641
75167672 Andy McCall 1 month ago
1642
let deps = Deps(
1643
[ ( h ( 2 ) , vec! [ h ( 1 ) , h ( 3 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1644
.into_iter ( )
1645
.collect ( ) ,
1646
) ;
ff0af1ee unknown 1 month ago
1647
let m = g.materialize ( & deps) ;
1648
assert! ( ! m.is_conflicted ( ) ) ;
1649
assert_eq! ( text ( & g, & m) , " after-a\n b\n " ) ;
1650
}
1651
1652
# [ test ]
23b217d7 Andy McCall 1 month ago ↶
1653
fn insert_after_a_line_deleted_by_a_dependency_is_not_a_conflict ( ) {
1654
1655
1656
let mut g = FileGraph:: new( ) ;
1657
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1658
g.delete (
1659
h ( 2 ) ,
1660
& AtomRange {
1661
change: h ( 1 ) ,
1662
from: 1 ,
1663
to: 2 ,
1664
} ,
1665
) ;
1666
g.insert (
1667
h ( 3 ) ,
1668
0 ,
1669
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1670
Vertex:: End,
1671
& lines ( & [ " c\n " ] ) ,
1672
) ;
1673
let deps = Deps(
1674
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 2 ) ] ) ]
1675
.into_iter ( )
1676
.collect ( ) ,
1677
) ;
23b217d7 Andy McCall 1 month ago ↶
1678
let m = g.materialize ( & deps) ;
1679
assert! ( ! m.is_conflicted ( ) , " {:?}" , m.segments) ;
1680
assert_eq! ( text ( & g, & m) , " a\n c\n " ) ;
1681
1682
1683
let mut g = FileGraph:: new( ) ;
1684
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " x\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1685
g.delete (
1686
h ( 1 ) ,
1687
& AtomRange {
1688
change: h ( 1 ) ,
1689
from: 0 ,
1690
to: 1 ,
1691
} ,
1692
) ;
1693
g.insert (
1694
h ( 2 ) ,
1695
0 ,
1696
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1697
Vertex:: End,
1698
& lines ( & [ " y\n " ] ) ,
1699
) ;
23b217d7 Andy McCall 1 month ago ↶
1700
let deps = Deps( [ ( h ( 2 ) , vec! [ h ( 1 ) ] ) ] .into_iter ( ) .collect ( ) ) ;
1701
let m = g.materialize ( & deps) ;
1702
assert! ( ! m.is_conflicted ( ) ) ;
1703
assert_eq! ( text ( & g, & m) , " y\n " ) ;
1704
}
1705
1706
# [ test ]
ff0af1ee unknown 1 month ago
1707
fn resolution_collapses_a_conflict ( ) {
1708
let mut g = FileGraph:: new( ) ;
1709
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1710
g.insert (
1711
h ( 2 ) ,
1712
0 ,
1713
Vertex:: Start,
1714
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1715
& lines ( & [ " x\n " ] ) ,
1716
) ;
1717
g.insert (
1718
h ( 3 ) ,
1719
0 ,
1720
Vertex:: Start,
1721
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1722
& lines ( & [ " y\n " ] ) ,
1723
) ;
1724
let mut deps: HashMap< _ , _ > = [ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1725
.into_iter ( )
1726
.collect ( ) ;
ff0af1ee unknown 1 month ago
1727
assert! ( g.materialize ( & Deps( deps.clone ( ) ) ) .is_conflicted ( ) ) ;
1728
75167672 Andy McCall 1 month ago
1729
g.delete (
1730
h ( 4 ) ,
1731
& AtomRange {
1732
change: h ( 2 ) ,
1733
from: 0 ,
1734
to: 1 ,
1735
} ,
1736
) ;
ff0af1ee unknown 1 month ago
1737
deps.insert ( h ( 4 ) , vec! [ h ( 2 ) , h ( 3 ) ] ) ;
1738
let m = g.materialize ( & Deps( deps) ) ;
1739
assert! ( ! m.is_conflicted ( ) ) ;
1740
assert_eq! ( text ( & g, & m) , " y\n a\n " ) ;
1741
}
1742
1743
# [ test ]
1744
fn empty_and_unterminated_files ( ) {
1745
let g = FileGraph:: new( ) ;
1746
let m = g.materialize ( & NoDeps) ;
1747
assert_eq! ( m.segments, vec! [ ] ) ;
1748
assert_eq! ( text ( & g, & m) , " " ) ;
1749
let mut g = FileGraph:: new( ) ;
1750
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " no newline" ] ) ) ;
1751
assert_eq! ( text ( & g, & g.materialize ( & NoDeps) ) , " no newline" ) ;
1752
}
1753
252e8cb2 Andy McCall 1 month ago ↶
1754
# [ test ]
1755
fn serialization_round_trip ( ) {
1756
let mut g = FileGraph:: new( ) ;
1757
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1758
g.insert (
1759
h ( 2 ) ,
1760
0 ,
1761
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1762
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1763
& lines ( & [ " x\n " ] ) ,
1764
) ;
1765
g.delete (
1766
h ( 3 ) ,
1767
& AtomRange {
1768
change: h ( 1 ) ,
1769
from: 1 ,
1770
to: 2 ,
1771
} ,
1772
) ;
252e8cb2 Andy McCall 1 month ago ↶
1773
let v = g.to_value ( ) ;
1774
let bytes = crate :: cbor:: encode( & v) ;
1775
let back = FileGraph:: from_value( & crate :: cbor:: decode( & bytes) .unwrap ( ) ) .unwrap ( ) ;
75167672 Andy McCall 1 month ago
1776
let deps = Deps(
1777
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1778
.into_iter ( )
1779
.collect ( ) ,
1780
) ;
252e8cb2 Andy McCall 1 month ago ↶
1781
assert_eq! ( back.materialize ( & deps) , g.materialize ( & deps) ) ;
1782
assert_eq! ( text ( & back, & back.materialize ( & deps) ) , " a\n x\n " ) ;
75167672 Andy McCall 1 month ago
1783
assert_eq! (
1784
crate :: cbor:: encode( & back.to_value ( ) ) ,
1785
bytes,
1786
" deterministic"
1787
) ;
252e8cb2 Andy McCall 1 month ago ↶
1788
}
1789
ff0af1ee unknown 1 month ago
1790
1791
# [ test ]
1792
fn application_order_is_irrelevant ( ) {
1793
use rand:: seq:: SliceRandom;
75167672 Andy McCall 1 month ago
1794
type Op = (
1795
ChangeHash,
01a47cd7 Andy McCall 1 month ago ↶
1796
Vec< ( u32 , Vertex, Vertex, Lines) > ,
75167672 Andy McCall 1 month ago
1797
Vec< AtomRange> ,
1798
) ;
ff0af1ee unknown 1 month ago
1799
let ops: Vec< Op> = vec! [
75167672 Andy McCall 1 month ago
1800
(
1801
h ( 1 ) ,
1802
vec! [ ( 0 , Vertex:: Start, Vertex:: End, lines ( & [ " a\n " , " b\n " , " c\n " ] ) ) ] ,
1803
vec! [ ] ,
1804
) ,
1805
(
1806
h ( 2 ) ,
1807
vec! [ (
1808
0 ,
1809
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1810
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1811
lines ( & [ " p\n " ] ) ,
1812
) ] ,
1813
vec! [ ] ,
1814
) ,
1815
(
1816
h ( 3 ) ,
1817
vec! [ (
1818
0 ,
1819
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1820
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1821
lines ( & [ " q\n " , " r\n " ] ) ,
1822
) ] ,
1823
vec! [ AtomRange {
1824
change: h ( 1 ) ,
1825
from: 2 ,
1826
to: 3 ,
1827
} ] ,
1828
) ,
1829
(
1830
h ( 4 ) ,
1831
vec! [ (
1832
0 ,
1833
Vertex:: Atom( ( h ( 3 ) , 1 ) ) ,
1834
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1835
lines ( & [ " s\n " ] ) ,
1836
) ] ,
1837
vec! [ AtomRange {
1838
change: h ( 1 ) ,
1839
from: 1 ,
1840
to: 2 ,
1841
} ] ,
1842
) ,
1843
(
1844
h ( 5 ) ,
1845
vec! [ ( 0 , Vertex:: Atom( ( h ( 1 ) , 2 ) ) , Vertex:: End, lines ( & [ " z\n " ] ) ) ] ,
1846
vec! [ ] ,
1847
) ,
ff0af1ee unknown 1 month ago
1848
] ;
1849
let deps = Deps(
75167672 Andy McCall 1 month ago
1850
[
1851
( h ( 2 ) , vec! [ h ( 1 ) ] ) ,
1852
( h ( 3 ) , vec! [ h ( 1 ) ] ) ,
1853
( h ( 4 ) , vec! [ h ( 3 ) , h ( 1 ) ] ) ,
1854
( h ( 5 ) , vec! [ h ( 1 ) ] ) ,
1855
]
1856
.into_iter ( )
1857
.collect ( ) ,
ff0af1ee unknown 1 month ago
1858
) ;
1859
let build = | order : & [usize ]| {
1860
let mut g = FileGraph:: new( ) ;
1861
for & i in order {
1862
let ( c, ins, dels) = & ops[ i] ;
1863
for ( idx, a, b, l) in ins {
1864
g.insert ( * c, * idx, * a, * b, l) ;
1865
}
1866
for d in dels {
1867
g.delete ( * c, d) ;
1868
}
1869
}
1870
let m = g.materialize ( & deps) ;
1871
( m.clone ( ) , text ( & g, & m) )
1872
} ;
1873
let reference = build ( & [ 0 , 1 , 2 , 3 , 4 ] ) ;
1874
assert! ( reference.0. is_conflicted ( ) ) ;
1875
let mut rng = rand:: thread_rng( ) ;
1876
let mut order: Vec< usize > = ( 0 .. ops.len ( ) ) .collect ( ) ;
1877
for _ in 0 .. 50 {
1878
order.shuffle ( & mut rng) ;
1879
assert_eq! ( build ( & order) , reference, " order {order:?}" ) ;
1880
}
1881
}
1882
}