Механизм переключения режимов транзакций Pangolin
В СУБД Pangolin реализован механизм, обеспечивающий установку режима транзакций для всего Pangolin при помощи функции с ролевым ограничением.
Ранее управление режимом «только чтение» транзакций по умолчанию осуществлялось при помощи GUC-параметра default_transaction_read_only. Данный параметр относится к параметрам клиентского сеанса (соединения). Когда параметр активен, все новые транзакции сеанса по умолчанию получают характеристику при помощи SET TRANSACTION READ ONLY. При этом каждый пользователь мог менять режим транзакций в своем сеансе, меняя значение параметра или настраивая текущую транзакцию при помощи SET TRANSACTION READ WRITE.
Эта возможность не позволяла гарантировать одинаковый режим транзакций для множества сессий Pangolin, не разграничивала права на его переключение и не позволяла выдать части пользователей право на запись при действующем для остального экземпляра режиме «только чтение», в отличие от текущего реализованного решения.
Функциональность доступна только для редакций Enterprise и Enterprise для ERP-систем.
Настройка
Реализованный механизм представляет из себя выполнение следующих пунктов:
- Добавление функции
psql_set_transaction_modeдля переключения RO в RW и обратно (RO – только чтение, RW – чтение и запись). Режим транзакционности, возникший в результате вызова функции, распространяется на все базы данных кластера. - Добавление списка пользователей, которые имеют права на вызов
psql_set_transaction_mode. Список реализован в виде GUC-параметраset_xact_mode_users. - Добавление списка пользователей, которые имеют права на выполнение пишущих транзакций. Список реализован в виде GUC-параметра
set_rw_users. - Добавление представления
psql_transaction_mode_history, в котором хранится история вызовов функцииpsql_set_transaction_mode. - Добавление параметра
transaction_mode_max_records, который регулирует максимальное количество записей в представленииpsql_transaction_mode_history.
Описание данных объектов и примеры управления механизмом при помощи них описаны в подразделах далее.
Конфигурационные параметры
Параметр | Тип данных | Значение по умолчанию | Применение | Описание |
|---|---|---|---|---|
|
| Пусто | Изменение значения данного параметра доступно только суперпользователям Имена пользователей разделяются символом | Список пользователей, которые будут иметь права на вызов |
|
| Пусто | Изменение значения данного параметра доступно только суперпользователям | Список пользователей, которые будут иметь права на выполнение пишущих транзакций |
|
|
| Изменение значения данного параметра доступно только суперпользователям и с выполнением перезапуска сервера | Максимальное количество записей в представлении |
Объекты БД
Функция
Название функции | Описание | Входные параметры | Возвращаемое значение | Примечание |
|---|---|---|---|---|
| Переключение режимов RO в RW и обратно. Режим транзакционности, возникший в результате вызова функции, распространяется на все базы данных кластера |
|
| При переключении от режима только чтение в режим чтение-запись, переход мгновенный. Параметр |
Представление
Представление psql_transaction_mode_history возвращает следующие поля информации:
| Название поля | Возвращаемое значение | Описание |
|---|---|---|
mode | text | Текущее состояние БД (выбранный режим) |
started | timestamp with time zone | Дата и время начала транзакции |
ended | timestamp with time zone | Дата и время начала завершения транзакции |
source | text | Причина наступления режима (старт СУБД или вызов функции) |
pending | boolean | Следующее состояние |
function_called | timestamp with time zone | Дата и время вызова функции для переключения в следующее состояние |
timeout | integer | Запрошенный тайм-аут завершения текущих RW транзакций |
Управление
Управление механизмом переключения режимов
Управление осуществляется с помощью функции psql_set_transaction_mode, которая переключает режимы RO, RW. При переключении из режима RW в RO происходит прерывание пишущих транзакций, при этом сессии не останавливаются. Вызывающая функцию сессия блокируется до завершения всех пишущих транзакции. Если происходит вызов функции в одной сессии, то в других сессиях вызов функции блокируется (mutual exclusive).
Если пишущая транзакция не может быть остановлена штатными средствами, то будет остановлена вся сессия. Соответствующая информация будет записана в системный лог.
Если режим успешно переключен после вызова функции, то выводится сообщение об успешном переключении режима уровня WARNING и функция возвращает текущий режим (RO либо RW). Если пользователю не доступна эта функция, то попытка вызова завершается ошибкой, функция ничего не возвращает.
Пример вызова функции psql_set_transaction_mode:
SELECT psql_set_transaction_mode('RO', 100);
WARNING: transaction mode successfully set to RO with 0 of aborted transactions
psql_set_transaction_mode
-----------------------
RO
(1 row)
При вызове функции psql_set_transaction_mode с параметром mode='RW' всегда необходимо указывать параметр timeout (иначе вызов функции закончится ошибкой), хотя переключение в режим RW происходит немедленно, без ожидания завершения текущих транзакций.
Пример вызова функции psql_set_transaction_mode с параметрами mode=RW, timeout=100:
SELECT psql_set_transaction_mode('RW', 100);
WARNING: transaction mode successfully set to RW
psql_set_transaction_mode
-----------------------
RW
(1 row)
Вызов функции psql_set_transaction_mode выводит предупреждение, если переключение режима не требуется, функция возвращает текущий режим (RW/RO):
SELECT psql_set_transaction_mode('RO', 200);
WARNING: current mode is "RO" (read only), nothing to do
psql_set_transaction_mode
----------------------
RO
(1 row)
Просмотреть текущий режим можно вспомогательной функцией psql_get_transaction_mode, которая возвращает RW (текущий режим чтение-запись) либо RO (текущий режим только чтение). Функция доступна любому пользователю:
SELECT psql_get_transaction_mode();
psql_get_transaction_mode
---------------------------
RO
(1 row)
Вызывать функцию psql_set_transaction_mode могут пользователи, которые перечислены в специальном списке (подробнее смотрите раздел «Управление списком пользователей, имеющих права на переключение режимов»).
При вызове функции, в лог базы данных пишется сообщение с уровнем WARNING:
- в какой режим выполнено переключение;
- результат операции;
- количество прерванных транзакций.
Информация о текущем режиме и история переключений содержится в представлении psql_transaction_mode_history.
Просмотреть представление psql_transaction_mode_history можно запросом SELECT:
SELECT * FROM psql_transaction_mode_history;
mode | started | ended | source | pending | function_called | timeout
--------------+----------------------------+----------------------------+----------+---------+----------------------------+---------
RW | 2025-01-21 10:44:04.582146 | 2025-01-21 11:56:16.790523| START | False | <NULL> | <NULL>
RO | 2025-01-21 11:56:16.090523 | 2025-01-21 14:42:14.230106| FUNCTION | False | 2025-01-21 11:56:15.991376 | 200
RW | 2025-01-21 14:42:14.230106 | 2025-01-21 14:49:54.067529| FUNCTION | False | 2025-01-21 14:42:14.230106 | 0
RO | 2025-01-21 14:49:54.067529 | 2025-01-21 16:15:28.292891| FUNCTION | False | 2025-01-21 14:49:53.967529 | 250
RW | 2025-01-21 16:15:28.292891 | <NULL> | FUNCTION | False | 2025-01-21 16:15:28.292887 | 0
RO | <NULL> | <NULL> | FUNCTION | True | 2025-01-21 18:53:34.891701 | -1
(6 rows)
Максимальное количество записей в представлении psql_transaction_mode_history определяется параметром transaction_mode_max_records (по умолчанию 10000 записей).
Просмотреть параметр запросом SHOW может любой пользователь:
SHOW transaction_mode_records;
transaction_mode_records
---------------------------
10000
(1 rows)
Изменять параметр может только суперпользователь, изменение параметра требует рестарта сервера:
ALTER SYSTEM SET transaction_mode_max_records = 100;
\q
sudo systemctl restart postgresql
Минимальное значение параметра transaction_mode_max_records - 0 (представление не хранит информацию об истории переключений режимов), максимальное - 100000 записей.
При перезапуске режим RO не сохраняется. После запуска база данных переходит в режим чтения и записи (RW). Пример:
psql -U user2
SELECT psql_set_transaction_mode('RO', 110);
WARNING: transaction mode successfully set to RO with 0 of aborted transactions
psql_set_transaction_mode
-----------------------
RO
(1 row)
INSERT INTO test_table(id, data) VALUES(100, 'very important data');
ERROR: cannot execute INSERT in a read-only transaction
\q
sudo systemctl restart postgresql
psql -U user2
INSERT INTO test_table(id, data) VALUES(100, 'very important data');
INSERT 0 1
Управление списком пользователей, имеющих права на переключение режимов
Имена пользователей, имеющих права на вызов функции psql_set_transaction_mode, перечисляются в настроечном GUC-параметре set_xact_mode_users. Имена пользователей разделяются символом , (запятая).
По умолчанию параметр пуст. Просмотреть список пользователей, имеющих права на переключение режимов, можно запросом SHOW:
SHOW set_xact_mode_users;
set_xact_mode_users
-----------------------
(1 row)
Изменять параметр set_xact_mode_users может только суперпользователь. Изменение параметра не требует перезагрузки сервера:
ALTER SYSTEM SET set_xact_mode_users = 'user1, user2';
SELECT pg_reload_conf();
Просматривать параметр set_xact_mode_users может любой пользователь:
SHOW set_xact_mode_users;
set_xact_mode_users
-----------------------
user1, user2
(1 row)
Очистить параметр set_xact_mode_users можно либо запросом RESET:
ALTER SYSTEM RESET set_xact_mode_users;
SELECT pg_reload_conf();
SHOW set_xact_mode_users;
set_xact_mode_users
------------------------
(1 row)
Либо передав в параметр пустую строку:
ALTER SYSTEM SET set_xact_mode_users='';
SELECT pg_reload_conf();
SHOW set_xact_mode_users;
set_xact_mode_users
------------------------
(1 row)
Управление списком пользователей, имеющих права на выполнение пишущих транзакций в режиме RO
Имена пользователей, имеющих права на выполнение пишущих транзакций в режиме RO, перечисляются в настроечном GUC-параметре set_rw_users.
По умолчанию параметр пуст. Просмотреть список пользователей, имеющих права на выполнение пишущих транзакций в режиме RO, можно запросом SHOW:
SHOW set_rw_users;
set_rw_users
----------------
(1 row)
Изменять параметр set_rw_users может только суперпользователь. Изменение параметра не требует перезагрузки сервера:
ALTER SYSTEM SET set_rw_users = 'user1, user2';
SELECT pg_reload_conf();
Просматривать параметр может любой пользователь:
SHOW set_rw_users;
set_rw_users
---------------
user1, user2
(1 row)
Очистить параметр можно либо запросом RESET:
ALTER SYSTEM RESET set_rw_users;
SELECT pg_reload_conf();
SHOW set_rw_users;
set_rw_users
----------------
(1 row)
Либо передав в параметр пустую строку:
ALTER SYSTEM SET set_rw_users='';
SELECT pg_reload_conf();
SHOW set_rw_users;
set_rw_users
----------------
(1 row)
Пользователь, указанный в параметре set_rw_users, может выполнять пишущие транзакции после переключения в режим RO. Сессия данного пользователя открывается сразу в режиме RW, никаких дополнительных действий не требуется:
ALTER SYSTEM SET set_rw_users = 'user1';
ALTER SYSTEM SET set_xact_mode_users='user1, user2';
SELECT pg_reload_conf();
\q
psql -U user1
SELECT psql_set_transaction_mode('RO', 10);
WARNING: transaction mode successfully set to RO with 0 of aborted transactions
psql_set_transaction_mode
-----------------------
RO
(1 row)
INSERT INTO test_table(id, data) VALUES(100, 'very important data');
INSERT 0 1
Диагностика
Попытка вызова функции psql_set_transaction_mode пользователем, не добавленным в список set_xact_mode_users, заканчивается ошибкой:
SELECT psql_set_transaction_mode('RO', 100);
ERROR: permission denied for function psql_set_transaction_mode
Вызов функции psql_set_transaction_mode с неверными параметрами mode или timeout пользователем, добавленным в параметр set_xact_mode_users, заканчивается ошибкой.
Вызов функции psql_set_transaction_mode с неверным параметром mode заканчивается ошибкой:
SELECT psql_set_transaction_mode('READ', 100);
ERROR: mode "READ" does not exist, choose a correct mode: "RO" or "RW"
Вызов функции psql_set_transaction_mode с неверными параметром timeout заканчивается ошибкой:
SELECT psql_set_transaction_mode('RO', -120);
ERROR: timeout must be a positive integer or "0" to interrupt all RW transactions immediately or "-1" for unlimited timeout
Вызов функции psql_set_transaction_mode с недопустимым значением параметров mode или timeout пользователем, добавленным в параметр set_xact_mode_users, заканчивается системной ошибкой.
Вызов функции psql_set_transaction_mode с попыткой передать строку в параметр timeout заканчивается ошибкой:
SELECT psql_set_transaction_mode('RO', 'l2o');
ERROR: invalid input syntax for type integer: "l2o"
Вызов функции psql_set_transaction_mode с попыткой передать дробное число в параметр timeout заканчивается ошибкой:
SELECT psql_set_transaction_mode('RO', 120.7);
ERROR: function psql_set_transaction_mode(unknown, numeric) does not exist
Вызов функции psql_set_transaction_mode в параллельной сессии блокируется и заканчивается ошибкой.
Пример вызова функции psql_set_transaction_mode в параллельной сессии:
SELECT psql_set_transaction_mode('RO', 200);
ERROR: function "psql_set_transaction_mode" was blocked due to concurrent call
Попытка изменить параметр transaction_mode_max_records не суперпользователем заканчивается ошибкой:
ALTER SYSTEM SET transaction_mode_max_records=2000;
ERROR: permission denied to set parameter "transaction_mode_max_records"
Попытка присвоить параметру transaction_mode_max_records значение, превышающее максимальное, заканчивается ошибкой:
ALTER SYSTEM SET transaction_mode_max_records=7007007;
ERROR: 7000007 is outside the valid range for parameter "transaction_mode_max_records" (0 .. 100000)
Попытка присвоить параметру transaction_mode_max_records невалидное значение заканчивается ошибкой:
ALTER SYSTEM SET transaction_mode_max_records='thousand';
ERROR: invalid value for parameter "transaction_mode_max_records": "thousand"
Попытка изменения параметра set_xact_mode_users не суперпользователем заканчивается ошибкой:
ALTER SYSTEM SET set_xact_mode_users = 'user1, user2';
ERROR: permission denied to set parameter "set_xact_mode_users"
Попытка вызова функции psql_set_transaction_mode пользователем, не добавленным в список set_xact_mode_users, заканчивается ошибкой (даже если он добавлен в параметр set_rw_users или является суперпользователем):
SELECT psql_set_transaction_mode('RO', 100);
ERROR: permission denied for function psql_set_transaction_mode
Попытка изменения параметра set_rw_users не суперпользователем заканчивается ошибкой:
ALTER SYSTEM SET set_rw_users = 'user1, user2';
ERROR: permission denied to set parameter "set_rw_users"
После вызова функции psql_set_transaction_mode, с переключением всех транзакций в режим RO, попытки выполнить RW-транзакции в тестовой базе данных по истечении периода, заданного в параметре timeout, пользователями, не добавленными в параметр set_rw_users, заканчиваются ошибкой (даже если они добавлены в параметр set_xact_mode_users или являются суперпользователями):
psql -U user2
SELECT psql_set_transaction_mode('RO', 10);
WARNING: transaction mode successfully set to RO with 0 of aborted transactions
psql_set_transaction_mode
-----------------------
RO
(1 row)
INSERT INTO test_table(id, data) VALUES(100, 'very important data');
ERROR: cannot execute INSERT in a read-only transaction