2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
2003-11-18 08:58:35 +01:00
|
|
|
* MODULE: rlck.cpp
|
2001-05-23 15:26:42 +02:00
|
|
|
* DESCRIPTION: Record and Relation Lock Manager
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Interbase 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.Inprise.com/IPL.html
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an
|
|
|
|
* "AS IS" basis, 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 Inprise Corporation
|
|
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
|
|
* Copyright (C) Inprise Corporation.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
2001-07-10 19:35:13 +02:00
|
|
|
* 2001.07.06 Sean Leyne - Code Cleanup, removed "#ifdef READONLY_DATABASE"
|
|
|
|
* conditionals, as the engine now fully supports
|
|
|
|
* readonly databases.
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "firebird.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/jrd.h"
|
|
|
|
#include "../jrd/tra.h"
|
|
|
|
#include "../jrd/lck.h"
|
|
|
|
#include "../jrd/req.h"
|
2003-11-11 13:19:20 +01:00
|
|
|
#include "gen/iberror.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/all.h"
|
|
|
|
#include "../jrd/all_proto.h"
|
|
|
|
#include "../jrd/err_proto.h"
|
|
|
|
#include "../jrd/isc_proto.h"
|
|
|
|
|
|
|
|
#include "../jrd/lck_proto.h"
|
|
|
|
#include "../jrd/rlck_proto.h"
|
|
|
|
#include "../jrd/thd_proto.h"
|
|
|
|
#include "../jrd/vio_proto.h"
|
|
|
|
|
2003-03-01 19:04:21 +01:00
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
static lck* allocate_record_lock(jrd_tra*, RPB *);
|
2003-03-01 19:04:21 +01:00
|
|
|
#endif
|
2004-02-20 07:43:27 +01:00
|
|
|
static lck* allocate_relation_lock(MemoryPool*, jrd_rel*);
|
2003-03-01 19:04:21 +01:00
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
static lck* attachment_relation_lock(jrd_rel*);
|
|
|
|
static void drop_record_lock(lck*);
|
|
|
|
static lck* find_record_lock(RPB *);
|
|
|
|
static BOOLEAN obtain_lock(jrd_tra*, lck*, USHORT);
|
2004-01-03 11:59:52 +01:00
|
|
|
static void start_record_locking(jrd_rel*);
|
2003-03-01 19:04:21 +01:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
lck* RLCK_lock_record(RPB * rpb,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT lock_level, int (*ast) (BLK), BLK ast_arg)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ l o c k _ r e c o r d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lock the current record in the provided
|
|
|
|
* record parameter block at the specified level.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-20 07:43:27 +01:00
|
|
|
// SLONG process_count;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* first get a record lock on the desired record;
|
|
|
|
if we can't get one then there is no point
|
|
|
|
in signalling that this process needs to acquire locks */
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
lck* lock = RLCK_lock_record_implicit(0, rpb, lock_level, ast, ast_arg);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!lock)
|
|
|
|
return NULL;
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/*
|
2001-05-23 15:26:42 +02:00
|
|
|
if the record is trying to be locked, check
|
2001-07-10 19:35:13 +02:00
|
|
|
whether the record has already been updated on page
|
2001-05-23 15:26:42 +02:00
|
|
|
by a transaction whose updates we cannot see yet--
|
|
|
|
in which case we effectively cannot get the lock */
|
|
|
|
|
|
|
|
if (VIO_check_if_updated(tdbb, rpb)) {
|
|
|
|
RLCK_unlock_record_implicit(lock, rpb);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if this process has no record locks outstanding,
|
|
|
|
indicate through the lock manager that we are
|
|
|
|
starting the record locking protocol */
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
jrd_rel* relation = rpb->rpb_relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!relation->rel_explicit_locks) {
|
2004-02-20 07:43:27 +01:00
|
|
|
lck* record_locking = RLCK_record_locking(relation);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* get a shared write lock to be compatible with other processes
|
|
|
|
that are doing record locking, but incompatible with those who aren't */
|
|
|
|
|
|
|
|
if (record_locking->lck_logical == LCK_none)
|
|
|
|
LCK_lock_non_blocking(tdbb, record_locking, LCK_SW, TRUE);
|
|
|
|
else
|
|
|
|
LCK_convert_non_blocking(tdbb, tdbb, record_locking, LCK_SW,
|
|
|
|
TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
relation->rel_explicit_locks++;
|
|
|
|
|
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
lck* RLCK_lock_record_implicit(jrd_tra* transaction,
|
2001-05-23 15:26:42 +02:00
|
|
|
RPB * rpb,
|
|
|
|
USHORT lock_level,
|
|
|
|
int (*ast) (BLK), BLK ast_arg)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ l o c k _ r e c o r d _ i m p l i c i t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lock the given record for implicit access, a subset
|
|
|
|
* of what we need to do to lock it explicitly.
|
|
|
|
*
|
|
|
|
* transaction is NULL for explicit record locking.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
USHORT interest_lock_level = 0;
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_rel* relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
lck* lock = allocate_record_lock(transaction, rpb);
|
2001-05-23 15:26:42 +02:00
|
|
|
lock->lck_ast = ast;
|
|
|
|
lock->lck_object = ast_arg;
|
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/* To ensure that relation and record locks respect each other,
|
2001-05-23 15:26:42 +02:00
|
|
|
utilize a multigranularity locking scheme, establishing
|
2001-07-10 19:35:13 +02:00
|
|
|
an interest lock level in the parent relation according to
|
2001-05-23 15:26:42 +02:00
|
|
|
the following scheme:
|
|
|
|
read lock on record := protected read
|
|
|
|
(implies) interest read lock on relation := shared read
|
|
|
|
write lock on record := exclusive
|
2001-07-10 19:35:13 +02:00
|
|
|
(implies) interest write lock on relation := shared write
|
|
|
|
Then as long as PR and EX locks are used to implement read
|
|
|
|
and write locking on relations, the relation locks will
|
2001-05-23 15:26:42 +02:00
|
|
|
be respected.
|
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
This also guarantees that implicit record locks won't result
|
|
|
|
in interest locks being taken out, since implicit record locks
|
|
|
|
are SW. Relations are already implicitly reserved in
|
2001-05-23 15:26:42 +02:00
|
|
|
RLCK_reserve_relation(), so there is no need for an additional
|
|
|
|
interest lock.
|
|
|
|
implicit read lock on record := NO LOCK
|
2001-07-10 19:35:13 +02:00
|
|
|
(implies) NO interest read lock on relation
|
2001-05-23 15:26:42 +02:00
|
|
|
implicit write lock on record := shared write
|
2001-07-10 19:35:13 +02:00
|
|
|
(implies) interest write lock on relation := shared write
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
relation = rpb->rpb_relation;
|
|
|
|
if (lock_level == LCK_EX) {
|
|
|
|
interest_lock_level = LCK_SW;
|
|
|
|
relation->rel_write_locks++;
|
|
|
|
relation->rel_lock_total++;
|
|
|
|
}
|
|
|
|
else if (lock_level == LCK_PR) {
|
|
|
|
interest_lock_level = LCK_SR;
|
|
|
|
relation->rel_read_locks++;
|
|
|
|
relation->rel_lock_total++;
|
|
|
|
}
|
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/* first attempt to get the parent lock then get the record lock,
|
2001-05-23 15:26:42 +02:00
|
|
|
using two-phase locking to help prevent deadlocks */
|
|
|
|
|
|
|
|
if (interest_lock_level
|
|
|
|
&& !obtain_lock(transaction, lock->lck_parent, interest_lock_level)
|
2003-12-22 11:00:59 +01:00
|
|
|
|| !obtain_lock(transaction, lock, lock_level))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
RLCK_unlock_record_implicit(lock, rpb);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
lck* RLCK_lock_relation(jrd_rel* relation,
|
2001-05-23 15:26:42 +02:00
|
|
|
USHORT lock_level, int (*ast) (BLK), BLK ast_arg)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ l o c k _ r e l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lock a relation at the specified level.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
/* allocate a relation lock hanging off the attachment
|
2001-07-10 19:35:13 +02:00
|
|
|
block, then keep a count of the number of times it
|
2001-05-23 15:26:42 +02:00
|
|
|
is used so that we know when to release it (bug #7478) */
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
lck* lock = attachment_relation_lock(relation);
|
2001-05-23 15:26:42 +02:00
|
|
|
lock->lck_count++;
|
|
|
|
lock->lck_ast = ast;
|
|
|
|
lock->lck_object = ast_arg;
|
|
|
|
|
|
|
|
if (!obtain_lock(0, lock, lock_level))
|
2003-11-11 13:19:20 +01:00
|
|
|
ERR_post(isc_relation_lock, isc_arg_string, relation->rel_name, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
lck* RLCK_range_relation(jrd_tra* transaction,
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_rel* relation, int (*ast) (BLK), BLK ast_arg)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ r a n g e _ r e l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lock a relation for a refresh range.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
USHORT level, wait;
|
|
|
|
USHORT result;
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
|
|
|
att* attachment = tdbb->tdbb_attachment;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (transaction->tra_flags & TRA_system)
|
|
|
|
return NULL;
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
lck* lock = allocate_relation_lock(transaction->tra_pool, relation);
|
2001-05-23 15:26:42 +02:00
|
|
|
lock->lck_owner = (BLK) attachment;
|
|
|
|
lock->lck_ast = ast;
|
|
|
|
lock->lck_object = ast_arg;
|
|
|
|
lock->lck_type = LCK_range_relation;
|
|
|
|
|
|
|
|
level = LCK_PR;
|
|
|
|
|
|
|
|
wait = (transaction->tra_flags & TRA_nowait) ? FALSE : TRUE;
|
|
|
|
|
|
|
|
/* get lock */
|
|
|
|
|
|
|
|
result = LCK_lock_non_blocking(tdbb, lock, level, wait);
|
|
|
|
|
|
|
|
if (result)
|
|
|
|
return lock;
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
lck* RLCK_record_locking(jrd_rel* relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ r e c o r d _ l o c k i n g
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Allocate a record locking lock, which determines
|
|
|
|
* when record locking is necessary for a particular
|
|
|
|
* relation.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
if (relation->rel_record_locking)
|
|
|
|
return relation->rel_record_locking;
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
|
|
|
DBB dbb = GET_DBB;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
lck* lock = FB_NEW_RPT(*dbb->dbb_permanent, sizeof(SLONG)) lck();
|
2001-05-23 15:26:42 +02:00
|
|
|
lock->lck_parent = dbb->dbb_lock;
|
|
|
|
lock->lck_dbb = dbb;
|
|
|
|
lock->lck_attachment = tdbb->tdbb_attachment;
|
|
|
|
lock->lck_type = LCK_record_locking;
|
|
|
|
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
|
|
|
|
|
|
|
|
/* make the lock specific to the relation */
|
|
|
|
|
|
|
|
lock->lck_length = sizeof(SLONG);
|
|
|
|
lock->lck_key.lck_long = relation->rel_id;
|
|
|
|
relation->rel_record_locking = lock;
|
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/* set up an ast to start record locking if
|
2001-05-23 15:26:42 +02:00
|
|
|
someone gets an incompatible lock */
|
|
|
|
|
|
|
|
lock->lck_ast = start_record_locking;
|
2002-03-31 01:40:08 +01:00
|
|
|
lock->lck_object = reinterpret_cast<blk*>(relation);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-10 19:35:13 +02:00
|
|
|
/* now attempt to get a PR on the lock to detect when
|
2001-05-23 15:26:42 +02:00
|
|
|
anyone locks a record explicitly */
|
|
|
|
|
|
|
|
LCK_lock(tdbb, _non_blocking(lock, LCK_PR, FALSE));
|
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
void RLCK_release_lock(lck* lock)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ r e l e a s e _ l o c k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release a lock of record or relation
|
|
|
|
* type. The lock handle came from the
|
|
|
|
* user, so validate it carefully.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
/* first do basic validation of the handle */
|
|
|
|
|
|
|
|
if (!lock)
|
2003-11-11 13:19:20 +01:00
|
|
|
ERR_post(isc_bad_lock_handle, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (((BLK) lock)->blk_type != (UCHAR) type_lck)
|
2003-11-11 13:19:20 +01:00
|
|
|
ERR_post(isc_bad_lock_handle, 0);
|
2001-07-10 19:35:13 +02:00
|
|
|
/* now use the lock type to determine the type
|
2001-05-23 15:26:42 +02:00
|
|
|
of lock to release */
|
|
|
|
if (lock->lck_type == LCK_relation)
|
2004-01-03 11:59:52 +01:00
|
|
|
RLCK_unlock_relation(0, (jrd_rel*) lock->lck_object);
|
2001-05-23 15:26:42 +02:00
|
|
|
else if (lock->lck_type == LCK_record)
|
|
|
|
RLCK_unlock_record(lock, 0);
|
|
|
|
else
|
2003-11-11 13:19:20 +01:00
|
|
|
ERR_post(isc_bad_lock_handle, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
|
|
|
void RLCK_release_locks(ATT attachment)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ r e l e a s e _ l o c k s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release all relation and record locks
|
|
|
|
* explicitly taken out during this attachment.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
VEC vector;
|
2001-12-24 03:51:06 +01:00
|
|
|
vec::iterator *lptr, *lend;
|
2001-05-23 15:26:42 +02:00
|
|
|
/* unlock all explicit relation locks */
|
2003-12-31 06:36:12 +01:00
|
|
|
if (vector = attachment->att_relation_locks) {
|
|
|
|
for (lptr = vector->begin(), lend = vector->end(); lptr < lend; lptr++) {
|
2004-02-20 07:43:27 +01:00
|
|
|
if (lock = ((lck*)(*lptr)) )
|
2004-01-03 11:59:52 +01:00
|
|
|
RLCK_unlock_relation(0, (jrd_rel*) lock->lck_object);
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
/* unlock all explicit record locks */
|
2003-12-31 06:36:12 +01:00
|
|
|
lck* lock;
|
|
|
|
while (lock = attachment->att_record_locks) {
|
2001-05-23 15:26:42 +02:00
|
|
|
RLCK_unlock_record(lock, 0);
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
/* clear the vector of user locks */
|
2003-12-31 06:36:12 +01:00
|
|
|
if (vector = attachment->att_lck_quick_ref) {
|
|
|
|
for (lptr = vector->begin(), lend = vector->end(); lptr < lend; lptr++) {
|
2001-05-23 15:26:42 +02:00
|
|
|
*lptr = NULL;
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
lck* RLCK_reserve_relation(TDBB tdbb,
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_tra* transaction,
|
|
|
|
jrd_rel* relation, USHORT write_flag, USHORT error_flag)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ r e s e r v e _ r e l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Lock a relation within a transaction. If the relation
|
|
|
|
* is already locked at a lower level, upgrade the lock.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
USHORT level, wait;
|
|
|
|
if (transaction->tra_flags & TRA_system)
|
|
|
|
return NULL;
|
|
|
|
if (write_flag && (tdbb->tdbb_database->dbb_flags & DBB_read_only))
|
|
|
|
ERR_post(isc_read_only_database, 0);
|
|
|
|
if (write_flag && (transaction->tra_flags & TRA_readonly))
|
2003-11-11 13:19:20 +01:00
|
|
|
ERR_post(isc_read_only_trans, 0);
|
2003-12-31 06:36:12 +01:00
|
|
|
lck* lock = RLCK_transaction_relation_lock(transaction, relation);
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Next, figure out what kind of lock we need */
|
|
|
|
if (transaction->tra_flags & TRA_degree3) {
|
|
|
|
if (write_flag)
|
|
|
|
level = LCK_EX;
|
|
|
|
else
|
|
|
|
level = LCK_PR;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (write_flag)
|
|
|
|
level = LCK_SW;
|
|
|
|
else
|
|
|
|
level = LCK_none;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the lock is already "good enough", we're done */
|
|
|
|
|
|
|
|
if (level <= lock->lck_logical)
|
|
|
|
return lock;
|
|
|
|
if (transaction->tra_flags & TRA_reserving)
|
2003-11-11 13:19:20 +01:00
|
|
|
ERR_post(isc_unres_rel, isc_arg_string, relation->rel_name, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
wait = (transaction->tra_flags & TRA_nowait) ? FALSE : TRUE;
|
|
|
|
/* get lock */
|
2003-12-31 06:36:12 +01:00
|
|
|
USHORT result;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (lock->lck_logical)
|
2003-09-01 13:08:30 +02:00
|
|
|
result = LCK_convert_non_blocking(NULL, lock, level, wait);
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
2003-09-01 13:08:30 +02:00
|
|
|
result = LCK_lock_non_blocking(NULL, lock, level, wait);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (result)
|
|
|
|
return lock;
|
|
|
|
else {
|
|
|
|
if (error_flag)
|
2003-11-11 13:19:20 +01:00
|
|
|
ERR_post((wait) ? isc_deadlock : isc_lock_conflict, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RLCK_shutdown_attachment(ATT attachment)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ s h u t d o w n _ a t t a c h m e n t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Shutdown the attachment's persistent record
|
|
|
|
* and relation locks. This runs at AST level.
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-12-24 03:51:06 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Release child record locks before parent relation locks */
|
2003-12-31 06:36:12 +01:00
|
|
|
for (lck* record_lock = attachment->att_record_locks;
|
2001-12-24 03:51:06 +01:00
|
|
|
record_lock;
|
|
|
|
record_lock = record_lock->lck_att_next)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
LCK_release(tdbb, record_lock);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
VEC lock_vector = attachment->att_relation_locks;
|
|
|
|
if (lock_vector) {
|
2003-12-31 06:36:12 +01:00
|
|
|
for (vec::iterator lock = lock_vector->begin();
|
|
|
|
lock != lock_vector->end(); ++lock)
|
|
|
|
{
|
2001-12-24 03:51:06 +01:00
|
|
|
if (*lock) {
|
2004-02-20 07:43:27 +01:00
|
|
|
LCK_release(tdbb, (lck*)(*lock));
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RLCK_shutdown_database(DBB dbb)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ s h u t d o w n _ d a t a b a s e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Shutdown the database locks shared for relation
|
|
|
|
* interest and record locking locks. This can be called
|
|
|
|
* at AST level.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
VEC vector;
|
2003-12-31 06:36:12 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!(vector = dbb->dbb_relations))
|
|
|
|
return;
|
2003-12-31 06:36:12 +01:00
|
|
|
|
|
|
|
vec::iterator ptr, end;
|
2001-12-24 03:51:06 +01:00
|
|
|
for (ptr = vector->begin(), end = vector->end(); ptr < end; ptr++)
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
|
|
|
jrd_rel* relation;
|
2004-01-03 11:59:52 +01:00
|
|
|
if ( (relation = ((jrd_rel*)(*ptr)) ) ) {
|
2001-05-23 15:26:42 +02:00
|
|
|
if (relation->rel_record_locking)
|
|
|
|
LCK_release(tdbb, relation->rel_record_locking);
|
|
|
|
if (relation->rel_interest_lock)
|
|
|
|
LCK_release(tdbb, relation->rel_interest_lock);
|
|
|
|
relation->rel_explicit_locks = 0;
|
|
|
|
relation->rel_read_locks = 0;
|
|
|
|
relation->rel_write_locks = 0;
|
|
|
|
relation->rel_lock_total = 0;
|
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-01-03 11:59:52 +01:00
|
|
|
void RLCK_signal_refresh(jrd_tra* transaction)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ s i g n a l _ r e f r e s h
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* For each reserved relation, get a refresh relation
|
|
|
|
* lock to signal possible refresh range users.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
USHORT i;
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_rel* relation;
|
2003-12-31 06:36:12 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
|
|
|
DBB dbb = tdbb->tdbb_database;
|
2001-05-23 15:26:42 +02:00
|
|
|
/* for each relation, take out a range relation lock and then release it */
|
2003-12-31 06:36:12 +01:00
|
|
|
vec* vector = transaction->tra_relation_locks;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (vector) {
|
|
|
|
|
|
|
|
/* allocate a local lock */
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
lck* local_lock = FB_NEW_RPT(*dbb->dbb_permanent, sizeof(SLONG)) lck();
|
2001-05-23 15:26:42 +02:00
|
|
|
local_lock->lck_dbb = dbb;
|
|
|
|
local_lock->lck_attachment = tdbb->tdbb_attachment;
|
|
|
|
local_lock->lck_length = sizeof(SLONG);
|
|
|
|
local_lock->lck_type = LCK_range_relation;
|
|
|
|
local_lock->lck_owner_handle =
|
|
|
|
LCK_get_owner_handle(tdbb, local_lock->lck_type);
|
|
|
|
local_lock->lck_parent = dbb->dbb_lock;
|
|
|
|
local_lock->lck_compatible = (BLK) tdbb->tdbb_attachment;
|
2001-12-24 03:51:06 +01:00
|
|
|
for (i = 0; i < vector->count(); i++) {
|
2004-02-20 07:43:27 +01:00
|
|
|
lck* lock = (lck**) ((*vector)[i]);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (lock) {
|
2004-01-03 11:59:52 +01:00
|
|
|
relation = (jrd_rel*) lock->lck_object;
|
2001-05-23 15:26:42 +02:00
|
|
|
local_lock->lck_key.lck_long = relation->rel_id;
|
2002-03-31 01:40:08 +01:00
|
|
|
local_lock->lck_object = reinterpret_cast<blk*>(relation);
|
2001-05-23 15:26:42 +02:00
|
|
|
LCK_lock_non_blocking(tdbb, local_lock, LCK_SW, 0);
|
|
|
|
LCK_release(tdbb, local_lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ALL_release(local_lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
lck* RLCK_transaction_relation_lock(jrd_tra* transaction, jrd_rel* relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ t r a n s a c t i o n _ r e l a t i o n _ l o c k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2001-07-10 19:35:13 +02:00
|
|
|
* Take out a relation lock within the context of
|
2001-05-23 15:26:42 +02:00
|
|
|
* a transaction.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
lck* lock;
|
2001-05-23 15:26:42 +02:00
|
|
|
VEC vector;
|
|
|
|
if ((vector = transaction->tra_relation_locks) &&
|
2001-12-24 03:51:06 +01:00
|
|
|
(relation->rel_id < vector->count()) &&
|
2004-02-20 07:43:27 +01:00
|
|
|
(lock = (lck*) (*vector)[relation->rel_id]))
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
return lock;
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2003-02-19 16:25:27 +01:00
|
|
|
|
|
|
|
vector = transaction->tra_relation_locks =
|
|
|
|
vec::newVector(*transaction->tra_pool, transaction->tra_relation_locks,
|
|
|
|
relation->rel_id + 1);
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
if ( (lock = (lck*) (*vector)[relation->rel_id]) )
|
2001-05-23 15:26:42 +02:00
|
|
|
return lock;
|
2003-02-19 16:25:27 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
lock = allocate_relation_lock(transaction->tra_pool, relation);
|
|
|
|
lock->lck_owner = (BLK) transaction;
|
2001-07-10 19:35:13 +02:00
|
|
|
/* for relations locked within a transaction, add a second level of
|
2001-05-23 15:26:42 +02:00
|
|
|
compatibility within the intra-process lock manager which specifies
|
|
|
|
that relation locks are incompatible with locks taken out by other
|
|
|
|
transactions, if a transaction is specified */
|
|
|
|
lock->lck_compatible2 = (BLK) transaction;
|
2001-12-24 03:51:06 +01:00
|
|
|
(*vector)[relation->rel_id] = (BLK) lock;
|
2003-02-19 16:25:27 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
void RLCK_unlock_record(lck* lock, RPB * rpb)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ u n l o c k _ r e c o r d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Unlock the specified record lock, or if
|
2001-07-10 19:35:13 +02:00
|
|
|
* it's not available use the current record
|
2001-05-23 15:26:42 +02:00
|
|
|
* in the specified record parameter block.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_rel* relation;
|
2004-02-20 07:43:27 +01:00
|
|
|
// SLONG process_count;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (rpb)
|
|
|
|
relation = rpb->rpb_relation;
|
|
|
|
else if (lock)
|
2004-01-03 11:59:52 +01:00
|
|
|
relation = (jrd_rel*) lock->lck_parent->lck_object;
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
|
|
|
relation = NULL; /* theoretically impossible */
|
|
|
|
RLCK_unlock_record_implicit(lock, rpb);
|
2003-12-31 06:36:12 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
|
|
|
att* attachment = tdbb->tdbb_attachment;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (attachment->att_flags & ATT_shutdown)
|
|
|
|
return;
|
|
|
|
/* decrement the count of explicit locks this process has taken out;
|
|
|
|
if there are none, go back to a PR on the lock--
|
|
|
|
if we cannot obtain this, it means someone else has explicit
|
|
|
|
record locks taken out and we should just release the lock */
|
|
|
|
if (relation && !--relation->rel_explicit_locks) {
|
2004-02-20 07:43:27 +01:00
|
|
|
lck* record_locking = relation->rel_record_locking;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!LCK_convert_non_blocking(tdbb, record_locking, LCK_PR, FALSE))
|
|
|
|
LCK_release(tdbb, record_locking);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
void RLCK_unlock_record_implicit(lck* lock, RPB * rpb)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ u n l o c k _ r e c o r d _ i m p l i c i t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2001-07-10 19:35:13 +02:00
|
|
|
* Unlock a record-level lock.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!lock)
|
|
|
|
lock = find_record_lock(rpb);
|
2003-12-31 06:36:12 +01:00
|
|
|
const USHORT lock_level = lock->lck_logical;
|
2001-05-23 15:26:42 +02:00
|
|
|
drop_record_lock(lock);
|
|
|
|
LCK_release(tdbb, lock);
|
2003-12-31 06:36:12 +01:00
|
|
|
att* attachment = tdbb->tdbb_attachment;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (attachment->att_flags & ATT_shutdown) {
|
|
|
|
ALL_release(lock);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle the release half of the multigranularity locking scheme:
|
|
|
|
if there are no more write locks, downgrade the interest
|
2001-07-10 19:35:13 +02:00
|
|
|
lock on the parent relation; if there are no more read or
|
2001-05-23 15:26:42 +02:00
|
|
|
write locks, release the lock entirely
|
|
|
|
|
|
|
|
For implicit locks, there are no relation intrest locks.
|
|
|
|
So do nothing.
|
|
|
|
*/
|
|
|
|
|
2004-01-03 11:59:52 +01:00
|
|
|
jrd_rel* relation = (jrd_rel*) lock->lck_parent->lck_object;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (lock_level == LCK_EX) {
|
|
|
|
if (!--relation->rel_write_locks)
|
|
|
|
if (!relation->rel_read_locks)
|
|
|
|
LCK_release(tdbb, relation->rel_interest_lock);
|
|
|
|
else
|
|
|
|
LCK_convert_non_blocking(tdbb, relation->rel_interest_lock,
|
|
|
|
LCK_SR, TRUE);
|
|
|
|
}
|
|
|
|
else if (lock_level == LCK_PR) {
|
|
|
|
if (!--relation->rel_read_locks && !relation->rel_write_locks)
|
|
|
|
LCK_release(tdbb, relation->rel_interest_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
ALL_release(lock);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
void RLCK_unlock_relation(lck* lock, jrd_rel* relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* R L C K _ u n l o c k _ r e l a t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Release the attachment's persistent lock
|
|
|
|
* on the specified relation.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
VEC vector;
|
|
|
|
USHORT id;
|
2003-12-31 06:36:12 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
|
|
|
att* attachment = tdbb->tdbb_attachment;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!(vector = attachment->att_relation_locks))
|
|
|
|
return;
|
|
|
|
if (relation) {
|
|
|
|
id = relation->rel_id;
|
2001-12-24 03:51:06 +01:00
|
|
|
if (id >= vector->count())
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
2004-02-20 07:43:27 +01:00
|
|
|
lock = (lck*) (*vector)[id];
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
2001-12-24 03:51:06 +01:00
|
|
|
for (id = 0; id < vector->count(); id++)
|
2004-02-20 07:43:27 +01:00
|
|
|
if (lock == (lck*) (*vector)[id])
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
if (!lock)
|
|
|
|
return;
|
2001-07-10 19:35:13 +02:00
|
|
|
/* decrement the use count; if it goes to zero,
|
|
|
|
there are no further locks taken out in this
|
2001-05-23 15:26:42 +02:00
|
|
|
attachment so we can release the lock (bug #7478) */
|
|
|
|
if (lock->lck_count > 1) {
|
|
|
|
lock->lck_count--;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LCK_release(tdbb, lock);
|
|
|
|
ALL_release(lock);
|
2001-12-24 03:51:06 +01:00
|
|
|
(*vector)[id] = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
static lck* allocate_record_lock(jrd_tra* transaction, RPB * rpb)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a l l o c a t e _ r e c o r d _ l o c k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Create a record lock block for the current
|
|
|
|
* record in the passed rpb.
|
|
|
|
* transaction used only for implicit record locks.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
|
|
|
DBB dbb = tdbb->tdbb_database;
|
|
|
|
att* attachment = tdbb->tdbb_attachment;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!rpb->rpb_record)
|
2003-11-11 13:19:20 +01:00
|
|
|
ERR_post(isc_no_cur_rec, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
/* allocate a lock block for the record lock */
|
2003-12-31 06:36:12 +01:00
|
|
|
lck* lock = FB_NEW_RPT(*dbb->dbb_permanent, sizeof(SLONG)) lck();
|
2001-05-23 15:26:42 +02:00
|
|
|
lock->lck_dbb = dbb;
|
|
|
|
lock->lck_attachment = attachment;
|
2002-03-31 01:40:08 +01:00
|
|
|
lock->lck_object = reinterpret_cast<blk*>(dbb);
|
2001-05-23 15:26:42 +02:00
|
|
|
lock->lck_type = LCK_record;
|
|
|
|
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
|
|
|
|
/* use the relation lock as the lock parent */
|
2003-12-31 06:36:12 +01:00
|
|
|
jrd_rel* relation = rpb->rpb_relation;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (transaction)
|
|
|
|
lock->lck_parent =
|
|
|
|
RLCK_transaction_relation_lock(transaction, relation);
|
|
|
|
else {
|
|
|
|
if (!relation->rel_interest_lock)
|
|
|
|
relation->rel_interest_lock =
|
|
|
|
allocate_relation_lock(dbb->dbb_permanent, relation);
|
|
|
|
lock->lck_parent = relation->rel_interest_lock;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* indicate that this lock should be compatible at the attachment
|
2001-07-10 19:35:13 +02:00
|
|
|
level--meaning that two record locks taken out within the same
|
2001-05-23 15:26:42 +02:00
|
|
|
attachment should always be compatible; ditto for the interest lock */
|
|
|
|
|
|
|
|
lock->lck_compatible = (BLK) attachment;
|
|
|
|
lock->lck_parent->lck_compatible = (BLK) attachment;
|
2001-07-10 19:35:13 +02:00
|
|
|
/* link in the record lock with the other record locks
|
2001-05-23 15:26:42 +02:00
|
|
|
taken out by this attachment */
|
|
|
|
lock->lck_att_next = attachment->att_record_locks;
|
|
|
|
attachment->att_record_locks = lock;
|
|
|
|
/* fill in the lock value using the record number */
|
|
|
|
lock->lck_length = sizeof(SLONG);
|
|
|
|
lock->lck_key.lck_long = rpb->rpb_number;
|
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|
2004-02-20 07:43:27 +01:00
|
|
|
static lck* allocate_relation_lock(MemoryPool* pool, jrd_rel* relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a l l o c a t e _ r e l a t i o n _ l o c k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Allocate a lock block for a relation lock.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
|
|
|
DBB dbb = tdbb->tdbb_database;
|
|
|
|
lck* lock = FB_NEW_RPT(*pool, sizeof(SLONG)) lck();
|
2001-05-23 15:26:42 +02:00
|
|
|
lock->lck_dbb = dbb;
|
|
|
|
lock->lck_attachment = tdbb->tdbb_attachment;
|
|
|
|
lock->lck_length = sizeof(SLONG);
|
|
|
|
lock->lck_key.lck_long = relation->rel_id;
|
|
|
|
lock->lck_type = LCK_relation;
|
|
|
|
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
|
|
|
|
lock->lck_parent = dbb->dbb_lock;
|
2001-07-10 19:35:13 +02:00
|
|
|
/* enter all relation locks into the intra-process lock manager and treat
|
2001-05-23 15:26:42 +02:00
|
|
|
them as compatible within the attachment according to IPLM rules */
|
|
|
|
lock->lck_compatible = (BLK) tdbb->tdbb_attachment;
|
|
|
|
/* the lck_object is used here to find the relation
|
|
|
|
block from the lock block */
|
2002-03-31 01:40:08 +01:00
|
|
|
lock->lck_object = reinterpret_cast<blk*>(relation);
|
2001-05-23 15:26:42 +02:00
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
|
2003-03-03 09:48:40 +01:00
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
static lck* attachment_relation_lock(jrd_rel* relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a t t a c h m e n t _ r e l a t i o n _ l o c k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Take out a persistent relation lock at the
|
|
|
|
* attachment level.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-02-20 07:43:27 +01:00
|
|
|
lck* lock;
|
2001-05-23 15:26:42 +02:00
|
|
|
VEC vector;
|
2003-12-31 06:36:12 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
|
|
|
DBB dbb = tdbb->tdbb_database;
|
|
|
|
att* attachment = tdbb->tdbb_attachment;
|
2003-02-19 16:25:27 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if ((vector = attachment->att_relation_locks) &&
|
2001-12-24 03:51:06 +01:00
|
|
|
(relation->rel_id < vector->count()) &&
|
2004-02-20 07:43:27 +01:00
|
|
|
(lock = (lck*) (*vector)[relation->rel_id]))
|
2001-05-23 15:26:42 +02:00
|
|
|
return lock;
|
2003-02-19 16:25:27 +01:00
|
|
|
|
|
|
|
vector = attachment->att_relation_locks =
|
|
|
|
vec::newVector(*dbb->dbb_permanent, attachment->att_relation_locks,
|
|
|
|
relation->rel_id + 1);
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
if ( (lock = (lck*) (*vector)[relation->rel_id]) )
|
2001-05-23 15:26:42 +02:00
|
|
|
return lock;
|
2003-02-19 16:25:27 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
lock = allocate_relation_lock(dbb->dbb_permanent, relation);
|
|
|
|
lock->lck_owner = (BLK) attachment;
|
2001-12-24 03:51:06 +01:00
|
|
|
(*vector)[relation->rel_id] = (BLK) lock;
|
2003-02-19 16:25:27 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
return lock;
|
|
|
|
}
|
2003-03-03 09:48:40 +01:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
static void drop_record_lock(lck* record_lock)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d r o p _ r e c o r d _ l o c k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Find the record lock in the linked list off
|
|
|
|
* the attachment block, and drop it from the list.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
/* look through all the record locks taken out by this attachment
|
|
|
|
looking for one with the same record number and relation id */
|
2003-12-31 06:36:12 +01:00
|
|
|
att* attachment = tdbb->tdbb_attachment;
|
|
|
|
for (lck** lock = &attachment->att_record_locks; *lock;
|
2003-09-13 14:03:11 +02:00
|
|
|
lock = &(*lock)->lck_att_next)
|
|
|
|
{
|
|
|
|
if (*lock == record_lock) {
|
2001-05-23 15:26:42 +02:00
|
|
|
*lock = (*lock)->lck_att_next;
|
|
|
|
break;
|
|
|
|
}
|
2003-09-13 14:03:11 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
static lck* find_record_lock(RPB * rpb)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* f i n d _ r e c o r d _ l o c k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2001-07-10 19:35:13 +02:00
|
|
|
* Find the record lock previously
|
2001-05-23 15:26:42 +02:00
|
|
|
* defined for a record.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
/* look through all the record locks taken out by this attachment
|
|
|
|
looking for one with the same record number and relation */
|
2003-12-31 06:36:12 +01:00
|
|
|
att* attachment = tdbb->tdbb_attachment;
|
|
|
|
lck* lock;
|
2001-05-23 15:26:42 +02:00
|
|
|
for (lock = attachment->att_record_locks; lock; lock = lock->lck_att_next)
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if ((rpb->rpb_number == lock->lck_key.lck_long)
|
2004-01-03 11:59:52 +01:00
|
|
|
&& (rpb->rpb_relation == (jrd_rel*) lock->lck_parent->lck_object))
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-03-03 09:48:40 +01:00
|
|
|
#ifdef PC_ENGINE
|
2004-02-20 07:43:27 +01:00
|
|
|
static BOOLEAN obtain_lock(jrd_tra* transaction, lck* lock, USHORT lock_level)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* o b t a i n _ l o c k
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2001-07-10 19:35:13 +02:00
|
|
|
* Obtain the specified lock at the
|
2001-05-23 15:26:42 +02:00
|
|
|
* necessary level.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
USHORT wait_flag;
|
|
|
|
if (transaction)
|
|
|
|
wait_flag = (transaction->tra_flags & TRA_nowait) ? FALSE : TRUE;
|
|
|
|
else
|
|
|
|
wait_flag = FALSE;
|
|
|
|
/* return if lock level OK and if the lock has not been released
|
|
|
|
(like as part of a refresh range) */
|
|
|
|
if ((lock_level <= lock->lck_logical) && (lock->lck_id != -1))
|
|
|
|
return TRUE;
|
|
|
|
if ((lock->lck_logical) && (lock->lck_id != -1)) {
|
2003-09-01 13:08:30 +02:00
|
|
|
if (LCK_convert_non_blocking(NULL, lock, lock_level, wait_flag))
|
2001-05-23 15:26:42 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
2003-09-01 13:08:30 +02:00
|
|
|
else if (LCK_lock_non_blocking(NULL, lock, lock_level, wait_flag))
|
2001-05-23 15:26:42 +02:00
|
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
2003-03-03 09:48:40 +01:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef PC_ENGINE
|
2004-01-03 11:59:52 +01:00
|
|
|
static void start_record_locking(jrd_rel* relation)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s t a r t _ r e c o r d _ l o c k i n g
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* A blocking AST has been issued to give up
|
|
|
|
* the lock on the record locking semaphore.
|
|
|
|
* Flag the fact that record locking is now
|
|
|
|
* necessary for reading and writing records.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
lck* record_locking = relation->rel_record_locking;
|
2001-07-10 19:35:13 +02:00
|
|
|
/* if we have shared write, it means we have records
|
2001-05-23 15:26:42 +02:00
|
|
|
locked; we won't give up this lock for anyone! */
|
|
|
|
if (record_locking->lck_physical == LCK_SW)
|
|
|
|
return;
|
|
|
|
ISC_ast_enter();
|
2003-09-01 13:08:30 +02:00
|
|
|
LCK_release(NULL, record_locking);
|
2001-05-23 15:26:42 +02:00
|
|
|
ISC_ast_exit();
|
|
|
|
}
|
2001-07-29 19:42:23 +02:00
|
|
|
#endif
|