How to write my own lock / unlock functions for PostgreSQL

I have a postgresql (in perlu) function getTravelTime (integer, timestamp) that tries to fetch data for a specified id and timestamp. If there is no data or the data is old, it downloads it from an external server (download time ~ 300ms).

Several processes use this database and this feature. There is an error when two processes do not find the data and do not load it and do not try to make an insert into the travel_time table (the id and timestamp pair must be unique). I thought about locks. Locking the entire table blocks all processes and allows only one to be executed. I only need to block ID and timestamp. It seems that pg_advisory_lock only locks on the "current session". But my processes are using their own sessions.

I tried to write my own lock / unlock functions. Am I doing it right? I am using active wait, how can I omit this? Maybe there is a way to use pg_advisory_lock () as a global lock?

My code:

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;

      

+2


a source to share


2 answers


Upon further testing, I found that "current session" means the entire PostgreSQL backend instance, not just one connection.



My solution: PERFORM pg_advisory_lock(id, extract(epoch from my_time)::int );

(+ unlock) inside my function getTravelTime

.

+1


a source


Use pg_advisory_lock()

. This is exactly what you need.



+5


a source







All Articles