2010-04-13 3 views
2

postgresql (perlu) 함수 getTravelTime (integer, timestamp)은 지정된 ID와 타임 스탬프에 대한 데이터를 선택하려고합니다. 데이터가 없거나 데이터가 오래된 경우 외부 서버에서 데이터를 다운로드합니다 (다운로드 시간 ~ 300ms).PostgreSQL에 대한 내 자신의 전역 잠금/잠금 해제 기능을 작성하는 방법

다중 프로세스는이 데이터베이스와이 기능을 사용합니다. 두 프로세스가 데이터를 찾지 못하고 다운로드하여 travel_time 테이블에 삽입하려고하면 오류가 발생합니다 (ID와 타임 스탬프 쌍은 고유해야합니다). 나는 자물쇠에 대해 생각했다. 전체 테이블을 잠그면 모든 프로세스가 차단되어 하나만 진행할 수 있습니다. ID와 타임 스탬프 만 잠글 필요가 있습니다. 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; 

답변

1

추가 테스트를 통해 "현재 세션"은 단일 연결뿐만 아니라 PostgreSQL 백엔드의 전체 인스턴스를 의미한다는 것을 알게되었습니다.

제 해결책은 getTravelTime 기능 내에서 PERFORM pg_advisory_lock(id, extract(epoch from my_time)::int); (+ 잠금 해제)입니다.

5

사용 pg_advisory_lock(). 그것은 정확히 당신이 필요로하는 것입니다.

+0

phppgadmin에서 수행 할 수있는 작업은 다음과 같습니다. SELECT pg_advisory_lock (5); SELECT pg_advisory_lock (5); SELECT 5; 두 번째 쿼리에서 차단 될 것으로 예상되지만 ... 대신 1ms 이상 지나면 "5"가됩니다 ... 왜요? – rafalmag

+0

확인. 이제 그 이유를 알았어. phpPgAdmin의 SQL 창이 트랜잭션이 아닙니다. 자물쇠는 아무 것도 사용하지 않을 때 자동으로 열립니다. 힌트 : 'psql'의 테스트 잠금 성능 향상 – rafalmag