2014-11-20 8 views
2

В настоящее время я работаю над базой данных PostgreSQL 9.2.x с большим количеством клиентов, а также таблиц и функций. Мы постоянно развертываем код, и иногда из-за этого развертывания необходимо даже отказаться от типа или функции.Postgres drop type XX000 "cache lookup failed for type"

Пример:

1.Script создать необходимые функции в первую очередь

CREATE TYPE tmp._myEnum AS ENUM ('OLD', 'NEW', 'BOTH'); 

CREATE OR REPLACE FUNCTION tmp._get_status() 
RETURNS tmp._myEnum AS 
$BODY$ 
BEGIN 
    RETURN 'OLD'::tmp._myEnum; 
END; 
$BODY$ 
LANGUAGE plpgsql VOLATILE SECURITY DEFINER COST 10; 


CREATE OR REPLACE FUNCTION tmp._my_testfunction() 
RETURNS VOID AS 
$BODY$ 
BEGIN 
    CASE tmp._get_status() 
     WHEN 'OLD'::tmp._myEnum THEN 
      RAISE INFO 'myEnum is OLD'; 
     WHEN 'NEW'::tmp._myEnum THEN 
      RAISE INFO 'myEnum is NEW'; 
     WHEN 'BOTH'::tmp._myEnum THEN 
      RAISE INFO 'myEnum is BOTH'; 
     ELSE 
      RAISE INFO 'myEnum has an unexpected value'; 
    END CASE; 

    FOR i IN 1..10 LOOP 
     RAISE INFO 'Step [%]',i; 
    END LOOP; 
    RETURN; 
END; 
$BODY$ 
LANGUAGE plpgsql VOLATILE SECURITY DEFINER COST 10; 

2.Scenario, что приводит к исключению:

а) один клиент постоянно с помощью ТМП ._my_testfunction()

SELECT tmp._my_testfunction() 

b) Чтобы развернуть изменение на t он Композитный тип я исполняю в другой сессии

DROP FUNCTION IF EXISTS tmp._get_status(); 
DROP TYPE IF EXISTS tmp._myEnum; 

CREATE TYPE tmp._myEnum AS ENUM ('OLD', 'NEW', 'BOTH','NOTHING'); 

CREATE OR REPLACE FUNCTION tmp._get_status() 
RETURNS tmp._myEnum AS 
$BODY$ 
BEGIN 
    RETURN 'OLD'::tmp._myEnum; 
END; 
$BODY$ 
LANGUAGE plpgsql VOLATILE SECURITY DEFINER COST 10; 

с) Клиент, который постоянно используя tmp._my_testfunction() imidiatly бросает

ERROR: cache lookup failed for type 386318 
CONTEXT: PL/pgSQL function tmp._my_testfunction() line 3 at CASE 

Как я могу предотвратить это?

ответ

0

Поскольку мы не смогли найти другой способ обойти эту проблему, мы внедрили решение, которое уведомляет все другие соединения, чтобы обновить себя, используя команды LISTEN и NOTIFY. Таким образом, все клиенты прослушивают определенные каналы для команды, которая сообщает им повторно подключиться. Команда ist затем отправляет в ту же транзакцию, которая удаляет тип.

0

Что похоже на это состояние гонки. Ваши клиенты звонят tmp._my_test_function(), и пока он настраивается путем интерпретации исходного кода функции, вы отбрасываете функцию и тип enum, а затем повторно создаете их. На внутреннем уровне практически все объекты ссылаются на их oid (со значением 386318 для типа в вашем случае), поэтому функция и enum в вашей клиентской функции разрешают oid с. Если интерпретатор разрешает функцию и enum до двух oid с, и затем вы отбрасываете функцию и enum и заново их создаете, старые oid s исчезают, а ваша вновь созданная функция и enum имеют разные значения oid. Новые вызовы функции будут работать, потому что интерпретатор находит новую функцию oid s для функции и enum.

Решение в таком сценарии должно быть REVOKE EXECUTE на клиентской функции, внести изменения, а затем GRANT EXECUTE привилегии снова. На стороне клиента вам придется иметь дело с ошибками привилегий, повторив вызов функции до тех пор, пока вы не добьетесь успеха.

В общем случае вы должны развернуть новый код на производственном сервере во время периодов низкого трафика и/или через управление сеансом, если вы хотите избежать накладных расходов на вызовы функций повторной попытки.

+0

Мы уже развертываем только часы с низким трафиком, но из-за потребительского трафика на нашем продукте его все еще, похоже, много для чистого развертывания. Нет ли какой-либо команды или способа уведомлять Postgres, чтобы очистить все сеансовые кеши? проблема заключалась в том, что исключение было выброшено через 20 минут после развертывания и остановлено только после того, как все соединения db были закрыты и снова открыты. – RootOfProblem

+0

Вы можете использовать консультативную блокировку, но тогда вам придется поместить это на каждую (несколько блоков) функцию (ы), и каждый запрос, используя любую такую ​​функцию, должен был бы получить консультативную блокировку до вызова функции. Мне кажется, это слишком много. Лучшее предложение, которое у меня есть, - это взять ваш вопрос на форум DBA, так как именно там вы можете встретить фотовспытателей. – Patrick

+0

Спасибо, я попробую удачу там. Спасибо, в любом случае. – RootOfProblem