src/DbLock.bend source
src/DbLock.bend on the hub · documented module
import Baseimport ./DurableError.bend as DurableErrorimport ./DbLockPolicy.bend as Policy# Owns the open LOCK file until release.type Lock is Type: Lock{file: File}# Builds the stable LOCK path for a database directory.def lock_path(path: String) -> String: path ++ "/LOCK"def DbLock.try_lock(file: File) -> IO(File & Result<&1, &1, U32 & String, Unit>): import "./effs/db_lock.c" import "./effs/db_lock.js"def DbLock.try_unlock(file: File) -> IO(File & Result<&1, &1, U32 & String, Unit>): import "./effs/db_unlock.c" import "./effs/db_unlock.js"# Classifies a failure to open the LOCK file.def open_failed(error: U32 & String, operation: String, path: String) -> IO(Result<&1, &1, DurableError.Error, Lock>): match error: case (code, message): IO.pure(Result<&1, &1, DurableError.Error, Lock>, Fail{Policy.classify_lock_error(code, message, operation, path)})# Closes the file and classifies a failed lock attempt.def lock_failed( file: File, error: U32 & String, operation: String, path: String) -> IO(Result<&1, &1, DurableError.Error, Lock>): match error: case (code, message): do IO<Result<&1, &1, DurableError.Error, Lock>>: _closed : Unit <- File.close(file) return Fail{Policy.classify_lock_error(code, message, operation, path)}# Returns an owned lock on success or closes the failed handle.def lock_result( pair: File & Result<&1, &1, U32 & String, Unit>, operation: String, path: String) -> IO(Result<&1, &1, DurableError.Error, Lock>): match pair: case (file, Fail{error}): lock_failed(file, error, operation, path) case (file, Done{Unit{}}): IO.pure(Result<&1, &1, DurableError.Error, Lock>, Done{Lock{file}})# Attempts the nonblocking OS lock on the open file.def lock_file(file: File, operation: String, path: String) -> IO(Result<&1, &1, DurableError.Error, Lock>): do IO<Result<&1, &1, DurableError.Error, Lock>>: pair : File & Result<&1, &1, U32 & String, Unit> <- DbLock.try_lock(file) lock_result(pair, operation, path)# Locks the opened file or classifies its open error.def opened( result: Result<&1, &1, U32 & String, File>, operation: String, path: String) -> IO(Result<&1, &1, DurableError.Error, Lock>): match result: case Fail{error}: open_failed(error, operation, path) case Done{file}: lock_file(file, operation, path)# Opens the stable LOCK file and acquires its OS lock.def acquire(+path: String, operation: String) -> IO(Result<&1, &1, DurableError.Error, Lock>): do IO<Result<&1, &1, DurableError.Error, Lock>>: result : Result<&1, &1, U32 & String, File> <- File.open(lock_path(path), "a") opened(result, operation, path)# Closes the file and preserves the unlock error.def release_failed( file: File, error: U32 & String, operation: String, path: String) -> IO(Result<&1, &1, DurableError.Error, Unit>): match error: case (code, message): do IO<Result<&1, &1, DurableError.Error, Unit>>: _closed : Unit <- File.close(file) return Fail{DurableError.classify_open(DurableError.OpenHostFailure{code, message}, operation, path)}# Closes the file after a successful unlock.def release_succeeded(file: File) -> IO(Result<&1, &1, DurableError.Error, Unit>): do IO<Result<&1, &1, DurableError.Error, Unit>>: _closed : Unit <- File.close(file) return Done{Unit{}}# Closes the file after either unlock result.def released( pair: File & Result<&1, &1, U32 & String, Unit>, operation: String, path: String) -> IO(Result<&1, &1, DurableError.Error, Unit>): match pair: case (file, Fail{error}): release_failed(file, error, operation, path) case (file, Done{Unit{}}): release_succeeded(file)# Unlocks the file and closes it after the result.def unlock_file(file: File, operation: String, path: String) -> IO(Result<&1, &1, DurableError.Error, Unit>): do IO<Result<&1, &1, DurableError.Error, Unit>>: pair : File & Result<&1, &1, U32 & String, Unit> <- DbLock.try_unlock(file) released(pair, operation, path)# Consumes the lock and releases its file handle.def release(lock: Lock, operation: String, path: String) -> IO(Result<&1, &1, DurableError.Error, Unit>): match lock: case Lock{file}: unlock_file(file, operation, path)