/*********************************************************************//**
Get a minimum bounding box from a Predicate
@return the minimum bounding box */
UNIV_INLINE
rtr_mbr_t*
prdt_get_mbr_from_prdt( /*===================*/ const lock_prdt_t* prdt) /*!< in: the lock predicate */
{
rtr_mbr_t* mbr_loc = reinterpret_cast<rtr_mbr_t*>(prdt->data);
return(mbr_loc);
}
/*********************************************************************//**
Get a predicate from a lock
@return the predicate */
lock_prdt_t*
lock_get_prdt_from_lock( /*====================*/ const lock_t* lock) /*!< in: the lock */
{
lock_prdt_t* prdt = reinterpret_cast<lock_prdt_t*>(
&((reinterpret_cast<byte*>( const_cast<lock_t*>(&lock[1])))[
UNIV_WORD_SIZE]));
return(prdt);
}
/*********************************************************************//**
Get a minimum bounding box directly from a lock
@return the minimum bounding box*/
UNIV_INLINE
rtr_mbr_t*
lock_prdt_get_mbr_from_lock( /*========================*/ const lock_t* lock) /*!< in: the lock */
{
ut_ad(lock->type_mode & LOCK_PREDICATE);
/** Check whether two predicate locks are compatible with each other @param[in]prdt1firstpredicatelock @param[in]prdt2secondpredicatelock @param[in]oppredicatecomparisonoperator
@return true if consistent */ static bool
lock_prdt_consistent(
lock_prdt_t* prdt1,
lock_prdt_t* prdt2,
ulint op)
{ bool ret = false;
rtr_mbr_t* mbr1 = prdt_get_mbr_from_prdt(prdt1);
rtr_mbr_t* mbr2 = prdt_get_mbr_from_prdt(prdt2);
ulint action;
if (op) {
action = op;
} else { if (prdt2->op != 0 && (prdt1->op != prdt2->op)) { return(false);
}
action = prdt1->op;
}
switch (action) { case PAGE_CUR_CONTAIN:
ret = MBR_CONTAIN_CMP(mbr1, mbr2); break; case PAGE_CUR_DISJOINT:
ret = MBR_DISJOINT_CMP(mbr1, mbr2); break; case PAGE_CUR_MBR_EQUAL:
ret = MBR_EQUAL_CMP(mbr1, mbr2); break; case PAGE_CUR_INTERSECT:
ret = MBR_INTERSECT_CMP(mbr1, mbr2); break; case PAGE_CUR_WITHIN:
ret = MBR_WITHIN_CMP(mbr1, mbr2); break; default:
ib::error() << "invalid operator " << action;
ut_error;
}
return(ret);
}
/*********************************************************************//**
Checks if a predicate lock request for a new lock has to wait for
another lock.
@returntrueifnew lock has to wait for lock2 to be released */ bool
lock_prdt_has_to_wait( /*==================*/ const trx_t* trx, /*!< in: trx of new lock */ unsigned type_mode,/*!< in: precise mode of the new lock toset:LOCK_SorLOCK_X,possibly ORedtoLOCK_PREDICATEorLOCK_PRDT_PAGE,
LOCK_INSERT_INTENTION */
lock_prdt_t* prdt, /*!< in: lock predicate to check */ const lock_t* lock2) /*!< in: another record lock; NOTE that itisassumedthatthishasalockbit setonthesamerecordasinthenew
lock we are setting */
{
lock_prdt_t* cur_prdt = lock_get_prdt_from_lock(lock2);
/* If it is a page lock, then return true (conflict) */ if (type_mode & LOCK_PRDT_PAGE) {
ut_ad(lock2->type_mode & LOCK_PRDT_PAGE);
return(true);
}
/* Predicate lock does not conflicts with non-predicate lock */ if (!(lock2->type_mode & LOCK_PREDICATE)) { return(FALSE);
}
ut_ad(lock2->type_mode & LOCK_PREDICATE);
if (!(type_mode & LOCK_INSERT_INTENTION)) { /* PREDICATE locks without LOCK_INSERT_INTENTION flag donotneedtowaitforanything.Thisisbecause differentuserscanhaveconflictinglocktypes
on predicates. */
return(FALSE);
}
if (lock2->type_mode & LOCK_INSERT_INTENTION) {
/* No lock request needs to wait for an insert intentionlocktoberemoved.Thismakesitsimilar toGAPlock,thatallowsconflictinginsertintention
locks */ return(FALSE);
}
if (!lock_prdt_consistent(cur_prdt, prdt, 0)) { return(false);
}
return(TRUE);
}
return(FALSE);
}
/*********************************************************************//**
Checks if a transaction has a GRANTED stronger or equal predicate lock
on the page
@return lock or NULL */
UNIV_INLINE
lock_t*
lock_prdt_has_lock( /*===============*/
ulint precise_mode, /*!< in: LOCK_S or LOCK_X */
hash_cell_t& cell, /*!< hash table cell of id */ const page_id_t id, /*!< in: page identifier */
lock_prdt_t* prdt, /*!< in: The predicate to be
attached to the new lock */ const trx_t* trx) /*!< in: transaction */
{
ut_ad((precise_mode & LOCK_MODE_MASK) == LOCK_S
|| (precise_mode & LOCK_MODE_MASK) == LOCK_X);
ut_ad(!(precise_mode & LOCK_INSERT_INTENTION));
/* if the lock predicate operator is the same astheonetolook,andpredicatetestissuccessful,
then we find a lock */ if (cur_prdt->op == prdt->op
&& lock_prdt_consistent(cur_prdt, prdt, 0)) {
return(lock);
}
}
}
return(NULL);
}
/*********************************************************************//**
Checks if some other transaction has a conflicting predicate
lock request in the queue, so that we have to wait.
@return lock or NULL */ static
lock_t*
lock_prdt_other_has_conflicting( /*============================*/ unsigned mode, /*!< in: LOCK_S or LOCK_X, possiblyORedtoLOCK_PREDICATEor
LOCK_PRDT_PAGE, LOCK_INSERT_INTENTION */ const hash_cell_t& cell, /*!< in: hash table cell */ const page_id_t id, /*!< in: page identifier */
lock_prdt_t* prdt, /*!< in: Predicates (currently) theMinimumBoundingRectangle)
the new lock will be on */ const trx_t* trx) /*!< in: our transaction */
{ for (lock_t* lock = lock_sys_t::get_first(cell, id, PRDT_HEAPNO);
lock != NULL;
lock = lock_rec_get_next(PRDT_HEAPNO, lock)) {
if (lock->trx == trx) { continue;
}
if (lock_prdt_has_to_wait(trx, mode, prdt, lock)) { return(lock);
}
}
return(NULL);
}
/*********************************************************************//**
Reset the Minimum Bounding Rectangle (to a large area) */ static void
lock_prdt_enlarge_mbr( /*==================*/ const lock_t* lock, /*!< in/out: lock to modify */
rtr_mbr_t* mbr) /*!< in: Minimum Bounding Rectangle */
{
rtr_mbr_t* cur_mbr = lock_prdt_get_mbr_from_lock(lock);
if (cur_mbr->xmin > mbr->xmin) {
cur_mbr->xmin = mbr->xmin;
}
if (cur_mbr->ymin > mbr->ymin) {
cur_mbr->ymin = mbr->ymin;
}
if (cur_mbr->xmax < mbr->xmax) {
cur_mbr->xmax = mbr->xmax;
}
if (cur_mbr->ymax < mbr->ymax) {
cur_mbr->ymax = mbr->ymax;
}
}
/*********************************************************************//**
Reset the predicates to a "covering" (larger) predicates */ static void
lock_prdt_enlarge_prdt( /*===================*/
lock_t* lock, /*!< in/out: lock to modify */
lock_prdt_t* prdt) /*!< in: predicate */
{
rtr_mbr_t* mbr = prdt_get_mbr_from_prdt(prdt);
lock_prdt_enlarge_mbr(lock, mbr);
}
/*********************************************************************//**
Check two predicates' MBRs are the same
@returntrueif they are the same */ static bool
lock_prdt_is_same( /*==============*/
lock_prdt_t* prdt1, /*!< in: MBR with the lock */
lock_prdt_t* prdt2) /*!< in: MBR with the lock */
{
rtr_mbr_t* mbr1 = prdt_get_mbr_from_prdt(prdt1);
rtr_mbr_t* mbr2 = prdt_get_mbr_from_prdt(prdt2);
if (prdt1->op == prdt2->op && MBR_EQUAL_CMP(mbr1, mbr2)) { return(true);
}
return(false);
}
/*********************************************************************//**
Looks for a similar predicate lock struct by the same trx on the same page. This can be used to save space when a new record lock should be set on a page:
no newstruct is needed, if a suitable old one is found.
@return lock or NULL */ static
lock_t*
lock_prdt_find_on_page( /*===================*/ unsigned type_mode, /*!< in: lock type_mode field */ const buf_block_t* block, /*!< in: buffer block */
lock_prdt_t* prdt, /*!< in: MBR with the lock */ const trx_t* trx) /*!< in: transaction */
{ const page_id_t id{block->page.id()};
hash_cell_t& cell = *lock_sys.hash_get(type_mode).cell_get(id.fold());
if (lock->trx == trx
&& lock->type_mode == type_mode) { if (lock->type_mode & LOCK_PRDT_PAGE) { return(lock);
}
ut_ad(lock->type_mode & LOCK_PREDICATE);
if (lock_prdt_is_same(lock_get_prdt_from_lock(lock),
prdt)) { return(lock);
}
}
}
return(NULL);
}
/*********************************************************************//**
Adds a predicate lock request in the predicate lock queue.
@return lock where the bit was set */ static
lock_t*
lock_prdt_add_to_queue( /*===================*/ unsigned type_mode,/*!< in: lock mode, wait, predicate
etc. flags */ const buf_block_t* block, /*!< in: buffer block containing
the record */
dict_index_t* index, /*!< in: index of record */
trx_t* trx, /*!< in/out: transaction */
lock_prdt_t* prdt, /*!< in: Minimum Bounding Rectangle
the new lock will be on */ bool caller_owns_trx_mutex) /*!< in: TRUE if caller owns the
transaction mutex */
{
ut_ad(caller_owns_trx_mutex == trx->mutex_is_owner());
ut_ad(index->is_spatial());
ut_ad(!dict_index_is_online_ddl(index));
ut_ad(type_mode & (LOCK_PREDICATE | LOCK_PRDT_PAGE));
#ifdef UNIV_DEBUG switch (type_mode & LOCK_MODE_MASK) { case LOCK_X: case LOCK_S: break; default:
ut_error;
} #endif/* UNIV_DEBUG */
/* Try to extend a similar non-waiting lock on the same page */ if (!(type_mode & LOCK_WAIT)) { const page_id_t id{block->page.id()};
hash_cell_t& cell = *lock_sys.hash_get(type_mode).
cell_get(id.fold());
if (lock_t* lock = lock_prdt_find_on_page(type_mode, block,
prdt, trx)) { if (lock->type_mode & LOCK_PREDICATE) {
lock_prdt_enlarge_prdt(lock, prdt);
}
return lock;
}
}
create: /* Note: We will not pass any conflicting lock to lock_rec_create(),
because we should be moving an existing waiting lock request. */
ut_ad(!(type_mode & LOCK_WAIT) || trx->lock.wait_trx);
{
LockGuard g{lock_sys.prdt_hash, id}; /* Because this code is invoked for a running transaction by thethreadthatisservingthetransaction,itisnotnecessary
to hold trx->mutex here. */
ut_ad(lock_table_has(trx, index->table, LOCK_IX));
/* Only need to check locks on prdt_hash */ if (ut_d(lock_t *lock=) lock_sys_t::get_first(g.cell(), id, PRDT_HEAPNO))
{
ut_ad(lock->type_mode & LOCK_PREDICATE);
/* If another transaction has an explicit lock request which locks thepredicate,waitingorgranted,onthesuccessor,theinsert hastowait.
SimilartoGAPlock,wedonotconsiderlockfrominsertsconflicts
with each other */
if (err == DB_SUCCESS) /* Update the page max trx id field */
page_update_max_trx_id(block, buf_block_get_page_zip(block), trx->id, mtr);
return err;
}
/**************************************************************//**
Check whether any predicate lock in parent needs to propagate to
child page after split. */ void
lock_prdt_update_parent( /*====================*/
buf_block_t* left_block, /*!< in/out: page to be split */
buf_block_t* right_block, /*!< in/out: the new half page */
lock_prdt_t* left_prdt, /*!< in: MBR on the old page */
lock_prdt_t* right_prdt, /*!< in: MBR on the new page */ const page_id_t page_id) /*!< in: parent page */
{ auto fold= page_id.fold();
LockMutexGuard g{SRW_LOCK_CALL};
hash_cell_t& cell = *lock_sys.prdt_hash.cell_get(fold);
/* Get all locks in parent */ for (lock_t *lock = lock_sys_t::get_first(cell, page_id);
lock;
lock = lock_rec_get_next_on_page(lock)) {
lock_prdt_t* lock_prdt;
ulint op = PAGE_CUR_DISJOINT;
/* Check each lock in parent to see if it intersects with
left or right child */ if (!lock_prdt_consistent(lock_prdt, left_prdt, op)
&& !lock_prdt_find_on_page(lock->type_mode, left_block,
lock_prdt, lock->trx)) {
lock_prdt_add_to_queue(lock->type_mode,
left_block, lock->index,
lock->trx, lock_prdt, false);
}
/* Another transaction cannot have an implicit lock on the record, becausewhenwecomehere,wealreadyhavemodifiedtheclustered indexrecord,andthiswouldnothavebeenpossibleifanotheractive
transaction had modified this secondary index record. */
trx->mutex_unlock();
} else { if (!lock_rec_get_nth_bit(lock, PRDT_HEAPNO)) {
lock_rec_set_nth_bit(lock, PRDT_HEAPNO);
status = LOCK_REC_SUCCESS_CREATED;
}
}
}
if (status == LOCK_REC_SUCCESS_CREATED && type_mode == LOCK_PREDICATE) { /* Append the predicate in the lock record */
lock_prdt_set_prdt(lock, prdt);
}
return(err);
}
/*********************************************************************//**
Acquire a "Page" lock on a block
@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */
dberr_t
lock_place_prdt_page_lock( const page_id_t page_id, /*!< in: page identifier */
dict_index_t* index, /*!< in: secondary index */
que_thr_t* thr) /*!< in: query thread */
{
ut_ad(thr != NULL);
ut_ad(!high_level_read_only);
ut_ad(index->is_spatial());
ut_ad(!dict_index_is_online_ddl(index)); if (index->table->is_temporary()) { return DB_SUCCESS;
}
/* Another transaction cannot have an implicit lock on the record, becausewhenwecomehere,wealreadyhavemodifiedtheclustered indexrecord,andthiswouldnothavebeenpossibleifanotheractive
transaction had modified this secondary index record. */
/** Check whether there are R-tree Page lock on a page @param[in]trxtrxtotestthelock @param[in]page_idpageidentifier
@return true if there is none */ bool lock_test_prdt_page_lock(const trx_t *trx, const page_id_t page_id)
{
LockGuard g{lock_sys.prdt_page_hash, page_id};
lock_t *lock= lock_sys_t::get_first(g.cell(), page_id); return !lock || trx == lock->trx;
}
/*************************************************************//**
Moves the locks of a page to another page and resets the lock bits of
the donating records. */ void
lock_prdt_rec_move( /*===============*/ const buf_block_t* receiver, /*!< in: buffer block containing
the receiving record */ const page_id_t donator) /*!< in: target page */
{
LockMultiGuard g{lock_sys.prdt_hash, receiver->page.id(), donator};
/** Remove locks on a discarded SPATIAL INDEX page. @paramidpagetobediscarded
@param page whether to discard also from lock_sys.prdt_hash */ void lock_sys_t::prdt_page_free_from_discard(const page_id_t id, bool all)
{ constauto id_fold= id.fold();
rd_lock(SRW_LOCK_CALL); auto cell= prdt_page_hash.cell_get(id_fold); auto latch= hash_table::latch(cell);
latch->acquire();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.