Beispiel #1
0
GlobalRWLock::GlobalRWLock(thread_db* tdbb, MemoryPool& p, locktype_t lckType,
		lck_owner_t lock_owner, bool lock_caching, size_t lockLen, const UCHAR* lockStr)
	: PermanentStorage(p), pendingLock(0), readers(0), pendingWriters(0), currentWriter(false),
	  lockCaching(lock_caching), blocking(false)
{
	SET_TDBB(tdbb);

	cachedLock = FB_NEW_RPT(getPool(), lockLen) Lock();
	cachedLock->lck_type = static_cast<lck_t>(lckType);
	cachedLock->lck_owner_handle = LCK_get_owner_handle_by_type(tdbb, lock_owner);
	cachedLock->lck_length = lockLen;

	Database* dbb = tdbb->getDatabase();
	cachedLock->lck_dbb = dbb;
	cachedLock->lck_parent = dbb->dbb_lock;
	cachedLock->lck_object = this;
	cachedLock->lck_ast = lockCaching ? blocking_ast_cached_lock : NULL;
	memcpy(&cachedLock->lck_key, lockStr, lockLen);
}
Beispiel #2
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);
	}
}
Beispiel #3
0
bool GlobalRWLock::lockRead(thread_db* tdbb, SSHORT wait, const bool queueJump)
{
	SET_TDBB(tdbb);

	Database* dbb = tdbb->getDatabase();

	bool needFetch;

	{	// scope 1
		Database::CheckoutLockGuard counterGuard(dbb, counterMutex);

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

		while (true)
		{
			if (readers > 0 && queueJump)
			{
				COS_TRACE(("(%p)->lockRead queueJump", this));
				readers++;
				return true;
			}

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

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

			if (!pendingLock)
				break;

			counterMutex.leave();
			Database::Checkout checkoutDbb(dbb);
			counterMutex.enter();
		}

		needFetch = cachedLock->lck_physical < LCK_read;
		if (!needFetch)
		{
			++readers;
			return true;
		}

		++pendingLock;

		fb_assert(cachedLock->lck_physical == LCK_none);
	}

	if (!LCK_lock(tdbb, cachedLock, LCK_read, wait))
	{
	    Database::CheckoutLockGuard counterGuard(dbb, counterMutex);
		--pendingLock;
		return false;
	}

	{	// scope 2
		Database::CheckoutLockGuard counterGuard(dbb, counterMutex);

		--pendingLock;
		++readers;

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

		return fetch(tdbb);
	}
}
Beispiel #4
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);
	}
}