From 7c8d021edd50f4c7eff3063e14568f4b5cc71049 Mon Sep 17 00:00:00 2001 From: Vlad Khorsun Date: Tue, 29 Sep 2026 16:35:59 +0300 Subject: [PATCH 1/2] Fixed bug #9169 : SuperServer: no attachment to ANY database can proceed while two or more attachments wait for a database under exclusive validation --- src/jrd/jrd.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 384cb9742b9..d31ad26b266 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1863,6 +1863,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch // Init complete - we can release dbInitMutex dbb->dbb_flags &= ~DBB_new; guardDbInit.leave(); + initGuard.leave(); } else { @@ -1881,6 +1882,8 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch jAtt->getStable()->manualAsyncUnlock(attachment->att_flags); INI_init(tdbb); + initGuard.leave(); + PAG_header(tdbb, true); dbb->dbb_crypto_manager->attach(tdbb, attachment); } @@ -1892,7 +1895,6 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch } // Basic DBB initialization complete - initGuard.leave(); // Attachments to a ReadOnly database need NOT do garbage collection if (dbb->readOnly()) From 4e1c496e660478cc292ccff5f738514b7f4ccca9 Mon Sep 17 00:00:00 2001 From: Vlad Khorsun Date: Thu, 1 Oct 2026 22:20:27 +0300 Subject: [PATCH 2/2] Rework fix. --- src/jrd/Database.h | 1 + src/jrd/dpm.epp | 1 + src/jrd/ini.epp | 11 +++++++++++ src/jrd/jrd.cpp | 7 ++----- src/jrd/pag.cpp | 12 +----------- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/jrd/Database.h b/src/jrd/Database.h index ac815b61034..47adeab5f38 100644 --- a/src/jrd/Database.h +++ b/src/jrd/Database.h @@ -482,6 +482,7 @@ class Database : public pool_alloc USHORT dbb_dp_per_pp; // data pages per pointer page USHORT dbb_max_records; // max record per data page USHORT dbb_max_idx; // max number of indexes on a root page + ULONG dbb_rdb_pages; // cached number of first PP of RDB$PAGES relation, see hdr_PAGES #ifdef SUPERSERVER_V2 USHORT dbb_prefetch_sequence; // sequence to pace frequency of prefetch requests diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index 9366903e6f2..4dbb1fbbb9f 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -604,6 +604,7 @@ void DPM_create_relation_pages(thread_db* tdbb, jrd_rel* relation, RelationPages header_page* header = (header_page*) CCH_FETCH(tdbb, &root_window, LCK_write, pag_header); CCH_MARK(tdbb, &root_window); header->hdr_PAGES = window.win_page.getPageNum(); + dbb->dbb_rdb_pages = header->hdr_PAGES; CCH_RELEASE(tdbb, &root_window); } diff --git a/src/jrd/ini.epp b/src/jrd/ini.epp index 3fdd87a420c..b55b1a7e85e 100644 --- a/src/jrd/ini.epp +++ b/src/jrd/ini.epp @@ -1094,6 +1094,17 @@ void INI_init(thread_db* tdbb) relation->rel_current_fmt = currentFormat; relation->rel_current_format = (*relation->rel_formats)[currentFormat]; } + + if (dbb->dbb_rdb_pages) + { + jrd_rel* relation = MET_relation(tdbb, 0); + RelationPages* relPages = relation->getBasePages(); + fb_assert(!relPages->rel_pages); + + vcl* vector = vcl::newVector(*relation->rel_pool, 1); + relPages->rel_pages = vector; + (*vector)[0] = dbb->dbb_rdb_pages; + } } diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index d31ad26b266..8a6e10aadb4 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1820,9 +1820,9 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch jAtt->getStable()->manualAsyncUnlock(attachment->att_flags); + PAG_header_init(tdbb); INI_init(tdbb); SHUT_init(tdbb); - PAG_header_init(tdbb); PAG_init(tdbb); if (options.dpb_set_page_buffers) @@ -1863,7 +1863,6 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch // Init complete - we can release dbInitMutex dbb->dbb_flags &= ~DBB_new; guardDbInit.leave(); - initGuard.leave(); } else { @@ -1882,9 +1881,6 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch jAtt->getStable()->manualAsyncUnlock(attachment->att_flags); INI_init(tdbb); - initGuard.leave(); - - PAG_header(tdbb, true); dbb->dbb_crypto_manager->attach(tdbb, attachment); } @@ -1895,6 +1891,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch } // Basic DBB initialization complete + initGuard.leave(); // Attachments to a ReadOnly database need NOT do garbage collection if (dbb->readOnly()) diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index 08c887d6a21..4b9e4dc1c62 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -1122,17 +1122,6 @@ void PAG_header(thread_db* tdbb, bool info) if (header->hdr_flags & hdr_SQL_dialect_3) dbb->dbb_flags |= DBB_DB_SQL_dialect_3; - jrd_rel* relation = MET_relation(tdbb, 0); - RelationPages* relPages = relation->getBasePages(); - if (!relPages->rel_pages) - { - // NS: There's no need to reassign first page for RDB$PAGES relation since - // current code cannot change its location after database creation. - vcl* vector = vcl::newVector(*relation->rel_pool, 1); - relPages->rel_pages = vector; - (*vector)[0] = header->hdr_PAGES; - } - dbb->dbb_next_transaction = next_transaction; if (!info || dbb->dbb_oldest_transaction < oldest_transaction) @@ -1334,6 +1323,7 @@ void PAG_header_init(thread_db* tdbb) dbb->dbb_page_size = header->hdr_page_size; dbb->dbb_page_buffers = header->hdr_page_buffers; + dbb->dbb_rdb_pages = header->hdr_PAGES; }