⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lock0lock.c

📁 这是linux下运行的mysql软件包,可用于linux 下安装 php + mysql + apach 的网络配置
💻 C
📖 第 1 页 / 共 5 页
字号:
/******************************************************The transaction lock system(c) 1996 Innobase OyCreated 5/7/1996 Heikki Tuuri*******************************************************/#include "lock0lock.h"#ifdef UNIV_NONINL#include "lock0lock.ic"#endif#include "usr0sess.h"#include "trx0purge.h"#include "dict0mem.h"#include "trx0sys.h"/* 2 function prototypes copied from ha_innodb.cc: *//*****************************************************************If you want to print a thd that is not associated with the current thread,you must call this function before reserving the InnoDB kernel_mutex, toprotect MySQL from setting thd->query NULL. If you print a thd of the currentthread, we know that MySQL cannot modify thd->query, and it is not necessaryto call this. Call innobase_mysql_end_print_arbitrary_thd() after you releasethe kernel_mutex.NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for thisfunction! */voidinnobase_mysql_prepare_print_arbitrary_thd(void);/*============================================*//*****************************************************************Relases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd().NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for thisfunction! */voidinnobase_mysql_end_print_arbitrary_thd(void);/*========================================*//* Restricts the length of search we will do in the waits-forgraph of transactions */#define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000/* Restricts the recursion depth of the search we will do in the waits-forgraph of transactions */#define LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK 200/* When releasing transaction locks, this specifies how often we releasethe kernel mutex for a moment to give also others access to it */#define LOCK_RELEASE_KERNEL_INTERVAL	1000/* Safety margin when creating a new record lock: this many extra recordscan be inserted to the page without need to create a lock with a biggerbitmap */#define LOCK_PAGE_BITMAP_MARGIN		64/* An explicit record lock affects both the record and the gap before it.An implicit x-lock does not affect the gap, it only locks the indexrecord from read or update. If a transaction has modified or inserted an index record, thenit owns an implicit x-lock on the record. On a secondary index record,a transaction has an implicit x-lock also if it has modified theclustered index record, the max trx id of the page where the secondaryindex record resides is >= trx id of the transaction (or database recoveryis running), and there are no explicit non-gap lock requests on thesecondary index record.This complicated definition for a secondary index comes from theimplementation: we want to be able to determine if a secondary indexrecord has an implicit x-lock, just by looking at the present clusteredindex record, not at the historical versions of the record. Thecomplicated definition can be explained to the user so that there isnondeterminism in the access path when a query is answered: we may,or may not, access the clustered index record and thus may, or may not,bump into an x-lock set there.Different transaction can have conflicting locks set on the gap at thesame time. The locks on the gap are purely inhibitive: an insert cannotbe made, or a select cursor may have to wait if a different transactionhas a conflicting lock on the gap. An x-lock on the gap does not givethe right to insert into the gap.An explicit lock can be placed on a user record or the supremum record ofa page. The locks on the supremum record are always thought to be of the gaptype, though the gap bit is not set. When we perform an update of a recordwhere the size of the record changes, we may temporarily store its explicitlocks on the infimum record of the page, though the infimum otherwise nevercarries locks.A waiting record lock can also be of the gap type. A waiting lock requestcan be granted when there is no conflicting mode lock request by anothertransaction ahead of it in the explicit lock queue.In version 4.0.5 we added yet another explicit lock type: LOCK_REC_NOT_GAP.It only locks the record it is placed on, not the gap before the record.This lock type is necessary to emulate an Oracle-like READ COMMITTED isolationlevel.-------------------------------------------------------------------------RULE 1: If there is an implicit x-lock on a record, and there are non-gap-------lock requests waiting in the queue, then the transaction holding the implicitx-lock also has an explicit non-gap record x-lock. Therefore, as locks arereleased, we can grant locks to waiting lock requests purely by looking atthe explicit lock requests in the queue.RULE 3: Different transactions cannot have conflicting granted non-gap locks-------on a record at the same time. However, they can have conflicting granted gaplocks.RULE 4: If a there is a waiting lock request in a queue, no lock request,-------gap or not, can be inserted ahead of it in the queue. In record deletesand page splits new gap type locks can be created by the database managerfor a transaction, and without rule 4, the waits-for graph of transactionsmight become cyclic without the database noticing it, as the deadlock checkis only performed when a transaction itself requests a lock!-------------------------------------------------------------------------An insert is allowed to a gap if there are no explicit lock requests byother transactions on the next record. It does not matter if these lockrequests are granted or waiting, gap bit set or not, with the exceptionthat a gap type request set by another transaction to wait forits turn to do an insert is ignored. On the other hand, animplicit x-lock by another transaction does not prevent an insert, whichallows for more concurrency when using an Oracle-style sequence numbergenerator for the primary key with many transactions doing insertsconcurrently.A modify of a record is allowed if the transaction has an x-lock on therecord, or if other transactions do not have any non-gap lock requests on therecord.A read of a single user record with a cursor is allowed if the transactionhas a non-gap explicit, or an implicit lock on the record, or if the othertransactions have no x-lock requests on the record. At a page supremum aread is always allowed.In summary, an implicit lock is seen as a granted x-lock only on therecord, not on the gap. An explicit lock with no gap bit set is a lockboth on the record and the gap. If the gap bit is set, the lock is onlyon the gap. Different transaction cannot own conflicting locks on therecord at the same time, but they may own conflicting locks on the gap.Granted locks on a record give an access right to the record, but gap typelocks just inhibit operations.NOTE: Finding out if some transaction has an implicit x-lock on a secondaryindex record can be cumbersome. We may have to look at previous versions ofthe corresponding clustered index record to find out if a delete markedsecondary index record was delete marked by an active transaction, not bya committed one.FACT A: If a transaction has inserted a row, it can delete it any timewithout need to wait for locks.PROOF: The transaction has an implicit x-lock on every index record insertedfor the row, and can thus modify each record without the need to wait. Q.E.D.FACT B: If a transaction has read some result set with a cursor, it can readit again, and retrieves the same result set, if it has not modified theresult set in the meantime. Hence, there is no phantom problem. If thebiggest record, in the alphabetical order, touched by the cursor is removed,a lock wait may occur, otherwise not.PROOF: When a read cursor proceeds, it sets an s-lock on each user recordit passes, and a gap type s-lock on each page supremum. The cursor mustwait until it has these locks granted. Then no other transaction canhave a granted x-lock on any of the user records, and therefore cannotmodify the user records. Neither can any other transaction insert intothe gaps which were passed over by the cursor. Page splits and merges,and removal of obsolete versions of records do not affect this, becausewhen a user record or a page supremum is removed, the next record inheritsits locks as gap type locks, and therefore blocks inserts to the same gap.Also, if a page supremum is inserted, it inherits its locks from the successorrecord. When the cursor is positioned again at the start of the result set,the records it will touch on its course are either records it touchedduring the last pass or new inserted page supremums. It can immediatelyaccess all these records, and when it arrives at the biggest record, itnotices that the result set is complete. If the biggest record was removed,lock wait can occur because the next record only inherits a gap type lock,and a wait may be needed. Q.E.D. *//* If an index record should be changed or a new inserted, we must checkthe lock on the record or the next. When a read cursor starts reading,we will set a record level s-lock on each record it passes, except on theinitial record on which the cursor is positioned before we start to fetchrecords. Our index tree search has the convention that the B-treecursor is positioned BEFORE the first possibly matching record inthe search. Optimizations are possible here: if the record is searchedon an equality condition to a unique key, we could actually set a speciallock on the record, a lock which would not prevent any insert beforethis record. In the next key locking an x-lock set on a record alsoprevents inserts just before that record.	There are special infimum and supremum records on each page.A supremum record can be locked by a read cursor. This records cannot beupdated but the lock prevents insert of a user record to the end ofthe page.	Next key locks will prevent the phantom problem where new rowscould appear to SELECT result sets after the select operation has beenperformed. Prevention of phantoms ensures the serilizability oftransactions.	What should we check if an insert of a new record is wanted?Only the lock on the next record on the same page, because also thesupremum record can carry a lock. An s-lock prevents insertion, butwhat about an x-lock? If it was set by a searched update, then thereis implicitly an s-lock, too, and the insert should be prevented.What if our transaction owns an x-lock to the next record, but there isa waiting s-lock request on the next record? If this s-lock was placedby a read cursor moving in the ascending order in the index, we cannotdo the insert immediately, because when we finally commit our transaction,the read cursor should see also the new inserted record. So we shouldmove the read cursor backward from the the next record for it to pass overthe new inserted record. This move backward may be too cumbersome toimplement. If we in this situation just enqueue a second x-lock requestfor our transaction on the next record, then the deadlock mechanismnotices a deadlock between our transaction and the s-lock requesttransaction. This seems to be an ok solution.	We could have the convention that granted explicit record locks,lock the corresponding records from changing, and also lock the gapsbefore them from inserting. A waiting explicit lock request locks the gapbefore from inserting. Implicit record x-locks, which we derive from thetransaction id in the clustered index record, only lock the record itselffrom modification, not the gap before it from inserting.	How should we store update locks? If the search is done by a uniquekey, we could just modify the record trx id. Otherwise, we could put a recordx-lock on the record. If the update changes ordering fields of theclustered index record, the inserted new record needs no record lock inlock table, the trx id is enough. The same holds for a secondary indexrecord. Searched delete is similar to update.PROBLEM:What about waiting lock requests? If a transaction is waiting to make anupdate to a record which another modified, how does the other transactionknow to send the end-lock-wait signal to the waiting transaction? If we havethe convention that a transaction may wait for just one lock at a time, howdo we preserve it if lock wait ends?PROBLEM:Checking the trx id label of a secondary index record. In the case of amodification, not an insert, is this necessary? A secondary index recordis modified only by setting or resetting its deleted flag. A secondary indexrecord contains fields to uniquely determine the corresponding clusteredindex record. A secondary index record is therefore only modified if wealso modify the clustered index record, and the trx id checking is doneon the clustered index record, before we come to modify the secondary indexrecord. So, in the case of delete marking or unmarking a secondary indexrecord, we do not have to care about trx ids, only the locks in the locktable must be checked. In the case of a select from a secondary index, thetrx id is relevant, and in this case we may have to search the clusteredindex record.PROBLEM: How to update record locks when page is split or merged, or--------------------------------------------------------------------a record is deleted or updated?If the size of fields in a record changes, we perform the update bya delete followed by an insert. How can we retain the locks set orwaiting on the record? Because a record lock is indexed in the bitmapby the heap number of the record, when we remove the record from therecord list, it is possible still to keep the lock bits. If the pageis reorganized, we could make a table of old and new heap numbers,and permute the bitmaps in the locks accordingly. We can add to thetable a row telling where the updated record ended. If the update doesnot require a reorganization of the page, we can simply move the lockbits for the updated record to the position determined by its new heapnumber (we may have to allocate a new lock, if we run out of the bitmapin the old one).	A more complicated case is the one where the reinsertion of theupdated record is done pessimistically, because the structure of thetree may change.PROBLEM: If a supremum record is removed in a page merge, or a record---------------------------------------------------------------------removed in a purge, what to do to the waiting lock requests? In a split tothe right, we just move the lock requests to the new supremum. If a recordis removed, we could move the waiting lock request to its inheritor, thenext record in the index. But, the next record may already have lockrequests on its own queue. A new deadlock check should be made then. Maybeit is easier just to release the waiting transactions. They can then enqueuenew lock requests on appropriate records.PROBLEM: When a record is inserted, what locks should it inherit from the-------------------------------------------------------------------------upper neighbor? An insert of a new supremum record in a page split isalways possible, but an insert of a new user record requires that the upperneighbor does not have any lock requests by other transactions, granted orwaiting, in its lock queue. Solution: We can copy the locks as gap typelocks, so that also the waiting locks are transformed to granted gap typelocks on the inserted record. *//* LOCK COMPATIBILITY MATRIX *    IS IX S  X  AI * IS +  +  +  -  + * IX +  +  -  -  + * S  +  -  +  -  - * X  -  -  -  -  - * AI +  +  -  -  - * * Note that for rows, InnoDB only acquires S or X locks. * For tables, InnoDB normally acquires IS or IX locks. * S or X table locks are only acquired for LOCK TABLES. * Auto-increment (AI) locks are needed because of * statement-level MySQL binlog. * See also lock_mode_compatible(). */#ifdef UNIV_DEBUGibool	lock_print_waits	= FALSE;#endif /* UNIV_DEBUG *//* The lock system */lock_sys_t*	lock_sys	= NULL;/* A table lock */typedef struct lock_table_struct	lock_table_t;struct lock_table_struct{	dict_table_t*	table;	/* database table in dictionary cache */	UT_LIST_NODE_T(lock_t)			locks; 	/* list of locks on the same table */};/* Record lock for a page */typedef struct lock_rec_struct		lock_rec_t;struct lock_rec_struct{	ulint	space;		/* space id */	ulint	page_no;	/* page number */	ulint	n_bits;		/* number of bits in the lock bitmap */				/* NOTE: the lock bitmap is placed immediately				after the lock struct */};/* Lock struct */struct lock_struct{	trx_t*		trx;		/* transaction owning the lock */	UT_LIST_NODE_T(lock_t)					trx_locks;	/* list of the locks of the					transaction */	ulint		type_mode;	/* lock type, mode, LOCK_GAP or					LOCK_REC_NOT_GAP,					LOCK_INSERT_INTENTION,					wait flag, ORed */	hash_node_t	hash;		/* hash chain node for a record lock */	dict_index_t*	index;		/* index for a record lock */	union {		lock_table_t	tab_lock;/* table lock */		lock_rec_t	rec_lock;/* record lock */	} un_member;};/* We store info on the latest deadlock error to this buffer. InnoDBMonitor will then fetch it and print */ibool	lock_deadlock_found = FALSE;FILE*	lock_latest_err_file;/* Flags for recursive deadlock search */#define LOCK_VICTIM_IS_START	1#define LOCK_VICTIM_IS_OTHER	2/************************************************************************Checks if a lock request results in a deadlock. */staticiboollock_deadlock_occurs(/*=================*/			/* out: TRUE if a deadlock was detected and we			chose trx as a victim; FALSE if no deadlock, or			there was a deadlock, but we chose other			transaction(s) as victim(s) */	lock_t*	lock,	/* in: lock the transaction is requesting */	trx_t*	trx);	/* in: transaction *//************************************************************************Looks recursively for a deadlock. */staticulintlock_deadlock_recursive(/*====================*/				/* out: 0 if no deadlock found,				LOCK_VICTIM_IS_START if there was a deadlock				and we chose 'start' as the victim,				LOCK_VICTIM_IS_OTHER if a deadlock				was found and we chose some other trx as a				victim: we must do the search again in this				last case because there may be another				deadlock! */	trx_t*	start,		/* in: recursion starting point */	trx_t*	trx,		/* in: a transaction waiting for a lock */	lock_t*	wait_lock,	/* in: the lock trx is waiting to be granted */	ulint*	cost,		/* in/out: number of calculation steps thus				far: if this exceeds LOCK_MAX_N_STEPS_...				we return LOCK_VICTIM_IS_START */	uint depth);            /* in: recursion depth: if this exceeds				LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK, we				return LOCK_VICTIM_IS_START *//*************************************************************************Gets the type of a lock. */UNIV_INLINEulintlock_get_type(/*==========*/			/* out: LOCK_TABLE or LOCK_REC */	lock_t*	lock)	/* in: lock */{	ut_ad(lock);	return(lock->type_mode & LOCK_TYPE_MASK);}/*************************************************************************Gets the nth bit of a record lock. */UNIV_INLINEiboollock_rec_get_nth_bit(/*=================*/			/* out: TRUE if bit set */	lock_t*	lock,	/* in: record lock */	ulint	i)	/* in: index of the bit */{	ulint	byte_index;	ulint	bit_index;	ulint	b;	ut_ad(lock);	ut_ad(lock_get_type(lock) == LOCK_REC);	if (i >= lock->un_member.rec_lock.n_bits) {		return(FALSE);	}	byte_index = i / 8;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -