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