関数特性
言語: PLPGSQL
戻り値: integer
failed_node to backup_node からフェイルオーバを開始します。この関数は全てのノードで呼ばれなければならず、そして全てのノードのデーモンの再起動に待機しなければなりません。declare
p_failed_node alias for $1;
p_backup_node alias for $2;
v_row record;
v_row2 record;
v_n int4;
begin
-- ----
-- 中枢構成にロックの取得
-- ----
lock table sl_config_lock;
-- ----
-- 全ての一貫性の検査が第一
-- 故障ノードへの経路を全てのシステムが所有しているかの検査
-- 同時にバックアップノードへの経路があるかも検査
-- ----
for v_row in select P.pa_client
from sl_path P
where P.pa_server = p_failed_node
and P.pa_client <> p_backup_node
and not exists (select true from sl_path PP
where PP.pa_server = p_backup_node
and PP.pa_client = P.pa_client)
loop
raise exception 'Slony-I: cannot failover - node % has no path to the backup node',
v_row.pa_client;
end loop;
-- ----
-- Check all sets originating on the failed node
-- ----
for v_row in select set_id
from sl_set
where set_origin = p_failed_node
loop
-- ----
-- 故障ノードのオリジンである全てのセットで
-- バックアップノードが購読されているかの検査
-- ----
select into v_row2 sub_forward, sub_active
from sl_subscribe
where sub_set = v_row.set_id
and sub_receiver = p_backup_node;
if not found then
raise exception 'Slony-I: cannot failover - node % is not subscribed to set %',
p_backup_node, v_row.set_id;
end if;
-- ----
-- 購読動作が有効かの検査
-- ----
if not v_row2.sub_active then
raise exception 'Slony-I: cannot failover - subscription for set % is not active',
v_row.set_id;
end if;
-- ----
-- 他に購読ノードがあれば、バックアップノードは
-- 発信ノードになる必要も同時にあります。
-- ----
select into v_n count(*)
from sl_subscribe
where sub_set = v_row.set_id
and sub_receiver <> p_backup_node;
if v_n > 0 and not v_row2.sub_forward then
raise exception 'Slony-I: cannot failover - node % is not a forwarder of set %',
p_backup_node, v_row.set_id;
end if;
end loop;
-- ----
-- 厳しく故障ノードの全ての接続を停止
-- ----
perform terminateNodeConnections(
'_schemadoc_Node_' || p_failed_node);
--
RebuildListenEntries() が有効になっていれば以下のコードは使われなくなる
--
事を覚えておいてください。
if false then
-- ----
-- 故障ノードから何かを監視している全てのノードに
-- 代わりとしてバックアップノード上のそれらを監視するようにします。
-- ----
for v_row in select * from sl_listen
where li_provider = p_failed_node
and li_receiver <> p_backup_node
loop
perform storeListen_int(v_row.li_origin,
p_backup_node, v_row.li_receiver);
end loop;
-- ----
-- 故障ノードが監視していた全ての事象を
-- バックアップノードが監視する様にします。
-- ----
for v_row in select li_origin, li_provider
from sl_listen
where li_receiver = p_failed_node
and li_provider <> p_backup_node
loop
perform storeListen_int(v_row.li_origin,
v_row.li_provider, p_backup_node);
end loop;
-- ----
-- 故障ノードから何んでも受け取る
-- 全ての sl_listen エントリを削除します。
-- ----
delete from sl_listen
where li_provider = p_failed_node
or li_receiver = p_failed_node;
end if;
-- ----
-- セットの移動
-- ----
for v_row in select S.set_id, (select count(*)
from sl_subscribe SUB
where S.set_id = SUB.sub_set
and SUB.sub_receiver <> p_backup_node
and SUB.sub_provider = p_failed_node)
as num_direct_receivers
from sl_set S
where S.set_origin = p_failed_node
for update
loop
-- ----
-- バックアップノードが唯一の直接購読ノードか否か。
-- ----
if v_row.num_direct_receivers = 0 then
raise notice 'failedNode: set % has no other direct receivers - move now', v_row.set_id;
-- ----
-- バックアップノードは唯一の直接購読ノードで、セットのすぐに移動します。
-- バックアップノード上でそれ自身は、次の作業をします。
-- 全てのユーザモードのトリガーのリストア
-- ログトリガーの追加、購読の削除、および
-- 旧くなった setsync ステータスの削除
-- ----
if p_backup_node = getLocalNodeId('_schemadoc') then
for v_row2 in select * from sl_table
where tab_set = v_row.set_id
loop
perform alterTableRestore(v_row2.tab_id);
end loop;
end if;
update sl_set set set_origin = p_backup_node
where set_id = v_row.set_id;
if p_backup_node = getLocalNodeId('_schemadoc') then
delete from sl_setsync
where ssy_setid = v_row.set_id;
for v_row2 in select * from sl_table
where tab_set = v_row.set_id
loop
perform alterTableForReplication(v_row2.tab_id);
end loop;
end if;
delete from sl_subscribe
where sub_set = v_row.set_id
and sub_receiver = p_backup_node;
else
raise notice 'failedNode: set % has other direct receivers - change providers only', v_row.set_id;
-- ----
-- バックアップノードは唯一の直接購読ノードではありません。
-- 意味する所は、この時点で全ての直接購読ノードをバックアップノードから
-- 受け取るようにリダイレクトし、バックアップノードそれ自身は
-- 他から受け取るようにします。
-- 管理ユーティリティは slon エンジンが再起動するまで待機し、
-- そのあと最高位の SYNC を所有しているノード上で failedNode2()
-- を呼び出し、そしてこれを後でバックアップノード上に
-- リダイレクトします。
-- ----
update sl_subscribe
set sub_provider = (select min(SS.sub_receiver)
from sl_subscribe SS
where SS.sub_set = v_row.set_id
and SS.sub_provider = p_failed_node
and SS.sub_receiver <> p_backup_node
and SS.sub_forward)
where sub_set = v_row.set_id
and sub_receiver = p_backup_node;
update sl_subscribe
set sub_provider = p_backup_node
where sub_set = v_row.set_id
and sub_provider = p_failed_node
and sub_receiver <> p_backup_node;
end if;
end loop;
-- sl_listen テーブルの書き換え
perform RebuildListenEntries();
-- ----
-- ノードデーモンの再起動の確認
-- ----
notify "_schemadoc_Restart";
-- ----
-- とりあえずこれでお終い
-- ----
return p_failed_node;
end;