innodb 트 랜 잭 션 잠 금 의 일반적인 데이터 구조

lock_sys_t
전체 innodb 의 잠 금 시스템 관리 구조 체 는 lock0 lock. h 에 정의 되 어 있 습 니 다.lock 0 lock. cc 에 lock 이 있 습 니 다.sys_t 의 전역 포인터 locksys, locksys_create 할당.
/** The lock system struct */
struct lock_sys_t{
    char        pad1[CACHE_LINE_SIZE];  /*!< padding to prevent other
                        memory update hotspots from
                        residing on the same memory
                        cache line */
    LockMutex   mutex;          /*!< Mutex protecting the
                        locks */
    /*       */
    hash_table_t*   rec_hash;       /*!< hash table of the record
                        locks */
    /*         */
    hash_table_t*   prdt_hash;      /*!< hash table of the predicate
                        lock */
    /*      */
    hash_table_t*   prdt_page_hash;     /*!< hash table of the page
                        lock */

    char        pad2[CACHE_LINE_SIZE];  /*!< Padding */
    LockMutex   wait_mutex;     /*!< Mutex protecting the
                        next two fields */
    /*               */
    srv_slot_t* waiting_threads;    /*!< Array  of user threads
                        suspended while waiting for
                        locks within InnoDB, protected
                        by the lock_sys->wait_mutex */
    /*          ,          */
    srv_slot_t* last_slot;      /*!< highest slot ever used
                        in the waiting_threads array,
                        protected by
                        lock_sys->wait_mutex */
    ibool       rollback_complete;
                        /*!< TRUE if rollback of all
                        recovered transactions is
                        complete. Protected by
                        lock_sys->mutex */

    ulint       n_lock_max_wait_time;   /*!< Max wait time */

    /*                */
    os_event_t  timeout_event;      /*!< Set to the event that is
                        created in the lock wait monitor
                        thread. A value of 0 means the
                        thread is not active */

    bool        timeout_thread_active;  /*!< True if the timeout thread
                        is running */
};

그 중의 rechash,prdt_hash, prdt_page_hash 는 줄 자물쇠, 시계 자물쇠, 페이지 자물쇠 의 해시 표 입 니 다.
lock_rec_t
잠 금 을 기록 하 는 구조 체 를 설명 하고 lock0priv. h 로 정의 합 니 다.
struct lock_rec_t {
    ib_uint32_t space;      /*!< space id */
    ib_uint32_t page_no;    /*!< page number */
    ib_uint32_t n_bits;     /*!< number of bits in the lock
                    bitmap; NOTE: the lock bitmap is
                    placed immediately after the
                    lock struct */

    /** Print the record lock into the given output stream
    @param[in,out]  out the output stream
    @return the given output stream. */
    std::ostream& print(std::ostream& out) const;
};

기록 잠 금 통과 space: pageno:heap_no 로 유일 하 게 확인, space 와 pageno. 해시 표 에서 사용 하 는 key 를 계산 합 니 다. 이 구조 체 는 실제 적 으로 분 배 된 메모리 가 그 자체 보다 큽 니 다. 뒤에 바짝 붙 어 있 는 것 은 하나의 비트 맵 입 니 다. 모든 비트 는 이 페이지 에 있 는 기록 에 자 물 쇠 를 추가 해 야 하 는 지 여 부 를 나타 내 는 데 사 용 됩 니 다. 모든 비트 의 오프셋 은 모든 기록 의 힙 입 니 다.no。
lock_table_t
표 잠 금 구조 체, lock0priv. h 에 정의
/** A table lock */
struct lock_table_t {
    /*    */
    dict_table_t*   table;      /*!< database table in dictionary
                    cache */
    /*            */
    UT_LIST_NODE_T(lock_t)
            locks;      /*!< list of locks on the same
                    table */
    /** Print the table lock into the given output stream
    @param[in,out]  out the output stream
    @return the given output stream. */
    std::ostream& print(std::ostream& out) const;
};

lock_t
lock0prive. h 에서 통용 되 는 자물쇠 구조 체 유형 을 정의 합 니 다. 각종 유형의 자 물 쇠 는 이런 구조 체 로 표현 할 수 있 습 니 다. locksys_t 의 해시 표 에 저 장 된 자물쇠 도 이런 유형의 자물쇠 구조 체 이다.
/** Lock struct; protected by lock_sys->mutex */
struct lock_t {
    /*         */
    trx_t*      trx;        /*!< transaction owning the
                    lock */
    /*                 */
    UT_LIST_NODE_T(lock_t)
            trx_locks;  /*!< list of the locks of the
                    transaction */

    dict_index_t*   index;      /*!< index for a record lock */
    
    /*       key            */
    lock_t*     hash;       /*!< hash chain node for a record
                    lock. The link node in a singly linked
                    list, used during hashing. */

    /*       lock_table_t,        lock_rec_t,  type_mode     */
    union {
        lock_table_t    tab_lock;/*!< table lock */
        lock_rec_t  rec_lock;/*!< record lock */
    } un_member;            /*!< lock details */
    
    /*                ,type_mode        lock0lock.h (LOCK_GAP  )*/
    ib_uint32_t type_mode;  /*!< lock type, mode, LOCK_GAP or
                    LOCK_REC_NOT_GAP,
                    LOCK_INSERT_INTENTION,
                    wait flag, ORed */

    /** Determine if the lock object is a record lock.
    @return true if record lock, false otherwise. */
    bool is_record_lock() const
    {
        return(type() == LOCK_REC);
    }

    bool is_waiting() const
    {
        return(type_mode & LOCK_WAIT);
    }

    bool is_gap() const
    {
        return(type_mode & LOCK_GAP);
    }

    bool is_record_not_gap() const
    {
        return(type_mode & LOCK_REC_NOT_GAP);
    }

    bool is_insert_intention() const
    {
        return(type_mode & LOCK_INSERT_INTENTION);
    }

    ulint type() const {
        return(type_mode & LOCK_TYPE_MASK);
    }

    enum lock_mode mode() const
    {
        return(static_cast(type_mode & LOCK_MODE_MASK));
    }

    /** Print the lock object into the given output stream.
    @param[in,out]  out the output stream
    @return the given output stream. */
    std::ostream& print(std::ostream& out) const;

    /** Convert the member 'type_mode' into a human readable string.
    @return human readable string */
    std::string type_mode_string() const;

    const char* type_string() const
    {
        switch (type_mode & LOCK_TYPE_MASK) {
        case LOCK_REC:
            return("LOCK_REC");
        case LOCK_TABLE:
            return("LOCK_TABLE");
        default:
            ut_error;
        }
    }
};

trx_t
이 구조 체 는 하나의 사 무 를 대표 하 는데 자물쇠 시스템 에서 주로 구성원 trxlock_t
struct trx_t {
    ···
    trx_lock_t  lock;       /*!< Information about the transaction
                    locks and state. Protected by
                    trx->mutex or lock_sys->mutex
                    or both */
    ···
}

trx_lock_t
트 랜 잭 션 처리 중 잠 금 시스템 과 관련 된 부분 은 trx 입 니 다.t 의 멤버
struct trx_lock_t {
    ulint       n_active_thrs;  /*!< number of active query threads */

    /*     */
    trx_que_t   que_state;  /*!< valid when trx->state
                    == TRX_STATE_ACTIVE: TRX_QUE_RUNNING,
                    TRX_QUE_LOCK_WAIT, ... */
    /*        */
    lock_t*     wait_lock;  /*!< if trx execution state is
                    TRX_QUE_LOCK_WAIT, this points to
                    the lock request, otherwise this is
                    NULL; set to non-NULL when holding
                    both trx->mutex and lock_sys->mutex;
                    set to NULL when holding
                    lock_sys->mutex; readers should
                    hold lock_sys->mutex, except when
                    they are holding trx->mutex and
                    wait_lock==NULL */
    /*                */
    ib_uint64_t deadlock_mark;  /*!< A mark field that is initialized
                    to and checked against lock_mark_counter
                    by lock_deadlock_recursive(). */
    /*       ,                */
    bool        was_chosen_as_deadlock_victim;
                    /*!< when the transaction decides to
                    wait for a lock, it sets this to false;
                    if another transaction chooses this
                    transaction as a victim in deadlock
                    resolution, it sets this to true.
                    Protected by trx->mutex. */
    time_t      wait_started;   /*!< lock wait started at this time,
                    protected only by lock_sys->mutex */

    que_thr_t*  wait_thr;   /*!< query thread belonging to this
                    trx that is in QUE_THR_LOCK_WAIT
                    state. For threads suspended in a
                    lock wait, this is protected by
                    lock_sys->mutex. Otherwise, this may
                    only be modified by the thread that is
                    serving the running transaction. */

    lock_pool_t rec_pool;   /*!< Pre-allocated record locks */

    lock_pool_t table_pool; /*!< Pre-allocated table locks */

    ulint       rec_cached; /*!< Next free rec lock in pool */

    ulint       table_cached;   /*!< Next free table lock in pool */

    mem_heap_t* lock_heap;  /*!< memory heap for trx_locks;
                    protected by lock_sys->mutex */
    /*          */
    trx_lock_list_t trx_locks;  /*!< locks requested by the transaction;
                    insertions are protected by trx->mutex
                    and lock_sys->mutex; removals are
                    protected by lock_sys->mutex */

    lock_pool_t table_locks;    /*!< All table locks requested by this
                    transaction, including AUTOINC locks */

    bool        cancel;     /*!< true if the transaction is being
                    rolled back either via deadlock
                    detection or due to lock timeout. The
                    caller has to acquire the trx_t::mutex
                    in order to cancel the locks. In
                    lock_trx_table_locks_remove() we
                    check for this cancel of a transaction's
                    locks and avoid reacquiring the trx
                    mutex to prevent recursive deadlocks.
                    Protected by both the lock sys mutex
                    and the trx_t::mutex. */
    ulint       n_rec_locks;    /*!< number of rec locks in this trx */

    /** The transaction called ha_innobase::start_stmt() to
    lock a table. Most likely a temporary table. */
    bool        start_stmt;
};

DeadlockChecker
자물쇠 검사 류 는 자 물 쇠 를 추가 할 때마다 이 종 류 를 사용 하여 자물쇠 검 사 를 한다.
/** Deadlock checker. */
class DeadlockChecker {
public:
    /** Checks if a joining lock request results in a deadlock. If
    a deadlock is found this function will resolve the deadlock
    by choosing a victim transaction and rolling it back. It
    will attempt to resolve all deadlocks. The returned transaction
    id will be the joining transaction id or 0 if some other
    transaction was chosen as a victim and rolled back or no
    deadlock found.

    @param lock lock the transaction is requesting
    @param trx transaction requesting the lock

    @return id of transaction chosen as victim or 0 */
    /*      */
    static const trx_t* check_and_resolve(
        const lock_t*   lock,
        trx_t*      trx);

private:
    /*         ,       check_and_resolve              DeadlockChecker   */
    /** Do a shallow copy. Default destructor OK.
    @param trx the start transaction (start node)
    @param wait_lock lock that a transaction wants
    @param mark_start visited node counter */
    DeadlockChecker(
        const trx_t*    trx,
        const lock_t*   wait_lock,
        ib_uint64_t mark_start)
        :
        m_cost(),
        m_start(trx),
        m_too_deep(),
        m_wait_lock(wait_lock),
        m_mark_start(mark_start),
        m_n_elems()
    {
    }

    /** Check if the search is too deep. */
    bool is_too_deep() const
    {
        return(m_n_elems > LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK
               || m_cost > LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK);
    }

    /** Save current state.
    @param lock lock to push on the stack.
    @param heap_no the heap number to push on the stack.
    @return false if stack is full. */
    bool push(const lock_t* lock, ulint heap_no)
    {
        ut_ad((lock_get_type_low(lock) & LOCK_REC)
              || (lock_get_type_low(lock) & LOCK_TABLE));

        ut_ad(((lock_get_type_low(lock) & LOCK_TABLE) != 0)
              == (heap_no == ULINT_UNDEFINED));

        /* Ensure that the stack is bounded. */
        if (m_n_elems >= UT_ARR_SIZE(s_states)) {
            return(false);
        }

        state_t&    state = s_states[m_n_elems++];

        state.m_lock = lock;
        state.m_wait_lock = m_wait_lock;
        state.m_heap_no =heap_no;

        return(true);
    }

    /** Restore state.
    @param[out] lock current lock
    @param[out] heap_no current heap_no */
    void pop(const lock_t*& lock, ulint& heap_no)
    {
        ut_a(m_n_elems > 0);

        const state_t&  state = s_states[--m_n_elems];

        lock = state.m_lock;
        heap_no = state.m_heap_no;
        m_wait_lock = state.m_wait_lock;
    }

    /** Check whether the node has been visited.
    @param lock lock to check
    @return true if the node has been visited */
    bool is_visited(const lock_t* lock) const
    {
        return(lock->trx->lock.deadlock_mark > m_mark_start);
    }

    /** Get the next lock in the queue that is owned by a transaction
    whose sub-tree has not already been searched.
    Note: "next" here means PREV for table locks.
    @param lock Lock in queue
    @param heap_no heap_no if lock is a record lock else ULINT_UNDEFINED
    @return next lock or NULL if at end of queue */
    const lock_t* get_next_lock(const lock_t* lock, ulint heap_no) const;

    /** Get the first lock to search. The search starts from the current
    wait_lock. What we are really interested in is an edge from the
    current wait_lock's owning transaction to another transaction that has
    a lock ahead in the queue. We skip locks where the owning transaction's
    sub-tree has already been searched.

    Note: The record locks are traversed from the oldest lock to the
    latest. For table locks we go from latest to oldest.

    For record locks, we first position the iterator on first lock on
    the page and then reposition on the actual heap_no. This is required
    due to the way the record lock has is implemented.

    @param[out] heap_no if rec lock, else ULINT_UNDEFINED.

    @return first lock or NULL */
    const lock_t* get_first_lock(ulint* heap_no) const;

    /** Notify that a deadlock has been detected and print the conflicting
    transaction info.
    @param lock lock causing deadlock */
    void notify(const lock_t* lock) const;

    /** Select the victim transaction that should be rolledback.
    @return victim transaction */
    const trx_t* select_victim() const;

    /** Rollback transaction selected as the victim. */
    void trx_rollback();

    /** Looks iteratively for a deadlock. Note: the joining transaction
    may have been granted its lock by the deadlock checks.

    @return 0 if no deadlock else the victim transaction.*/
    const trx_t* search();

    /** Print transaction data to the deadlock file and possibly to stderr.
    @param trx transaction
    @param max_query_len max query length to print */
    static void print(const trx_t* trx, ulint max_query_len);

    /** rewind(3) the file used for storing the latest detected deadlock
    and print a heading message to stderr if printing of all deadlocks to
    stderr is enabled. */
    static void start_print();

    /** Print lock data to the deadlock file and possibly to stderr.
    @param lock record or table type lock */
    static void print(const lock_t* lock);

    /** Print a message to the deadlock file and possibly to stderr.
    @param msg message to print */
    static void print(const char* msg);

    /** Print info about transaction that was rolled back.
    @param trx transaction rolled back
    @param lock lock trx wants */
    static void rollback_print(const trx_t* trx, const lock_t* lock);

private:
    /** DFS state information, used during deadlock checking. */
    struct state_t {
        const lock_t*   m_lock;     /*!< Current lock */
        const lock_t*   m_wait_lock;    /*!< Waiting for lock */
        ulint       m_heap_no;  /*!< heap number if rec lock */
    };

    /** Used in deadlock tracking. Protected by lock_sys->mutex. */
    static ib_uint64_t  s_lock_mark_counter;

    /** Calculation steps thus far. It is the count of the nodes visited. */
    ulint           m_cost;

    /** Joining transaction that is requesting a lock in an
    incompatible mode */
    const trx_t*        m_start;

    /** TRUE if search was too deep and was aborted */
    bool            m_too_deep;

    /** Lock that trx wants */
    const lock_t*       m_wait_lock;

    /**  Value of lock_mark_count at the start of the deadlock check. */
    ib_uint64_t     m_mark_start;

    /** Number of states pushed onto the stack */
    size_t          m_n_elems;

    /** This is to avoid malloc/free calls. */
    static state_t      s_states[MAX_STACK_SIZE];
};

다음으로 전송:https://www.cnblogs.com/FateTHarlaown/p/9364091.html

좋은 웹페이지 즐겨찾기