mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 06:03:02 +01:00
Implemented CORE-2644: Make lock table expandable on HPUX
This commit is contained in:
parent
74be1581ee
commit
ecbf4312a1
@ -32,7 +32,6 @@
|
||||
|
||||
#include "firebird.h"
|
||||
#include "../jrd/cch.h"
|
||||
#include "../jrd/que.h"
|
||||
#include "../jrd/gdsassert.h"
|
||||
#include "../jrd/common.h"
|
||||
#include "../jrd/dsc.h"
|
||||
|
@ -29,7 +29,6 @@
|
||||
|
||||
#include "firebird.h"
|
||||
#include "GlobalRWLock.h"
|
||||
#include "../lock/lock.h"
|
||||
#include "../lock/lock_proto.h"
|
||||
#include "isc_proto.h"
|
||||
#include "jrd.h"
|
||||
|
@ -363,6 +363,8 @@ extern "C" int remove(const char* path);
|
||||
|
||||
#ifdef HPUX
|
||||
|
||||
#define USE_SHMEM_EXT // Looks like everyone else can ISC_remap
|
||||
|
||||
#define UNIX
|
||||
//#define CURSES_KEYPAD
|
||||
|
||||
|
@ -894,9 +894,6 @@ typedef Firebird::HalfStaticArray<UCHAR, 256> MoveBuffer;
|
||||
|
||||
} //namespace Jrd
|
||||
|
||||
// Lock levels
|
||||
#include "../lock/lock.h"
|
||||
|
||||
// Random string block -- as long as impure areas don't have
|
||||
// constructors and destructors, the need this varying string
|
||||
|
||||
|
@ -108,8 +108,12 @@ inline bool QUE_EMPTY(const que& aque)
|
||||
// Self-relative queue BASE should be defined in the source which includes this
|
||||
#define SRQ_PTR SLONG
|
||||
|
||||
#ifndef SRQ_REL_PTR
|
||||
#define SRQ_REL_PTR(item) (SRQ_PTR) ((UCHAR*) item - SRQ_BASE)
|
||||
#endif
|
||||
#ifndef SRQ_ABS_PTR
|
||||
#define SRQ_ABS_PTR(item) (SRQ_BASE + item)
|
||||
#endif
|
||||
|
||||
// CVC: I cannot convert these four to inline functions because SRQ_BASE
|
||||
// is defined in event.cpp!
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "../jrd/common.h"
|
||||
#include "../jrd/ibase.h"
|
||||
#include "../jrd/isc.h"
|
||||
#include "../lock/lock.h"
|
||||
//#include "../lock/lock.h"
|
||||
|
||||
#ifdef WIN_NT
|
||||
#include <process.h>
|
||||
|
@ -40,9 +40,12 @@
|
||||
|
||||
#include "firebird.h"
|
||||
#include "../jrd/common.h"
|
||||
|
||||
#include "../lock/lock.h"
|
||||
#include "../lock/lock_proto.h"
|
||||
|
||||
#include "../jrd/ThreadStart.h"
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/isc.h"
|
||||
#include "gen/iberror.h"
|
||||
#include "../jrd/gds_proto.h"
|
||||
#include "../jrd/gdsassert.h"
|
||||
@ -55,8 +58,6 @@
|
||||
#include "../common/classes/semaphore.h"
|
||||
#include "../common/classes/init.h"
|
||||
#include "../common/classes/timestamp.h"
|
||||
#include "../lock/lock.h"
|
||||
#include "../lock/lock_proto.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
@ -191,6 +192,9 @@ LockManager::LockManager(const Firebird::string& id)
|
||||
m_dbId(getPool(), id),
|
||||
m_acquireSpins(Config::getLockAcquireSpins()),
|
||||
m_memorySize(Config::getLockMemSize())
|
||||
#ifdef USE_SHMEM_EXT
|
||||
, m_extents(getPool())
|
||||
#endif
|
||||
{
|
||||
ISC_STATUS_ARRAY local_status;
|
||||
if (!attach_shared_file(local_status))
|
||||
@ -245,10 +249,23 @@ LockManager::~LockManager()
|
||||
Firebird::PathName name;
|
||||
get_shared_file_name(name);
|
||||
ISC_remove_map_file(name.c_str());
|
||||
#ifdef USE_SHMEM_EXT
|
||||
for (ULONG i = 1; i < m_extents.getCount(); ++i)
|
||||
{
|
||||
get_shared_file_name(name, i);
|
||||
ISC_remove_map_file(name.c_str());
|
||||
}
|
||||
#endif //USE_SHMEM_EXT
|
||||
}
|
||||
release_mutex();
|
||||
|
||||
detach_shared_file(local_status);
|
||||
#ifdef USE_SHMEM_EXT
|
||||
for (ULONG i = 1; i < m_extents.getCount(); ++i)
|
||||
{
|
||||
ISC_unmap_file(local_status, &m_extents[i].sh_data);
|
||||
}
|
||||
#endif //USE_SHMEM_EXT
|
||||
|
||||
Firebird::MutexLockGuard guard(g_mapMutex);
|
||||
|
||||
@ -259,6 +276,39 @@ LockManager::~LockManager()
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_SHMEM_EXT
|
||||
SRQ_PTR LockManager::REL_PTR(const void* par_item)
|
||||
{
|
||||
const UCHAR* item = static_cast<const UCHAR*>(par_item);
|
||||
for (ULONG i = 0; i < m_extents.getCount(); ++i)
|
||||
{
|
||||
Extent& l = m_extents[i];
|
||||
UCHAR* adr = reinterpret_cast<UCHAR*>(l.table);
|
||||
if (item >= adr && item < adr + getExtendSize())
|
||||
{
|
||||
return getStartOffset(i) + (item - adr);
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
bug(NULL, "Extend not found in REL_PTR()");
|
||||
return 0; // compiler silencer
|
||||
}
|
||||
|
||||
|
||||
void* LockManager::ABS_PTR(SRQ_PTR item)
|
||||
{
|
||||
ULONG extent = item / getExtendSize();
|
||||
if (extent >= m_extents.getCount())
|
||||
{
|
||||
errno = 0;
|
||||
bug(NULL, "Extend not found in ABS_PTR()");
|
||||
}
|
||||
return reinterpret_cast<UCHAR*>(m_extents[extent].table) + (item % getExtendSize());
|
||||
}
|
||||
#endif //USE_SHMEM_EXT
|
||||
|
||||
|
||||
bool LockManager::attach_shared_file(ISC_STATUS* status)
|
||||
{
|
||||
Firebird::PathName name;
|
||||
@ -270,6 +320,9 @@ bool LockManager::attach_shared_file(ISC_STATUS* status)
|
||||
return false;
|
||||
|
||||
fb_assert(m_header->lhb_version == LHB_VERSION);
|
||||
#ifdef USE_SHMEM_EXT
|
||||
m_extents[0].sh_data = m_shmem;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -285,9 +338,15 @@ void LockManager::detach_shared_file(ISC_STATUS* status)
|
||||
}
|
||||
|
||||
|
||||
void LockManager::get_shared_file_name(Firebird::PathName& name) const
|
||||
void LockManager::get_shared_file_name(Firebird::PathName& name, ULONG extent) const
|
||||
{
|
||||
name.printf(LOCK_FILE, m_dbId.c_str());
|
||||
if (extent)
|
||||
{
|
||||
Firebird::PathName ename;
|
||||
ename.printf("%s.ext%d", name.c_str(), extent);
|
||||
name = ename;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1075,6 +1134,16 @@ void LockManager::acquire_shmem(SRQ_PTR owner_offset)
|
||||
owner->own_thread_id = getThreadId();
|
||||
}
|
||||
|
||||
#ifdef USE_SHMEM_EXT
|
||||
while (m_header->lhb_length > getTotalMapped())
|
||||
{
|
||||
if (! newExtent())
|
||||
{
|
||||
bug(NULL, "map of lock file extent failed");
|
||||
}
|
||||
}
|
||||
#else //USE_SHMEM_EXT
|
||||
|
||||
if (m_header->lhb_length > m_shmem.sh_mem_length_mapped
|
||||
#ifdef LOCK_DEBUG_REMAP
|
||||
// If we're debugging remaps, force a remap every-so-often.
|
||||
@ -1082,9 +1151,9 @@ void LockManager::acquire_shmem(SRQ_PTR owner_offset)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if (defined HAVE_MMAP || defined WIN_NT)
|
||||
const ULONG new_length = m_header->lhb_length;
|
||||
|
||||
#if (defined HAVE_MMAP || defined WIN_NT)
|
||||
Firebird::WriteLockGuard guard(m_remapSync);
|
||||
// Post remapping notifications
|
||||
remap_local_owners();
|
||||
@ -1100,6 +1169,7 @@ void LockManager::acquire_shmem(SRQ_PTR owner_offset)
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif //USE_SHMEM_EXT
|
||||
|
||||
// If we were able to acquire the MUTEX, but there is an prior owner marked
|
||||
// in the the lock table, it means that someone died while owning
|
||||
@ -1132,6 +1202,31 @@ void LockManager::acquire_shmem(SRQ_PTR owner_offset)
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_SHMEM_EXT
|
||||
namespace {
|
||||
void initializeExtent(void*, sh_mem*, bool) { }
|
||||
}
|
||||
|
||||
bool LockManager::newExtent()
|
||||
{
|
||||
Firebird::PathName name;
|
||||
get_shared_file_name(name, m_extents.getCount());
|
||||
ISC_STATUS_ARRAY local_status;
|
||||
|
||||
Extent extent;
|
||||
|
||||
if (!(extent.table = (lhb*) ISC_map_file(local_status, name.c_str(), initializeExtent,
|
||||
this, m_memorySize, &extent.sh_data)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_extents.add(extent);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
UCHAR* LockManager::alloc(USHORT size, ISC_STATUS* status_vector)
|
||||
{
|
||||
/**************************************
|
||||
@ -1146,13 +1241,21 @@ UCHAR* LockManager::alloc(USHORT size, ISC_STATUS* status_vector)
|
||||
**************************************/
|
||||
size = FB_ALIGN(size, FB_ALIGNMENT);
|
||||
ASSERT_ACQUIRED;
|
||||
const ULONG block = m_header->lhb_used;
|
||||
ULONG block = m_header->lhb_used;
|
||||
|
||||
// Make sure we haven't overflowed the lock table. If so, bump the size of the table.
|
||||
|
||||
if (m_header->lhb_used + size > m_header->lhb_length)
|
||||
{
|
||||
#if (defined HAVE_MMAP || defined WIN_NT)
|
||||
#ifdef USE_SHMEM_EXT
|
||||
// round up so next object starts at beginngin of next extent
|
||||
block = m_header->lhb_used = m_header->lhb_length;
|
||||
if (newExtent())
|
||||
{
|
||||
m_header->lhb_length += m_memorySize;
|
||||
}
|
||||
else
|
||||
#elif (defined HAVE_MMAP || defined WIN_NT)
|
||||
Firebird::WriteLockGuard guard(m_remapSync);
|
||||
// Post remapping notifications
|
||||
remap_local_owners();
|
||||
@ -2171,7 +2274,7 @@ SRQ_PTR LockManager::grant_or_que(thread_db* tdbb, lrq* request, lbl* lock, SSHO
|
||||
}
|
||||
|
||||
|
||||
void LockManager::init_owner_block(own* owner, UCHAR owner_type, LOCK_OWNER_T owner_id) const
|
||||
void LockManager::init_owner_block(own* owner, UCHAR owner_type, LOCK_OWNER_T owner_id)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -2225,6 +2328,15 @@ void LockManager::initialize(sh_mem* shmem_data, bool initializeMemory)
|
||||
m_header = (lhb*) shmem_data->sh_mem_address;
|
||||
m_sharedFileCreated = initializeMemory;
|
||||
|
||||
#ifdef USE_SHMEM_EXT
|
||||
if (m_extents.getCount() == 0)
|
||||
{
|
||||
Extent zero;
|
||||
zero.table = m_header;
|
||||
m_extents.push(zero);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!initializeMemory) {
|
||||
return;
|
||||
}
|
||||
|
266
src/lock/lock.h
266
src/lock/lock.h
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* PROGRAM: JRD Lock Manager
|
||||
* MODULE: lock.h
|
||||
* DESCRIPTION: Lock manager structure definitions
|
||||
* DESCRIPTION: Lock manager specific SRQ definition
|
||||
*
|
||||
* The contents of this file are subject to the Interbase Public
|
||||
* License Version 1.0 (the "License"); you may not use this file
|
||||
@ -41,267 +41,9 @@
|
||||
#ifndef ISC_LOCK_LOCK_H
|
||||
#define ISC_LOCK_LOCK_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if !defined(WIN_NT)
|
||||
#include <signal.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/sem.h>
|
||||
#ifdef USE_SHMEM_EXT
|
||||
#define SRQ_ABS_PTR(x) ABS_PTR(x)
|
||||
#define SRQ_REL_PTR(x) REL_PTR(x)
|
||||
#endif
|
||||
|
||||
#include "../jrd/common.h"
|
||||
#include "../jrd/file_params.h"
|
||||
#include "../jrd/que.h"
|
||||
|
||||
typedef FB_UINT64 LOCK_OWNER_T; // Data type for the Owner ID
|
||||
|
||||
// Maximum lock series for gathering statistics and querying data
|
||||
|
||||
const int LCK_MAX_SERIES = 7;
|
||||
|
||||
// Lock query data aggregates
|
||||
|
||||
const int LCK_MIN = 1;
|
||||
const int LCK_MAX = 2;
|
||||
const int LCK_CNT = 3;
|
||||
const int LCK_SUM = 4;
|
||||
const int LCK_AVG = 5;
|
||||
const int LCK_ANY = 6;
|
||||
|
||||
// Lock states
|
||||
// in LCK_convert the type of level is USHORT instead of UCHAR
|
||||
const UCHAR LCK_none = 0;
|
||||
const UCHAR LCK_null = 1;
|
||||
const UCHAR LCK_SR = 2; // Shared Read
|
||||
const UCHAR LCK_PR = 3; // Protected Read
|
||||
const UCHAR LCK_SW = 4; // Shared Write
|
||||
const UCHAR LCK_PW = 5; // Protected Write
|
||||
const UCHAR LCK_EX = 6; // Exclusive
|
||||
const UCHAR LCK_max = 7;
|
||||
|
||||
enum locklevel_t {LCK_read = LCK_PR, LCK_write = LCK_EX};
|
||||
|
||||
const SSHORT LCK_WAIT = 1;
|
||||
const SSHORT LCK_NO_WAIT = 0;
|
||||
|
||||
// Lock block types
|
||||
|
||||
const UCHAR type_null = 0;
|
||||
const UCHAR type_lhb = 1;
|
||||
const UCHAR type_lrq = 2;
|
||||
const UCHAR type_lbl = 3;
|
||||
const UCHAR type_his = 4;
|
||||
const UCHAR type_shb = 5;
|
||||
const UCHAR type_own = 6;
|
||||
const UCHAR type_lpr = 7;
|
||||
const UCHAR type_MAX = type_lpr;
|
||||
|
||||
// Version number of the lock table.
|
||||
// Must be increased every time the shmem layout is changed.
|
||||
const UCHAR BASE_LHB_VERSION = 17;
|
||||
|
||||
#if SIZEOF_VOID_P == 8
|
||||
const UCHAR PLATFORM_LHB_VERSION = 128; // 64-bit target
|
||||
#else
|
||||
const UCHAR PLATFORM_LHB_VERSION = 0; // 32-bit target
|
||||
#endif
|
||||
|
||||
const UCHAR LHB_VERSION = PLATFORM_LHB_VERSION + BASE_LHB_VERSION;
|
||||
|
||||
#ifndef SUPERSERVER
|
||||
#define USE_BLOCKING_THREAD
|
||||
#endif
|
||||
|
||||
#ifdef DEV_BUILD
|
||||
#define VALIDATE_LOCK_TABLE
|
||||
#endif
|
||||
|
||||
// Lock header block -- one per lock file, lives up front
|
||||
|
||||
struct lhb
|
||||
{
|
||||
UCHAR lhb_type; // memory tag - always type_lbh
|
||||
UCHAR lhb_version; // Version of lock table
|
||||
SRQ_PTR lhb_secondary; // Secondary lock header block
|
||||
SRQ_PTR lhb_active_owner; // Active owner, if any
|
||||
srq lhb_owners; // Que of active owners
|
||||
srq lhb_processes; // Que of active processes
|
||||
srq lhb_free_processes; // Free process blocks
|
||||
srq lhb_free_owners; // Free owner blocks
|
||||
srq lhb_free_locks; // Free lock blocks
|
||||
srq lhb_free_requests; // Free lock requests
|
||||
ULONG lhb_length; // Size of lock table
|
||||
ULONG lhb_used; // Bytes of lock table in use
|
||||
USHORT lhb_hash_slots; // Number of hash slots allocated
|
||||
USHORT lhb_flags; // Miscellaneous info
|
||||
struct mtx lhb_mutex; // Mutex controlling access
|
||||
SRQ_PTR lhb_history;
|
||||
ULONG lhb_scan_interval; // Deadlock scan interval (secs)
|
||||
ULONG lhb_acquire_spins;
|
||||
FB_UINT64 lhb_acquires;
|
||||
FB_UINT64 lhb_acquire_blocks;
|
||||
FB_UINT64 lhb_acquire_retries;
|
||||
FB_UINT64 lhb_retry_success;
|
||||
FB_UINT64 lhb_enqs;
|
||||
FB_UINT64 lhb_converts;
|
||||
FB_UINT64 lhb_downgrades;
|
||||
FB_UINT64 lhb_deqs;
|
||||
FB_UINT64 lhb_read_data;
|
||||
FB_UINT64 lhb_write_data;
|
||||
FB_UINT64 lhb_query_data;
|
||||
FB_UINT64 lhb_operations[LCK_MAX_SERIES];
|
||||
FB_UINT64 lhb_waits;
|
||||
FB_UINT64 lhb_denies;
|
||||
FB_UINT64 lhb_timeouts;
|
||||
FB_UINT64 lhb_blocks;
|
||||
FB_UINT64 lhb_wakeups;
|
||||
FB_UINT64 lhb_scans;
|
||||
FB_UINT64 lhb_deadlocks;
|
||||
srq lhb_data[LCK_MAX_SERIES];
|
||||
srq lhb_hash[1]; // Hash table
|
||||
};
|
||||
|
||||
// lhb_flags
|
||||
const USHORT LHB_lock_ordering = 1; // Lock ordering is enabled
|
||||
|
||||
// Secondary header block -- exists only in V3.3 and later lock managers.
|
||||
// It is pointed to by the word in the lhb that used to contain a pattern.
|
||||
|
||||
struct shb
|
||||
{
|
||||
UCHAR shb_type; // memory tag - always type_shb
|
||||
SRQ_PTR shb_history;
|
||||
SRQ_PTR shb_remove_node; // Node removing itself
|
||||
SRQ_PTR shb_insert_que; // Queue inserting into
|
||||
SRQ_PTR shb_insert_prior; // Prior of inserting queue
|
||||
};
|
||||
|
||||
// Lock block
|
||||
|
||||
struct lbl
|
||||
{
|
||||
UCHAR lbl_type; // mem tag: type_lbl=in use, type_null=free
|
||||
UCHAR lbl_state; // High state granted
|
||||
UCHAR lbl_size; // Key bytes allocated
|
||||
UCHAR lbl_length; // Key bytes used
|
||||
srq lbl_requests; // Requests granted
|
||||
srq lbl_lhb_hash; // Collision que for hash table
|
||||
srq lbl_lhb_data; // Lock data que by series
|
||||
SLONG lbl_data; // User data
|
||||
SRQ_PTR lbl_parent; // Parent
|
||||
UCHAR lbl_series; // Lock series
|
||||
UCHAR lbl_flags; // Unused. Misc flags
|
||||
USHORT lbl_pending_lrq_count; // count of lbl_requests with LRQ_pending
|
||||
USHORT lbl_counts[LCK_max]; // Counts of granted locks
|
||||
UCHAR lbl_key[1]; // Key value
|
||||
};
|
||||
|
||||
/* Lock requests */
|
||||
|
||||
struct lrq
|
||||
{
|
||||
UCHAR lrq_type; // mem tag: type_lrq=in use, type_null=free
|
||||
UCHAR lrq_requested; // Level requested
|
||||
UCHAR lrq_state; // State of lock request
|
||||
USHORT lrq_flags; // Misc crud
|
||||
SRQ_PTR lrq_owner; // Owner making request
|
||||
SRQ_PTR lrq_lock; // Lock requested
|
||||
SLONG lrq_data; // Lock data requested
|
||||
srq lrq_own_requests; // Locks granted for owner
|
||||
srq lrq_lbl_requests; // Que of requests (active, pending)
|
||||
srq lrq_own_blocks; // Owner block que
|
||||
lock_ast_t lrq_ast_routine; // Block ast routine
|
||||
void* lrq_ast_argument; // Ast argument
|
||||
};
|
||||
|
||||
// lrq_flags
|
||||
const USHORT LRQ_blocking = 1; // Request is blocking
|
||||
const USHORT LRQ_pending = 2; // Request is pending
|
||||
const USHORT LRQ_converting = 4; // Request is pending conversion
|
||||
const USHORT LRQ_rejected = 8; // Request is rejected
|
||||
const USHORT LRQ_timed_out = 16; // Wait timed out
|
||||
const USHORT LRQ_deadlock = 32; // Request has been seen by the deadlock-walk
|
||||
const USHORT LRQ_repost = 64; // Request block used for repost
|
||||
const USHORT LRQ_scanned = 128; // Request already scanned for deadlock
|
||||
const USHORT LRQ_blocking_seen = 256; // Blocking notification received by owner
|
||||
const USHORT LRQ_just_granted = 512; // Request is just granted and blocked owners still have not sent blocking AST
|
||||
|
||||
// Process block
|
||||
|
||||
struct prc
|
||||
{
|
||||
UCHAR prc_type; // memory tag - always type_lpr
|
||||
int prc_process_id; // Process ID
|
||||
srq prc_lhb_processes; // Process que
|
||||
srq prc_owners; // Owners
|
||||
event_t prc_blocking; // Blocking event block
|
||||
USHORT prc_flags; // Unused. Misc flags
|
||||
};
|
||||
|
||||
// Owner block
|
||||
|
||||
struct own
|
||||
{
|
||||
UCHAR own_type; // memory tag - always type_own
|
||||
UCHAR own_owner_type; // type of owner
|
||||
SSHORT own_count; // init count for the owner
|
||||
LOCK_OWNER_T own_owner_id; // Owner ID
|
||||
srq own_lhb_owners; // Owner que (global)
|
||||
srq own_prc_owners; // Owner que (process wide)
|
||||
srq own_requests; // Lock requests granted
|
||||
srq own_blocks; // Lock requests blocking
|
||||
SRQ_PTR own_pending_request; // Request we're waiting on
|
||||
SRQ_PTR own_process; // Process we belong to
|
||||
FB_THREAD_ID own_thread_id; // Last thread attached to the owner
|
||||
FB_UINT64 own_acquire_time; // lhb_acquires when owner last tried acquire()
|
||||
USHORT own_ast_count; // Number of ASTs being delivered
|
||||
event_t own_wakeup; // Wakeup event block
|
||||
USHORT own_flags; // Misc stuff
|
||||
};
|
||||
|
||||
// Flags in own_flags
|
||||
const USHORT OWN_blocking = 1; // Owner is blocking
|
||||
const USHORT OWN_scanned = 2; // Owner has been deadlock scanned
|
||||
const USHORT OWN_waiting = 4; // Owner is waiting inside wait_for_request()
|
||||
const USHORT OWN_wakeup = 8; // Owner has been awoken
|
||||
const USHORT OWN_signaled = 16; // Signal is thought to be delivered
|
||||
const USHORT OWN_timeout = 32; // Owner is waiting with timeout
|
||||
|
||||
// Lock manager history block
|
||||
|
||||
struct his
|
||||
{
|
||||
UCHAR his_type; // memory tag - always type_his
|
||||
UCHAR his_operation; // operation that occurred
|
||||
SRQ_PTR his_next; // SRQ_PTR to next item in history list
|
||||
SRQ_PTR his_process; // owner to record for this operation
|
||||
SRQ_PTR his_lock; // lock to record for operation
|
||||
SRQ_PTR his_request; // request to record for operation
|
||||
};
|
||||
|
||||
// his_operation definitions
|
||||
// should be UCHAR according to his_operation but is USHORT in lock.cpp:post_operation
|
||||
const UCHAR his_enq = 1;
|
||||
const UCHAR his_deq = 2;
|
||||
const UCHAR his_convert = 3;
|
||||
const UCHAR his_signal = 4;
|
||||
const UCHAR his_post_ast = 5;
|
||||
const UCHAR his_wait = 6;
|
||||
const UCHAR his_del_process = 7;
|
||||
const UCHAR his_del_lock = 8;
|
||||
const UCHAR his_del_request = 9;
|
||||
const UCHAR his_deny = 10;
|
||||
const UCHAR his_grant = 11;
|
||||
const UCHAR his_leave_ast = 12;
|
||||
const UCHAR his_scan = 13;
|
||||
const UCHAR his_dead = 14;
|
||||
const UCHAR his_enter = 15;
|
||||
const UCHAR his_bug = 16;
|
||||
const UCHAR his_active = 17;
|
||||
const UCHAR his_cleanup = 18;
|
||||
const UCHAR his_del_owner = 19;
|
||||
const UCHAR his_MAX = his_del_owner;
|
||||
|
||||
#endif // ISC_LOCK_LOCK_H
|
||||
|
@ -24,12 +24,281 @@
|
||||
#ifndef LOCK_LOCK_PROTO_H
|
||||
#define LOCK_LOCK_PROTO_H
|
||||
|
||||
#if defined(USE_SHMEM_EXT) && (! defined(SRQ_ABS_PTR))
|
||||
#define SRQ_ABS_PTR(x) ABS_PTR(x)
|
||||
#define SRQ_REL_PTR(x) REL_PTR(x)
|
||||
#endif
|
||||
|
||||
#include "../common/classes/semaphore.h"
|
||||
#include "../common/classes/GenericMap.h"
|
||||
#include "../common/classes/init.h"
|
||||
#include "../common/classes/RefCounted.h"
|
||||
#include "../common/classes/array.h"
|
||||
#include "../jrd/ThreadStart.h"
|
||||
#include "../lock/lock.h"
|
||||
#include "../jrd/isc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if !defined(WIN_NT)
|
||||
#include <signal.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/sem.h>
|
||||
#endif
|
||||
|
||||
#include "../jrd/common.h"
|
||||
#include "../jrd/file_params.h"
|
||||
#include "../jrd/que.h"
|
||||
|
||||
typedef FB_UINT64 LOCK_OWNER_T; // Data type for the Owner ID
|
||||
|
||||
// Maximum lock series for gathering statistics and querying data
|
||||
|
||||
const int LCK_MAX_SERIES = 7;
|
||||
|
||||
// Lock query data aggregates
|
||||
|
||||
const int LCK_MIN = 1;
|
||||
const int LCK_MAX = 2;
|
||||
const int LCK_CNT = 3;
|
||||
const int LCK_SUM = 4;
|
||||
const int LCK_AVG = 5;
|
||||
const int LCK_ANY = 6;
|
||||
|
||||
// Lock states
|
||||
// in LCK_convert the type of level is USHORT instead of UCHAR
|
||||
const UCHAR LCK_none = 0;
|
||||
const UCHAR LCK_null = 1;
|
||||
const UCHAR LCK_SR = 2; // Shared Read
|
||||
const UCHAR LCK_PR = 3; // Protected Read
|
||||
const UCHAR LCK_SW = 4; // Shared Write
|
||||
const UCHAR LCK_PW = 5; // Protected Write
|
||||
const UCHAR LCK_EX = 6; // Exclusive
|
||||
const UCHAR LCK_max = 7;
|
||||
|
||||
enum locklevel_t {LCK_read = LCK_PR, LCK_write = LCK_EX};
|
||||
|
||||
const SSHORT LCK_WAIT = 1;
|
||||
const SSHORT LCK_NO_WAIT = 0;
|
||||
|
||||
// Lock block types
|
||||
|
||||
const UCHAR type_null = 0;
|
||||
const UCHAR type_lhb = 1;
|
||||
const UCHAR type_lrq = 2;
|
||||
const UCHAR type_lbl = 3;
|
||||
const UCHAR type_his = 4;
|
||||
const UCHAR type_shb = 5;
|
||||
const UCHAR type_own = 6;
|
||||
const UCHAR type_lpr = 7;
|
||||
const UCHAR type_MAX = type_lpr;
|
||||
|
||||
// Version number of the lock table.
|
||||
// Must be increased every time the shmem layout is changed.
|
||||
const UCHAR BASE_LHB_VERSION = 17;
|
||||
|
||||
#if SIZEOF_VOID_P == 8
|
||||
const UCHAR PLATFORM_LHB_VERSION = 128; // 64-bit target
|
||||
#else
|
||||
const UCHAR PLATFORM_LHB_VERSION = 0; // 32-bit target
|
||||
#endif
|
||||
|
||||
const UCHAR LHB_VERSION = PLATFORM_LHB_VERSION + BASE_LHB_VERSION;
|
||||
|
||||
#ifndef SUPERSERVER
|
||||
#define USE_BLOCKING_THREAD
|
||||
#endif
|
||||
|
||||
#ifdef DEV_BUILD
|
||||
#define VALIDATE_LOCK_TABLE
|
||||
#endif
|
||||
|
||||
// Lock header block -- one per lock file, lives up front
|
||||
|
||||
struct lhb
|
||||
{
|
||||
UCHAR lhb_type; // memory tag - always type_lbh
|
||||
UCHAR lhb_version; // Version of lock table
|
||||
SRQ_PTR lhb_secondary; // Secondary lock header block
|
||||
SRQ_PTR lhb_active_owner; // Active owner, if any
|
||||
srq lhb_owners; // Que of active owners
|
||||
srq lhb_processes; // Que of active processes
|
||||
srq lhb_free_processes; // Free process blocks
|
||||
srq lhb_free_owners; // Free owner blocks
|
||||
srq lhb_free_locks; // Free lock blocks
|
||||
srq lhb_free_requests; // Free lock requests
|
||||
ULONG lhb_length; // Size of lock table
|
||||
ULONG lhb_used; // Bytes of lock table in use
|
||||
USHORT lhb_hash_slots; // Number of hash slots allocated
|
||||
USHORT lhb_flags; // Miscellaneous info
|
||||
struct mtx lhb_mutex; // Mutex controlling access
|
||||
SRQ_PTR lhb_history;
|
||||
ULONG lhb_scan_interval; // Deadlock scan interval (secs)
|
||||
ULONG lhb_acquire_spins;
|
||||
FB_UINT64 lhb_acquires;
|
||||
FB_UINT64 lhb_acquire_blocks;
|
||||
FB_UINT64 lhb_acquire_retries;
|
||||
FB_UINT64 lhb_retry_success;
|
||||
FB_UINT64 lhb_enqs;
|
||||
FB_UINT64 lhb_converts;
|
||||
FB_UINT64 lhb_downgrades;
|
||||
FB_UINT64 lhb_deqs;
|
||||
FB_UINT64 lhb_read_data;
|
||||
FB_UINT64 lhb_write_data;
|
||||
FB_UINT64 lhb_query_data;
|
||||
FB_UINT64 lhb_operations[LCK_MAX_SERIES];
|
||||
FB_UINT64 lhb_waits;
|
||||
FB_UINT64 lhb_denies;
|
||||
FB_UINT64 lhb_timeouts;
|
||||
FB_UINT64 lhb_blocks;
|
||||
FB_UINT64 lhb_wakeups;
|
||||
FB_UINT64 lhb_scans;
|
||||
FB_UINT64 lhb_deadlocks;
|
||||
srq lhb_data[LCK_MAX_SERIES];
|
||||
srq lhb_hash[1]; // Hash table
|
||||
};
|
||||
|
||||
// lhb_flags
|
||||
const USHORT LHB_lock_ordering = 1; // Lock ordering is enabled
|
||||
|
||||
// Secondary header block -- exists only in V3.3 and later lock managers.
|
||||
// It is pointed to by the word in the lhb that used to contain a pattern.
|
||||
|
||||
struct shb
|
||||
{
|
||||
UCHAR shb_type; // memory tag - always type_shb
|
||||
SRQ_PTR shb_history;
|
||||
SRQ_PTR shb_remove_node; // Node removing itself
|
||||
SRQ_PTR shb_insert_que; // Queue inserting into
|
||||
SRQ_PTR shb_insert_prior; // Prior of inserting queue
|
||||
};
|
||||
|
||||
// Lock block
|
||||
|
||||
struct lbl
|
||||
{
|
||||
UCHAR lbl_type; // mem tag: type_lbl=in use, type_null=free
|
||||
UCHAR lbl_state; // High state granted
|
||||
UCHAR lbl_size; // Key bytes allocated
|
||||
UCHAR lbl_length; // Key bytes used
|
||||
srq lbl_requests; // Requests granted
|
||||
srq lbl_lhb_hash; // Collision que for hash table
|
||||
srq lbl_lhb_data; // Lock data que by series
|
||||
SLONG lbl_data; // User data
|
||||
SRQ_PTR lbl_parent; // Parent
|
||||
UCHAR lbl_series; // Lock series
|
||||
UCHAR lbl_flags; // Unused. Misc flags
|
||||
USHORT lbl_pending_lrq_count; // count of lbl_requests with LRQ_pending
|
||||
USHORT lbl_counts[LCK_max]; // Counts of granted locks
|
||||
UCHAR lbl_key[1]; // Key value
|
||||
};
|
||||
|
||||
/* Lock requests */
|
||||
|
||||
struct lrq
|
||||
{
|
||||
UCHAR lrq_type; // mem tag: type_lrq=in use, type_null=free
|
||||
UCHAR lrq_requested; // Level requested
|
||||
UCHAR lrq_state; // State of lock request
|
||||
USHORT lrq_flags; // Misc crud
|
||||
SRQ_PTR lrq_owner; // Owner making request
|
||||
SRQ_PTR lrq_lock; // Lock requested
|
||||
SLONG lrq_data; // Lock data requested
|
||||
srq lrq_own_requests; // Locks granted for owner
|
||||
srq lrq_lbl_requests; // Que of requests (active, pending)
|
||||
srq lrq_own_blocks; // Owner block que
|
||||
lock_ast_t lrq_ast_routine; // Block ast routine
|
||||
void* lrq_ast_argument; // Ast argument
|
||||
};
|
||||
|
||||
// lrq_flags
|
||||
const USHORT LRQ_blocking = 1; // Request is blocking
|
||||
const USHORT LRQ_pending = 2; // Request is pending
|
||||
const USHORT LRQ_converting = 4; // Request is pending conversion
|
||||
const USHORT LRQ_rejected = 8; // Request is rejected
|
||||
const USHORT LRQ_timed_out = 16; // Wait timed out
|
||||
const USHORT LRQ_deadlock = 32; // Request has been seen by the deadlock-walk
|
||||
const USHORT LRQ_repost = 64; // Request block used for repost
|
||||
const USHORT LRQ_scanned = 128; // Request already scanned for deadlock
|
||||
const USHORT LRQ_blocking_seen = 256; // Blocking notification received by owner
|
||||
const USHORT LRQ_just_granted = 512; // Request is just granted and blocked owners still have not sent blocking AST
|
||||
|
||||
// Process block
|
||||
|
||||
struct prc
|
||||
{
|
||||
UCHAR prc_type; // memory tag - always type_lpr
|
||||
int prc_process_id; // Process ID
|
||||
srq prc_lhb_processes; // Process que
|
||||
srq prc_owners; // Owners
|
||||
event_t prc_blocking; // Blocking event block
|
||||
USHORT prc_flags; // Unused. Misc flags
|
||||
};
|
||||
|
||||
// Owner block
|
||||
|
||||
struct own
|
||||
{
|
||||
UCHAR own_type; // memory tag - always type_own
|
||||
UCHAR own_owner_type; // type of owner
|
||||
SSHORT own_count; // init count for the owner
|
||||
LOCK_OWNER_T own_owner_id; // Owner ID
|
||||
srq own_lhb_owners; // Owner que (global)
|
||||
srq own_prc_owners; // Owner que (process wide)
|
||||
srq own_requests; // Lock requests granted
|
||||
srq own_blocks; // Lock requests blocking
|
||||
SRQ_PTR own_pending_request; // Request we're waiting on
|
||||
SRQ_PTR own_process; // Process we belong to
|
||||
FB_THREAD_ID own_thread_id; // Last thread attached to the owner
|
||||
FB_UINT64 own_acquire_time; // lhb_acquires when owner last tried acquire()
|
||||
USHORT own_ast_count; // Number of ASTs being delivered
|
||||
event_t own_wakeup; // Wakeup event block
|
||||
USHORT own_flags; // Misc stuff
|
||||
};
|
||||
|
||||
// Flags in own_flags
|
||||
const USHORT OWN_blocking = 1; // Owner is blocking
|
||||
const USHORT OWN_scanned = 2; // Owner has been deadlock scanned
|
||||
const USHORT OWN_waiting = 4; // Owner is waiting inside wait_for_request()
|
||||
const USHORT OWN_wakeup = 8; // Owner has been awoken
|
||||
const USHORT OWN_signaled = 16; // Signal is thought to be delivered
|
||||
const USHORT OWN_timeout = 32; // Owner is waiting with timeout
|
||||
|
||||
// Lock manager history block
|
||||
|
||||
struct his
|
||||
{
|
||||
UCHAR his_type; // memory tag - always type_his
|
||||
UCHAR his_operation; // operation that occurred
|
||||
SRQ_PTR his_next; // SRQ_PTR to next item in history list
|
||||
SRQ_PTR his_process; // owner to record for this operation
|
||||
SRQ_PTR his_lock; // lock to record for operation
|
||||
SRQ_PTR his_request; // request to record for operation
|
||||
};
|
||||
|
||||
// his_operation definitions
|
||||
// should be UCHAR according to his_operation but is USHORT in lock.cpp:post_operation
|
||||
const UCHAR his_enq = 1;
|
||||
const UCHAR his_deq = 2;
|
||||
const UCHAR his_convert = 3;
|
||||
const UCHAR his_signal = 4;
|
||||
const UCHAR his_post_ast = 5;
|
||||
const UCHAR his_wait = 6;
|
||||
const UCHAR his_del_process = 7;
|
||||
const UCHAR his_del_lock = 8;
|
||||
const UCHAR his_del_request = 9;
|
||||
const UCHAR his_deny = 10;
|
||||
const UCHAR his_grant = 11;
|
||||
const UCHAR his_leave_ast = 12;
|
||||
const UCHAR his_scan = 13;
|
||||
const UCHAR his_dead = 14;
|
||||
const UCHAR his_enter = 15;
|
||||
const UCHAR his_bug = 16;
|
||||
const UCHAR his_active = 17;
|
||||
const UCHAR his_cleanup = 18;
|
||||
const UCHAR his_del_owner = 19;
|
||||
const UCHAR his_MAX = his_del_owner;
|
||||
|
||||
namespace Firebird {
|
||||
class AtomicCounter;
|
||||
@ -99,7 +368,7 @@ private:
|
||||
lrq* get_request(SRQ_PTR);
|
||||
void grant(lrq*, lbl*);
|
||||
SRQ_PTR grant_or_que(thread_db*, lrq*, lbl*, SSHORT);
|
||||
void init_owner_block(own*, UCHAR, LOCK_OWNER_T) const;
|
||||
void init_owner_block(own*, UCHAR, LOCK_OWNER_T);
|
||||
void initialize(sh_mem*, bool);
|
||||
void insert_data_que(lbl*);
|
||||
void insert_tail(SRQ, SRQ);
|
||||
@ -132,7 +401,7 @@ private:
|
||||
USHORT wait_for_request(thread_db*, lrq*, SSHORT);
|
||||
bool attach_shared_file(ISC_STATUS* status);
|
||||
void detach_shared_file(ISC_STATUS* status);
|
||||
void get_shared_file_name(Firebird::PathName&) const;
|
||||
void get_shared_file_name(Firebird::PathName&, ULONG extend = 0) const;
|
||||
|
||||
static THREAD_ENTRY_DECLARE blocking_action_thread(THREAD_ENTRY_PARAM arg)
|
||||
{
|
||||
@ -170,6 +439,34 @@ private:
|
||||
#ifdef WIN_NT
|
||||
struct mtx m_shmemMutex;
|
||||
#endif
|
||||
|
||||
#ifdef USE_SHMEM_EXT
|
||||
struct Extent
|
||||
{
|
||||
lhb* table;
|
||||
sh_mem sh_data;
|
||||
};
|
||||
Firebird::Array<Extent> m_extents;
|
||||
|
||||
ULONG getTotalMapped() const
|
||||
{
|
||||
return m_extents.getCount() * getExtendSize();
|
||||
}
|
||||
|
||||
ULONG getExtendSize() const
|
||||
{
|
||||
return m_memorySize;
|
||||
}
|
||||
|
||||
ULONG getStartOffset(ULONG n) const
|
||||
{
|
||||
return n * getExtendSize();
|
||||
}
|
||||
|
||||
SRQ_PTR REL_PTR(const void* item);
|
||||
void* ABS_PTR(SRQ_PTR item);
|
||||
bool newExtent();
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -40,7 +40,6 @@
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/lck.h"
|
||||
#include "../jrd/isc.h"
|
||||
#include "../lock/lock.h"
|
||||
#include "../jrd/gdsassert.h"
|
||||
#include "../jrd/db_alias.h"
|
||||
#include "../jrd/gds_proto.h"
|
||||
@ -486,16 +485,51 @@ int CLIB_ROUTINE main( int argc, char *argv[])
|
||||
ISC_mutex_lock(MUTEX);
|
||||
}
|
||||
|
||||
#ifdef USE_SHMEM_EXT
|
||||
ULONG extentSize = shmem_data.sh_mem_length_mapped;
|
||||
ULONG totalSize = LOCK_header->lhb_length;
|
||||
ULONG extentsCount = totalSize / extentSize + (totalSize % extentSize == 0 ? 0 : 1);
|
||||
|
||||
try
|
||||
{
|
||||
buffer = new UCHAR[extentsCount * extentSize];
|
||||
}
|
||||
catch (const Firebird::BadAlloc&)
|
||||
{
|
||||
FPRINTF(outfile, "Insufficient memory for lock statistics.\n");
|
||||
exit(FINI_OK);
|
||||
}
|
||||
|
||||
memcpy(buffer, LOCK_header, extentSize);
|
||||
|
||||
for (ULONG extent = 1; extent < extentsCount; ++extent)
|
||||
{
|
||||
Firebird::PathName extName;
|
||||
sh_mem extData;
|
||||
extName.printf("%s.ext%d", filename.c_str(), extent);
|
||||
UCHAR* ext = (UCHAR*) ISC_map_file(status_vector, extName.c_str(),
|
||||
prt_lock_init, NULL, 0, &extData);
|
||||
if (! ext)
|
||||
{
|
||||
FPRINTF(outfile, "Could not map extent number %d, file %s.\n", extent, extName.c_str());
|
||||
exit(FINI_OK);
|
||||
}
|
||||
memcpy(((UCHAR*) buffer) + extent * extentSize, ext, extentSize);
|
||||
ISC_unmap_file(status_vector, &extData);
|
||||
}
|
||||
|
||||
LOCK_header = (lhb*)(UCHAR*) buffer;
|
||||
#elif (defined HAVE_MMAP || defined WIN_NT)
|
||||
if (LOCK_header->lhb_length > shmem_data.sh_mem_length_mapped)
|
||||
{
|
||||
#if defined HAVE_MMAP || defined WIN_NT
|
||||
const ULONG length = LOCK_header->lhb_length;
|
||||
LOCK_header = (lhb*) ISC_remap_file(status_vector, &shmem_data, length, false);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sw_consistency)
|
||||
{
|
||||
#ifndef USE_SHMEM_EXT
|
||||
// To avoid changes in the lock file while we are dumping it - make
|
||||
// a local buffer, lock the lock file, copy it, then unlock the
|
||||
// lock file to let processing continue. Printing of the lock file
|
||||
@ -512,10 +546,11 @@ int CLIB_ROUTINE main( int argc, char *argv[])
|
||||
exit(FINI_OK);
|
||||
}
|
||||
|
||||
memcpy(buffer, LOCK_header, LOCK_header->lhb_length);
|
||||
ISC_mutex_unlock(MUTEX);
|
||||
|
||||
memcpy((UCHAR*) buffer, LOCK_header, LOCK_header->lhb_length);
|
||||
LOCK_header = (lhb*)(UCHAR*) buffer;
|
||||
#endif
|
||||
|
||||
ISC_mutex_unlock(MUTEX);
|
||||
|
||||
#ifdef WIN_NT
|
||||
ISC_mutex_fini(MUTEX);
|
||||
@ -559,6 +594,50 @@ int CLIB_ROUTINE main( int argc, char *argv[])
|
||||
LOCK_header = (lhb*)(UCHAR*) buffer;
|
||||
read(fd, LOCK_header, file_stat.st_size);
|
||||
close(fd);
|
||||
|
||||
#ifdef USE_SHMEM_EXT
|
||||
ULONG extentSize = file_stat.st_size;
|
||||
ULONG totalSize = LOCK_header->lhb_length;
|
||||
ULONG extentsCount = totalSize / extentSize + (totalSize % extentSize == 0 ? 0 : 1);
|
||||
UCHAR* newBuf = NULL;
|
||||
|
||||
try
|
||||
{
|
||||
newBuf = new UCHAR[extentsCount * extentSize];
|
||||
}
|
||||
catch (const Firebird::BadAlloc&)
|
||||
{
|
||||
FPRINTF(outfile, "Insufficient memory for lock statistics.\n");
|
||||
exit(FINI_OK);
|
||||
}
|
||||
|
||||
memcpy(newBuf, LOCK_header, extentSize);
|
||||
buffer = newBuf;
|
||||
|
||||
for (ULONG extent = 1; extent < extentsCount; ++extent)
|
||||
{
|
||||
Firebird::PathName extName;
|
||||
extName.printf("%s.ext%d", filename.c_str(), extent);
|
||||
|
||||
const int fd = open(extName.c_str(), O_RDONLY | O_BINARY);
|
||||
if (fd == -1)
|
||||
{
|
||||
FPRINTF(outfile, "Unable to open lock file extent number %d, file %s.\n",
|
||||
extent, extName.c_str());
|
||||
exit(FINI_OK);
|
||||
}
|
||||
|
||||
if (read(fd, ((UCHAR*) buffer) + extent * extentSize, extentSize) != extentSize)
|
||||
{
|
||||
FPRINTF(outfile, "Could not read lock file extent number %d, file %s.\n",
|
||||
extent, extName.c_str());
|
||||
exit(FINI_OK);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
LOCK_header = (lhb*)(UCHAR*) buffer;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "/sys5/usr/include/sys/ipc.h"
|
||||
#include "/sys5/usr/include/sys/shm.h"
|
||||
#include "/sys5/usr/include/sys/sem.h"
|
||||
#include "lock.h"
|
||||
//#include "lock.h"
|
||||
|
||||
int main( int argc, char **argv)
|
||||
{
|
||||
|
@ -37,7 +37,6 @@
|
||||
#include "../jrd/common.h"
|
||||
#include "../jrd/isc.h"
|
||||
#include "../jrd/isc_s_proto.h"
|
||||
#include "../lock/lock.h"
|
||||
#include "../lock/lock_proto.h"
|
||||
#include "../jrd/license.h"
|
||||
#include "../jrd/gds_proto.h"
|
||||
|
Loading…
Reference in New Issue
Block a user