-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This implements a RwLock type, which is very equal to the std::sync equivalent.
- Loading branch information
Showing
11 changed files
with
509 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
/// The read lock script. | ||
/// | ||
/// Checks if the writer list besides the key is empty or the lock is set. | ||
/// If there are no writers, the uuid will be set as a reader and returns true. | ||
/// Returns false otherwise. | ||
/// | ||
/// The timeout will be used for the reader lock. You need to retry to get the lock again if you want to keep it. | ||
/// But if a writer comes in scope, the reader lock will be dropped after the timeout and you have to wait. | ||
/// | ||
/// Takes 3 arguments: | ||
/// 1. The key to lock | ||
/// 2. The uuid of the lock | ||
/// 3. The timeout in seconds | ||
pub const READER_LOCK: &str = r#" | ||
if redis.call("exists", ARGV[1] .. ":lock") == 1 then | ||
return 0 | ||
end | ||
local res = redis.call("scan", 0, "match", ARGV[1] .. ":writer_waiting_list:*") | ||
if next(res[2]) == nil then | ||
redis.call("set", ARGV[1] .. ":reader_locks:" .. ARGV[2], 1, "ex", ARGV[3]) | ||
return 1 | ||
end | ||
return 0 | ||
"#; | ||
|
||
/// The read lock drop script. | ||
/// | ||
/// Removes the uuid from the reader list. | ||
/// | ||
/// Takes 2 arguments: | ||
/// 1. The key to lock | ||
/// 2. The uuid of the lock | ||
pub const READER_LOCK_DROP: &str = r#" | ||
redis.call("del", ARGV[1] .. ":reader_locks:" .. ARGV[2]) | ||
return 1 | ||
"#; | ||
|
||
/// The writer lock script. | ||
/// | ||
/// Checks if the reader list besides the key is empty. | ||
/// Also add the uuid to the writer waiting list. | ||
/// If there are no readers, the uuid will be set as the lock and returns true. | ||
/// Returns false otherwise. | ||
/// | ||
/// The timeout will also be used for the waiting ticket, so if you wait too long, your intention will be dropped and reader can be acquired. | ||
/// So be sure to request the lock again fast enough. | ||
/// | ||
/// Takes 3 arguments: | ||
/// 1. The key to lock | ||
/// 2. The uuid of the lock | ||
/// 3. The timeout in seconds for waiting | ||
// TODO: Should lock be expanded, if there is already another writer waiting? | ||
pub const WRITER_LOCK: &str = r#" | ||
redis.call("set", ARGV[1] .. ":writer_waiting_list:" .. ARGV[2], 1, "ex", ARGV[3]) | ||
if redis.call("exists", ARGV[1] .. ":lock") == 1 then | ||
return 0 | ||
end | ||
return redis.call("set", ARGV[1] .. ":lock", ARGV[2], "nx", "ex", ARGV[3]) | ||
"#; | ||
|
||
/// The writer lock drop script. | ||
/// | ||
/// Removes the uuid from the writer list. | ||
/// | ||
/// Takes 2 arguments: | ||
/// 1. The key to lock | ||
/// 2. The uuid of the lock | ||
pub const WRITER_LOCK_DROP: &str = r#" | ||
redis.call("del", ARGV[1] .. ":writer_waiting_list:" .. ARGV[2]) | ||
if redis.call("get", ARGV[1] .. ":lock") == ARGV[2] then | ||
redis.call("del", ARGV[1] .. ":lock") | ||
end | ||
return 1 | ||
"#; | ||
|
||
/// The uuid script. | ||
/// | ||
/// Increments the uuid counter and returns the new value. | ||
/// | ||
/// Takes 1 argument: | ||
/// 1. The key to lock | ||
pub const UUID_SCRIPT: &str = r#" | ||
return redis.call("INCR", ARGV[1] .. ":lock_counter") | ||
"#; | ||
|
||
/// The read script. | ||
/// | ||
/// Reads the value from the key, only if the uuid is in reader list or if the lock is equal to uuid. | ||
/// | ||
/// Takes 2 argument: | ||
/// 1. The key to read | ||
/// 2. The uuid of the lock | ||
pub const LOAD_SCRIPT: &str = r#" | ||
if redis.call("get", ARGV[1] .. ":lock") == ARGV[2] then | ||
return redis.call("get", ARGV[1]) | ||
end | ||
if redis.call("exists", ARGV[1] .. ":reader_locks:" .. ARGV[2]) then | ||
return redis.call("get", ARGV[1]) | ||
end | ||
"#; | ||
|
||
/// The store script. | ||
/// | ||
/// Stores the value to the key, only if the uuid is in lock. | ||
/// | ||
/// Takes 3 arguments: | ||
/// 1. The key to store | ||
/// 2. The uuid of the lock | ||
/// 3. The value to store | ||
pub const STORE_SCRIPT: &str = r#" | ||
if redis.call("get", ARGV[1] .. ":lock") == ARGV[2] then | ||
redis.call("set", ARGV[1], ARGV[3]) | ||
return 1 | ||
end | ||
return 0 | ||
"#; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
use thiserror::Error; | ||
#[derive(Error, Debug)] | ||
pub enum RwLockError { | ||
#[error("The lock is already locked for writer.")] | ||
WriterAlreadyLocked, | ||
#[error("The lock is already locked for reader.")] | ||
StillReader, | ||
#[error("The lock could not be dropped.")] | ||
LockNotDroppable, | ||
#[error("The lock is expired. Failed UUID: {0} ")] | ||
LockExpired(usize), | ||
} |
Oops, something went wrong.