Optimistic locking queue

半腔热情 提交于 2021-02-10 13:16:01

问题


I'm writing an application in Node.js using PostgreSQL as database. But I have some problems. I have a table with information about resources in region:

CREATE TABLE regions_indexes
(
  id integer NOT NULL,
  resource_type integer NOT NULL,
  current_resource integer,
  maximum_resource integer,
  CONSTRAINT regions_indexes_pkey PRIMARY KEY (id, resource_type)
)

Users clicks on button, application calculates various parameters based on current_resource and then do current_resource - $calc_value. Because it's maybe very concurently I use transactions. But in process calculation maybe some errors, and we need to repeat calculations. Now I'm using SELECT ... FOR UPDATE for locking row with using current_resource. How i can do it with no lock using optimistic locking, if current value of current_resource is very important, and user who clicks first should use max. avalaible current_resource. In other words, I should implement acess queue for current_resource.


回答1:


For optimistic locking you need to define some means to check if a row has changed since you saw it last time. For example, lets just add another identifier:

alter table regions_indexes add version_id integer default 1 not null;

Now the application reads some row, shows the data to the user and waits until button is clicked. We must remember the value of version_id we got.

After button is clicked, you perform all the necessary calculations. When you're ready to update the row, you lock the row and check whether version_id has not changed. If it has not, increment version_id and commit. If it has, bad luck --- you need to tell the user to repeat the operation because someone outrun him.

It may looks like this (in pseudocode):

-- remember version_id
select *
from regions_indexes
where id = ... and resource_type = ...;

-- wait for user click
-- you can wait for a long time, because no lock is yet acquired
...

update regions_indexes
set current_resource = current_resource - ..., version_id = version_id + 1
where id = ... and resource_type = ...
returning version_id;

if new_version_id = old_version_id + 1 then
  -- success, commit
else 
  -- fail, rollback
end if;

But optimistic locking does not work well in situation of high concurrency. When conflicts are not rare, you will have to restart transactions frequently.



来源:https://stackoverflow.com/questions/34834357/optimistic-locking-queue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!