Open Menci opened 4 years ago
Hi @Menci,
It's essential to the safety of the locking algorithm that the internal value is present when releasing an acquired lock.
I'm curious why your algorithm would need this ability, if you can explain it here I may be able to point you in another direction.
The algorithm is here https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock#Using_two_mutexes.
The last finished reader should unlock the write lock, but the lock may be locked by another reader.
I can only implement it with the second algorithm in https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock#Using_a_condition_variable_and_a_mutex.
But in Redis I have to reaplce conditional variables with sleeping and polling (https://github.com/syzoj/syzoj-ng/blob/master/src/redis/redis.service.ts#L94). I'm wondering if there're a better approach?
@Menci It's somewhat stale, but still will answer (got interested into topic).
TL;DR: - You can't implement safe R/W Lock on top of only Redlock algorithm, since it requires atomic counter next to lock.
Redstone provides mutex locking only, no counting. Sleeping & polling is unsafe for atomic locking as well - value could be changed by neighbour request before you know about it. Distributed systems 🤷 Everything what's not atomic inside single data source is unsafe - intermediate state could be altered by some concurrent interaction from different request/thread.
You could design something similar on your own, but then you need to dive into internals and write your own "EVAL" version of REDIS script to atomically lock keys & increment/decrement counters.
@meredian I know simple sleeping & polling is unsafe. I used a redlock to read and write the counters to ensure the consistant of the state.
@Menci So, if I got it right you use Redlock to lock counters as a resource, so they could be operated atomically 🙂 That's kind smart, yeah! I thought your original intention was to count using redlock itself (which doesn't work obviously). I think it's best possible solution using library.
Unfortunately there doesn't seem to be a RW lock library with Redis on NPM.
Implementing an Read/Write lock algorithm would be extremely useful.
I stumbled in here from a web search trying to solve the same problem but in Ruby land - also trying to implement an algorithm from the aforementioned Wikipedia page. Unless I misunderstand something about how condition variables work, I didn't see an easy way to replicate "thread land" condition variables in the context of Redis and multiple hosts. So I started to implement the read-preferring algorithm on the same page, and realized that while redlock-rb doesn't explicitly provide a mechanism for unlocking a lock from a process that did not originally acquire the lock, I was able to work around that.
At least in the case of redlock-rb (the Ruby implementation, obviously), the method to acquire a lock, when successful, returns a plain Ruby Hash object, containing the actual lock ID. I was able to serialize this and store it in Redis, so when it comes time for the "final reader" do unlock the global lock, it fetches the lock hash from Redis, deserializes it, and passes it to the redlock-rb-provided #unlock
method.
I suppose this really depends on implementation, but the Ruby one at least means that I was free to do what I wanted with the lock details, including store them for later.
I'm trying to implement a Read/Write lock, which allows multiple readers or one writer to acquire the lock. But Redlock has no way to unlock something with the resource ID, which is required by the Read/Write lock algorithm. So are there anyway to have a Read/Write lock?