Crate optimistic_lock_coupling[][src]

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 Definitions

OptimisticLockCouplingResult

Result type~