diff --git a/src/burp/BurpTasks.cpp b/src/burp/BurpTasks.cpp index d6a0cd66821..4a90179dd8f 100644 --- a/src/burp/BurpTasks.cpp +++ b/src/burp/BurpTasks.cpp @@ -902,7 +902,7 @@ void RestoreRelationTask::initItem(BurpGlobals* tdgbl, Item& item) m_masterGbl->gbl_dpb_data.begin(), m_masterGbl->gbl_dpb_data.getCount()); - dpb.deleteWithTag(isc_dpb_gbak_attach); + //dpb.deleteWithTag(isc_dpb_gbak_attach); const UCHAR* dpbBuffer = dpb.getBuffer(); const USHORT dpbLength = dpb.getBufferLength(); diff --git a/src/include/firebird/impl/msg/jrd.h b/src/include/firebird/impl/msg/jrd.h index dff756e1630..dc4fe7f69bd 100644 --- a/src/include/firebird/impl/msg/jrd.h +++ b/src/include/firebird/impl/msg/jrd.h @@ -995,3 +995,4 @@ FB_IMPL_MSG(JRD, 992, invalid_timezone_region_or_displacement, -901, "HY", "000" FB_IMPL_MSG(JRD, 993, argmustbe_exact_range_for, -833, "42", "000", "Arguments for range-based FOR must be exact numeric types") FB_IMPL_MSG(JRD, 994, range_for_by_should_be_positive, -833, "42", "000", "Range-based FOR BY argument must be positive") FB_IMPL_MSG(JRD, 995, missing_value_for_format_pattern, -901, "HY", "000", "Cannot find value in input string for \"@1\" pattern") +FB_IMPL_MSG(JRD, 996, no_user_att_while_restore, -901, "HY", "000", "User attachments are not allowed for the database being restored") diff --git a/src/jrd/Database.h b/src/jrd/Database.h index ba8b1339e92..a2739a86308 100644 --- a/src/jrd/Database.h +++ b/src/jrd/Database.h @@ -228,8 +228,9 @@ const ULONG DBB_new = 0x8000L; // Database object is just created const ULONG DBB_gc_cooperative = 0x10000L; // cooperative garbage collection const ULONG DBB_gc_background = 0x20000L; // background garbage collection by gc_thread const ULONG DBB_sweep_starting = 0x40000L; // Auto-sweep is starting -const ULONG DBB_creating = 0x80000L; // Database creation is in progress +const ULONG DBB_creating = 0x80000L; // Database creation is in progress const ULONG DBB_shared = 0x100000L; // Database object is shared among connections +const ULONG DBB_restoring = 0x200000L; // Database restore is in progress // // dbb_ast_flags @@ -718,6 +719,19 @@ class Database : public pool_alloc dbb_gblobj_holder->decTempCacheUsage(size); } + bool isRestoring() const + { + return dbb_flags & DBB_restoring; + } + + void setRestoring(bool value) + { + if (value) + dbb_flags |= DBB_restoring; + else + dbb_flags &= ~DBB_restoring; + } + private: //static int blockingAstSharedCounter(void*); static int blocking_ast_sweep(void* ast_object); diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index 5d1ef64924a..94c01d8564f 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -100,6 +100,11 @@ namespace return lock.release(); } + + inline bool swept_at_restore(thread_db* tdbb, const jrd_rel* relation) + { + return tdbb->getDatabase()->isRestoring() && !relation->isSystem(); + } } @@ -2232,7 +2237,14 @@ void DPM_store( thread_db* tdbb, record_param* rpb, PageStack& stack, const Jrd: memset(data + size, 0, fill); Ods::pag* page = rpb->getWindow(tdbb).win_buffer; - if (page->pag_flags & dpg_swept) + + // When restoring, mark primary data page as swept, pointer page already marked by locate_space() + if (swept_at_restore(tdbb, rpb->rpb_relation) && (type == DPM_primary)) + { + page->pag_flags |= dpg_swept; + CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); + } + else if (page->pag_flags & dpg_swept) { page->pag_flags &= ~dpg_swept; mark_full(tdbb, rpb); @@ -3083,7 +3095,13 @@ static void extend_relation(thread_db* tdbb, jrd_rel* relation, WIN* window, con UCHAR* bits = (UCHAR*) (ppage->ppg_page + dbb->dbb_dp_per_pp); PPG_DP_BIT_CLEAR(bits, slot, PPG_DP_ALL_BITS); - if (type != DPM_primary) + if (type == DPM_primary) + { + // When restoring, mark slot as swept, data page will be marked by our caller + if (swept_at_restore(tdbb, relation)) + PPG_DP_BIT_SET(bits, slot, ppg_dp_swept); + } + else PPG_DP_BIT_SET(bits, slot, ppg_dp_secondary); for (unsigned i = 1; i < cntAlloc; i++) @@ -3536,7 +3554,13 @@ static rhd* locate_space(thread_db* tdbb, PPG_DP_BIT_CLEAR(bits, slot, ppg_dp_empty); if (type == DPM_primary) + { PPG_DP_BIT_CLEAR(bits, slot, ppg_dp_secondary); + + // When restoring, mark slot as swept, data page will be marked by our caller + if (swept_at_restore(tdbb, relation)) + PPG_DP_BIT_SET(bits, slot, ppg_dp_swept); + } else PPG_DP_BIT_SET(bits, slot, ppg_dp_secondary); @@ -3918,11 +3942,28 @@ static void store_big_record(thread_db* tdbb, header->rhdf_b_page, header->rhdf_b_line); #endif + + bool markPP = false; + + // When restoring, mark primary data page as swept, pointer page already marked by locate_space() + if (swept_at_restore(tdbb, rpb->rpb_relation) && (type == DPM_primary)) + { + page->dpg_header.pag_flags |= dpg_swept; + } + else if (page->dpg_header.pag_flags & dpg_swept) + { + page->dpg_header.pag_flags &= ~dpg_swept; + markPP = true; + } + if (!(page->dpg_header.pag_flags & dpg_large)) { page->dpg_header.pag_flags |= dpg_large; - mark_full(tdbb, rpb); + markPP = true; } + + if (markPP) + mark_full(tdbb, rpb); else CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); } diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 32ab921533e..e3314b580e3 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1913,6 +1913,12 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch dbb->dbb_crypto_manager->attach(tdbb, attachment); } + if (dbb->isRestoring()) + { + if (!options.dpb_gbak_attach && !options.dpb_map_attach && !options.dpb_worker_attach) + ERR_post(Arg::Gds(isc_no_user_att_while_restore)); + } + // Basic DBB initialization complete initGuard.leave(); @@ -3105,6 +3111,8 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch // Initialize the global objects dbb->initGlobalObjects(); + if (attachment->isGbak()) + dbb->setRestoring(true); // Initialize locks LCK_init(tdbb, LCK_OWNER_database); @@ -7894,6 +7902,9 @@ void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment, XThreadEns if (!other) sync.lock(SYNC_EXCLUSIVE); + if (attachment->att_flags & ATT_creator) + dbb->setRestoring(false); + // remove the attachment block from the dbb linked list for (Jrd::Attachment** ptr = &dbb->dbb_attachments; *ptr; ptr = &(*ptr)->att_next) { diff --git a/src/jrd/shut.cpp b/src/jrd/shut.cpp index 9264af0c28d..36d9f7e9065 100644 --- a/src/jrd/shut.cpp +++ b/src/jrd/shut.cpp @@ -52,6 +52,10 @@ union shutdown_data SLONG data_long; }; +// Low byte of shutdown_data::flag used by shutdown modes, see isc_dpb_shut_XXX +// High byte used for additional flags + +const SSHORT SHUT_flag_restoring = 0x0100; // database restore is in progress // Define this to true if you need to allow no-op behavior when requested shutdown mode // matches current. Logic of jrd8_create_database may need attention in this case too @@ -122,6 +126,9 @@ bool SHUT_blocking_ast(thread_db* tdbb, bool ast) return false; } + if (flag & SHUT_flag_restoring) + dbb->setRestoring(true); + if ((flag & isc_dpb_shut_force) && !delay) return shutdown(tdbb, flag, ast); @@ -472,6 +479,9 @@ static bool notify_shutdown(thread_db* tdbb, SSHORT flag, SSHORT delay, Sync* gu data.data_items.flag = flag; data.data_items.delay = delay; + if (dbb->isRestoring()) + data.data_items.flag |= SHUT_flag_restoring; + LCK_write_data(tdbb, dbb->dbb_lock, data.data_long); { // scope