I have many places in my application where users are doing something that should be non-concurrent in per-user-and-namespace bases. So that means that:
- Two users can press the same button at the same time
- One user can't press the same button second time until the first press is finished
- One user can press different buttons at the same time
What solutions I tried:
- Advisory lock with hash function on user uuid - has collisions and this advisory lock, but the lock locks all user interactions - so he can't press two buttons at the same time
INSERT&SELECT FOR UPDATE- good, but I need to prepopulate table with "pending" row so it pollutes table schema with unnecessary columns.- Want to implement: locktable. So what I mean is to create a table with advisory-like locks. It will have two columns
namespaceandid- composite primary key. Each time user presses button#1 there will beINSERT&FOR UPDATEfor namespace=button#1and id={userid}.
I feel like there are some hidden stones of this (3rd) approach - do anyone knows about it? Could you kindly list these problems?
I'm sure it will be worse in terms of performance than advisory locks, but is it much-much worse? Also, I couldn't really find implementations of this approach - looks like I came up with a stupid idea that no one use for some important reason.
Check this interesting conversation in 2009 regarding this problem: https://www.postgresql.org/message-id/[email protected]
By INSERT&FOR UPDATE I mean:
INSERT INTO adv_locks VALUES ('btn1', '123') ON CONFLICT ON CONSTRAINT adv_locks_pk DO NOTHING;
SELECT 1 FROM adv_locks WHERE namespace='btn1' and id='123' FOR UPDATE;
So that way there is always a row in a table with this table that can be locked. (I don't care about table size much yet)
I understand that an order of this could be broken (I mean request#1 creates a row and then request#2 selects the row faster), but it isn't a problem for me.