mysql 同步机制 之 innodb内部并发控制
数据库一致性原理 ARIES
ARIES, Algorithms for Recovery and Isolation Exploiting Semantics, is a recovery algorithm used by almost all modern database systems.
Three main principles lie behind ARIES:
- Write ahead logging (WAL)
- Repeating history during Redo
- Logging changes during Undo
-
innodb mutex 数据结构 (sync0sync.h)
/** InnoDB mutex */ struct ib_mutex_t { os_event_t event; /*!< Used by sync0arr.cc for the wait queue */ volatile lock_word_t lock_word; /*!< lock_word is the target of the atomic test-and-set instruction when atomic operations are enabled. */ #if !defined(HAVE_ATOMIC_BUILTINS) os_fast_mutex_t os_fast_mutex; /*!< We use this OS mutex in place of lock_word when atomic operations are not enabled */ #endif ulint waiters; /*!< This ulint is set to 1 if there are (or may be) threads waiting in the global wait array for this mutex to be released. Otherwise, this is 0. */ UT_LIST_NODE_T(ib_mutex_t) list; /*!< All allocated mutexes are put into a list. Pointers to the next and prev. */ #ifdef UNIV_SYNC_DEBUG const char* file_name; /*!< File where the mutex was locked */ ulint line; /*!< Line where the mutex was locked */ ulint level; /*!< Level in the global latching order */ #endif /* UNIV_SYNC_DEBUG */ const char* cfile_name;/*!< File name where mutex created */ ulint cline; /*!< Line where created */ ulong count_os_wait; /*!< count of os_wait */ #ifdef UNIV_DEBUG /** Value of mutex_t::magic_n */ # define MUTEX_MAGIC_N 979585UL os_thread_id_t thread_id; /*!< The thread id of the thread which locked the mutex. */ ulint magic_n; /*!< MUTEX_MAGIC_N */ const char* cmutex_name; /*!< mutex name */ ulint ib_mutex_type; /*!< 0=usual mutex, 1=rw_lock mutex */ #endif /* UNIV_DEBUG */ #ifdef UNIV_PFS_MUTEX struct PSI_mutex* pfs_psi; /*!< The performance schema instrumentation hook */ #endif };
innodb mutex 全局等待队列 (sync0arr.cc)
/** Synchronization array */ struct sync_array_t { ulint n_reserved; /*!< number of currently reserved cells in the wait array */ ulint n_cells; /*!< number of cells in the wait array */ sync_cell_t* array; /*!< pointer to wait array */ ib_mutex_t mutex; /*!< possible database mutex protecting this data structure */ os_ib_mutex_t os_mutex; /*!< Possible operating system mutex protecting the data structure. As this data structure is used in constructing the database mutex, to prevent infinite recursion in implementation, we fall back to an OS mutex. */ ulint res_count; /*!< count of cell reservations since creation of the array */ }; /** User configured sync array size */ UNIV_INTERN ulong srv_sync_array_size = 32; /** Locally stored copy of srv_sync_array_size */ static ulint sync_array_size; /** The global array of wait cells for implementation of the database's own mutexes and read-write locks */ static sync_array_t** sync_wait_array;
其中,sync_wait_array 为全局mutex等待队列(global wait array).
全局等待队列的初始化代码为 (sync0arr.cc):
/**********************************************************************//** Create the primary system wait array(s), they are protected by an OS mutex */ UNIV_INTERN void sync_array_init( /*============*/ ulint n_threads) /*!< in: Number of slots to create in all arrays */ { ulint i; ulint n_slots; ut_a(sync_wait_array == NULL); ut_a(srv_sync_array_size > 0); ut_a(n_threads > 0); sync_array_size = srv_sync_array_size; /* We have to use ut_malloc() because the mutex infrastructure hasn't been initialised yet. It is required by mem_alloc() and the heap functions. */ sync_wait_array = static_cast<sync_array_t**>( ut_malloc(sizeof(*sync_wait_array) * sync_array_size)); n_slots = 1 + (n_threads - 1) / sync_array_size; for (i = 0; i < sync_array_size; ++i) { sync_wait_array[i] = sync_array_create(n_slots); } }