Files
notes/divers/xtts_non-cdb_to_cdb_01.md

556 lines
14 KiB
Markdown
Raw Normal View History

2026-03-12 22:01:38 +01:00
## Context
- Source: non-CDB = GREEDO@rodia-scan
- Target: PDB = REEK, CDB=AERONPRD@ylesia-scan
## Setup
Create tablespaces and users:
```
create tablespace TS1 datafile size 16M autoextend on next 16M;
create tablespace TS2 datafile size 16M autoextend on next 16M;
create tablespace TS3 datafile size 16M autoextend on next 16M;
alter tablespace TS1 add datafile size 16M autoextend on next 16M;
alter tablespace TS1 add datafile size 16M autoextend on next 16M;
alter tablespace TS2 add datafile size 16M autoextend on next 16M;
alter tablespace TS3 add datafile size 16M autoextend on next 16M;
alter tablespace TS3 add datafile size 16M autoextend on next 16M;
alter tablespace TS3 add datafile size 16M autoextend on next 16M;
create user U1 identified by secret;
grant connect, resource, create view,create job to U1;
alter user U1 quota unlimited on TS1;
alter user U1 quota unlimited on TS2;
alter user U1 quota unlimited on TS3;
create user U2 identified by secret;
grant connect, resource, create view,create job to U2;
alter user U2 quota unlimited on TS1;
alter user U2 quota unlimited on TS2;
alter user U2 quota unlimited on TS3;
```
For each user, create objects:
connect U1/secret
-- create objcts
connect U2/secret
-- create objcts
Create objects script:
```
-- TABLE 1 dans TS1
CREATE TABLE table1_ts1 (
id NUMBER PRIMARY KEY,
data VARCHAR2(100),
created_at DATE DEFAULT SYSDATE
) TABLESPACE TS1;
CREATE SEQUENCE table1_seq
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
CREATE OR REPLACE TRIGGER trg_table1_id
BEFORE INSERT ON table1_ts1
FOR EACH ROW
BEGIN
IF :NEW.id IS NULL THEN
SELECT table1_seq.NEXTVAL INTO :NEW.id FROM dual;
END IF;
END;
/
-- TABLE 2 dans TS2
CREATE TABLE table2_ts2 (
id NUMBER PRIMARY KEY,
data VARCHAR2(100),
updated_at DATE
) TABLESPACE TS2;
CREATE SEQUENCE table2_seq
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
CREATE OR REPLACE TRIGGER trg_table2_id
BEFORE INSERT ON table2_ts2
FOR EACH ROW
BEGIN
IF :NEW.id IS NULL THEN
SELECT table2_seq.NEXTVAL INTO :NEW.id FROM dual;
END IF;
END;
/
-- TABLE 3 dans TS3
CREATE TABLE table3_ts3 (
id NUMBER PRIMARY KEY,
info VARCHAR2(100),
status VARCHAR2(20)
) TABLESPACE TS3;
CREATE SEQUENCE table3_seq
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
CREATE OR REPLACE TRIGGER trg_table3_id
BEFORE INSERT ON table3_ts3
FOR EACH ROW
BEGIN
IF :NEW.id IS NULL THEN
SELECT table3_seq.NEXTVAL INTO :NEW.id FROM dual;
END IF;
END;
/
CREATE OR REPLACE VIEW combined_view AS
SELECT id, data, created_at, NULL AS updated_at, NULL AS status FROM table1_ts1
UNION ALL
SELECT id, data, updated_at, NULL AS created_at, NULL AS status FROM table2_ts2
UNION ALL
SELECT id, info AS data, NULL, NULL, status FROM table3_ts3;
CREATE OR REPLACE PACKAGE data_ops AS
PROCEDURE insert_random_data;
PROCEDURE update_random_data;
PROCEDURE delete_random_data;
END data_ops;
/
CREATE OR REPLACE PACKAGE BODY data_ops AS
PROCEDURE insert_random_data IS
BEGIN
FOR i IN 1..10 LOOP
INSERT INTO table1_ts1 (data)
VALUES (DBMS_RANDOM.STRING('A', 10));
END LOOP;
FOR i IN 1..3 LOOP
INSERT INTO table3_ts3 (info, status)
VALUES (DBMS_RANDOM.STRING('A', 10), 'NEW');
END LOOP;
END;
PROCEDURE update_random_data IS
BEGIN
FOR i IN 1..7 LOOP
INSERT INTO table2_ts2 (data)
VALUES (DBMS_RANDOM.STRING('A', 10));
END LOOP;
FOR rec IN (
SELECT id FROM (
SELECT id FROM table2_ts2 ORDER BY DBMS_RANDOM.VALUE
) WHERE ROWNUM <= 5
) LOOP
UPDATE table2_ts2
SET data = DBMS_RANDOM.STRING('A', 10), updated_at = SYSDATE
WHERE id = rec.id;
END LOOP;
END;
PROCEDURE delete_random_data IS
BEGIN
FOR rec IN (
SELECT id FROM (
SELECT id FROM table3_ts3 ORDER BY DBMS_RANDOM.VALUE
) WHERE ROWNUM <= 2
) LOOP
DELETE FROM table3_ts3 WHERE id = rec.id;
END LOOP;
END;
END data_ops;
/
```
Create job to run every 1 minute:
```
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'random_ops_job',
job_type => 'PLSQL_BLOCK',
job_action => '
BEGIN
data_ops.insert_random_data;
data_ops.update_random_data;
data_ops.delete_random_data;
END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=MINUTELY; INTERVAL=1',
enabled => TRUE,
comments => 'Job to insert, update and delete random data every minute.'
);
END;
/
```
To restart the job:
```
--Restart the job
BEGIN
DBMS_SCHEDULER.enable('random_ops_job');
END;
/
```
Count the lines in tables:
```
select
'u1.table1_ts1:'||count(*) from u1.table1_ts1
union select
'u1.table2_ts2:'||count(*) from u1.table2_ts2
union select
'u1.table3_ts3:'||count(*) from u1.table3_ts3
union select
'u2.table1_ts1:'||count(*) from u2.table1_ts1
union select
'u2.table2_ts2:'||count(*) from u2.table2_ts2
union select
'u2.table3_ts3:'||count(*) from u2.table3_ts3
order by 1 asc
/
```
To ensure the automatic opening of PDB, create a service to start automatically in the PDB:
srvctl add service -s adm_reek -db AERONPRD -preferred AERONPRD1,AERONPRD2,AERONPRD3 -pdb REEK -role PRIMARY
srvctl start service -s adm_reek -db AERONPRD
## XTTS
> Note MOS: V4 Reduce Transportable Tablespace Downtime using Cross Platform Incremental Backup (Doc ID 2471245.1)
### Initial setup
Identify tablespaces to transport, probably all non "administrative" tablespaces:
```
select
listagg(tablespace_name, ',')
within group
(order by tablespace_name) as non_sys_ts
from
dba_tablespaces
where
contents not in ('UNDO','TEMPORARY') and
tablespace_name not in ('SYSTEM','SYSAUX');
```
For source and target servers, define folders to be used for scripts, backupset, datapump etc.
In our case, that will be a shared NFS folder `/mnt/unprotected/tmp/oracle/xtts`
> The size of folder should be greather than the size of full database.
Unzip xtts scripts:
cd /mnt/unprotected/tmp/oracle/xtts
unzip /mnt/yavin4/kit/Oracle/XTTS/rman_xttconvert_VER4.3.zip
Configure xtt.properties file:
```
tablespaces=TS1,TS2,TS3,USERS
src_scratch_location=/mnt/unprotected/tmp/oracle/xtts/scratch
dest_datafile_location=+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/xtts/
dest_scratch_location=/mnt/unprotected/tmp/oracle/xtts/scratch
asm_home=/app/oracle/grid/product/19
asm_sid=+ASM1
destconnstr=sys/"Secret00!"@ylesia-scan/adm_reek
usermantransport=1
```
On target server, create ASM directory where the datafile will be restored:
mkdir +DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/xtts
On **both source and target** servers, set `TMPDIR` environment variable to the path of xtts scripts:
export TMPDIR=/mnt/unprotected/tmp/oracle/xtts
### Prepare Phase
This step corresponds to initial full backup/restore of source database on target system.
Initial backup on source server:
```
export TMPDIR=/mnt/unprotected/tmp/oracle/xtts
cd $TMPDIR
$ORACLE_HOME/perl/bin/perl xttdriver.pl --backup --debug 3
```
Initial restore on target server:
```
export TMPDIR=/mnt/unprotected/tmp/oracle/xtts
cd $TMPDIR
$ORACLE_HOME/perl/bin/perl xttdriver.pl --restore --debug 3
```
> `debug` argument is optional
### Roll Forward Phase
As long as necessary we can do incremental backup/resore operations.
> New datafiles add to source database are automatically managed by this step.
The commands are exactly the sames (with or without debug mode).
For backup:
```
export TMPDIR=/mnt/unprotected/tmp/oracle/xtts
cd $TMPDIR
$ORACLE_HOME/perl/bin/perl xttdriver.pl --backup
```
For restore:
```
export TMPDIR=/mnt/unprotected/tmp/oracle/xtts
cd $TMPDIR
$ORACLE_HOME/perl/bin/perl xttdriver.pl --restore
```
> Running succesives backup or successive restore operations does not pose a problem.
### Final Incremental Backup
On **source** database, put tablespaces in **read-only** mode:
```
select
'alter tablespace '||tablespace_name||' read only;' as COMMAND
from
dba_tablespaces
where
contents not in ('UNDO','TEMPORARY') and
tablespace_name not in ('SYSTEM','SYSAUX');
```
Check:
```
select distinct status
from
dba_tablespaces
where
contents not in ('UNDO','TEMPORARY') and
tablespace_name not in ('SYSTEM','SYSAUX');
```
Take final incremental backup:
```
export TMPDIR=/mnt/unprotected/tmp/oracle/xtts
cd $TMPDIR
$ORACLE_HOME/perl/bin/perl xttdriver.pl --backup
```
Rstore final incremental backup:
```
export TMPDIR=/mnt/unprotected/tmp/oracle/xtts
cd $TMPDIR
$ORACLE_HOME/perl/bin/perl xttdriver.pl --restore
```
### Metadata export
Create DATAPUMP directory on **both** source and destination databases.
On source (non-CDB):
SQL> create or replace directory XTTS as '/mnt/unprotected/tmp/oracle/xtts';
On destination (PDB):
export ORACLE_PDB_SID=REEK
SQL> create or replace directory XTTS as '/mnt/unprotected/tmp/oracle/xtts';
Export metadata
expdp userid="'/ as sysdba'" dumpfile=XTTS:metadata.dmp logfile=XTTS:metadata.log FULL=y TRANSPORTABLE=always
### Optionally: on target, pout target datafiles read-only at OS level
Identify OMF target datafiles:
```
asmcmd -p
cd +DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/xtts
ls --permission
```
For each datafile, set read-olny permisions, example:
chmod 444 +DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/xtts/*
If you got:
ORA-15304: operation requires ACCESS_CONTROL.ENABLED attribute to be TRUE (DBD ERROR: OCIStmtExecute)
then set following diskgroup attributes and retry.
```
column dg_name format a20
column name format a50
column VALUE format a30
set lines 120
select
dg.name dg_name, attr.name, attr.value
from
v$asm_attribute attr
join v$asm_diskgroup dg on attr.group_number=dg.group_number
where
attr.name in ('compatible.rdbms','access_control.enabled')
order by dg.name, attr.name
/
alter diskgroup DATA set attribute 'compatible.rdbms' = '19.0.0.0.0';
alter diskgroup RECO set attribute 'compatible.rdbms' = '19.0.0.0.0';
alter diskgroup DATA set attribute 'access_control.enabled' = 'TRUE';
alter diskgroup RECO set attribute 'access_control.enabled' = 'TRUE';
```
> Compare number of datafiles transported and the number of datafiles of non-Oracle tablespaces
> Check if transported tablespaces already exists on target database
### Metadata import and tablespace plug-in
Create impdp parfile `impo_metadata.par`:
```
userid="/ as sysdba"
dumpfile=XTTS:metadata.dmp
logfile=XTTS:impo_metadata.log
transport_datafiles=
+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/TS1.290.1205059373,
+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/TS1.291.1205059373,
+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/TS1.298.1205060113,
+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/TS1.289.1205059373,
+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/TS2.293.1205059375,
+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/TS2.300.1205060113,
+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/TS2.292.1205059375,
+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/TS3.294.1205059381,
+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/TS3.295.1205059381,
+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/TS3.296.1205059381,
+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/TS3.297.1205059381,
+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/TS3.299.1205060113,
+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/USERS.302.1205084171
```
Run import:
impdp parfile=impo_metadata.par
Rebounce the PDB (or the CDB), otherwise we can get errors like:
```
ORA-01114: IO error writing block to file 33 (block # 1)
ORA-01110: data file 33:
'+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/ts1.298.1205060113'
ORA-27009: cannot write to file opened for read
```
Put plugged tablespaces in read/write mode:
```
select
'alter tablespace '||tablespace_name||' read write;' as COMMAND
from
dba_tablespaces
where
contents not in ('UNDO','TEMPORARY') and
tablespace_name not in ('SYSTEM','SYSAUX');
```
Remove aliases in order to user only OMF datafiles:
```
cd +DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/xtts
rmalias ts1_8.dbf ts2_13.dbf... .... ...
cd ..
rm -rf xtts
```
## Unxexpectd issues
In metadata import step I relize I forgot to include USER tablespace in `xtt.properties` and impdp failed wit error:
ORA-39352: Wrong number of TRANSPORT_DATAFILES specified: expected 13, received 12
The tablespace USER being in read-only mode I copied the datafile manually on target database.
Identify the file number:
```
SQL> select FILE_ID from dba_data_files where TABLESPACE_NAME='USERS';
FILE_ID
----------
7
```
Backup datafile on source:
```
run{
set nocfau;
backup datafile 7 format '/mnt/unprotected/tmp/oracle/xtts/%d_%U_%s_%t.bck';
}
```
Restore datafile on target;
```
run {
restore from platform 'Linux x86 64-bit'
foreign datafile 7 format '+DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/xtts//USERS.dbf'
from backupset '/mnt/unprotected/tmp/oracle/xtts/GREEDO_0i3t87ss_18_1_1_18_1205084060.bck';
}
```
Put datafile in read-ony at ASM level:
chmod 444 +DATA/AERONPRD/389011A6CB11A654E0635000A8C07D80/DATAFILE/USERS.302.1205084171
Run the impdp again.
## Troubleshooting
Having datafile to plug-in in read-only mode at ASM level allow to repeat tne impdp operations as many time as necessary.
For example, to completly re-execute the impdp metadata as on initial conditions:
- drop new plugged tablespaces
- drop non oracle maintened users
- run impdp metadata again
```
drop tablespace TS1 including contents;
drop tablespace TS2 including contents;
drop tablespace TS3 including contents;
drop tablespace USERS including contents;
select 'drop user '||USERNAME||' cascade;' from dba_users where ORACLE_MAINTAINED='N';
```