From 9612a8600bc104023386ebe968797fd39013859d Mon Sep 17 00:00:00 2001 From: hvlad Date: Thu, 29 May 2014 07:54:15 +0000 Subject: [PATCH] Fixed bug CORE-4444 : Engine could hung and block all attachments in out of disk space condition during physical backup Improvement CORE-4445 : Extend main database file faster when physical backup state changed from stalled to merge --- src/jrd/GlobalRWLock.cpp | 9 ++++---- src/jrd/GlobalRWLock.h | 2 +- src/jrd/nbak.cpp | 50 ++++++++++++++++++++++++++++++++++++++++ src/jrd/nbak.h | 3 ++- 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/jrd/GlobalRWLock.cpp b/src/jrd/GlobalRWLock.cpp index 8b33601c82..abada36e70 100644 --- a/src/jrd/GlobalRWLock.cpp +++ b/src/jrd/GlobalRWLock.cpp @@ -188,7 +188,7 @@ bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait) } } -void GlobalRWLock::unlockWrite(thread_db* tdbb) +void GlobalRWLock::unlockWrite(thread_db* tdbb, const bool release) { SET_TDBB(tdbb); @@ -201,13 +201,12 @@ void GlobalRWLock::unlockWrite(thread_db* tdbb) currentWriter = false; - if (!lockCaching) + if (!lockCaching || release) LCK_release(tdbb, cachedLock); else if (blocking) - { LCK_downgrade(tdbb, cachedLock); - blocking = false; - } + + blocking = false; if (cachedLock->lck_physical < LCK_read) invalidate(tdbb); diff --git a/src/jrd/GlobalRWLock.h b/src/jrd/GlobalRWLock.h index 3e8559177a..dfbddb3553 100644 --- a/src/jrd/GlobalRWLock.h +++ b/src/jrd/GlobalRWLock.h @@ -65,7 +65,7 @@ public: // This function returns false if it cannot take the lock bool lockWrite(thread_db* tdbb, SSHORT wait); - void unlockWrite(thread_db* tdbb); + void unlockWrite(thread_db* tdbb, const bool release = false); bool lockRead(thread_db* tdbb, SSHORT wait, const bool queueJump = false); void unlockRead(thread_db* tdbb); bool tryReleaseLock(thread_db* tdbb); diff --git a/src/jrd/nbak.cpp b/src/jrd/nbak.cpp index fae74a6c91..62d533b22f 100644 --- a/src/jrd/nbak.cpp +++ b/src/jrd/nbak.cpp @@ -360,6 +360,46 @@ ULONG BackupManager::getPageCount() } +bool BackupManager::extendDatabase(thread_db* tdbb) +{ + ULONG maxPage = 0; + { + LocalAllocReadGuard localAllocGuard(this); + AllocItemTree::Accessor all(alloc_table); + + if (all.getFirst()) { + do + { + const ULONG pg = all.current().db_page; + if (maxPage < pg) + maxPage = pg; + } while (all.getNext()); + } + } + + PageSpace *pgSpace = database->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); + ULONG maxAllocPage = pgSpace->maxAlloc(database->dbb_page_size); + if (maxAllocPage >= maxPage) + return true; + + if (!pgSpace->extend(tdbb, maxPage, true)) + return false; + + maxAllocPage = pgSpace->maxAlloc(database->dbb_page_size); + while (maxAllocPage < maxPage) + { + const USHORT ret = PIO_init_data(database, pgSpace->file, tdbb->tdbb_status_vector, + maxAllocPage, 256); + + if (ret != 256) + return false; + + maxAllocPage += ret; + } + return true; +} + + // Merge difference file to main files (if needed) and unlink() difference // file then. If merge is already in progress method silently returns and // does nothing (so it can be used for recovery on database startup). @@ -398,6 +438,9 @@ void BackupManager::endBackup(thread_db* tdbb, bool recover) endLock.unlockWrite(tdbb); return; } + + if (backup_state == nbak_state_stalled && !extendDatabase(tdbb)) + status_exception::raise(tdbb->tdbb_status_vector); } // Here backup state can be changed. Need to check it again after lock @@ -410,6 +453,13 @@ void BackupManager::endBackup(thread_db* tdbb, bool recover) endLock.unlockWrite(tdbb); return; } + + if (!extendDatabase(tdbb)) + { + stateGuard.setSuccess(); + status_exception::raise(tdbb->tdbb_status_vector); + } + header = (Ods::header_page*) window.win_buffer; NBAK_TRACE(("difference file %s, current backup state is %d", diff_name.c_str(), backup_state)); diff --git a/src/jrd/nbak.h b/src/jrd/nbak.h index fc1a615a02..39fc7539e8 100644 --- a/src/jrd/nbak.h +++ b/src/jrd/nbak.h @@ -365,7 +365,7 @@ public: void unlockStateWrite(thread_db* tdbb) { tdbb->tdbb_flags &= ~TDBB_backup_write_locked; - stateLock->unlockWrite(tdbb); + stateLock->unlockWrite(tdbb, backup_state == nbak_state_unknown); } bool lockStateRead(thread_db* tdbb, SSHORT wait) @@ -464,6 +464,7 @@ private: ULONG findPageIndex(thread_db* tdbb, ULONG db_page); void generateFilename(); + bool extendDatabase(thread_db* tdbb); void lockAllocWrite(thread_db* tdbb) {