8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 06:43:04 +01:00
firebird-mirror/src/jrd/GlobalRWLock.h
2008-12-05 00:56:15 +00:00

173 lines
5.4 KiB
C++

/*
* PROGRAM: JRD Access Method
* MODULE: GlobalRWLock.h
* DESCRIPTION: Cached Object Synchronizer
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Nickolay Samofatov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2006 Nickolay Samofatov
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*
*/
#include "../common/classes/alloc.h"
#include "../jrd/jrd.h"
#include "../jrd/lck.h"
#include "../jrd/lck_proto.h"
#include "../include/fb_types.h"
#include "os/pio.h"
//#define COS_DEBUG
#ifdef COS_DEBUG
DEFINE_TRACE_ROUTINE(cos_trace);
#define COS_TRACE(args) cos_trace args
#define COS_TRACE_AST(message) gds__trace(message)
#else
#define COS_TRACE(args) /* nothing */
#define COS_TRACE_AST(message) /* nothing */
#endif
namespace Jrd {
typedef USHORT locktype_t;
struct ObjectOwnerData
{
SLONG owner_handle;
ULONG entry_count;
static const SLONG& generate(const void* sender, const ObjectOwnerData& value)
{
return value.owner_handle;
}
ObjectOwnerData()
{
owner_handle = 0;
entry_count = 0;
}
};
/*
* Architecture goals for the class
* - Lock to protect intra-process cached resources with object-oriented interface:
* invalidate()/fetch()
* - Two lock modes: LCK_read (LCK_PR) and LCK_write (LCK_EX)
* - Support for lock recursion (multiple acquires of a lock by a given owner)
* - Flexible execution environment
* - Multiple threads
* - Multiple processes
* - Signals
* - Locks belong to logical owners (typically type ATTACHMENT or DATABASE, but
* potentially also THREAD and PROCESS)
* - Logical ownership of a lock may change during the object access lifecycle
* (somewhat special case, happens if cached resource needs to be passed from
* one worker thread to another without releasing the lock)
*
* Implementation constraints
* - Avoid calling lock manager for synchronization in non-contention case
* (for performance reasons, especially in DLM environments)
* - All contention to be handled via Lock manager to ensure reliable deadlock
* detection and to be monitored and debuggable via standard means
*/
class GlobalRWLock : public Firebird::PermanentStorage
{
public:
GlobalRWLock(thread_db* tdbb, MemoryPool& p, locktype_t lckType,
size_t lockLen, const UCHAR* lockStr,
lck_owner_t physical_lock_owner = LCK_OWNER_database,
lck_owner_t default_logical_lock_owner = LCK_OWNER_attachment,
bool lock_caching = true);
virtual ~GlobalRWLock();
// As usual,
// wait = 0 - try to lock a thing instantly (doesn't send ASTs)
// wait < 0 - timeout in seconds (doesn't deadlock)
// wait > 0 - infinite wait (may deadlock)
//
// This function returns false if it cannot take the lock
bool lock(thread_db* tdbb, const locklevel_t level, SSHORT wait, SLONG owner_handle);
bool lock(thread_db* tdbb, const locklevel_t level, SSHORT wait)
{
return lock(tdbb, level, wait, LCK_get_owner_handle_by_type(tdbb, defaultLogicalLockOwner));
}
// NOTE: unlock method must be signal safe
// This function may be called in AST. The function doesn't wait.
void unlock(thread_db* tdbb, const locklevel_t level, SLONG owner_handle);
void unlock(thread_db* tdbb, const locklevel_t level)
{
unlock(tdbb, level, LCK_get_owner_handle_by_type(tdbb, defaultLogicalLockOwner));
}
// Change the lock owner. The function doesn't wait.
void changeLockOwner(thread_db* tdbb, locklevel_t level, SLONG old_owner_handle, SLONG new_owner_handle);
SLONG getLockData() const
{
return cached_lock->lck_data;
}
void setLockData(thread_db* tdbb, SLONG lck_data);
// Release physical lock if possible. Use to force refetch
// Returns true if lock was released
bool tryReleaseLock(thread_db* tdbb);
Database* getDatabase()
{
return dbb;
}
protected:
Lock* cached_lock;
// Flag to indicate that somebody is waiting via lock manager.
// If somebody uses lock manager, all concurrent requests should also
// go via lock manager to prevent starvation.
int internal_blocking;
bool external_blocking; // Unprocessed AST pending
// Load the object from shared location.
virtual void fetch(thread_db* tdbb) {}
// May be called under AST. Should not throw exceptions.
virtual void invalidate(thread_db* tdbb, bool ast_handler) {}
virtual void blockingAstHandler(thread_db* tdbb);
private:
Firebird::Mutex lockMutex; // Protects status of logical lock, counters and blocking flag
lck_owner_t physicalLockOwner; // Holds cached lock
lck_owner_t defaultLogicalLockOwner; // Requests new lock to replace cached
// true - unlock keep cached lock and release by AST.
// false - unlock releases cached lock if possible
bool lockCaching;
Database* dbb;
Firebird::SortedArray<ObjectOwnerData, Firebird::EmptyStorage<ObjectOwnerData>,
SLONG, ObjectOwnerData, Firebird::DefaultComparator<SLONG> > readers;
ObjectOwnerData writer;
static int blocking_ast_cached_lock(void* ast_object);
};
}