Skip to main content

instance_copy_on_write/
lib.rs

1/*-
2 * instance-copy-on-write - a synchronization primitive based on copy-on-write.
3 * 
4 * Copyright (C) 2025 Aleksandr Morozov alex@4neko.org
5 * 
6 * The instance-copy-on-write crate can be redistributed and/or modified
7 * under the terms of either of the following licenses:
8 *
9 *   1. The MIT License (MIT)
10 */
11
12/*!
13 An experimental thread access synchronization primitive 
14 which is based on CoW Copy-on-Write and also exclusive lock.
15 
16 By default an `RwLock` based implementation is used, because the 
17 `atomics` based implementation is still not ready. It can be activated 
18 by enabling the feature prefer_mutex.
19
20 **feature = prefer_mutex**
21 
22 The `ICoWRead<DATA>` instance with inner value `DATA` obtained from the 
23 `ICoW<DATA>` is valid even after the inner value was copied and copy was 
24 commited back. All `readers` which will will read the `ICoW` instance after 
25 the `commit` will receive a `ICoWRead<DATA>` with updated `DATA`.
26
27 Exclusive copying prevents `readers` from reading while simple `non-exclusive` 
28 copy allows to access the inner data for reading and further copying. But, the 
29 `non-exclusive` copies are not in sync, so each copy is uniq. The `sequential` 
30 commit of copied data is not yet supported.
31
32 The experimental `cow_refcell.rs` was added to support single-thread mode
33 pure CoW model which is not really usefull, but this is a path to the future
34 `async` implementation.
35
36 *  ```ignore
37
38    let val = 
39        ICoW::new(TestStruct::new(1, 2));
40
41    // read only 
42    let read1 = val.read();
43    //..
44    drop(read1);
45
46    // ...
47
48    // copy on write NON-exclusively, read is possible
49    let mut transaction = val.clone_copy();
50
51    transaction.start = 5;
52    transaction.stop = 6;
53
54    // update, after calling this function, all reades who 
55    // read before will still see old version.
56    // all reades after, new
57    transaction.commit();
58    //or
59    drop(transaction); // to drop changes
60
61
62    // exclusive lock, read is also not possible
63
64    let res = val.clone_exclusivly();
65    // ..
66    // commit changes releasing lock
67    commit(val); //or
68    drop(val); // to drop changes and release lock
69
70    ```
71 */
72
73//extern crate thread_local;
74
75 /// Type of the sync code.
76 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
77 pub enum ICoWLockTypes
78 {
79    /// Based on atomic and backoff.
80    Atomic,
81
82    /// based on the OS RwLock
83    RwLock,
84 }
85
86impl fmt::Display for ICoWLockTypes
87{
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
89    {
90        match self
91        {
92            Self::Atomic => 
93                write!(f, "atomic"),
94            Self::RwLock => 
95                write!(f, "rwlock"),
96        }
97    }
98}
99
100/// Errors which may be returned.
101#[derive(Copy, Clone, Debug, PartialEq, Eq)]
102pub enum ICoWError
103{
104    /// An attempt to write to the instance using non exclusive copy-on-write operation
105    /// while the exclusive is still going.
106    ExclusiveLockPending,
107
108    /// Is issued if "exponential backoff has completed and blocking the thread is advised".
109    WouldBlock,
110}
111
112impl fmt::Display for ICoWError
113{
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
115    {
116        match self
117        {
118            Self::ExclusiveLockPending => 
119                write!(f, "already exlcusivly locked"),
120            Self::WouldBlock => 
121                write!(f, "cannot perform try operation due to blocking"),
122        }
123    }
124}
125
126
127/// A lightweight CoW implementation.
128#[cfg(all(target_has_atomic = "32", feature = "prefer_mutex"))]
129pub mod cow;
130
131/// A RwLock based copy-on-write.
132#[cfg(any(not(target_has_atomic = "32"), not(feature = "prefer_mutex")))]
133pub mod cow_mutex;
134
135#[cfg(any(not(target_has_atomic = "32"), not(feature = "prefer_mutex")))]
136pub mod cow_refcell;
137
138use std::fmt;
139
140#[cfg(all(target_has_atomic = "32", feature = "prefer_mutex"))]
141pub use cow::{ICoW, ICoWRead, ICoWCopy, ICoWLock, ICoWWeak, ICoWWeakRead};
142
143#[cfg(any(not(target_has_atomic = "32"), not(feature = "prefer_mutex")))]
144pub use cow_mutex::{ICoW, ICoWRead, ICoWCopy, ICoWLock, ICoWWeak, ICoWWeakRead};
145
146#[cfg(all(not(target_has_atomic = "32"), feature = "prefer_mutex"))]
147compile_error!("target CPU does not support 'target_has_atomic'");
148
149pub trait ICowType
150{
151    fn get_lock_type() -> ICoWLockTypes;
152}
153
154#[cfg(test)]
155mod test
156{
157    use std::{sync::{LazyLock, mpsc}, thread, time::{Duration, Instant}};
158
159    use super::*;
160
161
162
163
164    #[test]
165    fn test_3()
166    {
167        #[derive(Debug, Clone)]
168        struct Test { s: String }
169
170        let icow = ICoW::new(Test{ s: "test".into() });
171
172        for _ in 0..10
173        {
174            let s = Instant::now();
175
176            let read0 = icow.read();
177
178            let e = s.elapsed();
179
180            println!("{:?}", e);
181        }
182
183    }
184
185    #[test]
186    fn test_33()
187    {
188        #[derive(Debug, Clone)]
189        struct Test { s: String };
190
191        let icow = ICoW::new(Test{ s: "test".into() });
192
193        let write_ex = icow.try_clone_copy_exclusivly().unwrap();
194
195        {
196        let write_ex_err = icow.try_clone_copy_exclusivly();
197        assert_eq!(write_ex_err.is_none(), true);
198        }
199
200        {
201        let write_ex_err = icow.try_clone_copy();
202        assert_eq!(write_ex_err.is_none(), true);
203        }
204        {
205        let read1 = icow.try_read();
206        assert_eq!(read1.is_none(), true);
207        }
208
209        drop(write_ex);
210
211        drop(icow);
212
213    }
214
215    #[test]
216    fn test_4()
217    {
218        #[derive(Debug, Clone)]
219        struct Test { s: u32 }
220
221        let icow = ICoW::new(Test{ s: 1 });
222
223        let read0 = icow.read();
224        let read1 = icow.read();
225
226        let mut excl_write = icow.try_clone_copy_exclusivly().unwrap();
227
228        excl_write.s = 5;
229
230
231        excl_write.commit();
232
233        assert_eq!(read0.s, 1);
234
235        let read3 = icow.read();
236        assert_eq!(read3.s, 5);
237
238        let mut writing = icow.try_clone_copy().unwrap();
239        writing.s = 4;
240
241        writing.commit().unwrap();
242
243        assert_eq!(read0.s, 1);
244        assert_eq!(read3.s, 5);
245
246        let read4 = icow.read();
247        assert_eq!(read4.s, 4);
248    }
249
250    #[test]
251    fn test_parking_lot_reader_wakeup()
252    {
253        #[derive(Debug, Clone)]
254        struct Test { s: u32 }
255
256        let icow = ICoW::new(Test{ s: 1 });
257
258        let read0 = icow.read();
259        let read2 = icow.read();
260
261        let c_icow = icow.clone();
262        let (se, rc) = mpsc::channel::<()>();
263        let handler0 = 
264            std::thread::spawn(move || 
265                {
266                    let mut lock0 = c_icow.try_clone_copy_exclusivly().unwrap();
267
268                    se.send(()).unwrap();
269
270                    lock0.s = 5;
271
272                    std::thread::sleep(Duration::from_secs(2));
273
274                    lock0.commit();
275                }
276            );
277
278        rc.recv().unwrap();
279
280        let s = Instant::now();
281
282        let read1 = icow.read();
283        
284        let e = s.elapsed();
285
286        println!("thread wait: {:?}", e);
287
288        assert_eq!(e.as_secs(), 2);
289
290        handler0.join().unwrap();
291
292        drop(read0);
293        drop(read1);
294        drop(read2);
295    }
296
297    #[test]
298    fn text_9_exclu_lock_pend()
299    {
300        #[derive(Debug, Clone)]
301        struct Test { s: u32 }
302
303        let icow = ICoW::new(Test{ s: 1 });
304
305            let mut write0 = icow.clone_copy();
306            write0.s = 1222;
307
308        let c_icow = icow.clone();
309        let (se, rc) = mpsc::channel::<()>();
310        let handler0 = 
311            std::thread::spawn(move || 
312                {
313                    let mut lock0 = 
314                        loop 
315                        {
316                            let res = c_icow.try_clone_copy_exclusivly();
317
318                            if res.is_none() == true
319                            {
320                                continue;
321                            }
322                            
323                            break res.unwrap();
324                        };
325
326                    se.send(()).unwrap();
327
328                    lock0.s = 5;
329
330                    std::thread::sleep(Duration::from_secs(1));
331
332                    lock0.commit();
333                }
334            );
335
336
337        rc.recv().unwrap();
338
339        let s = Instant::now();
340
341        let commit_res = write0.commit();
342        assert_eq!(commit_res.is_err(), true);
343        assert_eq!(commit_res.as_ref().err().unwrap().0, ICoWError::ExclusiveLockPending);
344        write0 = commit_res.err().unwrap().1;
345
346        write0.commit_blocking(true).unwrap();
347        
348        let e = s.elapsed();
349
350        println!("thread wait: {:?}", e);
351
352        assert_eq!(e.as_secs(), 1);
353
354        handler0.join().unwrap();
355
356        return;
357    }
358
359    #[test]
360    fn test_5()
361    {
362        #[derive(Debug, Clone)]
363        struct Test { s: u32 }
364
365        let icow = ICoW::new(Test{ s: 1 });
366
367        let read0 = icow.read();
368        let read2 = icow.read();
369        
370        let c_icow = icow.clone();
371
372        let (se, rc) = mpsc::channel::<()>();
373        let handler0 = 
374            std::thread::spawn(move || 
375                {
376                    let mut lock0 = c_icow.try_clone_copy_exclusivly().unwrap();
377
378                    se.send(()).unwrap();
379
380                    lock0.s = 5;
381
382                    std::thread::sleep(Duration::from_micros(2));
383
384                    lock0.commit();
385                }
386            );
387
388        rc.recv().unwrap();
389
390        let s = Instant::now();
391
392        let read1 = icow.read();
393        
394        let e = s.elapsed();
395
396        println!("{:?}", e);
397
398        
399        assert_eq!(read1.s, 5);
400        assert_eq!(read0.s, 1);
401
402        handler0.join().unwrap();
403
404        let weak0 = read0.weak();
405        let weak1 = read1.weak();
406
407        drop(read0);
408        drop(read1);
409
410        assert_eq!(weak0.upgrade().is_some(), true);
411        assert_eq!(weak1.upgrade().is_some(), true);
412
413        drop(read2);
414        assert_eq!(weak0.upgrade().is_none(), true);
415        assert_eq!(weak1.upgrade().is_some(), true);
416    }
417
418    #[test]
419    fn test_5_read_lock()
420    {
421        #[derive(Debug, Clone)]
422        struct Test { s: u32 }
423
424        let icow = ICoW::new(Test{ s: 1 });
425        
426        let c_icow = icow.clone();
427
428        let (se, rc) = mpsc::channel::<()>();
429        let (se2, rc2) = mpsc::channel::<()>();
430        let handler0 = 
431            std::thread::spawn(move || 
432                {
433                    rc2.recv().unwrap();
434
435                    let mut lock0 = 
436                        loop 
437                        {
438                            let res = c_icow.try_clone_copy_exclusivly();
439
440                            if res.is_none() == true
441                            {
442                                continue;
443                            }
444                            
445                            break res.unwrap();
446                        };
447
448                    se.send(()).unwrap();
449
450                    lock0.s = 5;
451
452                    lock0.commit();
453                }
454            );
455
456        let mut reads = Vec::<ICoWRead<'_, Test>>::with_capacity(20000);  
457        let mut sent = false;
458
459        let s = Instant::now();
460
461        for i in 0..10000
462        {
463            let read0 = icow.read();
464            if read0.s == 5
465            {
466                println!("break at {}", i);
467                break;
468            }
469
470            reads.push(read0);
471
472            if sent == false
473            {
474                se2.send(());
475                sent = true;
476            }
477        }
478        
479        let e = s.elapsed();
480
481        println!("{:?}", e);
482
483        assert_eq!(reads[0].s, 1);
484
485        handler0.join().unwrap();
486    }
487
488    #[test]
489    fn test_6()
490    {
491        #[derive(Debug, Clone)]
492        struct Test { s: u32 }
493
494        let icow = ICoW::new(Test{ s: 1 });
495
496        let read0 = icow.read();
497        let read2 = icow.read();
498        
499        let c_icow = icow.clone();
500
501        let (se, rc) = mpsc::channel::<()>();
502        let handler0 = 
503            std::thread::spawn(move || 
504                {
505                    let read2 = c_icow.read();
506
507                    let mut lock0 = c_icow.try_clone_copy_exclusivly().unwrap();
508
509                    se.send(()).unwrap();
510
511                    lock0.s = 5;
512
513                    std::thread::sleep(Duration::from_nanos(50));
514                    lock0.commit();
515
516                    let read3 = c_icow.read();
517
518                    assert_eq!(read2.s, 1);
519                    assert_eq!(read3.s, 5);
520                }
521            );
522
523        rc.recv().unwrap();
524
525        for _ in 0..100000000
526        {
527            let read1 = icow.read();
528
529            if read1.s == 1
530            {
531                continue;
532            }
533            else
534            {
535                break;
536            }
537        }
538
539        let read1 = icow.read();
540        assert_eq!(read1.item.s, 5);
541
542        handler0.join().unwrap();
543
544        return;
545    }
546
547    #[test]
548    fn test_6_drop()
549    {
550        #[derive(Debug, Clone)]
551        struct Test { s: u32 }
552
553        let icow = ICoW::new(Test{ s: 1 });
554
555        let read0 = icow.read();
556        let read2 = icow.read();
557        
558        let c_icow = icow.clone();
559
560        let (se, rc) = mpsc::channel::<()>();
561        let handler0 = 
562            std::thread::spawn(move || 
563                {
564                    let read2 = c_icow.read();
565
566                    let mut lock0 = c_icow.try_clone_copy_exclusivly().unwrap();
567
568                    rc.recv().unwrap();
569
570                    lock0.s = 5;
571
572                    std::thread::sleep(Duration::from_millis(1500));
573                    lock0.commit();
574
575                    let read3 = c_icow.read();
576
577                    assert_eq!(read2.s, 1);
578                    assert_eq!(read3.s, 5);
579                }
580            );
581
582        drop(read0);
583        let r2 = read2.clone_copy_into_inner();
584
585        se.send(()).unwrap();
586
587        drop(icow);
588
589        assert_eq!(r2.s, 1);
590
591        handler0.join().unwrap();
592
593        return;
594    }
595
596
597    #[test]
598    fn test_7()
599    {
600        #[derive(Debug, Clone)]
601        struct TestStruct { s: u32 }
602
603        impl TestStruct
604        {
605            fn new(s: u32) -> Self
606            {
607                return Self{ s: s };
608            }
609        }
610
611        static VAL: LazyLock<ICoW<TestStruct>> = 
612            LazyLock::new(|| ICoW::new(TestStruct::new(1))); 
613        
614
615        
616        
617            let borrow1 = VAL.read();
618            assert_eq!(borrow1.item.s, 1);
619
620            let (mpsc_send, mpsc_rcv) = mpsc::channel::<u64>();
621            let (mpsc_send2, mpsc_rcv2) = mpsc::channel::<u64>();
622
623            let thread1 = 
624                std::thread::spawn(move ||
625                    {
626                        for _ in 0..1000
627                        {
628                            let _ = mpsc_rcv2.recv();
629                            let borrow1 = VAL.read();
630
631                            let mut transaction = VAL.try_clone_copy_exclusivly().unwrap();
632
633                            transaction.s = 5;
634
635                            
636
637                            std::thread::sleep(Duration::from_nanos(1001));
638                            transaction.commit();
639                            let borrow2 = VAL.read();
640                            
641
642                            assert_eq!(borrow1.item.s, 1);
643
644                            assert_eq!(borrow2.item.s, 5);
645
646                            let _ = mpsc_send.send(1);
647                        }
648                    }
649                );
650            
651            
652
653            for x in 0..1000
654            {
655                println!("{}", x);
656                mpsc_send2.send(1).unwrap();
657                let _ = mpsc_rcv.recv();
658
659                let borrow1 = VAL.read();
660                assert_eq!(borrow1.s, 5);
661
662                let mut transaction = VAL.try_clone_copy_exclusivly().unwrap();
663                transaction.s = 1;
664                transaction.commit();
665
666                let borrow1 = VAL.read();
667                assert_eq!(borrow1.s, 1);
668                
669            }
670            
671            
672
673            thread1.join().unwrap();
674
675            
676    }
677
678
679    #[test]
680    fn test_8()
681    {
682        #[derive(Debug, Clone)]
683        struct Test { s: u32 }
684
685        let icow = ICoW::new(Test{ s: 1 });
686
687        for _ in 0..20
688        {
689            let read0 = icow.read();
690            let read2 = icow.read();
691            
692            let c_icow = icow.clone();
693
694            //let (se, rc) = mpsc::channel::<()>();
695            let handler0 = 
696                std::thread::spawn(move || 
697                    {
698                        let read2 = c_icow.read();
699
700                        let mut lock0 = c_icow.clone_copy();
701
702                        //se.send(()).unwrap();
703
704                        lock0.s = 5;
705
706                        std::thread::sleep(Duration::from_micros(1));
707                        lock0.commit_blocking(false).unwrap();
708
709                        let read3 = c_icow.read();
710
711                        assert_eq!(read2.s, 1);
712                        assert_eq!(read3.s, 5);
713                    }
714                );
715
716            //rc.recv().unwrap();
717
718            for i in 0..1000000000
719            {
720                let read1 = icow.read();
721
722                if read1.s == 1
723                {
724                    continue;
725                }
726                else
727                {
728                    println!("{}", i);
729                    break;
730                }
731            }
732
733            let read1 = icow.read();
734            assert_eq!(read1.s, 5);
735
736            handler0.join().unwrap();
737
738            let mut lock0 = icow.try_clone_copy().unwrap();
739            lock0.s = 1;
740            lock0.commit_blocking(false).unwrap();
741        }
742
743        return;
744    }
745
746    #[test]
747    fn test_9()
748    {
749        #[derive(Debug, Clone)]
750        struct Test { s: u32 }
751
752        let icow = ICoW::new(Test{ s: 1 });
753
754        let weak_reader = icow.reader();
755
756        let weak_r0 = weak_reader.aquire().unwrap();
757
758        assert_eq!(weak_r0.s, 1);
759
760        drop(weak_r0);
761
762        let mut copy1 = icow.clone_copy();
763        copy1.s = 8;
764        copy1.commit_blocking(true).unwrap();
765
766        let weak_r0 = weak_reader.aquire().unwrap();
767
768        assert_eq!(weak_r0.s, 8);
769
770        drop(weak_r0);
771
772        // drop icow, check that the aquire() returns None because the data and
773        // icow instance have gone.
774        drop(icow);
775
776        let weak_r0 = weak_reader.aquire();
777        assert_eq!(weak_r0.is_none(), true);
778
779    }
780
781    #[test]
782    fn test_10()
783    {
784        #[derive(Debug, Clone)]
785        struct Test { s: u32 }
786
787        let icow = ICoW::new(Test{ s: 1 });
788
789        let weak_reader = icow.reader();
790
791        let (tx, rx) = mpsc::channel::<()>();
792        let (tx2, rx2) = mpsc::channel::<()>();
793
794        let thread_hndl = 
795            thread::spawn(move ||
796                {
797                    let weak_r0 = weak_reader.aquire().unwrap();
798
799                    assert_eq!(weak_r0.s, 1);
800
801                    drop(weak_r0);
802
803                    tx.send(()).unwrap();
804
805                    // ----
806                    let _ = rx2.recv().unwrap();
807
808                    let weak_r0 = weak_reader.aquire().unwrap();
809
810                    assert_eq!(weak_r0.item_updated(), true);
811                    assert_eq!(weak_r0.s, 8);
812
813                    drop(weak_r0);
814
815                    tx.send(()).unwrap();
816                    // ----
817                    let _ = rx2.recv().unwrap();
818
819                    // check that icow dropped
820                    let weak_r0 = weak_reader.aquire();
821                    assert_eq!(weak_r0.is_none(), true);
822                }
823            );
824
825        let _ = rx.recv().unwrap();
826
827        let mut copy1 = icow.clone_copy();
828        copy1.s = 8;
829        copy1.commit_blocking(true).unwrap();
830
831        tx2.send(()).unwrap();
832        let _ = rx.recv().unwrap();
833
834        // drop icow, check that the aquire() returns None because the data and
835        // icow instance have gone.
836        drop(icow);
837
838        tx2.send(()).unwrap();
839
840        thread_hndl.join().unwrap();
841
842        return;
843
844    }
845}