Example #1
0
void GlobalRWLock::unlockWrite(thread_db* tdbb, const bool release)
{
	SET_TDBB(tdbb);

	Database* dbb = tdbb->getDatabase();

	Database::CheckoutLockGuard counterGuard(dbb, counterMutex);

	COS_TRACE(("(%p)->unlockWrite readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
		this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));

	currentWriter = false;

	if (!lockCaching || release)
		LCK_release(tdbb, cachedLock);
	else if (blocking)
		LCK_downgrade(tdbb, cachedLock);

	blocking = false;

	if (cachedLock->lck_physical < LCK_read)
		invalidate(tdbb);

	writerFinished.notifyAll();
	COS_TRACE(("(%p)->unlockWrite end readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
		this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
}
Example #2
0
void GlobalRWLock::unlockRead(thread_db* tdbb)
{
	SET_TDBB(tdbb);

	Database* dbb = tdbb->getDatabase();

	Database::CheckoutLockGuard counterGuard(dbb, counterMutex);

	COS_TRACE(("(%p)->unlockRead readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
		this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
	readers--;

	if (!readers)
	{
		if (!lockCaching || pendingWriters || blocking)
		{
			LCK_release(tdbb, cachedLock);	// Release since concurrent request needs LCK_write
			invalidate(tdbb);
		}

		noReaders.notifyAll();
	}
	COS_TRACE(("(%p)->unlockRead end readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
		this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
}
Example #3
0
	void Database::SharedCounter::shutdown(thread_db* tdbb)
	{
		for (size_t i = 0; i < TOTAL_ITEMS; i++)
		{
			if (m_counters[i].lock)
				LCK_release(tdbb, m_counters[i].lock);
		}
	}
Example #4
0
	void CryptoManager::blockingAstChangeCryptState()
	{
		AsyncContextHolder tdbb(&dbb, FB_FUNCTION);

		fb_assert(stateLock);
		LCK_release(tdbb, stateLock);
		needLock = true;
	}
Example #5
0
void Collation::release(thread_db* tdbb)
{
	fb_assert(useCount >= 0);

	if (existenceLock)
		LCK_release(tdbb, existenceLock);

	useCount = 0;
}
Example #6
0
	void Database::clearSweepFlags(thread_db* tdbb)
	{
		if (!(dbb_flags & (DBB_sweep_starting | DBB_sweep_in_progress)))
			return;

		if (dbb_sweep_lock)
			LCK_release(tdbb, dbb_sweep_lock);

		dbb_flags &= ~(DBB_sweep_in_progress | DBB_sweep_starting);
	}
Example #7
0
	int Database::blocking_ast_sweep(void* ast_object)
	{
		Database* dbb = static_cast<Database*>(ast_object);
		AsyncContextHolder tdbb(dbb, FB_FUNCTION);

		if ((dbb->dbb_flags & DBB_sweep_starting) && !(dbb->dbb_flags & DBB_sweep_in_progress))
		{
			dbb->dbb_flags &= ~DBB_sweep_starting;
			LCK_release(tdbb, dbb->dbb_sweep_lock);
		}

		return 0;
	}
Example #8
0
	void CryptoManager::shutdown(thread_db* tdbb)
	{
		terminateCryptThread(tdbb);

		if (cryptPlugin)
		{
			PluginManagerInterfacePtr()->releasePlugin(cryptPlugin);
			cryptPlugin = NULL;
		}

		if (stateLock)
		{
			LCK_release(tdbb, stateLock);
			stateLock = NULL;
		}
	}
Example #9
0
void GlobalRWLock::shutdownLock()
{
	thread_db* tdbb = JRD_get_thread_data();

	Database::CheckoutLockGuard counterGuard(tdbb->getDatabase(), counterMutex);

	COS_TRACE(("(%p)->shutdownLock readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
		this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));

	if (!cachedLock)
		return;

	LCK_release(tdbb, cachedLock);

	delete cachedLock;
	cachedLock = NULL;
}
Example #10
0
bool GlobalRWLock::tryReleaseLock(thread_db* tdbb)
{
	Database::CheckoutLockGuard counterGuard(tdbb->getDatabase(), counterMutex);

	COS_TRACE(("(%p)->tryReleaseLock readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
		this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));

	if (readers || currentWriter)
		return false;

	if (cachedLock->lck_physical > LCK_none)
	{
		LCK_release(tdbb, cachedLock);
		invalidate(tdbb);
	}

	return true;
}
Example #11
0
bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait)
{
	SET_TDBB(tdbb);

	Database* dbb = tdbb->getDatabase();

	{	// scope 1

		Database::CheckoutLockGuard counterGuard(dbb, counterMutex);

		COS_TRACE(("(%p)->lockWrite stage 1 readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
			this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
		++pendingWriters;

		while (readers > 0 )
		{
			Database::Checkout checkoutDbb(dbb);
			noReaders.wait(counterMutex);
		}

		COS_TRACE(("(%p)->lockWrite stage 2 readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
			this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));

		while (currentWriter || pendingLock)
		{
			Database::Checkout checkoutDbb(dbb);
			writerFinished.wait(counterMutex);
		}

		COS_TRACE(("(%p)->lockWrite stage 3 readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
			this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));

		fb_assert(!readers && !currentWriter);

		if (cachedLock->lck_physical > LCK_none)
		{
			LCK_release(tdbb, cachedLock);	// To prevent self deadlock
			invalidate(tdbb);
		}

		++pendingLock;
	}


	COS_TRACE(("(%p)->lockWrite LCK_lock readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d), pendingLock(%d)",
		this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical, pendingLock));

	if (!LCK_lock(tdbb, cachedLock, LCK_write, wait))
	{
	    Database::CheckoutLockGuard counterGuard(dbb, counterMutex);
		--pendingLock;
	    if (--pendingWriters)
	    {
	        if (!currentWriter)
	            writerFinished.notifyAll();
	    }
	    return false;
	}

	{	// scope 2

		Database::CheckoutLockGuard counterGuard(dbb, counterMutex);

		--pendingLock;
		--pendingWriters;

		fb_assert(!currentWriter);

		currentWriter = true;

		COS_TRACE(("(%p)->lockWrite end readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
			this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));

		return fetch(tdbb);
	}
}
Example #12
0
// Remove a routine from cache.
void Routine::remove(thread_db* tdbb)
{
	SET_TDBB(tdbb);
	Jrd::Attachment* att = tdbb->getAttachment();

	// MET_procedure locks it. Lets unlock it now to avoid troubles later
	if (existenceLock)
		LCK_release(tdbb, existenceLock);

	// Routine that is being altered may have references
	// to it by other routines via pointer to current meta
	// data structure, so don't lose the structure or the pointer.
	if (checkCache(tdbb) && !(flags & Routine::FLAG_BEING_ALTERED))
		clearCache(tdbb);

	// deallocate all structure which were allocated.  The routine
	// blr is originally read into a new pool from which all request
	// are allocated.  That will not be freed up.

	if (existenceLock)
	{
		delete existenceLock;
		existenceLock = NULL;
	}

	// deallocate input param structures

	for (Array<NestConst<Parameter> >::iterator i = getInputFields().begin();
		 i != getInputFields().end(); ++i)
	{
		if (*i)
			delete i->getObject();
	}

	getInputFields().clear();

	// deallocate output param structures

	for (Array<NestConst<Parameter> >::iterator i = getOutputFields().begin();
		 i != getOutputFields().end(); ++i)
	{
		if (*i)
			delete i->getObject();
	}

	getOutputFields().clear();

	if (!useCount)
		releaseFormat();

	if (!(flags & Routine::FLAG_BEING_ALTERED) && useCount == 0)
		delete this;
	else
	{
		// Fully clear routine block. Some pieces of code check for empty
		// routine name and ID, this is why we do it.
		setName(QualifiedName());
		setSecurityName("");
		setId(0);
		setDefaultCount(0);
	}
}
Example #13
0
	void CryptoManager::cryptThread()
	{
		ISC_STATUS_ARRAY status_vector;

		try
		{
			// Try to take crypt mutex
			// If can't take that mutex - nothing to do, cryptThread already runs in our process
			MutexEnsureUnlock guard(cryptThreadMtx, FB_FUNCTION);
			if (!guard.tryEnter())
			{
				return;
			}

			// establish context
			UserId user;
			user.usr_user_name = "(Crypt thread)";

			Jrd::Attachment* const attachment = Jrd::Attachment::create(&dbb);
			RefPtr<SysAttachment> jAtt(new SysAttachment(attachment));
			attachment->att_interface = jAtt;
			attachment->att_filename = dbb.dbb_filename;
			attachment->att_user = &user;

			BackgroundContextHolder tdbb(&dbb, attachment, status_vector, FB_FUNCTION);
			tdbb->tdbb_quantum = SWEEP_QUANTUM;

			ULONG lastPage = getLastPage(tdbb);
			ULONG runpage = 1;
			Stack<ULONG> pages;

			// Take exclusive threadLock
			// If can't take that lock - nothing to do, cryptThread already runs somewhere
			if (!LCK_lock(tdbb, threadLock, LCK_EX, LCK_NO_WAIT))
			{
				return;
			}

			bool lckRelease = false;

			try
			{
				do
				{
					// Check is there some job to do
					while ((runpage = currentPage.exchangeAdd(+1)) < lastPage)
					{
						// forced terminate
						if (down)
						{
							break;
						}

						// nbackup state check
						if (dbb.dbb_backup_manager && dbb.dbb_backup_manager->getState() != nbak_state_normal)
						{
							if (currentPage.exchangeAdd(-1) >= lastPage)
							{
								// currentPage was set to last page by thread, closing database
								break;
							}
							THD_sleep(100);
							continue;
						}

						// scheduling
						if (--tdbb->tdbb_quantum < 0)
						{
							JRD_reschedule(tdbb, SWEEP_QUANTUM, true);
						}

						// writing page to disk will change it's crypt status in usual way
						WIN window(DB_PAGE_SPACE, runpage);
						Ods::pag* page = CCH_FETCH(tdbb, &window, LCK_write, pag_undefined);
						if (page && page->pag_type <= pag_max &&
							(bool(page->pag_flags & Ods::crypted_page) != crypt) &&
							Ods::pag_crypt_page[page->pag_type])
						{
							CCH_MARK(tdbb, &window);
							pages.push(runpage);
						}
						CCH_RELEASE_TAIL(tdbb, &window);

						// sometimes save currentPage into DB header
						++runpage;
						if ((runpage & 0x3FF) == 0)
						{
							writeDbHeader(tdbb, runpage, pages);
						}
					}

					// At this moment of time all pages with number < lastpage
					// are guaranteed to change crypt state. Check for added pages.
					lastPage = getLastPage(tdbb);

					// forced terminate
					if (down)
					{
						break;
					}
				} while (runpage < lastPage);

				// Finalize crypt
				if (!down)
				{
					writeDbHeader(tdbb, 0, pages);
				}

				// Release exclusive lock on StartCryptThread
				lckRelease = true;
				LCK_release(tdbb, threadLock);
			}
			catch (const Exception&)
			{
				try
				{
					if (!lckRelease)
					{
						// try to save current state of crypt thread
						if (!down)
						{
							writeDbHeader(tdbb, runpage, pages);
						}

						// Release exclusive lock on StartCryptThread
						LCK_release(tdbb, threadLock);
					}
				}
				catch (const Exception&)
				{ }

				throw;
			}
		}
		catch (const Exception& ex)
		{
			// Error during context creation - we can't even release lock
			iscLogException("Crypt thread:", ex);
		}
	}
Example #14
0
	void CryptoManager::startCryptThread(thread_db* tdbb)
	{
		// Try to take crypt mutex
		// If can't take that mutex - nothing to do, cryptThread already runs in our process
		MutexEnsureUnlock guard(cryptThreadMtx, FB_FUNCTION);
		if (!guard.tryEnter())
		{
			return;
		}

		// Take exclusive threadLock
		// If can't take that lock - nothing to do, cryptThread already runs somewhere
		if (!LCK_lock(tdbb, threadLock, LCK_EX, LCK_NO_WAIT))
		{
			// Cleanup lock manager error
			fb_utils::init_status(tdbb->tdbb_status_vector);

			return;
		}

		bool releasingLock = false;
		try
		{
			// Cleanup resources
			terminateCryptThread(tdbb);
			down = false;

			// Determine current page from the header
			Header hdr(tdbb, LCK_read);
			process = hdr->hdr_flags & Ods::hdr_crypt_process ? true : false;
			if (!process)
			{
				releasingLock = true;
				LCK_release(tdbb, threadLock);
				return;
			}
			currentPage.setValue(hdr->hdr_crypt_page);

			// Refresh encryption flag
			crypt = hdr->hdr_flags & Ods::hdr_encrypted ? true : false;

			// If we are going to start crypt thread, we need plugin to be loaded
			loadPlugin(hdr->hdr_crypt_plugin);

			// ready to go
			guard.leave();		// release in advance to avoid races with cryptThread()
			Thread::start(cryptThreadStatic, (THREAD_ENTRY_PARAM) this, 0, &cryptThreadId);
		}
		catch (const Firebird::Exception&)
		{
			if (!releasingLock)		// avoid secondary exception in catch
			{
				try
				{
					LCK_release(tdbb, threadLock);
				}
				catch (const Firebird::Exception&)
				{ }
			}

			throw;
		}
	}