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
126extern crate crossbeam_utils;
127extern crate crossbeam_deque;
128
129/// A lightweight CoW implementation.
130#[cfg(all(target_has_atomic = "32", feature = "prefer_mutex"))]
131pub mod cow;
132
133/// A RwLock based copy-on-write.
134#[cfg(any(not(target_has_atomic = "32"), not(feature = "prefer_mutex")))]
135pub mod cow_mutex;
136
137#[cfg(any(not(target_has_atomic = "32"), not(feature = "prefer_mutex")))]
138pub mod cow_refcell;
139
140use std::fmt;
141
142#[cfg(all(target_has_atomic = "32", feature = "prefer_mutex"))]
143pub use cow::{ICoW, ICoWRead, ICoWCopy, ICoWLock, ICoWWeak, ICoWWeakRead};
144
145#[cfg(any(not(target_has_atomic = "32"), not(feature = "prefer_mutex")))]
146pub use cow_mutex::{ICoW, ICoWRead, ICoWCopy, ICoWLock, ICoWWeak, ICoWWeakRead};
147
148#[cfg(all(not(target_has_atomic = "32"), feature = "prefer_mutex"))]
149compile_error!("target CPU does not support 'target_has_atomic'");
150
151pub trait ICowType
152{
153    fn get_lock_type() -> ICoWLockTypes;
154}
155
156#[cfg(test)]
157mod test
158{
159    use std::{sync::{LazyLock, mpsc}, thread, time::{Duration, Instant}};
160
161    use super::*;
162
163
164
165
166    #[test]
167    fn test_3()
168    {
169        #[derive(Debug, Clone)]
170        struct Test { s: String }
171
172        let icow = ICoW::new(Test{ s: "test".into() });
173
174        for _ in 0..10
175        {
176            let s = Instant::now();
177
178            let read0 = icow.read();
179
180            let e = s.elapsed();
181
182            println!("{:?}", e);
183        }
184
185    }
186
187    #[test]
188    fn test_33()
189    {
190        #[derive(Debug, Clone)]
191        struct Test { s: String };
192
193        let icow = ICoW::new(Test{ s: "test".into() });
194
195        let write_ex = icow.try_clone_copy_exclusivly().unwrap();
196
197        {
198        let write_ex_err = icow.try_clone_copy_exclusivly();
199        assert_eq!(write_ex_err.is_none(), true);
200        }
201
202        {
203        let write_ex_err = icow.try_clone_copy();
204        assert_eq!(write_ex_err.is_none(), true);
205        }
206        {
207        let read1 = icow.try_read();
208        assert_eq!(read1.is_none(), true);
209        }
210
211        drop(write_ex);
212
213        drop(icow);
214
215    }
216
217    #[test]
218    fn test_4()
219    {
220        #[derive(Debug, Clone)]
221        struct Test { s: u32 }
222
223        let icow = ICoW::new(Test{ s: 1 });
224
225        let read0 = icow.read();
226        let read1 = icow.read();
227
228        let mut excl_write = icow.try_clone_copy_exclusivly().unwrap();
229
230        excl_write.s = 5;
231
232
233        excl_write.commit();
234
235        assert_eq!(read0.s, 1);
236
237        let read3 = icow.read();
238        assert_eq!(read3.s, 5);
239
240        let mut writing = icow.try_clone_copy().unwrap();
241        writing.s = 4;
242
243        writing.commit().unwrap();
244
245        assert_eq!(read0.s, 1);
246        assert_eq!(read3.s, 5);
247
248        let read4 = icow.read();
249        assert_eq!(read4.s, 4);
250    }
251
252    #[test]
253    fn test_parking_lot_reader_wakeup()
254    {
255        #[derive(Debug, Clone)]
256        struct Test { s: u32 }
257
258        let icow = ICoW::new(Test{ s: 1 });
259
260        let read0 = icow.read();
261        let read2 = icow.read();
262
263        let c_icow = icow.clone();
264        let (se, rc) = mpsc::channel::<()>();
265        let handler0 = 
266            std::thread::spawn(move || 
267                {
268                    let mut lock0 = c_icow.try_clone_copy_exclusivly().unwrap();
269
270                    se.send(()).unwrap();
271
272                    lock0.s = 5;
273
274                    std::thread::sleep(Duration::from_secs(2));
275
276                    lock0.commit();
277                }
278            );
279
280        rc.recv().unwrap();
281
282        let s = Instant::now();
283
284        let read1 = icow.read();
285        
286        let e = s.elapsed();
287
288        println!("thread wait: {:?}", e);
289
290        assert_eq!(e.as_secs(), 2);
291
292        handler0.join().unwrap();
293
294        drop(read0);
295        drop(read1);
296        drop(read2);
297    }
298
299    #[test]
300    fn text_9_exclu_lock_pend()
301    {
302        #[derive(Debug, Clone)]
303        struct Test { s: u32 }
304
305        let icow = ICoW::new(Test{ s: 1 });
306
307            let mut write0 = icow.clone_copy();
308            write0.s = 1222;
309
310        let c_icow = icow.clone();
311        let (se, rc) = mpsc::channel::<()>();
312        let handler0 = 
313            std::thread::spawn(move || 
314                {
315                    let mut lock0 = 
316                        loop 
317                        {
318                            let res = c_icow.try_clone_copy_exclusivly();
319
320                            if res.is_none() == true
321                            {
322                                continue;
323                            }
324                            
325                            break res.unwrap();
326                        };
327
328                    se.send(()).unwrap();
329
330                    lock0.s = 5;
331
332                    std::thread::sleep(Duration::from_secs(1));
333
334                    lock0.commit();
335                }
336            );
337
338
339        rc.recv().unwrap();
340
341        let s = Instant::now();
342
343        let commit_res = write0.commit();
344        assert_eq!(commit_res.is_err(), true);
345        assert_eq!(commit_res.as_ref().err().unwrap().0, ICoWError::ExclusiveLockPending);
346        write0 = commit_res.err().unwrap().1;
347
348        write0.commit_blocking(true).unwrap();
349        
350        let e = s.elapsed();
351
352        println!("thread wait: {:?}", e);
353
354        assert_eq!(e.as_secs(), 1);
355
356        handler0.join().unwrap();
357
358        return;
359    }
360
361    #[test]
362    fn test_5()
363    {
364        #[derive(Debug, Clone)]
365        struct Test { s: u32 }
366
367        let icow = ICoW::new(Test{ s: 1 });
368
369        let read0 = icow.read();
370        let read2 = icow.read();
371        
372        let c_icow = icow.clone();
373
374        let (se, rc) = mpsc::channel::<()>();
375        let handler0 = 
376            std::thread::spawn(move || 
377                {
378                    let mut lock0 = c_icow.try_clone_copy_exclusivly().unwrap();
379
380                    se.send(()).unwrap();
381
382                    lock0.s = 5;
383
384                    std::thread::sleep(Duration::from_micros(2));
385
386                    lock0.commit();
387                }
388            );
389
390        rc.recv().unwrap();
391
392        let s = Instant::now();
393
394        let read1 = icow.read();
395        
396        let e = s.elapsed();
397
398        println!("{:?}", e);
399
400        
401        assert_eq!(read1.s, 5);
402        assert_eq!(read0.s, 1);
403
404        handler0.join().unwrap();
405
406        let weak0 = read0.weak();
407        let weak1 = read1.weak();
408
409        drop(read0);
410        drop(read1);
411
412        assert_eq!(weak0.upgrade().is_some(), true);
413        assert_eq!(weak1.upgrade().is_some(), true);
414
415        drop(read2);
416        assert_eq!(weak0.upgrade().is_none(), true);
417        assert_eq!(weak1.upgrade().is_some(), true);
418    }
419
420    #[test]
421    fn test_5_read_lock()
422    {
423        #[derive(Debug, Clone)]
424        struct Test { s: u32 }
425
426        let icow = ICoW::new(Test{ s: 1 });
427        
428        let c_icow = icow.clone();
429
430        let (se, rc) = mpsc::channel::<()>();
431        let (se2, rc2) = mpsc::channel::<()>();
432        let handler0 = 
433            std::thread::spawn(move || 
434                {
435                    rc2.recv().unwrap();
436
437                    let mut lock0 = 
438                        loop 
439                        {
440                            let res = c_icow.try_clone_copy_exclusivly();
441
442                            if res.is_none() == true
443                            {
444                                continue;
445                            }
446                            
447                            break res.unwrap();
448                        };
449
450                    se.send(()).unwrap();
451
452                    lock0.s = 5;
453
454                    lock0.commit();
455                }
456            );
457
458        let mut reads = Vec::<ICoWRead<'_, Test>>::with_capacity(20000);  
459        let mut sent = false;
460
461        let s = Instant::now();
462
463        for i in 0..10000
464        {
465            let read0 = icow.read();
466            if read0.s == 5
467            {
468                println!("break at {}", i);
469                break;
470            }
471
472            reads.push(read0);
473
474            if sent == false
475            {
476                se2.send(());
477                sent = true;
478            }
479        }
480        
481        let e = s.elapsed();
482
483        println!("{:?}", e);
484
485        assert_eq!(reads[0].s, 1);
486
487        handler0.join().unwrap();
488    }
489
490    #[test]
491    fn test_6()
492    {
493        #[derive(Debug, Clone)]
494        struct Test { s: u32 }
495
496        let icow = ICoW::new(Test{ s: 1 });
497
498        let read0 = icow.read();
499        let read2 = icow.read();
500        
501        let c_icow = icow.clone();
502
503        let (se, rc) = mpsc::channel::<()>();
504        let handler0 = 
505            std::thread::spawn(move || 
506                {
507                    let read2 = c_icow.read();
508
509                    let mut lock0 = c_icow.try_clone_copy_exclusivly().unwrap();
510
511                    se.send(()).unwrap();
512
513                    lock0.s = 5;
514
515                    std::thread::sleep(Duration::from_nanos(50));
516                    lock0.commit();
517
518                    let read3 = c_icow.read();
519
520                    assert_eq!(read2.s, 1);
521                    assert_eq!(read3.s, 5);
522                }
523            );
524
525        rc.recv().unwrap();
526
527        for _ in 0..100000000
528        {
529            let read1 = icow.read();
530
531            if read1.s == 1
532            {
533                continue;
534            }
535            else
536            {
537                break;
538            }
539        }
540
541        let read1 = icow.read();
542        assert_eq!(read1.item.s, 5);
543
544        handler0.join().unwrap();
545
546        return;
547    }
548
549    #[test]
550    fn test_6_drop()
551    {
552        #[derive(Debug, Clone)]
553        struct Test { s: u32 }
554
555        let icow = ICoW::new(Test{ s: 1 });
556
557        let read0 = icow.read();
558        let read2 = icow.read();
559        
560        let c_icow = icow.clone();
561
562        let (se, rc) = mpsc::channel::<()>();
563        let handler0 = 
564            std::thread::spawn(move || 
565                {
566                    let read2 = c_icow.read();
567
568                    let mut lock0 = c_icow.try_clone_copy_exclusivly().unwrap();
569
570                    rc.recv().unwrap();
571
572                    lock0.s = 5;
573
574                    std::thread::sleep(Duration::from_millis(1500));
575                    lock0.commit();
576
577                    let read3 = c_icow.read();
578
579                    assert_eq!(read2.s, 1);
580                    assert_eq!(read3.s, 5);
581                }
582            );
583
584        drop(read0);
585        let r2 = read2.clone_copy_into_inner();
586
587        se.send(()).unwrap();
588
589        drop(icow);
590
591        assert_eq!(r2.s, 1);
592
593        handler0.join().unwrap();
594
595        return;
596    }
597
598
599    #[test]
600    fn test_7()
601    {
602        #[derive(Debug, Clone)]
603        struct TestStruct { s: u32 }
604
605        impl TestStruct
606        {
607            fn new(s: u32) -> Self
608            {
609                return Self{ s: s };
610            }
611        }
612
613        static VAL: LazyLock<ICoW<TestStruct>> = 
614            LazyLock::new(|| ICoW::new(TestStruct::new(1))); 
615        
616
617        
618        
619            let borrow1 = VAL.read();
620            assert_eq!(borrow1.item.s, 1);
621
622            let (mpsc_send, mpsc_rcv) = mpsc::channel::<u64>();
623            let (mpsc_send2, mpsc_rcv2) = mpsc::channel::<u64>();
624
625            let thread1 = 
626                std::thread::spawn(move ||
627                    {
628                        for _ in 0..1000
629                        {
630                            let _ = mpsc_rcv2.recv();
631                            let borrow1 = VAL.read();
632
633                            let mut transaction = VAL.try_clone_copy_exclusivly().unwrap();
634
635                            transaction.s = 5;
636
637                            
638
639                            std::thread::sleep(Duration::from_nanos(1001));
640                            transaction.commit();
641                            let borrow2 = VAL.read();
642                            
643
644                            assert_eq!(borrow1.item.s, 1);
645
646                            assert_eq!(borrow2.item.s, 5);
647
648                            let _ = mpsc_send.send(1);
649                        }
650                    }
651                );
652            
653            
654
655            for x in 0..1000
656            {
657                println!("{}", x);
658                mpsc_send2.send(1).unwrap();
659                let _ = mpsc_rcv.recv();
660
661                let borrow1 = VAL.read();
662                assert_eq!(borrow1.s, 5);
663
664                let mut transaction = VAL.try_clone_copy_exclusivly().unwrap();
665                transaction.s = 1;
666                transaction.commit();
667
668                let borrow1 = VAL.read();
669                assert_eq!(borrow1.s, 1);
670                
671            }
672            
673            
674
675            thread1.join().unwrap();
676
677            
678    }
679
680
681    #[test]
682    fn test_8()
683    {
684        #[derive(Debug, Clone)]
685        struct Test { s: u32 }
686
687        let icow = ICoW::new(Test{ s: 1 });
688
689        for _ in 0..20
690        {
691            let read0 = icow.read();
692            let read2 = icow.read();
693            
694            let c_icow = icow.clone();
695
696            //let (se, rc) = mpsc::channel::<()>();
697            let handler0 = 
698                std::thread::spawn(move || 
699                    {
700                        let read2 = c_icow.read();
701
702                        let mut lock0 = c_icow.clone_copy();
703
704                        //se.send(()).unwrap();
705
706                        lock0.s = 5;
707
708                        std::thread::sleep(Duration::from_micros(1));
709                        lock0.commit_blocking(false).unwrap();
710
711                        let read3 = c_icow.read();
712
713                        assert_eq!(read2.s, 1);
714                        assert_eq!(read3.s, 5);
715                    }
716                );
717
718            //rc.recv().unwrap();
719
720            for i in 0..1000000000
721            {
722                let read1 = icow.read();
723
724                if read1.s == 1
725                {
726                    continue;
727                }
728                else
729                {
730                    println!("{}", i);
731                    break;
732                }
733            }
734
735            let read1 = icow.read();
736            assert_eq!(read1.s, 5);
737
738            handler0.join().unwrap();
739
740            let mut lock0 = icow.try_clone_copy().unwrap();
741            lock0.s = 1;
742            lock0.commit_blocking(false).unwrap();
743        }
744
745        return;
746    }
747
748    #[test]
749    fn test_9()
750    {
751        #[derive(Debug, Clone)]
752        struct Test { s: u32 }
753
754        let icow = ICoW::new(Test{ s: 1 });
755
756        let weak_reader = icow.reader();
757
758        let weak_r0 = weak_reader.aquire().unwrap();
759
760        assert_eq!(weak_r0.s, 1);
761
762        drop(weak_r0);
763
764        let mut copy1 = icow.clone_copy();
765        copy1.s = 8;
766        copy1.commit_blocking(true).unwrap();
767
768        let weak_r0 = weak_reader.aquire().unwrap();
769
770        assert_eq!(weak_r0.s, 8);
771
772        drop(weak_r0);
773
774        // drop icow, check that the aquire() returns None because the data and
775        // icow instance have gone.
776        drop(icow);
777
778        let weak_r0 = weak_reader.aquire();
779        assert_eq!(weak_r0.is_none(), true);
780
781    }
782
783    #[test]
784    fn test_10()
785    {
786        #[derive(Debug, Clone)]
787        struct Test { s: u32 }
788
789        let icow = ICoW::new(Test{ s: 1 });
790
791        let weak_reader = icow.reader();
792
793        let (tx, rx) = mpsc::channel::<()>();
794        let (tx2, rx2) = mpsc::channel::<()>();
795
796        let thread_hndl = 
797            thread::spawn(move ||
798                {
799                    let weak_r0 = weak_reader.aquire().unwrap();
800
801                    assert_eq!(weak_r0.s, 1);
802
803                    drop(weak_r0);
804
805                    tx.send(()).unwrap();
806
807                    // ----
808                    let _ = rx2.recv().unwrap();
809
810                    let weak_r0 = weak_reader.aquire().unwrap();
811
812                    assert_eq!(weak_r0.item_updated(), true);
813                    assert_eq!(weak_r0.s, 8);
814
815                    drop(weak_r0);
816
817                    tx.send(()).unwrap();
818                    // ----
819                    let _ = rx2.recv().unwrap();
820
821                    // check that icow dropped
822                    let weak_r0 = weak_reader.aquire();
823                    assert_eq!(weak_r0.is_none(), true);
824                }
825            );
826
827        let _ = rx.recv().unwrap();
828
829        let mut copy1 = icow.clone_copy();
830        copy1.s = 8;
831        copy1.commit_blocking(true).unwrap();
832
833        tx2.send(()).unwrap();
834        let _ = rx.recv().unwrap();
835
836        // drop icow, check that the aquire() returns None because the data and
837        // icow instance have gone.
838        drop(icow);
839
840        tx2.send(()).unwrap();
841
842        thread_hndl.join().unwrap();
843
844        return;
845
846    }
847}