У меня есть функция postGresql (в perlu) getTravelTime (integer, timestamp), которая пытается выбрать данные для указанного идентификатора и отметки времени. Если данные отсутствуют или данные устарели, они загружаются с внешнего сервера (время загрузки ~ 300 мс).
Несколько процессов используют эту базу данных и эту функцию. Возникает ошибка, когда два процесса не находят данные и не загружают их и пытаются выполнить вставку в таблицу travel_time (пара id и timestamp должны быть уникальными). Я думал о замках. Блокировка всей таблицы заблокирует все процессы и позволит только одному продолжить. Мне нужно заблокировать только идентификатор и метку времени. Кажется, pg_advisory_lock блокируется только в «текущем сеансе». Но мои процессы используют свои собственные сеансы.
Я пытался написать свои собственные функции блокировки / разблокировки. Я делаю это правильно? Я использую активное ожидание, как я могу опустить это? Может быть, есть способ использовать pg_advisory_lock () в качестве глобальной блокировки?
Мой код:
CREATE TABLE travel_time_locks (
id_key integer NOT NULL,
time_key timestamp without time zone NOT NULL,
UNIQUE (id_key, time_key)
);
------------
-- Function: mylock(integer, timestamp)
DROP FUNCTION IF EXISTS mylock(integer, timestamp) CASCADE;
-- Usage: SELECT mylock(1, '2010-03-28T19:45');
-- function tries to do a global lock similar to pg_advisory_lock(key, key)
CREATE OR REPLACE FUNCTION mylock(id_input integer, time_input timestamp)
RETURNS void AS
$BODY$
DECLARE
rows int;
BEGIN
LOOP
BEGIN
-- active waiting here !!!! :(
INSERT INTO travel_time_locks (id_key, time_key) VALUES (id_input, time_input);
EXCEPTION WHEN unique_violation THEN
CONTINUE;
END;
EXIT;
END LOOP;
END;
$BODY$ LANGUAGE 'plpgsql' VOLATILE
COST 1;
------------
-- Function: myunlock(integer, timestamp)
DROP FUNCTION IF EXISTS myunlock(integer, timestamp) CASCADE;
-- Usage: SELECT myunlock(1, '2010-03-28T19:45');
-- function tries to do a global unlock similar to pg_advisory_unlock(key, key)
CREATE OR REPLACE FUNCTION myunlock(id_input integer, time_input timestamp)
RETURNS integer AS
$BODY$
DECLARE
BEGIN
DELETE FROM ONLY travel_time_locks WHERE id_key=id_input AND time_key=time_input;
RETURN 1;
END;
$BODY$ LANGUAGE 'plpgsql' VOLATILE
COST 1;