2009-06-30

Убить defunct процесс в linux

Как оказалось, команда kill для defunct процессов не работает. Как же все-таки такой процесс убить??? А вот как:

Для того, чтобы грохнуть такой процесс, нужно сначала убить родительский процесс. Родительские процессы ищем такой командой:

ps -xal | grep фильтр_процесса_который_нужно_убить

В выведенном листинге в колонке PPID будет родительский процесс. Убиваем его при помощи kill, а потом и процесс_который_нужно_убить. Вот так ;)
Читать далее

2009-06-22

Репликация PostgreSQL+Bucardo. Первые рабочие изменение структуры БД.

Вот первые рабочие изменение структуры БД.
То, что дали программисты:


-- ################################################################

-- ПРОВЕРИТЬ!!!!! должно уже быть
DROP INDEX "u_cntrgn0";
CREATE UNIQUE INDEX "u_cntrinvnmbr" ON countergen
USING btree ("invnumber");
////////////////////////////////////////////////////////


update countergen set ownershiptypecod = 1
where invnumber is not null;

-- нормы льготы для тарифов ЭлектроОбогрев
update tariff set extralimit = 25, maxlimit = 200,
usagelimit = 100, diflimit = 200 where code in (5,6,9);

-- 73 кат СIЛЬСЬКИЙ ПРАЦIВНИК КРИМIНАЛЬНО-ВИКОНАВЧОI СИСТЕМИ НА ПЕНСII
-- 50% без лимита
update benefitcategory set coeff = 50, islimitcode = 0 where code = 73;


CREATE TABLE "judicialdebt" (
"code" DOUBLE PRECISION NOT NULL,
"name" VARCHAR(50),
"dategen" DATE,
"contractnumber" VARCHAR(50),
"contractdate" DATE,
"courtnumber" VARCHAR(50),
"courtdate" DATE,
"isincourt" DOUBLE PRECISION NOT NULL,
"operationdate" DATE,
"courtsum" NUMERIC(16,2),
"courtverdict" VARCHAR(100),
"profitsdate" DATE,
"typegen" DOUBLE PRECISION NOT NULL,
"recordpontrfcode" DOUBLE PRECISION NOT NULL,
"periodrefcode" DOUBLE PRECISION,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
CONSTRAINT "pk_juddebtcd" PRIMARY KEY("code"),
CONSTRAINT "fk_juddebtrpcd" FOREIGN KEY ("recordpontrfcode")
REFERENCES "recordpoint"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE
) WITHOUT OIDS;

ALTER TABLE judicialdebt
ADD CONSTRAINT "fk_jdbtprdcd" FOREIGN KEY ("periodrefcode")
REFERENCES "currentperiod"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;

CREATE INDEX "ind_jdbtprdcd" ON "judicialdebt"
USING btree ("periodrefcode");

CREATE TABLE "juddebtstatus" (
"code" DOUBLE PRECISION NOT NULL,
"name" VARCHAR(50),
CONSTRAINT "pk_juddebtstts" PRIMARY KEY("code")
) WITHOUT OIDS;

INSERT INTO "juddebtstatus" ("code", "name")
VALUES (0, 'Отсутствует');

INSERT INTO "juddebtstatus" ("code", "name")
VALUES (1, 'Не погашено');

INSERT INTO "juddebtstatus" ("code", "name")
VALUES (2, 'Погашено');

CREATE TABLE "judicialdebtentry" (
"code" DOUBLE PRECISION NOT NULL,
"judicialdebtcode" DOUBLE PRECISION NOT NULL,
"dataenddate" DATE NOT NULL,
"datasumtopay" NUMERIC(16,2) NOT NULL,
"datapaiddate" DATE,
"datapaidsum" NUMERIC(16,2) NOT NULL,
"datastatuscode" DOUBLE PRECISION NOT NULL,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
CONSTRAINT "pk_juddebtntrcd" PRIMARY KEY("code"),
CONSTRAINT "fk_judnttrdebtcd" FOREIGN KEY ("judicialdebtcode")
REFERENCES "judicialdebt"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE
) WITHOUT OIDS;

CREATE INDEX "juddebtentrydebtcd" ON "judicialdebtentry"
USING btree ("judicialdebtcode");
CREATE INDEX "judicialdebtrpcode" ON "klres"."judicialdebt"
USING btree ("recordpontrfcode");

INSERT INTO "invstatus" ("code", "name")
VALUES (4, 'Исковый');

INSERT INTO "saldotype" ("code", "name")
VALUES (5, 'По исковой (электричество)');

INSERT INTO "saldotype" ("code", "name")
VALUES (6, 'По исковой (акты)');

CREATE TABLE "sordebttobill" (
"code" DOUBLE PRECISION NOT NULL,
"sumgen" NUMERIC(16,2),
"entrycode" DOUBLE PRECISION NOT NULL,
"billrefcode" DOUBLE PRECISION NOT NULL,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
CONSTRAINT "pk_srdbttbll" PRIMARY KEY("code")
) WITHOUT OIDS;

CREATE TABLE "paymentjd" (
"code" DOUBLE PRECISION NOT NULL,
"paydate" DATE NOT NULL,
"value" NUMERIC(16,2) NOT NULL,
"pymntdcmntrfcode" DOUBLE PRECISION NOT NULL,
"statuscode" DOUBLE PRECISION NOT NULL,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
"jdtype" DOUBLE PRECISION,
"entrycode" DOUBLE PRECISION,
CONSTRAINT "pk_pmntjd" PRIMARY KEY("code"),
CONSTRAINT "fk_pmntjdsttscd" FOREIGN KEY ("statuscode")
REFERENCES "paymentstatus"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE
) WITHOUT OIDS;

CREATE INDEX "paymentjd_idx" ON "paymentjd"
USING btree ("pymntdcmntrfcode");

INSERT INTO "paymenttype" ("code", "name")
VALUES (16, 'По ИЗ');

INSERT INTO "paymenttype" ("code", "name")
VALUES (17, 'По ИЗ (акты)');

INSERT INTO "paymentdocmnttyp" ("code", "name")
VALUES (8, 'Корректировка иска судом');

-- #################################################################

Вот что делаем мы:

-- #################################################################

0. Останавливаем репликацию

-- #################################################################

1. Под res на на главной БД:

CREATE TABLE "judicialdebt" (
"code" DOUBLE PRECISION NOT NULL,
"name" VARCHAR(50),
"dategen" DATE,
"contractnumber" VARCHAR(50),
"contractdate" DATE,
"courtnumber" VARCHAR(50),
"courtdate" DATE,
"isincourt" DOUBLE PRECISION NOT NULL,
"operationdate" DATE,
"courtsum" NUMERIC(16,2),
"courtverdict" VARCHAR(100),
"profitsdate" DATE,
"typegen" DOUBLE PRECISION NOT NULL,
"recordpontrfcode" DOUBLE PRECISION NOT NULL,
"periodrefcode" DOUBLE PRECISION,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
CONSTRAINT "pk_juddebtcd" PRIMARY KEY("code"),
CONSTRAINT "fk_juddebtrpcd" FOREIGN KEY ("recordpontrfcode")
REFERENCES "recordpoint"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE
) WITHOUT OIDS;

ALTER TABLE judicialdebt
ADD CONSTRAINT "fk_jdbtprdcd" FOREIGN KEY ("periodrefcode")
REFERENCES "currentperiod"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;

CREATE INDEX "ind_jdbtprdcd" ON "judicialdebt"
USING btree ("periodrefcode");

CREATE TABLE "juddebtstatus" (
"code" DOUBLE PRECISION NOT NULL,
"name" VARCHAR(50),
CONSTRAINT "pk_juddebtstts" PRIMARY KEY("code")
) WITHOUT OIDS;

CREATE TABLE "judicialdebtentry" (
"code" DOUBLE PRECISION NOT NULL,
"judicialdebtcode" DOUBLE PRECISION NOT NULL,
"dataenddate" DATE NOT NULL,
"datasumtopay" NUMERIC(16,2) NOT NULL,
"datapaiddate" DATE,
"datapaidsum" NUMERIC(16,2) NOT NULL,
"datastatuscode" DOUBLE PRECISION NOT NULL,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
CONSTRAINT "pk_juddebtntrcd" PRIMARY KEY("code"),
CONSTRAINT "fk_judnttrdebtcd" FOREIGN KEY ("judicialdebtcode")
REFERENCES "judicialdebt"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE
) WITHOUT OIDS;

CREATE INDEX "juddebtentrydebtcd" ON "judicialdebtentry"
USING btree ("judicialdebtcode");
CREATE INDEX "judicialdebtrpcode" ON "judicialdebt"
USING btree ("recordpontrfcode");

CREATE TABLE "sordebttobill" (
"code" DOUBLE PRECISION NOT NULL,
"sumgen" NUMERIC(16,2),
"entrycode" DOUBLE PRECISION NOT NULL,
"billrefcode" DOUBLE PRECISION NOT NULL,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
CONSTRAINT "pk_srdbttbll" PRIMARY KEY("code")
) WITHOUT OIDS;

CREATE TABLE "paymentjd" (
"code" DOUBLE PRECISION NOT NULL,
"paydate" DATE NOT NULL,
"value" NUMERIC(16,2) NOT NULL,
"pymntdcmntrfcode" DOUBLE PRECISION NOT NULL,
"statuscode" DOUBLE PRECISION NOT NULL,
"modify_time" DOUBLE PRECISION,
"domain_info" VARCHAR(100) NOT NULL,
"jdtype" DOUBLE PRECISION,
"entrycode" DOUBLE PRECISION,
CONSTRAINT "pk_pmntjd" PRIMARY KEY("code"),
CONSTRAINT "fk_pmntjdsttscd" FOREIGN KEY ("statuscode")
REFERENCES "paymentstatus"("code")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE
) WITHOUT OIDS;

CREATE INDEX "paymentjd_idx" ON "paymentjd"
USING btree ("pymntdcmntrfcode");

-- #################################################################

2. Под bucardo на главной БД:

INSERT INTO goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
VALUES ('skres','res','judicialdebt','code','bigint','false');
INSERT INTO goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
VALUES ('skres','res','juddebtstatus','code','bigint','false');
INSERT INTO goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
VALUES ('skres','res','judicialdebtentry','code','bigint','false');
INSERT INTO goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
VALUES ('skres','res','sordebttobill','code','bigint','false');
INSERT INTO goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
VALUES ('skres','res','paymentjd','code','bigint','false');

INSERT INTO herdmap (herd, goat)
SELECT 'herd_skres', id
FROM goat WHERE db = 'skres'
AND tablename IN ('judicialdebt','juddebtstatus',
'judicialdebtentry','sordebttobill','paymentjd');

UPDATE sync SET synctype = 'fullcopy' WHERE name = 'sync_skres';
UPDATE sync SET synctype = 'pushdelta' WHERE name = 'sync_skres';

-- #################################################################

3. На подчиненной БД в РЭС под res:

update judicialdebt set code = code;
update juddebtstatus set code = code;
update judicialdebtentry set code = code;
update sordebttobill set code = code;
update paymentjd set code = code;

-- #################################################################

4. Запускаем репликацию

-- #################################################################



Читать далее

2009-06-19

Монтирование windows share на linux

Используем openSUSE 11.1
Вот скриптец:

#!/bin/bash
sudo /bin/umount ~/Desktop/netshare
sudo /bin/umount ~/Desktop/netshare
sudo /bin/umount ~/Desktop/netshare
mkdir ~/Desktop/netshare
sudo /bin/mount -t cifs //111.111.111.111/netshare ~/Desktop/netshare -o user=abon111,password=abon111,rw
Читать далее

2009-06-16

Репликация PostgreSQL+Bucardo. Работа с РЭСами

Привычка все документировать :)
После всех экспериментов начинаю реализовывать промышленную схему репликации. Тут последовательность действий. Комментариев будет мало, в основном конкретные инструкции.
Поехали...

Скадовск. Первая БД.

alexsf@shaman:~> ssh alexsf@10.77.11.71
alexsf@bucardik:~> sudo -s
bucardik:/home/alexsf # /etc/init.d/bucardo_stop
postgres@bucardik:~> cd work
postgres@bucardik:~/work> mkdir old.1
postgres@bucardik:~/work> mv old old.1
postgres@bucardik:~/work> mv skres_schema.sql old.1
postgres@bucardik:~/work> pg_dump -h 10.77.25.2 -p 5432 -U postgres -F p -s -s -v -f "skres_schema.sql" -n 'res' "UTF8_sk"
postgres@bucardik:~/work> psql -h 10.77.11.71 -U postgres res
res=# drop schema res cascade;
res=# CREATE SCHEMA res AUTHORIZATION res;
res=# \q
postgres@bucardik:~/work> psql -f skres_schema.sql -h 10.77.11.71 -U postgres res
postgres@bucardik:~/work> psql -h 10.77.11.71 -U res res
res=# \o drop_constr.sql
res=# \t
res=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
res-# FROM pg_constraint con, pg_class cl, pg_tables t, information_schema.constraint_column_usage cc
res-# WHERE t.schemaname = 'res'
res-# AND t.tablename = cl.relname
res-# AND con.contype = 'c'
res-# AND con.conrelid = cl.oid
res-# AND cc.constraint_name = con.conname
res-# AND cl.relname not in ('billsqlreport','dual','rp_abon','log')
res-# ORDER BY con.conname;
res=# \o drop_rule.sql
res=# SELECT 'DROP RULE '||rulename||' ON '||tablename||';'
res-# FROM pg_rules
res-# WHERE schemaname = 'res'
res-# ORDER BY tablename, rulename;
res=# \i drop_constr.sql
res=# \i drop_rule.sql
res=# \q
postgres@bucardik:~/work> psql -h 10.77.11.71 -U bucardo bucardo
bucardo=# INSERT INTO bucardo.db (name, dbhost, dbname, dbuser, dbpass)
bucardo-# VALUES ('skres','10.77.25.2','UTF8_sk','res','???');
bucardo=# INSERT INTO bucardo.db (name, dbhost, dbname, dbuser, dbpass)
bucardo-# VALUES ('allres','10.77.11.71','res','res','???');
bucardo=# INSERT INTO bucardo.dbgroup(name) VALUES('slave');
bucardo=# INSERT INTO bucardo.dbgroup(name) VALUES('master');
bucardo=# INSERT INTO bucardo.dbmap(db, dbgroup) VALUES('skres','slave');
bucardo=# INSERT INTO bucardo.dbmap(db, dbgroup) VALUES('allres','master');
bucardo=# \q
postgres@bucardik:~/work> psql -h 10.77.11.71 -U res res
res=# \o 2goat.sql
res=# \t
res=# SELECT 'INSERT INTO bucardo.goat
res'# (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
res'# VALUES (''skres'',''res'','''||cl.relname
res-# ||''','''||cc.column_name||''',''bigint'',''false'');'
res-# FROM pg_constraint con, pg_class cl, pg_tables t,
res-# information_schema.constraint_column_usage cc
res-# WHERE t.schemaname = 'res'
res-# AND t.tablename = cl.relname
res-# AND con.contype = 'p'
res-# AND con.conrelid = cl.oid
res-# AND cc.constraint_name = con.conname
res-# AND cl.relname not in ('billsqlreport','dual','rp_abon',
res(# 'log','auth_action','auth_domain',
res(# 'auth_dt_ac_type','auth_entity','auth_entity_segr',
res(# 'auth_group','auth_group_action','auth_role',
res(# 'auth_role_action','auth_segr','auth_segrtype',
res(# 'auth_user','auth_user_action','auth_user_group',
res(# 'auth_userstatus')
res-# ORDER BY cl.relname;
res=# \q
postgres@bucardik:~/work> psql -h 10.77.11.71 -U bucardo bucardo
bucardo=# \i 2goat.sql
bucardo=# INSERT INTO bucardo.herd(name) VALUES('herd_skres');
bucardo=# INSERT INTO bucardo.herdmap (herd, goat)
bucardo-# SELECT 'herd_skres', id
bucardo-# FROM goat WHERE db = 'skres';
bucardo=# \q
postgres@bucardik:~/work> ssh root@10.77.25.2
linux01:~ # su - postgres -c "cd /files/ftp; pg_dump -C -F c -b -f pgsql.UTF8_sk "UTF8_sk""
linux01:~ # exit
postgres@bucardik:~/work> wget --no-proxy -c --ftp-user=sit --ftp-password=??? ftp://10.77.25.2/ftp/pgsql.UTF8_sk
postgres@bucardik:~/work> psql -h 10.77.11.71 -U bucardo bucardo
bucardo=# INSERT INTO bucardo.sync (name,source,targetdb,synctype,
bucardo(# stayalive,checktime,analyze_after_copy)
bucardo-# VALUES('sync_skres','herd_skres','allres','pushdelta','false','60 minutes','false');
bucardo=# \q
postgres@bucardik:~/work> psql -h 10.77.11.71 -U res res
res=# \o drop_fk.sql
res=# \t
res=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
res-# FROM pg_constraint con, pg_class cl, pg_tables t, information_schema.constraint_column_usage cc
res-# WHERE t.schemaname = 'res'
res-# AND t.tablename = cl.relname
res-# AND con.contype = 'f'
res-# AND con.conrelid = cl.oid
res-# AND cc.constraint_name = con.conname
res-# ORDER BY con.conname;
res=# \q
postgres@bucardik:~/work> psql -h 10.77.11.71 -U res res
res=# \i drop_fk.sql
res=# \q
postgres@bucardik:~/work> /usr/bin/pg_restore -h 10.77.11.71 -p 5432 -U res -d res -a -v "pgsql.UTF8_sk"
postgres@bucardik:~/work> grep FOREIGN -B 1 skres_schema.sql > restore_fk.sql
postgres@bucardik:~/work> psql -h 10.77.11.71 -U res res
res=# \i restore_fk.sql
res=# \q
postgres@bucardik:~/work> exit
bucardik:~ # /etc/init.d/bucardo_start

Все, проверил, Скадовск катается. Теперь Новотроицк.

bucardik:~ # /etc/init.d/bucardo_stop
bucardik:~ # su - postgres
postgres@bucardik:~> cd work
postgres@bucardik:~/work> mkdir skres
postgres@bucardik:~/work> mv 2* skres; mv d* skres
postgres@bucardik:~/work> mv p* skres; mv r* skres; mv skres_* skres
postgres@bucardik:~/work> mkdir ntres
postgres@bucardik:~/work> cd ntres
postgres@bucardik:~/work/ntres> psql -h 10.77.50.2 -U postgres ntres
ntres=# ALTER ROLE res SUPERUSER;
ntres=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.50.2 -U res ntres
ntres=# CREATE LANGUAGE plpgsql;
ntres=# CREATE LANGUAGE plperlu;
ntres=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U bucardo bucardo
bucardo=# INSERT INTO bucardo.db (name, dbhost, dbname, dbuser, dbpass)
bucardo-# VALUES ('ntres','10.77.50.2','ntres','res','???');
bucardo=# INSERT INTO bucardo.dbmap(db, dbgroup) VALUES('ntres','slave');
bucardo=# \q
postgres@bucardik:~/work/ntres> mkdir /u02/pgdata/prepload
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U postgres postgres
postgres=# CREATE TABLESPACE prepload OWNER res
postgres-# LOCATION '/u02/pgdata/prepload';
postgres=# CREATE DATABASE prepload WITH ENCODING='UTF8'
postgres-# OWNER=res TABLESPACE=prepload;
postgres=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# CREATE SCHEMA res AUTHORIZATION res;
prepload=# GRANT ALL ON SCHEMA res TO res;
prepload=# \q
postgres@bucardik:~/work/ntres> pg_dump -h 10.77.50.2 -p 5432 -U postgres -F p -s -s -v -f "ntres_schema.sql" -n 'res' "ntres"
postgres@bucardik:~/work/ntres> psql -f ntres_schema.sql -h 10.77.11.71 -U res prepload
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# \o tmp_drop_fk.sql
prepload=# \t
prepload=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
prepload-# FROM pg_constraint con, pg_class cl, pg_tables t,
prepload-# information_schema.constraint_column_usage cc
prepload-# WHERE t.schemaname = 'res'
prepload-# AND t.tablename = cl.relname
prepload-# AND con.contype = 'f'
prepload-# AND con.conrelid = cl.oid
prepload-# AND cc.constraint_name = con.conname
prepload-# ORDER BY con.conname;
prepload=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# \i tmp_drop_fk.sql
prepload=# \o tmp_drop_constr.sql
prepload=# \t
prepload=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
prepload-# FROM pg_constraint con, pg_class cl, pg_tables t,
prepload-# information_schema.constraint_column_usage cc
prepload-# WHERE t.schemaname = 'res'
prepload-# AND t.tablename = cl.relname
prepload-# AND con.conrelid = cl.oid
prepload-# AND cc.constraint_name = con.conname
prepload-# ORDER BY con.conname;
prepload=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# \i tmp_drop_constr.sql
prepload=# \o tmp_drop_tables.sql
prepload=# \t
prepload=# select 'drop table '||table_name||' cascade;'
prepload-# from information_schema.tables
prepload-# where table_schema = 'res'
prepload-# and table_type = 'BASE TABLE'
prepload-# and (table_name like 'auth%'
prepload(# or table_name in ('billsqlreport','dual','rp_abon','log')
prepload(# or table_name not in (select table_name
prepload(# from information_schema.columns
prepload(# where column_name = 'domain_info'))
prepload-# order by table_name;
prepload=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# \i tmp_drop_tables.sql
prepload=# \q
postgres@bucardik:~/work/ntres> grep PRIMARY -B 1 ntres_schema.sql > restore_pk.sql
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# \i restore_pk.sql
prepload=# \o 2goat.sql
prepload=# \t
prepload=# SELECT 'INSERT INTO bucardo.goat
prepload'# (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy)
prepload'# VALUES (''ntres'',''res'','''||cl.relname
prepload-# ||''','''||cc.column_name||''',''bigint'',''false'');'
prepload-# FROM pg_constraint con, pg_class cl, pg_tables t,
prepload-# information_schema.constraint_column_usage cc
prepload-# WHERE t.schemaname = 'res'
prepload-# AND t.tablename = cl.relname
prepload-# AND con.contype = 'p'
prepload-# AND con.conrelid = cl.oid
prepload-# AND cc.constraint_name = con.conname
prepload-# ORDER BY cl.relname;
prepload=# \q
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U bucardo bucardo
bucardo=# \i 2goat.sql
bucardo=# INSERT INTO bucardo.herd(name) VALUES('herd_ntres');
bucardo=# INSERT INTO bucardo.herdmap (herd, goat)
bucardo-# SELECT 'herd_ntres', id
bucardo-# FROM goat WHERE db = 'ntres';
bucardo=# \q
postgres@bucardik:~/work/ntres> ssh root@10.77.50.2
linux01:~ # su - postgres -c "pg_dump -C -F c -b -f pgsql.ntres "ntres""
linux01:/u02/scheduler # exit
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U bucardo bucardo
bucardo=# INSERT INTO bucardo.sync (name,source,targetdb,synctype,
bucardo(# stayalive,checktime,analyze_after_copy)
bucardo-# VALUES('sync_ntres','herd_ntres','allres','pushdelta','false','60 minutes','false');
bucardo=# \q
postgres@bucardik:~/work/ntres> ssh root@10.77.50.2
linux01:~ # cp /var/lib/pgsql/pgsql.ntres /u02/scheduler
linux01:~ # exit
postgres@bucardik:~/work/ntres> ssh root@10.77.50.3
linux02:~ # mkdir /mnt/linux01
linux02:~ # mount 10.77.50.2:/u02/scheduler /mnt/linux01
linux02:~ # cp /mnt/linux01/pgsql.ntres /files/
linux02:~ # exit
postgres@bucardik:~/work/ntres> wget --no-proxy -c --ftp-user=sit --ftp-password=??? ftp://10.77.50.3/pgsql.ntres
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# drop schema res cascade;
prepload=# create schema res authorization res;
prepload=# \q
postgres@bucardik:~/work/ntres> /usr/bin/pg_restore -h 10.77.11.71 -p 5432 -U res -d prepload -v "pgsql.ntres"
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res prepload
prepload=# \o drop_tables_2load.sql
prepload=# \t
prepload=# select 'drop table '||table_name||' cascade;'
prepload-# from information_schema.tables
prepload-# where table_schema = 'res'
prepload-# and table_type = 'BASE TABLE'
prepload-# and (table_name like 'auth%'
prepload(# or table_name in ('billsqlreport','dual','rp_abon','log')
prepload(# or table_name not in (select table_name
prepload(# from information_schema.columns
prepload(# where column_name = 'domain_info'))
prepload-# order by table_name;
prepload=# \o tmp.log
prepload=# \i drop_tables_2load.sql \q
postgres@bucardik:~/work/ntres> pg_dump -F c -b -a -f pgsql.ntres2load -U res "prepload"
postgres@bucardik:~/work/ntres> pg_dump -F c -b -C -f pgsql.res.backup -U postgres "res"
postgres@bucardik:~/work/ntres> pg_dump -h 10.77.11.71 -p 5432 -U res -F p -s -s -v -f "res_schema.sql" -n 'res' "res"
postgres@bucardik:~/work/ntres> psql -h 10.77.11.71 -U res res
res=# \o drop_fk_2load_tmp.sql
res=# \t
res=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
res-# FROM pg_constraint con, pg_class cl, pg_tables t, information_schema.constraint_column_usage cc
res-# WHERE t.schemaname = 'res'
res-# AND t.tablename = cl.relname
res-# AND con.contype = 'f'
res-# AND con.conrelid = cl.oid
res-# AND cc.constraint_name = con.conname
res-# ORDER BY con.conname;
res=# \o tmp.log
res=# \i drop_fk_2load_tmp.sql \q
postgres@bucardik:~/work/ntres> /usr/bin/pg_restore -h 10.77.11.71 -p 5432 -U res -d res -a -v "pgsql.ntres2load"

########################################################################
-- удаление новотроицка из общей БД
select 'delete from '||table_name||' where domain_info = ''root.nt'';'
from information_schema.tables
where table_schema = 'res'
and table_type = 'BASE TABLE'
order by table_name;
########################################################################

prepload=# \o drop_tables_2load.sql
prepload=# select 'drop table '||table_name||' cascade;'
prepload-# from information_schema.tables
prepload-# where table_schema = 'res'
prepload-# and table_type = 'BASE TABLE'
prepload-# and (table_name like 'auth%'
prepload(# or table_name in ('billsqlreport','dual','rp_abon','log')
prepload(# or table_name not in (select table_name
prepload(# from information_schema.columns
prepload(# where column_name = 'domain_info'))
prepload-# order by table_name;
prepload=# \o tmp.log
prepload=# \i drop_tables_2load.sql


prepload=# \o drop_fk_2load.sql
prepload=# \t
prepload=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
prepload-# FROM pg_constraint con, pg_class cl, pg_tables t,
prepload-# information_schema.constraint_column_usage cc
prepload-# WHERE t.schemaname = 'res'
prepload-# AND t.tablename = cl.relname
prepload-# AND con.contype = 'f'
prepload-# AND con.conrelid = cl.oid
prepload-# AND cc.constraint_name = con.conname
prepload-# ORDER BY con.conname;
prepload=# \o tmp.log
prepload=# \i drop_fk_2load.sql
prepload=# \o drop_constr_2load.sql
prepload=# SELECT 'ALTER TABLE res.'||t.tablename||' DROP CONSTRAINT '||con.conname||';'
prepload-# FROM pg_constraint con, pg_class cl, pg_tables t,
prepload-# information_schema.constraint_column_usage cc
prepload-# WHERE t.schemaname = 'res'
prepload-# AND t.tablename = cl.relname
prepload-# AND con.conrelid = cl.oid
prepload-# AND cc.constraint_name = con.conname
prepload-# ORDER BY con.conname;
prepload=# \o tmp.log
prepload=# \i drop_constr_2load.sql
prepload=# \o drop_rule_2load.sql
prepload=# SELECT 'DROP RULE '||rulename||' ON '||tablename||';'
prepload-# FROM pg_rules
prepload-# WHERE schemaname = 'res'
prepload-# ORDER BY tablename, rulename;
prepload=# \o tmp.log
prepload=# \i drop_rule_2load.sql
prepload=# \o drop_tables_2load.sql
prepload=# select 'drop table '||table_name||' cascade;'
prepload-# from information_schema.tables
prepload-# where table_schema = 'res'
prepload-# and table_type = 'BASE TABLE'
prepload-# and (table_name like 'auth%'
prepload(# or table_name in ('billsqlreport','dual','rp_abon','log')
prepload(# or table_name not in (select table_name
prepload(# from information_schema.columns
prepload(# where column_name = 'domain_info'))
prepload-# order by table_name;
prepload=# \o tmp.log
prepload=# \i drop_tables_2load.sql
prepload=# \o drop_views_2load.sql
prepload=# select 'drop view '||table_name||';'
prepload-# from information_schema.views
prepload-# where table_catalog = 'prepload'
prepload-# and table_schema = 'res';
prepload=# \o tmp.log
prepload=# \i drop_views_2load.sql
prepload=# \o drop_index_2load.sql
prepload=# select 'alter table '||tablename||' drop index '||indexname||';'
prepload-# from pg_indexes
prepload-# where schemaname = 'res'
prepload-# order by tablename;
prepload=# \o tmp.log



Читать далее

2009-06-15

Репликация PostgreSQL+Bucardo. Правила при изменении структуры БД

Итак, наконец мы можем сформировать набор правил, как работать с bucardo при изменении структуры подчиненных БД.

При изменении структуры существующих таблиц, если изменения структуры не затронули первичные ключи:
1. Остановить репликацию.
2. Обновить ВСЕ подчиненные БД.
3. Теми же скриптами обновить главную БД. В скриптах ни в коем случае не должны меняться данные - только структура.
4. Запустить репликацию.
5. Проверить, что все работает.

При изменении структуры существующих таблиц, если затронуты первичные ключи:
1. Остановить репликацию.
2. Выполнить скрипты по изменению структуры подчиненных БД. Данные пока не менять.
3. Те же скрипты по изменению структуры выполнить на главной БД.
4. Изменить таблицу bucardo.goat в соответствии с изменениями поля первичного ключа подчиненной БД.
5. На подчиненных БД на таблицах, где поменялось поле первичного ключа удалить триггера bucardo_add_delta_d, bucardo_add_delta_i, bucardo_add_delta_u, bucardo_triggerkick_..._sync.
6. На главной БД выполнить обновление таблицы sync следующим образом:
UPDATE bucardo.sync SET synctype = 'fullcopy' WHERE name = 'правильная_ссылка';
UPDATE bucardo.sync SET synctype = 'pushdelta' WHERE name = 'правильная_ссылка';
7. Проверить, что в подчиненных БД на таблицах с измененным полем ПК созданы новые триггера.
8. В подчиненных БД выполнить изменение данных, если это предусмотрено обновлением.
9. Запустить репликацию.
10. Проверить, что все работает.

При добавлении новых таблиц в репликацию.
1. Создать таблицы в подчиненной БД.
2. Создать таблицы в главной БД.
3. Добавить данные по таблицам в БД bucardo в goat и herdmap.
4. Остановить репликацию.
5. На главной БД выполнить обновление таблицы sync следующим образом:
UPDATE bucardo.sync SET synctype = 'fullcopy' WHERE name = 'правильная_ссылка';
UPDATE bucardo.sync SET synctype = 'pushdelta' WHERE name = 'правильная_ссылка';
6. Проверить, что на новых таблицах создались триггера.
7. Запустить репликацию.
8. Проверить, что все работает.

При удалении таблиц из репликации:
1. Остановить репликацию.
2. Удалить таблицы из goat и herdmap.
3. На главной БД выполнить обновление таблицы sync следующим образом:
UPDATE bucardo.sync SET synctype = 'fullcopy' WHERE name = 'правильная_ссылка';
UPDATE bucardo.sync SET synctype = 'pushdelta' WHERE name = 'правильная_ссылка';
4. На подчиненных БД на таблицах, которые больше не нужно реплицировать удалить триггера bucardo_add_delta_d, bucardo_add_delta_i, bucardo_add_delta_u, bucardo_triggerkick_..._sync.
5. Запустить репликацию.
6. Проверить, что все работает.

Читать далее

2009-06-09

Репликация PostgreSQL+Bucardo. Изменение структуры БД. Тестирование.

Итак. В рабочем варианте №1 докатились до того, что репликация поехала, но потом заткнулась на изменении структуры БД. Тема интересная и актуальная. Нужна методика поддержки репликации в рабочем состоянии в условиях постоянного изменения структуры БД. Приступим.

На своей локальной машине сделал БД alexsf_test и схему alexsf. Плюс ко всему:

ALTER ROLE alexsf SUPERUSER;
CREATE LANGUAGE plpgsql;
CREATE LANGUAGE plperlu;

и получаю: ERROR: не получилось загрузить библиотеку "/usr/lib/postgresql/plperl.so": libperl.so: невозможно открыть разделяемый объектный файл: Нет такого файла или каталога
SQL state: 58P01

Бл... Как всегда без приключений никуда... Такая библиотека есть, вот она:

/usr/lib/perl5/5.10.0/i586-linux-thread-multi/CORE/libperl.so

Че за херня!!! Как всегда отделываемся костылем:

ln -s /usr/lib/perl5/5.10.0/i586-linux-thread-multi/CORE/libperl.so /usr/lib/libperl.so

Теперь наполняем схему объектами и данными:

CREATE TABLE fio(
pk integer NOT NULL,
f character varying(100),
i character varying(100),
o character varying(100),
CONSTRAINT pk_fio PRIMARY KEY (pk)
)
WITH (OIDS=FALSE);
ALTER TABLE fio OWNER TO alexsf;

CREATE TABLE car(
pk integer NOT NULL,
model character varying(100),
nomer character varying(100),
CONSTRAINT pk_car PRIMARY KEY (pk)
)
WITH (OIDS=FALSE);
ALTER TABLE car OWNER TO alexsf;

CREATE TABLE telefon(
pk integer NOT NULL,
model character varying(100),
"operator" character varying(100),
nomer character varying(100),
CONSTRAINT pk_telefon PRIMARY KEY (pk)
)
WITH (OIDS=FALSE);
ALTER TABLE telefon OWNER TO alexsf;

insert into alexsf.fio VALUES('0','Пупкин0','Серафим0','Опанасович0');
insert into alexsf.fio VALUES('1','Пупкин1','Серафим1','Опанасович1');
insert into alexsf.fio VALUES('2','Пупкин2','Серафим2','Опанасович2');
insert into alexsf.fio VALUES('3','Пупкин3','Серафим3','Опанасович3');
insert into alexsf.fio VALUES('4','Пупкин4','Серафим4','Опанасович4');
insert into alexsf.fio VALUES('5','Пупкин5','Серафим5','Опанасович5');
insert into alexsf.fio VALUES('6','Пупкин6','Серафим6','Опанасович6');
insert into alexsf.fio VALUES('7','Пупкин7','Серафим7','Опанасович7');
insert into alexsf.fio VALUES('8','Пупкин8','Серафим8','Опанасович8');
insert into alexsf.fio VALUES('9','Пупкин9','Серафим9','Опанасович9');

insert into alexsf.car VALUES('0','Жигули0','0');
insert into alexsf.car VALUES('1','Жигули1','1');
insert into alexsf.car VALUES('2','Жигули2','2');
insert into alexsf.car VALUES('3','Жигули3','3');
insert into alexsf.car VALUES('4','Жигули4','4');
insert into alexsf.car VALUES('5','Жигули5','5');
insert into alexsf.car VALUES('6','Жигули6','6');
insert into alexsf.car VALUES('7','Жигули7','7');
insert into alexsf.car VALUES('8','Жигули8','8');
insert into alexsf.car VALUES('9','Жигули9','9');

insert into alexsf.telefon VALUES('0','Nokia0','MTS0','000');
insert into alexsf.telefon VALUES('1','Nokia1','MTS1','001');
insert into alexsf.telefon VALUES('2','Nokia2','MTS2','002');
insert into alexsf.telefon VALUES('3','Nokia3','MTS3','003');
insert into alexsf.telefon VALUES('4','Nokia4','MTS4','004');
insert into alexsf.telefon VALUES('5','Nokia5','MTS5','005');
insert into alexsf.telefon VALUES('6','Nokia6','MTS6','006');
insert into alexsf.telefon VALUES('7','Nokia7','MTS7','007');
insert into alexsf.telefon VALUES('8','Nokia8','MTS8','008');
insert into alexsf.telefon VALUES('9','Nokia9','MTS9','009');

После этого на многострадальном сервере bucardo делаю БД alexsf и схему alexsf, и создаю там аналогичные объекты. Не забываем дать alexsf права SUPERUSER. Затем настраиваем репликацию:

INSERT INTO bucardo.db (name, dbhost, dbname, dbuser, dbpass)
VALUES ('alexsf_slave_db','10.77.11.200','alexsf','alexsf','alexsf');
INSERT INTO bucardo.db (name, dbhost, dbname, dbuser, dbpass)
VALUES ('alexsf_master_db','10.77.11.71','alexsf_test','alexsf','alexsf');

INSERT INTO bucardo.dbgroup(name) VALUES('alexsf_slave_group');
INSERT INTO bucardo.dbgroup(name) VALUES('alexsf_master_group');

INSERT INTO bucardo.dbmap(db, dbgroup) VALUES('alexsf_slave_db','alexsf_slave_group');
INSERT INTO bucardo.dbmap(db, dbgroup) VALUES('alexsf_master_db','alexsf_master_group');

INSERT INTO bucardo.goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy) VALUES ('alexsf_slave_db','alexsf','car','pk','bigint','false');
INSERT INTO bucardo.goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy) VALUES ('alexsf_slave_db','alexsf','fio','pk','bigint','false');
INSERT INTO bucardo.goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy) VALUES ('alexsf_slave_db','alexsf','telefon','pk','bigint','false');

INSERT INTO bucardo.herd(name) VALUES('alexsf_herd');

INSERT INTO bucardo.herdmap (herd, goat)
SELECT 'alexsf_herd', id
FROM goat WHERE db = 'alexsf_slave_db';

INSERT INTO bucardo.sync (name,source,targetdb,synctype,stayalive,checktime,analyze_after_copy)
VALUES('alexsf_sync','alexsf_herd','alexsf_master_db','pushdelta','false','1 minutes','false');

Вроде все. Перед тем, как запустить репликацию, ставлю inactive на не тестовых БД в таблице bucardo.db. Ну и запускаю... Делаю пинки по таблицам в slave БД, и вижу, что репликация работает.

Теперь дело за малым, разобраться в интересующем нас вопросе, а именно в изменении структуры БД...

Меняем структуру нашей подчиненной БД:

alter table car add column probeg numeric;
alter table telefon drop column "operator";
alter table telefon rename column nomer to n;

Перезапускаем bucardo и получаем:

May 28 09:39:46 bucardik Bucardo[16849]: MCP Validating source table "alexsf.car" on alexsf_slave_db
May 28 09:39:47 bucardik Bucardo[16849]: MCP Comparing tables and columns on alexsf_master_db
May 28 09:39:47 bucardik Bucardo[16849]: MCP FATAL: Source database "alexsf_sync", table alexsf.car has more columns than target "alexsf_master_db"
May 28 09:39:47 bucardik Bucardo[16849]: MCP Validation of sync FAILED

Обращаем внимание на то, что несмотря на изменение двух таблиц, bucardo ругается только на одну. То есть он не делает валидацию ВСЕХ таблиц, а обрывает этот процесс на первой, не прошедшей валидацию!!! Воблинзараза!!!

Итак, повторяем изменение структуры на master базе, и перезапускаем bucardo.

И ХРЕНЕЕМ!!! Bucardo не выдает никаких ошибок!!! Просто говорит, что реплицировать нечего!!! Возникает вопрос, то ли лыжи не едут, толи реально так и надо??? Делаем пинки по таблицам и наблюдаем за реакцией... Нормальная реакция, все работает... То есть так и надо, с репликацией ничего не случилось...

Будем считать то, что мы сделали первым вариантом. А именно:
-- изменили структуру подчиненной БД.
-- изменили структуру главной БД.
-- в промежутке между первыми двумя пунктами данные в подчиненной БД не менялись.
-- количество объектов участников репликации не изменилось.

Вывод по первому варианту: да просто офигенный вариант!!! малой кровью решаем проблемы с изменением структуры БД и не нарушаем при этом работу репликации!!! Имеет 100% право на жизнь, будем использовать.

Теперь опишем второй вариант:
-- меняем структуру подчиненной БД.
-- пинаем в подчиненной БД данные со всех сторон, особенно в местах, где произошли изменения структуры.
-- меняем структуру главной БД
-- количество объектов участников репликации не меняем.

Поехали делать второй вариант:

alter table fio add column vozr numeric;
alter table fio drop column o;
update fio set vozr=100;

Bucardo начинает орать всягую лабудень. Перезапустим его на всякий случай. И видим: таблица fio не прошла валидацию... Меняем структуру в главной БД, но НЕ ТРОГАЕМ там данные!!! Перезапускаем bucardo. И зашибись, репликация поехала. все пинки среплицировались!!!

Вывод по 2-му варианту: ну нормально!!! 100% рабочий. Крови больше не стало по сравнению с 1-м. Бум использовать.

Описываем 3-й вариант:
-- меняется поле первичного ключа в подчиненной БД.
-- тусуются данные в поле первичного ключа.
-- аналогично меняется поле первичного ключа в главной БД.
-- количество объектов репликации не меняем.

Поехали:

alter table telefon rename column pk to pkey;
update telefon set pkey=pkey+1000;

И вот о чудо, ничего не получилось. При выполнении update получили ошибку:

ERROR: record "old" has no field "pk"
SQL state: 42703
Контекст:PL/pgSQL function "bucardo_add_delta_u_pk" line 3 at SQL statement

,что вполне закономерно, ведь созданные объекты bucardo в подчиненной базе вроде как подвязаны на имена первичных ключей.

Анализируем...

-- Все объекты bucardo в подчиненной БД были созданы автоматически при внесении данных в таблицу bucardo.sync главной БД. То есть процесс выполнялся удаленно с главной БД.
-- Логично предположить, что в главной БД все эти объекты, а также таблицы и ключи на которые они ссылаются, зарегистрированы в конфигурационных таблицах bucardo.
-- Логично предположить, что изменение объектов в подчиненной БД также должно проводится с главной БД для обеспечения согласованности объектов подчиненной БД и конфигурационной информации в главной БД bucardo.
-- Объекты включались в репликацию фактически тремя действиями: вставка в таблицу goat, вставка в таблицу herdmap, вставка в таблицу sync.
-- Вставка в таблицы goat и herdmap была пообектной и создала, насколько я понял, набор конфигурационной информации объектов репликации. Вставка в таблицу sync ссылалась на весь набор объектов участников, была проведена одной строкой и привела к созданию набора объектов в подчиненной БД, с которыми у нас теперь проблемы.
-- На таблице sync есть триггер validate_sync AFTER INSERT OR UPDATE, который, как я предполагаю, и выполняет работы по удаленному созданию объектов в подчиненной БД. Логично предположить, что в случае изменения конфигурационной информации в goat и herdmap достаточно будет сделать UPDATE на sync для проведения удаленной корректировки объектов в подчиненной БД.

Вроде проанализировали и придумали, что делать дальше. А делать следующее:

Вариант 1:
-- Остановить репликацию
-- Из goat и herdmap выкосить telefon
-- Провести копию изменений структуры подчиненной БД в главной БД
-- В goat и herdmap занести telefon
-- Сделать UPDATE sync
-- Попробовать сделать неотработавший UPDATE в подчиненной БД
-- Запустить репликацию.

Вариант2:
-- Остановить репликацию
-- Порихтовать таблицы goat и herdmap с учетом изменения PK в telefon.
-- Провести копию изменений структуры подчиненной БД в главной БД
-- Сделать UPDATE sync
-- Проверить, изменились ли объекты bucardo в подчиненной БД на таблице telefon.
-- Запустить репликацию.

Пробуем вариант 1. Останавливаем bucardo и:

DELETE FROM bucardo.goat
WHERE db='alexsf_slave_db'
AND schemaname = 'alexsf'
AND tablename = 'telefon';

DELETE FROM bucardo.herdmap
WHERE goat = (SELECT id FROM bucardo.goat WHERE db='alexsf_slave_db'
AND schemaname = 'alexsf' AND tablename = 'telefon');

alter table telefon rename column pk to pkey;

INSERT INTO bucardo.goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy) VALUES ('alexsf_slave_db','alexsf','telefon','pkey','bigint','false');

INSERT INTO bucardo.herdmap (herd, goat)
SELECT 'alexsf_herd', id
FROM goat
WHERE db = 'alexsf_slave_db'
AND schemaname = 'alexsf'
AND tablename = 'telefon';

UPDATE bucardo.sync SET status = 'inactive' WHERE name = 'alexsf_sync';
UPDATE bucardo.sync SET status = 'active' WHERE name = 'alexsf_sync';

В подчиненной БД выполняем:

update telefon set pkey=pkey+1000;

... и получаем ту же ошибку... БЛ....!!!

Попробуем грохнуть триггера на telefon и опять обновить sync:

-- В подчиненной БД
drop trigger bucardo_add_delta_d on alexsf.telefon;
drop trigger bucardo_add_delta_i on alexsf.telefon;
drop trigger bucardo_add_delta_u on alexsf.telefon;
drop trigger bucardo_triggerkick_alexsf_sync on alexsf.telefon;

-- В главной БД
UPDATE bucardo.sync SET status = 'inactive' WHERE name = 'alexsf_sync';
UPDATE bucardo.sync SET status = 'active' WHERE name = 'alexsf_sync';

Смотрим, и видим, что на таблице telefon в удаленной БД триггера не создались :( Я буду плакать... Ну почему bucardo не реплицирует DDL????

Перечитал сейчас всю доку, благо ее там не так много(или хреново, что немного), и ничего по работе с отдельными goat не нашел...

Попробую сделать еще одну таблицу и включить ее в репликацию...

-- В подчиненной БД:

CREATE TABLE komp(
pklu4 integer NOT NULL,
cpu character varying(100),
hdd character varying(100),
ozu character varying(100),
CONSTRAINT pk_komp PRIMARY KEY (pklu4)
)
WITH (OIDS=FALSE);
ALTER TABLE telefon OWNER TO alexsf;

-- В БД bucardo в главной БД:

INSERT INTO bucardo.goat (db,schemaname,tablename,pkey,pkeytype,analyze_after_copy) VALUES ('alexsf_slave_db','alexsf','komp','pklu4','bigint','false');

INSERT INTO bucardo.herdmap (herd, goat)
SELECT 'alexsf_herd', id
FROM goat
WHERE db = 'alexsf_slave_db'
AND schemaname = 'alexsf'
AND tablename = 'komp';

UPDATE bucardo.sync SET status = 'active' WHERE name = 'alexsf_sync';
UPDATE bucardo.sync SET synctype = 'fullcopy' WHERE name = 'alexsf_sync';
UPDATE bucardo.sync SET synctype = 'pushdelta' WHERE name = 'alexsf_sync';

И вот на synctype = 'fullcopy' я получил ошибку:

NOTICE: Issuing rollback() for database handle being DESTROY'd without explicit disconnect() at line 29.
КОНТЕКСТ: SQL-команда: "SELECT validate_sync('alexsf_sync')"
ERROR: error from Perl trigger function: error from Perl function: No such table found for database alexsf_master_db: "alexsf.komp" at line 259. at line 30.

О-о-о-о!!!!!!!!!!!!! Эврика!!!!!!!!!! Нашел!!!!!!!!!!
Триггер на таблице sync на UPDATE реагирует не при каждом UPDATE, а только каких-то конкретных полей!!!! Например очень хорошо реагирует на поле synctype. По крайней мере на таблице telefon создались триггера. Новую таблицу komp я пока выкосил...

Так, нужно теперь мысли в кучу собрать и расписать принципы работы 3-го варианта(переименования поля с PK)... Попробуем для порядка опять поменять имя ключа и проверить:

-- На подчиненной БД и на главной БД:
alter table telefon rename column pkey to pklu4;

-- На главной БД:

update bucardo.goat set pkey = 'pklu4'
where db = 'alexsf_slave_db'
and schemaname = 'alexsf'
and tablename = 'telefon';

UPDATE bucardo.sync SET synctype = 'fullcopy' WHERE name = 'alexsf_sync';
UPDATE bucardo.sync SET synctype = 'pushdelta' WHERE name = 'alexsf_sync';

И видим, что триггера на талбице telefon в подчиненной БД не поменялись, но при этом были созданы bucardo.bucardo_add_delta_d_pklu4, bucardo.bucardo_add_delta_i_pklu4 bucardo.bucardo_add_delta_u_pklu4 в подчиненной БД... То есть не до конца отработало, частично, так сказать, по кривому, если точнее :( Я зол.

Попробуем удалить триггера с таблицы telefon и заново пихнуть sync:

-- На пордчиненной БД alexsf:
drop trigger bucardo_add_delta_d on alexsf.telefon;
drop trigger bucardo_add_delta_i on alexsf.telefon;
drop trigger bucardo_add_delta_u on alexsf.telefon;
drop trigger bucardo_triggerkick_alexsf_sync on alexsf.telefon;

О, вот так получилось!!!

Теперь проверим, что не потеряются данные репликации при пинках по таблице sync:

Для этого мы:
- выключим репликацию
- напихаем новых данных в таблицу
- поменяем поле первичного ключа
- проведем изменения в структуре bucardo. Сделаем согласованной схему(sync)...
- опять понапихаем данных
- запустим репликацию
- проверим, что оба запихивания среплицировались

Поехали(напомню, что на данный момент у нас рабочая схема репликации):

#на хосте bucardo
/etc/init.d/bucardo_stop

-- на подчиненной БД под alexsf
insert into alexsf.telefon VALUES('20006','Nokia6','MTS6');
insert into alexsf.telefon VALUES('20007','Nokia7','MTS7');
insert into alexsf.telefon VALUES('20008','Nokia8','MTS8');
insert into alexsf.telefon VALUES('20009','Nokia9','MTS9');
alter table telefon rename column pklu4 to primokey;
drop trigger bucardo_add_delta_d on alexsf.telefon;
drop trigger bucardo_add_delta_i on alexsf.telefon;
drop trigger bucardo_add_delta_u on alexsf.telefon;

drop trigger bucardo_triggerkick_alexsf_sync on alexsf.telefon;

-- на главной БД alexsf
alter table telefon rename column pklu4 to primokey;

-- на главной БД bucardo
UPDATE bucardo.goat SET pkey = 'primokey'
WHERE db = 'alexsf_slave_db'
AND schemaname = 'alexsf'
AND tablename = 'telefon';
UPDATE bucardo.sync SET synctype = 'fullcopy' WHERE name = 'alexsf_sync';
UPDATE bucardo.sync SET synctype = 'pushdelta' WHERE name = 'alexsf_sync';

Ну и радость, все работает, ничего не потерялось... Вроде все варианты рассмотрели... Теперь подитожить, и сформировать набор правил...

Читать далее