콘텐츠로 이동

(KO) CUBRID migrate — 볼륨 헤더, active log codeset, collation sync 를 위한 one-shot 9.1→9.2 in-place 형식 업그레이더

Disk-format 업그레이더는 데이터베이스 엔진이 버전 사이에서 on-disk 레이아웃이 비호환적으로 바뀔 때 함께 배포하는 도구다. 두 가지 디자인 선택이 도구의 모양을 지배한다.

  1. In-place 와 dump-and-reload 가운데 무엇을 고르는가. In-place 는 기존 볼륨 파일을 다시 쓴다. 더 빠르고 (두 번째 디스크 공간 이 필요 없고 re-import 도 없다) per-format 변환기와 견고한 크래시-복구 story 가 필요하다. Dump-and-reload (이전 바이너리 로 export, 새 바이너리로 import) 는 더 느리지만 개념적으로 단순하고 표준 export / import 경로를 재사용한다.
  2. Single-version-pair 와 multi-version-chain 가운데 무엇을 고르는가. Single-pair 도구가 엄격히 버전 N 에서 N+1 로 마이 그레이트한다. Chain 도구는 모든 historical 형식을 이해하고 어떤 것에서든 current 로 변환한다. Chain 은 운영자에게 더 쉽 지만 (업그레이드당 한 도구) 테스트 매트릭스를 폭발시킨다. Pair 는 단순하고 명시적이지만 운영자가 중간 버전을 traverse 해야 한다.

CUBRID 의 migrate 는 in-place 와 single-pair (9.1→9.2) 조합 을 고른다. startup 의 hard guard rel_disk_compatible() != V9_2_LEVEL 가 다른 CUBRID 버전이 링크되어 있으면 마이그레이터를 거절한다. 9.1→9.2 변환기를 9.0 또는 9.3 install 에 실수로 돌리는 일을 막는 장치다. 이후 모든 버전 업그레이드는 자기 pair 도구 (또는 dump-and-reload 의 release-note 지시) 를 가진다.

In-place 선택이 마이그레이터에 undo journal 유지를 강제한다. 모든 수정된 볼륨 헤더가 먼저 read 되고 옆 버퍼에 write 되고 새 형식으로 다시 write 된다. mid-migration 크래시가 나면 journal 의 각 entry 를 undo_fix_volume_header 로 rollback 할 수 있다.

migrate <db_name> 가 엄격한 네 단계 시퀀스를 돌린다는 점이다:

  1. 볼륨 헤더 재작성. 데이터베이스의 볼륨-info 파일에 list 된 모든 데이터 볼륨을 walk 한다. 각 볼륨을 v9.1 r91_disk_var_header (migrate.c:115 의 struct) 로 read 한 뒤 v9.2 레이아웃으로 reshape 해 다시 write 한다. 각 pre-rewrite 헤더가 in-memory undo list (vol_undo_info, max UNDO_LIST_SIZE = 32) 에 capture 된다.
  2. Active log 의 codeset patch. active log 헤더가 codeset 필드 를 운반한다. 그 값이 카탈로그 (db_root.codeset) 와 어긋나 있으면 fix_codeset_in_active_log 가 in-place 로 patch 해서 migration 후 log 의 텍스트 record 해석이 카탈로그와 매치되게 한다.
  3. db_restartsynccoll_force 를 통한 카탈로그 reconcile. 새 바이너리로 데이터베이스를 부팅하고 db_collation 의 모든 collation 행을 walk 한 뒤 (catcls_get_db_collation 통해) 각각을 같은 collation 의 locale 라이브러리 view 와 비교한다. id, 이름, codeset, checksum 이 모두 일치해야 하며, contraction 이 있는 경우는 예외다 (9.2 에서 on-disk COLL_CONTRACTION 표현이 reorganise 되었으므로 checksum drift 가 허용된다). 그 다음 synccoll_force 가 locale 라이브러리에서 collation 행을 다시 쓴다.
  4. 볼륨 통계 refresh. file_update_used_pages_of_vol_header 가 헤더의 used-pages counter 를 refresh 하기 위해 모든 볼륨을 스캔한다. 이 값은 9.1 에서 다르게 계산되었고 9.2 의미로 다시 빌드되어야 한다.

어느 단계가 실패하면 마이그레이터가 unwind 된다 — error_undo_vol_header 가 undo list 의 모든 entry 를 역순으로 다시 적용해 원래 v9.1 헤더를 복원한다. 그 다음 error_undo_compat 가 compat-level 마커 (check_and_fix_compat_level)를 되돌려 데이터베이스가 9.1 바이너리로 다시 열릴 수 있게 한다.

// migrate.c (의역)
fix_all_volume_header (db_path) {
walk volume info;
for each volume {
undo_page = make_volume_header_undo_page (vol_path, size); // read + journal
if (undo_page) {
vol_undo_info[vol_undo_count++] = (vol_path, undo_page, size);
}
fix_volume_header (vol_path); // in-place 재작성
}
}
error_undo_vol_header:
for (i = vol_undo_count - 1; i >= 0; i--) {
undo_fix_volume_header (vol_undo_info[i].filename,
vol_undo_info[i].page,
vol_undo_info[i].page_size);
}
free_volume_header_undo_list ();

Journal 은 in-memory 전용이다. mid-rewrite 프로세스 크래시가 journal 을 잃고 볼륨을 mixed 상태로 남긴다는 의미다. 운영자는 migrate 를 돌리기 전에 cold backup 을 갖추고 있어야 한다. 도구 외부에 process-crash 복구 경로가 존재하도록 보장하는 장치다.

시그널 핸들러 (intr_handler, SIGINT 와 Windows console-control 에 설치)가 loop 가 볼륨 사이에 검사하는 플래그를 설정한다 — mid-volume 으로 abort 하는 대신 같은 undo 시퀀스를 trigger 하는 graceful Ctrl-C 를 허용한다.

r91_disk_var_header — 레거시 on-disk 모양

섹션 제목: “r91_disk_var_header — 레거시 on-disk 모양”
// migrate.c — 마이그레이트되는 형식
struct r91_disk_var_header {
char magic[CUBRID_MAGIC_MAX_LENGTH];
INT16 iopagesize;
INT16 volid;
DISK_VOLPURPOSE purpose;
INT32 sect_npgs;
INT32 total_sects;
INT32 free_sects;
INT32 hint_allocsect;
INT32 total_pages;
INT32 free_pages;
INT32 sect_alloctb_npages;
INT32 page_alloctb_npages;
INT32 sect_alloctb_page1;
INT32 page_alloctb_page1;
INT32 sys_lastpage;
INT64 db_creation;
INT32 max_npages;
INT32 dummy;
LOG_LSA chkpt_lsa;
HFID boot_hfid;
INT16 offset_to_vol_fullname;
INT16 offset_to_next_vol_fullname;
INT16 offset_to_vol_remarks;
char var_fields[1];
};

9.2 헤더 (disk_manager.{c,h} 에 정의)가 이를 다른 필드 레이아웃 으로 reorganise 한다 — sector-allocation 추적이 별도 per-볼륨 metadata page 로 옮겨가고, dummy 필드가 repurpose 되고, 여러 offset 이 재계산된다. fix_volume_header 가 필드별 번역을 담고 있다. 마이그레이터가 코드베이스에서 v9.1 레이아웃을 아는 유일한 곳이다.

check_and_fix_compat_level 이 “migration in progress” 를 나타내는 sentinel 을 데이터베이스에 쓴다. 마이그레이터 프로세스가 깨끗하게 kill 되거나 (또는 성공적으로 끝나면) sentinel 이 클리어된다. sentinel 이 set 인 동안 데이터베이스가 9.1 또는 9.2 바이너리로 열리면 둘 다 mount 를 거절한다 — migration window 동안 double- migration 또는 사고 액세스를 방지한다는 뜻이다.

// migrate.c::main (의역)
if (rel_disk_compatible () != V9_2_LEVEL) {
printf ("CUBRID library version is invalid.\n"
"Please upgrade to CUBRID 9.2 and retry migrate.\n");
return EXIT_FAILURE;
}

rel_disk_compatible() 이 링크된 CUBRID 라이브러리의 disk-compat level 을 돌려준다. 마이그레이터는 링크된 level 이 정확히 9.2 가 아니면 시작을 거절한다 — 바이너리가 다른 target 버전으로 마이그레이트하는 데 잘못 사용되는 것을 방지한다. 이것이 migrate 가 엄격히 버전 잠긴 도구인 이유다 — “현재가 무엇이든 업그레이드” 가 아니라 “9.1 → 9.2, 그것 외에는 없다” 라는 뜻이다.

심볼역할
main진입; arg 검사; 버전 가드; 네 단계 orchestration; 에러 rollback
intr_handlerSIGINT 핸들러; graceful abort 위한 interrupt 플래그 설정
fix_all_volume_header단계 1 driver: 볼륨 info walk, 볼륨당 fix_volume_header 호출
fix_volume_header볼륨별 헤더 재작성 (v9.1 → v9.2)
make_volume_header_undo_pageundo journal 위해 기존 헤더를 옆 버퍼로 read
undo_fix_volume_headerundo journal 의 한 entry 복원
free_volume_header_undo_list성공 후 in-memory undo journal drop
get_active_log_vol_path볼륨-info 파일에서 active log 경로 찾기
get_db_path데이터베이스 이름 → full path 해석 (databases.txt 통해)
check_and_fix_compat_levelmigration-in-progress sentinel write
fix_codeset_in_active_log단계 2: active log 헤더의 codeset 필드 patch
get_codeset_from_db_rootpatch 를 위해 카탈로그의 정규 codeset read
r91_disk_var_header (struct)레거시 v9.1 볼륨-헤더 레이아웃
VOLUME_UNDO_INFO (struct)per-undo-entry record (파일명 + page bytes + 크기)
vol_undo_info (전역 배열)undo journal, max 32 entry
심볼경로
mainsrc/executables/migrate.c:404
r91_disk_var_header (struct)src/executables/migrate.c:115
fix_all_volume_header (선언)src/executables/migrate.c:155
get_active_log_vol_pathsrc/executables/migrate.c:167
fix_codeset_in_active_logsrc/executables/migrate.c:200
V9_1_LEVEL / V9_2_LEVEL (define)src/executables/migrate.c:49–50

심볼 이름이 정규 anchor 이고, 라인 번호는 updated: 날짜에 스코프된 힌트이다.

  • One-pair 범위가 디자인의 핵심이다. 모던 CUBRID (10.x 이후) 는 다른 업그레이드 경로를 사용한다. release note 가 보통 in-place 마이그레이터가 아니라 unloaddb / loaddb 를 통한 dump-and-reload 를 처방한다. 이 바이너리는 누군가가 pre-9.2 데이터베이스를 업그레이드하는 archaeological / DR 시나리오를 위해 보존된다.
  • In-memory undo journal 의 한도 문제. UNDO_LIST_SIZE = 32 는 32 볼륨 이상의 데이터베이스가 가장 최근 32 개의 in-flight 재작성 너머로 rollback 할 수 없다는 의미다. 어쨌든 mid-migration abort 가 (시그널 이유가 아닌) 크래시 이유로는 journal 을 잃기 때문에 실제로는 받아들일 만하다.
  • Collation contraction 의 허용 list. checksum 비교 주변의 count_contr == 0 검사가 존재하는 이유는 9.2 의 COLL_CONTRACTION struct 가 reorganise 되었기 때문이다. contraction 이 있는 collation 은 사용자에게 보이는 동작이 변하지 않았더라도 9.2 에서 의도적으로 다른 on-disk checksum 을 가진다. 그 collation 들의 checksum 비교를 우회하는 것은 의도된 신뢰 호출이다.
  • AU_DISABLE_PASSWORDS 다음에 db_login("DBA", NULL). 마이 그레이터는 auth 가 우회된 채로 돈다. DBA login 은 인증된 것이 아니라 위치적이다. 마이그레이터가 데이터베이스 파일에서 로컬로 돌고 두 번째 연결이 불가능하기 때문에 (compat-level sentinel 이 정상 mount 를 방지) 안전하다.
  • cubrid migrate verb 가 없다. 대부분 utility 와 달리 migrateua_Utility_Map 에 등록되지 않은 standalone 바이너리다 (cubrid-cub-admin.md 참조). 운영자는 migrate <db_name> 으로 직접 invoke 한다. 의도적인 omission 이 그 좁은 범위와 매치된다. 일반 admin-CLI 모양에 맞지 않기 때문이다.
  • 모던 형식 업그레이드 경로가 무엇인가. 예컨대 10.x → 11.x 에 대한 이 도구의 문서화된 동등물이 없다. dump-and-reload 경로가 release note 에 암묵적이다. 미래 버전이 비슷한 in-place 마이 그레이터로 이득을 볼지는 미정이다.
  • Cold-backup 요구사항을 도구가 강제하지 않는다. 운영자는 migrate 를 돌리기 전에 cold backup 을 갖추고 있어야 하지만 도구 자체가 강제하지는 않는다. 최근 backup 이 감지되지 않으면 돌기를 거절하는 pre-flight 검사가 프로세스를 강화할 것이다.
  • 32-entry undo cap 의 적정성. 일반적인 데이터베이스에는 충분히 크지만 큰 다중 볼륨 install 에는 작다. (또는 journal 을 on-disk 파일로 옮기는 것을) widen 할지는 도구가 활발히 개발 되지 않기 때문에 떠오르지 않은 scoping 질문이다.
  • src/executables/migrate.c — 전체 utility (단일 파일, ~830 줄)
  • src/executables/AGENTS.md — agent 가이드
  • 인접 문서: cubrid-disk-manager.md (migrate 가 생산하는 모던 볼륨-헤더 형식), cubrid-charset-collation.md (단계 3 이 reconcile 하는 collation 인프라), cubrid-log-manager.md (단계 2 가 patch 하는 active-log 헤더), cubrid-boot.md (단계 3 이 db_restart 통해 행사하는 데이터베이스-부팅 경로), cubrid-cub-admin.md (통합 admin CLI; migrate 는 ua_Utility_Map없다)