@@ -451,23 +451,26 @@ public void check() {
451451 try {
452452 initializeDatabaseEncryptors ();
453453
454- // DB version 테이블의 latest 행 삭제
455- final CloudStackVersion dbVersionInitial = CloudStackVersion .parse (_dao .getCurrentVersion ());
456- deleteCurrentVersionRowIfPresent (dbVersionInitial );
457-
454+ // 1) 코드(설치될) 버전 먼저 파싱
458455 final String currentVersionValue = this .getClass ().getPackage ().getImplementationVersion ();
459456 if (StringUtils .isBlank (currentVersionValue )) return ;
460457 final CloudStackVersion currentVersion = CloudStackVersion .parse (currentVersionValue );
461458
459+ // 2) DB 최신 버전 읽기
460+ final CloudStackVersion dbLatestVersion = CloudStackVersion .parse (_dao .getCurrentVersion ());
461+
462+ // 3) 베이스라인 보장 + (db==code) 같으면 삭제 스킵
463+ enforceBaselineThenDeleteLastVersionIfNeeded (dbLatestVersion , currentVersion );
464+
462465 ///////////////////// Ablestack 업그레이드 //////////////////////////
463466 beforeUpgradeAblestack ("Bronto" );
464467 beforeUpgradeAblestack ("Cerato" );
465468 beforeUpgradeAblestack ("Diplo" );
466469 ///////////////////// Ablestack 업그레이드 //////////////////////////
467470
468- // 삭제 후 DB 버전 재조회
471+ // 4) 재조회 후 본 업그레이드 진행
469472 final CloudStackVersion dbVersion = CloudStackVersion .parse (_dao .getCurrentVersion ());
470- LOGGER .info ("After deletion , DB version = {} , Code version = {}" , dbVersion , currentVersion );
473+ LOGGER .info ("After enforcement , DB version = {} , Code version = {}" , dbVersion , currentVersion );
471474
472475 String csVersion = SystemVmTemplateRegistration .parseMetadataFile ();
473476 final CloudStackVersion sysVmVersion = CloudStackVersion .parse (csVersion );
@@ -495,6 +498,85 @@ public void check() {
495498 }
496499 }
497500
501+ private void enforceBaselineThenDeleteLastVersionIfNeeded (final CloudStackVersion dbLatestVersion ,
502+ final CloudStackVersion currentVersion ) {
503+ final String BASELINE_VERSION = "4.0.0" ;
504+ final TransactionLegacy txn = TransactionLegacy .open ("enforce-baseline-then-delete-last" );
505+ txn .start ();
506+ try {
507+ final Connection conn = txn .getConnection ();
508+
509+ // 0) DB 최신버전 == 코드버전이면 삭제/삽입 모두 스킵
510+ final boolean sameAsCode = (dbLatestVersion != null
511+ && currentVersion != null
512+ && dbLatestVersion .compareTo (currentVersion ) == 0 );
513+ if (sameAsCode ) {
514+ LOGGER .info ("DB latest version equals code version (db={}, code={}). Skipping baseline insert and deletion." ,
515+ dbLatestVersion , currentVersion );
516+ txn .commit ();
517+ return ;
518+ }
519+
520+ // 1) sameAsCode == false 인 경우에만 베이스라인 보장 (없으면 삽입)
521+ final String insertIfMissingSql =
522+ "INSERT INTO `cloud`.`version` (`version`, `step`, `updated`) " +
523+ "SELECT ?, 'Complete', NOW() FROM DUAL " +
524+ "WHERE NOT EXISTS (SELECT 1 FROM `cloud`.`version` WHERE `version` = ?)" ;
525+ try (PreparedStatement ins = conn .prepareStatement (insertIfMissingSql )) {
526+ ins .setString (1 , BASELINE_VERSION );
527+ ins .setString (2 , BASELINE_VERSION );
528+ int inserted = ins .executeUpdate ();
529+ if (inserted > 0 ) {
530+ LOGGER .info ("Inserted baseline version row: {}" , BASELINE_VERSION );
531+ txn .commit ();
532+ return ; // 여기서 종료
533+ }
534+ }
535+
536+ // 2) 삭제 대상: dbLatestVersion 의 최신 1건 (단, 베이스라인이면 삭제 금지)
537+ if (dbLatestVersion != null
538+ && currentVersion != null
539+ && dbLatestVersion .compareTo (currentVersion ) != 0
540+ && !BASELINE_VERSION .equals (dbLatestVersion .toString ())) {
541+
542+ final String deleteLatestOneSql =
543+ "DELETE FROM `cloud`.`version` " +
544+ "WHERE `id` IN ( " +
545+ " SELECT id FROM ( " +
546+ " SELECT `id` " +
547+ " FROM `cloud`.`version` " +
548+ " WHERE `version` = ? AND (`step` IS NULL OR `step` = 'Complete') " +
549+ " ORDER BY COALESCE(`updated`, FROM_UNIXTIME(0)) DESC " +
550+ " LIMIT 1 " +
551+ " ) AS _x " +
552+ ")" ;
553+ try (PreparedStatement delLatest = conn .prepareStatement (deleteLatestOneSql )) {
554+ delLatest .setString (1 , dbLatestVersion .toString ());
555+ int deleted = delLatest .executeUpdate ();
556+ if (deleted > 0 ) {
557+ LOGGER .warn ("Deleted {} latest row for version {}" , deleted , dbLatestVersion .toString ());
558+ txn .commit ();
559+ return ;
560+ } else {
561+ LOGGER .info ("No deletable row found for targetVersion={}; skipping targeted delete." ,
562+ dbLatestVersion .toString ());
563+ }
564+ }
565+ } else {
566+ // null-safe 로깅
567+ LOGGER .info ("Target version is baseline or null ({}). Skipping targeted delete." ,
568+ String .valueOf (dbLatestVersion ));
569+ }
570+
571+ txn .commit ();
572+ } catch (SQLException e ) {
573+ txn .rollback ();
574+ LOGGER .error ("Failed in enforceBaselineThenDeleteLastVersionIfNeeded" , e );
575+ } finally {
576+ txn .close ();
577+ }
578+ }
579+
498580 // Cloudstack DB 업데이트 전 Ablestack DB 업데이트 진행
499581 public void beforeUpgradeAblestack (String ablestackVersion ) {
500582 TransactionLegacy txn = TransactionLegacy .open ("Upgrade" );
@@ -530,27 +612,6 @@ public void beforeUpgradeAblestack (String ablestackVersion) {
530612 }
531613 }
532614
533- private void deleteCurrentVersionRowIfPresent (final CloudStackVersion currentVersion ) {
534- TransactionLegacy txn = TransactionLegacy .open ("delete-current-version-row" );
535- txn .start ();
536- try {
537- Connection conn = txn .getConnection ();
538- try (PreparedStatement ps = conn .prepareStatement (
539- "DELETE FROM `cloud`.`version` WHERE `version` = ? AND (`step` IS NULL OR `step` = 'Complete')" )) {
540- ps .setString (1 , currentVersion .toString ());
541- int deleted = ps .executeUpdate ();
542- LOGGER .warn ("Deleted {} row(s) from cloud.version for {}" , deleted , currentVersion );
543- }
544- txn .commit ();
545- } catch (SQLException e ) {
546- txn .rollback ();
547- LOGGER .error ("Unable to delete current version row" , e );
548- throw new CloudRuntimeException ("Unable to delete current version row" , e );
549- } finally {
550- txn .close ();
551- }
552- }
553-
554615 // Cloudstack DB 업데이트 후 Ablestack DB 업데이트 진행
555616 public void afterUpgradeAblestack (String ablestackVersion ) {
556617 TransactionLegacy txn = TransactionLegacy .open ("Upgrade" );
0 commit comments