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 * 
14 * 
15 *  ```ignore
16
17    let val = 
18        ICoW::new(TestStruct::new(1, 2));
19
20    // read only 
21    let read1 = val.read();
22    //..
23    drop(read1);
24
25    // ...
26
27    // copy on write NON-exclusively, read is possible
28    let mut transaction = val.clone();
29
30    transaction.start = 5;
31    transaction.stop = 6;
32
33    // update, after calling this function, all reades who 
34    // read before will still see old version.
35    // all reades after, new
36    transaction.commit();
37    //or
38    drop(transaction); // to drop changes
39
40
41    // exclusive lock, read is also not possible
42
43    let res = val.clone_exclusivly();
44    // ..
45    // commit changes releasing lock
46    commit(val); //or
47    drop(val); // to drop changes and release lock
48
49    ```
50 */
51
52 /// Type of the sync code.
53 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
54 pub enum ICoWLockTypes
55 {
56    /// Based on atomic and backoff.
57    Atomic,
58
59    /// based on the OS RwLock
60    RwLock,
61 }
62
63impl fmt::Display for ICoWLockTypes
64{
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
66    {
67        match self
68        {
69            Self::Atomic => 
70                write!(f, "atomic"),
71            Self::RwLock => 
72                write!(f, "rwlock"),
73        }
74    }
75}
76
77/// Errors which may be returned.
78#[derive(Copy, Clone, Debug, PartialEq, Eq)]
79pub enum ICoWError
80{
81    /// An attempt to write to the instance using non exclusive copy-on-write operation
82    /// while the exclusive is still going.
83    ExclusiveLockPending,
84
85    /// Is issued if "exponential backoff has completed and blocking the thread is advised".
86    WouldBlock,
87
88    /// Duplicate write operation prevented.
89    AlreadyUpdated,
90}
91
92impl fmt::Display for ICoWError
93{
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
95    {
96        match self
97        {
98            Self::ExclusiveLockPending => 
99                write!(f, "already exlcusivly locked"),
100            Self::WouldBlock => 
101                write!(f, "cannot perform try operation due to blocking"),
102            Self::AlreadyUpdated => 
103                write!(f, "the value has been updated before the current thread"),
104        }
105    }
106}
107
108extern crate crossbeam_utils;
109extern crate crossbeam_deque;
110
111/// A lightweight CoW implementation.
112#[cfg(all(target_has_atomic = "ptr", feature = "prefer_atomic"))]
113pub mod cow;
114
115/// A RwLock based copy-on-write.
116#[cfg(any(not(target_has_atomic = "ptr"), not(feature = "prefer_atomic")))]
117pub mod cow_mutex;
118
119use std::fmt;
120
121#[cfg(all(target_has_atomic = "ptr", feature = "prefer_atomic"))]
122pub use cow::{ICoW, ICoWRead, ICoWCopy, ICoWLock};
123
124#[cfg(any(not(target_has_atomic = "ptr"), not(feature = "prefer_atomic")))]
125pub use cow_mutex::{ICoW, ICoWRead, ICoWCopy, ICoWLock};
126
127
128#[cfg(test)]
129mod test
130{
131    use std::{sync::{mpsc, Arc, LazyLock}, time::{Duration, Instant}};
132
133    use super::*;
134
135
136
137
138    #[test]
139    fn test_3()
140    {
141        #[derive(Debug, Clone)]
142        struct Test { s: String }
143
144        let icow = ICoW::new(Test{ s: "test".into() });
145
146        for _ in 0..10
147        {
148            let s = Instant::now();
149
150            let read0 = icow.read();
151
152            let e = s.elapsed();
153
154            println!("{:?}", e);
155        }
156
157    }
158
159    #[test]
160    fn test_33()
161    {
162        #[derive(Debug, Clone)]
163        struct Test { s: String };
164
165        let icow = ICoW::new(Test{ s: "test".into() });
166
167        let write_ex = icow.try_clone_exclusivly().unwrap();
168
169        {
170        let write_ex_err = icow.try_clone_exclusivly();
171        assert_eq!(write_ex_err.is_none(), true);
172        }
173
174        let write_ex_err = icow.try_clone();
175        assert_eq!(write_ex_err.is_none(), true);
176
177        let read1 = icow.try_read();
178        assert_eq!(read1.is_none(), true);
179
180        drop(write_ex);
181
182        drop(icow);
183
184    }
185
186    #[test]
187    fn test_4()
188    {
189        #[derive(Debug, Clone)]
190        struct Test { s: u32 }
191
192        let icow = ICoW::new(Test{ s: 1 });
193
194        let read0 = icow.read();
195        let read1 = icow.read();
196
197        let mut excl_write = icow.try_clone_exclusivly().unwrap();
198
199        excl_write.s = 5;
200
201
202        excl_write.commit();
203
204        assert_eq!(read0.s, 1);
205
206        let read3 = icow.read();
207        assert_eq!(read3.s, 5);
208
209        let mut writing = icow.try_clone().unwrap();
210        writing.s = 4;
211
212        writing.commit().unwrap();
213
214        assert_eq!(read0.s, 1);
215        assert_eq!(read3.s, 5);
216
217        let read4 = icow.read();
218        assert_eq!(read4.s, 4);
219    }
220
221    #[test]
222    fn test_5()
223    {
224        #[derive(Debug, Clone)]
225        struct Test { s: u32 }
226
227        let icow = Arc::new(ICoW::new(Test{ s: 1 }));
228
229        let read0 = icow.read();
230        let read2 = icow.read();
231        
232        let c_icow = icow.clone();
233
234        let (se, rc) = mpsc::channel::<()>();
235        let handler0 = 
236            std::thread::spawn(move || 
237                {
238                    let mut lock0 = c_icow.try_clone_exclusivly().unwrap();
239
240                    se.send(()).unwrap();
241
242                    lock0.s = 5;
243
244                    std::thread::sleep(Duration::from_micros(2));
245
246                    lock0.commit();
247                }
248            );
249
250        rc.recv().unwrap();
251
252        let s = Instant::now();
253
254        let read1 = icow.read();
255        
256        let e = s.elapsed();
257
258        println!("{:?}", e);
259
260        
261        assert_eq!(read1.s, 5);
262        assert_eq!(read0.s, 1);
263
264        handler0.join().unwrap();
265
266        let weak0 = read0.weak();
267        let weak1 = read1.weak();
268
269        drop(read0);
270        drop(read1);
271
272        assert_eq!(weak0.upgrade().is_some(), true);
273        assert_eq!(weak1.upgrade().is_some(), true);
274
275        drop(read2);
276        assert_eq!(weak0.upgrade().is_none(), true);
277        assert_eq!(weak1.upgrade().is_some(), true);
278    }
279
280
281    #[test]
282    fn test_6()
283    {
284        #[derive(Debug, Clone)]
285        struct Test { s: u32 }
286
287        let icow = Arc::new(ICoW::new(Test{ s: 1 }));
288
289        let read0 = icow.read();
290        let read2 = icow.read();
291        
292        let c_icow = icow.clone();
293
294        let (se, rc) = mpsc::channel::<()>();
295        let handler0 = 
296            std::thread::spawn(move || 
297                {
298                    let read2 = c_icow.read();
299
300                    let mut lock0 = c_icow.try_clone_exclusivly().unwrap();
301
302                    se.send(()).unwrap();
303
304                    lock0.s = 5;
305
306                    std::thread::sleep(Duration::from_nanos(50));
307                    lock0.commit();
308
309                    let read3 = c_icow.read();
310
311                    assert_eq!(read2.s, 1);
312                    assert_eq!(read3.s, 5);
313                }
314            );
315
316        rc.recv().unwrap();
317
318        for _ in 0..100000000
319        {
320            let read1 = icow.read();
321
322            if read1.s == 1
323            {
324                continue;
325            }
326            else
327            {
328                break;
329            }
330        }
331
332        let read1 = icow.read();
333        assert_eq!(read1.item.s, 5);
334
335        handler0.join().unwrap();
336
337        return;
338    }
339
340
341    #[test]
342    fn test_7()
343    {
344        #[derive(Debug, Clone)]
345        struct TestStruct { s: u32 }
346
347        impl TestStruct
348        {
349            fn new(s: u32) -> Self
350            {
351                return Self{ s: s };
352            }
353        }
354
355        static VAL: LazyLock<ICoW<TestStruct>> = 
356            LazyLock::new(|| ICoW::new(TestStruct::new(1))); 
357        
358
359        
360        
361            let borrow1 = VAL.read();
362            assert_eq!(borrow1.item.s, 1);
363
364            let (mpsc_send, mpsc_rcv) = mpsc::channel::<u64>();
365            let (mpsc_send2, mpsc_rcv2) = mpsc::channel::<u64>();
366
367            let thread1 = 
368                std::thread::spawn(move ||
369                    {
370                        for _ in 0..1000
371                        {
372                            let _ = mpsc_rcv2.recv();
373                            let borrow1 = VAL.read();
374
375                            let mut transaction = VAL.try_clone_exclusivly().unwrap();
376
377                            transaction.s = 5;
378
379                            
380
381                            std::thread::sleep(Duration::from_nanos(1001));
382                            transaction.commit();
383                            let borrow2 = VAL.read();
384                            
385
386                            assert_eq!(borrow1.item.s, 1);
387
388                            assert_eq!(borrow2.item.s, 5);
389
390                            let _ = mpsc_send.send(1);
391                        }
392                    }
393                );
394            
395            
396
397            for x in 0..1000
398            {
399                println!("{}", x);
400                mpsc_send2.send(1).unwrap();
401                let _ = mpsc_rcv.recv();
402
403                let borrow1 = VAL.read();
404                assert_eq!(borrow1.s, 5);
405
406                let mut transaction = VAL.try_clone_exclusivly().unwrap();
407                transaction.s = 1;
408                transaction.commit();
409
410                let borrow1 = VAL.read();
411                assert_eq!(borrow1.s, 1);
412                
413            }
414            
415            
416
417            thread1.join().unwrap();
418
419            
420    }
421
422
423    #[test]
424    fn test_8()
425    {
426        #[derive(Debug, Clone)]
427        struct Test { s: u32 }
428
429        let icow = Arc::new(ICoW::new(Test{ s: 1 }));
430
431        for _ in 0..20
432        {
433            let read0 = icow.read();
434            let read2 = icow.read();
435            
436            let c_icow = icow.clone();
437
438            //let (se, rc) = mpsc::channel::<()>();
439            let handler0 = 
440                std::thread::spawn(move || 
441                    {
442                        let read2 = c_icow.read();
443
444                        let mut lock0 = c_icow.try_clone().unwrap();
445
446                        //se.send(()).unwrap();
447
448                        lock0.s = 5;
449
450                        std::thread::sleep(Duration::from_micros(1));
451                        lock0.commit_blocking().unwrap();
452
453                        let read3 = c_icow.read();
454
455                        assert_eq!(read2.s, 1);
456                        assert_eq!(read3.s, 5);
457                    }
458                );
459
460            //rc.recv().unwrap();
461
462            for i in 0..1000000000
463            {
464                let read1 = icow.read();
465
466                if read1.s == 1
467                {
468                    continue;
469                }
470                else
471                {
472                    println!("{}", i);
473                    break;
474                }
475            }
476
477            let read1 = icow.read();
478            assert_eq!(read1.s, 5);
479
480            handler0.join().unwrap();
481
482            let mut lock0 = icow.try_clone().unwrap();
483            lock0.s = 1;
484            lock0.commit_blocking().unwrap();
485        }
486
487        return;
488    }
489}