void SHUT_database(thread_db* tdbb, SSHORT flag, SSHORT delay) { /************************************** * * S H U T _ d a t a b a s e * ************************************** * * Functional description * Schedule database for shutdown * **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); Attachment* attachment = tdbb->getAttachment(); /* Only platform's user locksmith can shutdown or bring online a database. */ if (!attachment->locksmith()) { ERR_post(Arg::Gds(isc_no_priv) << "shutdown" << "database" << dbb->dbb_filename); } const int shut_mode = flag & isc_dpb_shut_mode_mask; // Check if requested shutdown mode is valid // Note that if we are already in requested mode we just return true. // This is required to ensure backward compatible behavior (gbak relies on that, // user-written scripts may rely on this behaviour too) switch (shut_mode) { case isc_dpb_shut_full: if (dbb->dbb_ast_flags & DBB_shutdown_full) { same_mode(); return; } break; case isc_dpb_shut_multi: if ((dbb->dbb_ast_flags & DBB_shutdown_full) || (dbb->dbb_ast_flags & DBB_shutdown_single)) { bad_mode(); } if (dbb->dbb_ast_flags & DBB_shutdown) { same_mode(); return; } break; case isc_dpb_shut_single: if (dbb->dbb_ast_flags & DBB_shutdown_full) { bad_mode(); } if (dbb->dbb_ast_flags & DBB_shutdown_single) { same_mode(); return; } break; case isc_dpb_shut_normal: if (!(dbb->dbb_ast_flags & DBB_shutdown)) { same_mode(); return; } bad_mode(); default: bad_mode(); // unexpected mode } // Reject exclusive and single-user shutdown attempts // for a physically locked database if (shut_mode == isc_dpb_shut_full || shut_mode == isc_dpb_shut_single) { check_backup_state(tdbb); } attachment->att_flags |= ATT_shutdown_manager; --dbb->dbb_use_count; /* Database is being shutdown. First notification gives shutdown type and delay in seconds. */ bool exclusive = notify_shutdown(tdbb, flag, delay); /* Notify local attachments */ SHUT_blocking_ast(tdbb); /* Try to get exclusive database lock periodically up to specified delay. If we haven't gotten it report shutdown error for weaker forms. For forced shutdown keep notifying until successful. */ SSHORT timeout = delay - SHUT_WAIT_TIME; if (!exclusive) { for (; timeout >= 0; timeout -= SHUT_WAIT_TIME) { if ((exclusive = notify_shutdown(tdbb, flag, timeout)) || !(dbb->dbb_ast_flags & (DBB_shut_attach | DBB_shut_tran | DBB_shut_force))) { break; } } } if (!exclusive && (timeout > 0 || flag & (isc_dpb_shut_attachment | isc_dpb_shut_transaction))) { notify_shutdown(tdbb, 0, -1); /* Tell everyone we're giving up */ SHUT_blocking_ast(tdbb); attachment->att_flags &= ~ATT_shutdown_manager; ++dbb->dbb_use_count; ERR_post(Arg::Gds(isc_shutfail)); } /* Once there are no more transactions active, force all remaining attachments to shutdown. */ if (flag & isc_dpb_shut_transaction) { exclusive = false; flag = isc_dpb_shut_force | shut_mode; } dbb->dbb_ast_flags |= DBB_shutdown; dbb->dbb_ast_flags &= ~(DBB_shutdown_single | DBB_shutdown_full); switch (shut_mode) { case isc_dpb_shut_normal: case isc_dpb_shut_multi: break; case isc_dpb_shut_single: dbb->dbb_ast_flags |= DBB_shutdown_single; break; case isc_dpb_shut_full: dbb->dbb_ast_flags |= DBB_shutdown_full; break; default: fb_assert(false); } if (!exclusive && (flag & isc_dpb_shut_force)) { // TMN: Ugly counting! while (!notify_shutdown(tdbb, flag, 0)) ; } ++dbb->dbb_use_count; dbb->dbb_ast_flags &= ~(DBB_shut_force | DBB_shut_attach | DBB_shut_tran); WIN window(HEADER_PAGE_NUMBER); Ods::header_page* header = (Ods::header_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_header); CCH_MARK_MUST_WRITE(tdbb, &window); // Set appropriate shutdown mode in database header header->hdr_flags &= ~Ods::hdr_shutdown_mask; switch (shut_mode) { case isc_dpb_shut_normal: break; case isc_dpb_shut_multi: header->hdr_flags |= Ods::hdr_shutdown_multi; break; case isc_dpb_shut_single: header->hdr_flags |= Ods::hdr_shutdown_single; break; case isc_dpb_shut_full: header->hdr_flags |= Ods::hdr_shutdown_full; break; default: fb_assert(false); } CCH_RELEASE(tdbb, &window); CCH_release_exclusive(tdbb); }