Saturday, April 19, 2025

#!/bin/bash # Main Redo Log Management Script # Usage: ./main_redolog.sh # Load configuration and library source redolog.conf source redolog_lib.sh # Initialize environment INPUT_FILE="$1" LOG_FILE="redolog_manage_$(date +%Y%m%d_%H%M).log" rl_init_logging "$LOG_FILE" # Read connection details PRIMARY_HOST=$(awk 'NR==1 {print $1}' "$INPUT_FILE") PRIMARY_DB=$(awk 'NR==1 {print $2}' "$INPUT_FILE") STANDBY_HOST=$(awk 'NR==2 {print $1}' "$INPUT_FILE") STANDBY_DB=$(awk 'NR==2 {print $2}' "$INPUT_FILE") # Get SYS password read -sp "Enter SYS password: " SYS_PASSWORD echo # Verify database roles if ! rl_verify_role "$PRIMARY_HOST" "$PRIMARY_DB" "PRIMARY" "$SYS_PASSWORD"; then echo "Primary database verification failed" exit 1 fi if ! rl_verify_role "$STANDBY_HOST" "$STANDBY_DB" "PHYSICAL STANDBY" "$SYS_PASSWORD"; then echo "Standby database verification failed" exit 1 fi # Main operations ( echo "=== Starting Redo Log Management ===" # Process standby rl_manage_mrp "$PRIMARY_DB" "$STANDBY_DB" "OFF" "$SYS_PASSWORD" rl_add_logs "$STANDBY_HOST" "$STANDBY_DB" "ONLINE" "$SYS_PASSWORD" rl_add_logs "$STANDBY_HOST" "$STANDBY_DB" "STANDBY" "$SYS_PASSWORD" rl_drop_old_logs "$STANDBY_HOST" "$STANDBY_DB" "LOG" "$SYS_PASSWORD" rl_drop_old_logs "$STANDBY_HOST" "$STANDBY_DB" "STANDBY" "$SYS_PASSWORD" rl_manage_mrp "$PRIMARY_DB" "$STANDBY_DB" "ON" "$SYS_PASSWORD" # Process primary rl_add_logs "$PRIMARY_HOST" "$PRIMARY_DB" "ONLINE" "$SYS_PASSWORD" rl_add_logs "$PRIMARY_HOST" "$PRIMARY_DB" "STANDBY" "$SYS_PASSWORD" rl_drop_old_logs "$PRIMARY_HOST" "$PRIMARY_DB" "LOG" "$SYS_PASSWORD" rl_drop_old_logs "$PRIMARY_HOST" "$PRIMARY_DB" "STANDBY" "$SYS_PASSWORD" echo "=== Operation Completed ===" ) | tee -a "$LOG_FILE" echo "Detailed log saved to: $LOG_FILE" #!/bin/bash # Configuration Variables ############################################ ONLINE_REDO_SIZE="512M" # New size for online redo logs STANDBY_REDO_SIZE="512M" # New size for standby redo logs ONLINE_GROUPS_PER_THREAD=4 # Online log groups per RAC thread STANDBY_GROUPS_PER_THREAD=5 # Standby log groups per RAC thread MAX_RETRIES=5 # Max attempts to switch logs RETRY_INTERVAL=5 # Seconds between retries ############################################ # Usage: ./safe_redolog_resize.sh # Input file format: # primary_scan primary_db # standby_scan standby_db # Check input parameters if [ $# -ne 1 ]; then echo "Usage: $0 " exit 1 fi INPUT_FILE="$1" PRIMARY_HOST=$(awk 'NR==1 {print $1}' "$INPUT_FILE") PRIMARY_DB=$(awk 'NR==1 {print $2}' "$INPUT_FILE") STANDBY_HOST=$(awk 'NR==2 {print $1}' "$INPUT_FILE") STANDBY_DB=$(awk 'NR==2 {print $2}' "$INPUT_FILE") DG_USER="sys" LOG_FILE="redolog_resize_$(date +%Y%m%d_%H%M).log" # Validate input if [[ -z "$PRIMARY_HOST" || -z "$PRIMARY_DB" || -z "$STANDBY_HOST" || -z "$STANDBY_DB" ]]; then echo "Invalid input file format. Expected:" echo "primary_scan primary_db" echo "standby_scan standby_db" exit 1 fi # Get SYS password read -s -p "Enter SYS password for ${PRIMARY_HOST}/${PRIMARY_DB}: " SYS_PASSWORD echo # Function to log messages log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE" } # Verify database role verify_role() { local host=$1 local db=$2 local expected_role=$3 role=$(sqlplus -S "${DG_USER}/${SYS_PASSWORD}@//${host}:1521/${db} as sysdba" << EOF SET HEADING OFF FEEDBACK OFF PAGESIZE 0 SELECT database_role FROM v\$database; EXIT; EOF ) if [[ "$role" != "$expected_role" ]]; then log "Error: ${host}/${db} is not a ${expected_role} (Role: ${role})" exit 1 fi log "${expected_role} database confirmed" } # Add new redo logs (common function) add_new_logs() { local host=$1 local db=$2 local log_type=$3 local groups_per_thread=$4 local size=$5 log "Adding ${groups_per_thread} new ${log_type} log groups/thread (${size}) to ${db}" sqlplus -S "${DG_USER}/${SYS_PASSWORD}@//${host}:1521/${db} as sysdba" << EOF >> "$LOG_FILE" 2>&1 SET SERVEROUTPUT ON DECLARE TYPE thread_t IS TABLE OF NUMBER; threads thread_t; BEGIN -- Get active threads SELECT thread# BULK COLLECT INTO threads FROM v\$thread; -- Add new groups FOR i IN 1..threads.COUNT LOOP FOR j IN 1..${groups_per_thread} LOOP BEGIN EXECUTE IMMEDIATE 'ALTER DATABASE ADD ${log_type} LOGFILE THREAD ' || threads(i) || ' SIZE ${size}'; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error adding group: ' || SQLERRM); END; END LOOP; END LOOP; END; / EXIT; EOF } # Drop old redo logs (role-specific) drop_old_logs() { local host=$1 local db=$2 local log_type=$3 log "Dropping old ${log_type} logs from ${db}" sqlplus -S "${DG_USER}/${SYS_PASSWORD}@//${host}:1521/${db} as sysdba" << EOF >> "$LOG_FILE" 2>&1 SET SERVEROUTPUT ON DECLARE TYPE log_info IS RECORD (group# NUMBER, thread# NUMBER, status VARCHAR2(15)); TYPE log_list IS TABLE OF log_info; logs log_list; db_role VARCHAR2(16); BEGIN SELECT database_role INTO db_role FROM v\$database; -- Get existing logs that don't match new size SELECT group#, thread#, status BULK COLLECT INTO logs FROM v\$${log_type}_log WHERE bytes != (SELECT bytes FROM v\$${log_type}_log WHERE ROWNUM = 1); FOR log_rec IN 1..logs.COUNT LOOP BEGIN IF db_role = 'PRIMARY' AND log_type = 'LOG' THEN -- Handle active logs on primary IF logs(log_rec).status IN ('CURRENT', 'ACTIVE') THEN FOR i IN 1..$MAX_RETRIES LOOP BEGIN EXECUTE IMMEDIATE 'ALTER SYSTEM SWITCH LOGFILE THREAD ' || logs(log_rec).thread#; DBMS_LOCK.SLEEP($RETRY_INTERVAL); EXIT WHEN logs(log_rec).status = 'INACTIVE'; EXCEPTION WHEN OTHERS THEN NULL; END; END LOOP; IF logs(log_rec).status != 'INACTIVE' THEN EXECUTE IMMEDIATE 'ALTER DATABASE CLEAR LOGFILE GROUP ' || logs(log_rec).group#; END IF; END IF; ELSE -- Force clear on standby EXECUTE IMMEDIATE 'ALTER DATABASE CLEAR LOGFILE GROUP ' || logs(log_rec).group# || ' UNARCHIVED'; END IF; EXECUTE IMMEDIATE 'ALTER DATABASE DROP ${log_type} LOGFILE GROUP ' || logs(log_rec).group#; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error dropping group ' || logs(log_rec).group# || ': ' || SQLERRM); END; END LOOP; END; / EXIT; EOF } # DG Broker MRP control manage_mrp() { local action=$1 log "${action} MRP on ${STANDBY_DB}..." echo -e "connect ${DG_USER}/${SYS_PASSWORD}@${PRIMARY_DB}\n"\ "edit database ${STANDBY_DB} set state='APPLY-${action}';" | dgmgrl / >> "$LOG_FILE" 2>&1 if [ $? -ne 0 ]; then log "Failed to ${action} MRP on ${STANDBY_DB}" exit 1 fi log "MRP ${action} successfully on ${STANDBY_DB}" } # Main execution { log "Starting Safe Redo Log Resize Operation" verify_role "$PRIMARY_HOST" "$PRIMARY_DB" "PRIMARY" verify_role "$STANDBY_HOST" "$STANDBY_DB" "PHYSICAL STANDBY" # Process standby first manage_mrp "OFF" # Add new logs on standby add_new_logs "$STANDBY_HOST" "$STANDBY_DB" "LOG" "$ONLINE_GROUPS_PER_THREAD" "$ONLINE_REDO_SIZE" add_new_logs "$STANDBY_HOST" "$STANDBY_DB" "STANDBY" "$STANDBY_GROUPS_PER_THREAD" "$STANDBY_REDO_SIZE" # Drop old logs on standby drop_old_logs "$STANDBY_HOST" "$STANDBY_DB" "LOG" drop_old_logs "$STANDBY_HOST" "$STANDBY_DB" "STANDBY" manage_mrp "ON" # Process primary add_new_logs "$PRIMARY_HOST" "$PRIMARY_DB" "LOG" "$ONLINE_GROUPS_PER_THREAD" "$ONLINE_REDO_SIZE" add_new_logs "$PRIMARY_HOST" "$PRIMARY_DB" "STANDBY" "$STANDBY_GROUPS_PER_THREAD" "$STANDBY_REDO_SIZE" drop_old_logs "$PRIMARY_HOST" "$PRIMARY_DB" "LOG" drop_old_logs "$PRIMARY_HOST" "$PRIMARY_DB" "STANDBY" # Verification log "Final Configuration - Primary DB:" sqlplus -S "${DG_USER}/${SYS_PASSWORD}@//${PRIMARY_HOST}:1521/${PRIMARY_DB} as sysdba" << EOF | tee -a "$LOG_FILE" SET LINES 200 PAGES 1000 COL group# FOR 999 COL thread# FOR 999 COL bytes FOR a15 SELECT 'Online' type, group#, thread#, bytes/1024/1024||'M' bytes, status FROM v\$log UNION ALL SELECT 'Standby', group#, thread#, bytes/1024/1024||'M', status FROM v\$standby_log ORDER BY 1,2; EXIT; EOF log "Final Configuration - Standby DB:" sqlplus -S "${DG_USER}/${SYS_PASSWORD}@//${STANDBY_HOST}:1521/${STANDBY_DB} as sysdba" << EOF | tee -a "$LOG_FILE" SET LINES 200 PAGES 1000 COL group# FOR 999 COL thread# FOR 999 COL bytes FOR a15 SELECT 'Online' type, group#, thread#, bytes/1024/1024||'M' bytes, status FROM v\$log UNION ALL SELECT 'Standby', group#, thread#, bytes/1024/1024||'M', status FROM v\$standby_log ORDER BY 1,2; EXIT; EOF log "Operation completed successfully" } | tee -a "$LOG_FILE" echo "Detailed log saved to: ${LOG_FILE}"