Crate optimistic_lock_coupling

Source
Expand description

This crate provides a general optimistic lock.

§Description

In actual projects, there are some lock-free data structures, especially database-related ones such as BwTree, Split-Ordered List (also known as Lock Free HashTable) when there are many write conflicts. The performance loss is very serious, and sometimes it is not as good as the brainless Mutex. However, the performance of the brainless Mutex is often very bad under normal circumstances, so is there an intermediate form that can solve this problem?

This is the intermediate form. So this can be used everywhere as a general lock, and the performance is satisfactory.

§Simple example for read

use optimistic_lock_coupling::{OptimisticLockCoupling, OptimisticLockCouplingErrorType};

#[inline(always)]
fn read_txn(lock: &OptimisticLockCoupling<i32>) -> Result<(), OptimisticLockCouplingErrorType> {
    // acquire the read lock
    let read_guard = lock.read()?;
    // do your stuff
    println!("status: {}", read_guard);
    println!("\tmy operations: {} + 1 = {}", *read_guard, *read_guard + 1);
    // remember to sync before drop
    let res = read_guard.try_sync();
    println!("safely synced");
    res
}

fn main() {
    let lock = OptimisticLockCoupling::new(1);
    // retry steps
    'retry: loop{
        // function call
        let res = read_txn(&lock);
        // before retry logics
        if res.is_err() {
            continue 'retry;
        }else{
            break 'retry;
        }
    }
}

or in a much easy way~

fn main(){
    let lock = OptimisticLockCoupling::new(1);
    lock.read_txn(
        // very important!
        #[inline(always)]
        |guard| {
            println!("{}", guard);
            Ok(())
        },
    )
    .unwrap();
}

§Thread-safety example

will create a read thread and a write thread both holding the same lock.

use optimistic_lock_coupling::*;
fn main() {
   let i = 10000;
   static mut lock: Option<OptimisticLockCoupling<i32>> = None;
   unsafe { lock = Some(OptimisticLockCoupling::from(0)) };
   let write_fn = move || unsafe {
       for _i in 0..i {
           // std::thread::sleep_ms(10);
           loop {
               match lock.as_ref().unwrap().write() {
                   Ok(mut guard) => {
                       *guard += 1;
                       break;
                   }
                   Err(_err) => {
                       continue;
                   }
               }
           }
       }
   };
   let read_fn = move || unsafe {
       for _i in 0..i {
           while let Ok(_) = lock.as_ref().unwrap().read_txn(
               #[inline(always)]
               |guard| {
                   println!("{}", guard);
                   Ok(())
               },
           ) {
               break;
           }
       }
   };
   use std::thread::spawn;
   let thread1 = spawn(write_fn);
   let thread2 = spawn(read_fn);

   let _ = thread1.join();
   let _ = thread2.join();
   unsafe { assert_eq!(*(lock.as_ref().unwrap().write().unwrap()), i) }
}

Structs§

OptimisticLockCoupling
Our data structure, the usage is ‘pretty much’ same as RwLock
OptimisticLockCouplingReadGuard
Usage: after getting the guard you can do what ever you want with Deref but after usage you MUST call try_sync if fails you must redo the hole function or other sync method to ensure the data you read is correct.
OptimisticLockCouplingWriteGuard
Only one instance because the data is locked implemented Deref and DerefMut release the lock on drop

Enums§

OptimisticLockCouplingErrorType
Error types

Type Aliases§

OptimisticLockCouplingResult
Result type~