1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, 2018, MariaDB Corporation. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /********************************************************************//** |
21 | @file include/btr0sea.h |
22 | The index tree adaptive search |
23 | |
24 | Created 2/17/1996 Heikki Tuuri |
25 | *************************************************************************/ |
26 | |
27 | #ifndef btr0sea_h |
28 | #define btr0sea_h |
29 | |
30 | #include "univ.i" |
31 | |
32 | #include "rem0rec.h" |
33 | #include "dict0dict.h" |
34 | #include "btr0types.h" |
35 | #include "mtr0mtr.h" |
36 | #ifdef BTR_CUR_HASH_ADAPT |
37 | #include "ha0ha.h" |
38 | |
39 | /** Creates and initializes the adaptive search system at a database start. |
40 | @param[in] hash_size hash table size. */ |
41 | void btr_search_sys_create(ulint hash_size); |
42 | |
43 | /** Resize hash index hash table. |
44 | @param[in] hash_size hash index hash table size */ |
45 | void btr_search_sys_resize(ulint hash_size); |
46 | |
47 | /** Frees the adaptive search system at a database shutdown. */ |
48 | void btr_search_sys_free(); |
49 | |
50 | /** Disable the adaptive hash search system and empty the index. |
51 | @param need_mutex need to acquire dict_sys->mutex */ |
52 | void btr_search_disable(bool need_mutex); |
53 | /** Enable the adaptive hash search system. */ |
54 | void btr_search_enable(); |
55 | |
56 | /** Returns the value of ref_count. The value is protected by latch. |
57 | @param[in] info search info |
58 | @param[in] index index identifier |
59 | @return ref_count value. */ |
60 | ulint |
61 | btr_search_info_get_ref_count( |
62 | btr_search_t* info, |
63 | dict_index_t* index); |
64 | |
65 | /*********************************************************************//** |
66 | Updates the search info. */ |
67 | UNIV_INLINE |
68 | void |
69 | btr_search_info_update( |
70 | /*===================*/ |
71 | dict_index_t* index, /*!< in: index of the cursor */ |
72 | btr_cur_t* cursor);/*!< in: cursor which was just positioned */ |
73 | |
74 | /** Tries to guess the right search position based on the hash search info |
75 | of the index. Note that if mode is PAGE_CUR_LE, which is used in inserts, |
76 | and the function returns TRUE, then cursor->up_match and cursor->low_match |
77 | both have sensible values. |
78 | @param[in,out] index index |
79 | @param[in,out] info index search info |
80 | @param[in] tuple logical record |
81 | @param[in] mode PAGE_CUR_L, .... |
82 | @param[in] latch_mode BTR_SEARCH_LEAF, ...; |
83 | NOTE that only if has_search_latch is 0, we will |
84 | have a latch set on the cursor page, otherwise |
85 | we assume the caller uses his search latch |
86 | to protect the record! |
87 | @param[out] cursor tree cursor |
88 | @param[in] ahi_latch the adaptive hash index latch being held, |
89 | or NULL |
90 | @param[in] mtr mini transaction |
91 | @return whether the search succeeded */ |
92 | bool |
93 | btr_search_guess_on_hash( |
94 | dict_index_t* index, |
95 | btr_search_t* info, |
96 | const dtuple_t* tuple, |
97 | ulint mode, |
98 | ulint latch_mode, |
99 | btr_cur_t* cursor, |
100 | rw_lock_t* ahi_latch, |
101 | mtr_t* mtr); |
102 | |
103 | /** Move or delete hash entries for moved records, usually in a page split. |
104 | If new_block is already hashed, then any hash index for block is dropped. |
105 | If new_block is not hashed, and block is hashed, then a new hash index is |
106 | built to new_block with the same parameters as block. |
107 | @param[in,out] new_block destination page |
108 | @param[in,out] block source page (subject to deletion later) */ |
109 | void |
110 | btr_search_move_or_delete_hash_entries( |
111 | buf_block_t* new_block, |
112 | buf_block_t* block); |
113 | |
114 | /** Drop any adaptive hash index entries that point to an index page. |
115 | @param[in,out] block block containing index page, s- or x-latched, or an |
116 | index page for which we know that |
117 | block->buf_fix_count == 0 or it is an index page which |
118 | has already been removed from the buf_pool->page_hash |
119 | i.e.: it is in state BUF_BLOCK_REMOVE_HASH */ |
120 | void btr_search_drop_page_hash_index(buf_block_t* block); |
121 | |
122 | /** Drop any adaptive hash index entries that may point to an index |
123 | page that may be in the buffer pool, when a page is evicted from the |
124 | buffer pool or freed in a file segment. |
125 | @param[in] page_id page id |
126 | @param[in] page_size page size */ |
127 | void btr_search_drop_page_hash_when_freed(const page_id_t& page_id); |
128 | |
129 | /** Updates the page hash index when a single record is inserted on a page. |
130 | @param[in] cursor cursor which was positioned to the place to insert |
131 | using btr_cur_search_, and the new record has been |
132 | inserted next to the cursor. |
133 | @param[in] ahi_latch the adaptive hash index latch */ |
134 | void |
135 | btr_search_update_hash_node_on_insert(btr_cur_t* cursor, rw_lock_t* ahi_latch); |
136 | |
137 | /** Updates the page hash index when a single record is inserted on a page. |
138 | @param[in,out] cursor cursor which was positioned to the |
139 | place to insert using btr_cur_search_..., |
140 | and the new record has been inserted next |
141 | to the cursor |
142 | @param[in] ahi_latch the adaptive hash index latch */ |
143 | void |
144 | btr_search_update_hash_on_insert(btr_cur_t* cursor, rw_lock_t* ahi_latch); |
145 | |
146 | /** Updates the page hash index when a single record is deleted from a page. |
147 | @param[in] cursor cursor which was positioned on the record to delete |
148 | using btr_cur_search_, the record is not yet deleted.*/ |
149 | void btr_search_update_hash_on_delete(btr_cur_t* cursor); |
150 | |
151 | /** Validates the search system. |
152 | @return true if ok */ |
153 | bool btr_search_validate(); |
154 | |
155 | /** Lock all search latches in exclusive mode. */ |
156 | static inline void btr_search_x_lock_all(); |
157 | |
158 | /** Unlock all search latches from exclusive mode. */ |
159 | static inline void btr_search_x_unlock_all(); |
160 | |
161 | /** Lock all search latches in shared mode. */ |
162 | static inline void btr_search_s_lock_all(); |
163 | |
164 | #ifdef UNIV_DEBUG |
165 | /** Check if thread owns all the search latches. |
166 | @param[in] mode lock mode check |
167 | @retval true if owns all of them |
168 | @retval false if does not own some of them */ |
169 | static inline bool btr_search_own_all(ulint mode); |
170 | |
171 | /** Check if thread owns any of the search latches. |
172 | @param[in] mode lock mode check |
173 | @retval true if owns any of them |
174 | @retval false if owns no search latch */ |
175 | static inline bool btr_search_own_any(ulint mode); |
176 | #endif /* UNIV_DEBUG */ |
177 | |
178 | /** Unlock all search latches from shared mode. */ |
179 | static inline void btr_search_s_unlock_all(); |
180 | |
181 | /** Get the latch based on index attributes. |
182 | A latch is selected from an array of latches using pair of index-id, space-id. |
183 | @param[in] index index handler |
184 | @return latch */ |
185 | static inline rw_lock_t* btr_get_search_latch(const dict_index_t* index); |
186 | |
187 | /** Get the hash-table based on index attributes. |
188 | A table is selected from an array of tables using pair of index-id, space-id. |
189 | @param[in] index index handler |
190 | @return hash table */ |
191 | static inline hash_table_t* btr_get_search_table(const dict_index_t* index); |
192 | #else /* BTR_CUR_HASH_ADAPT */ |
193 | # define btr_search_sys_create(size) |
194 | # define btr_search_sys_free() |
195 | # define btr_search_drop_page_hash_index(block) |
196 | # define btr_search_s_lock_all(index) |
197 | # define btr_search_s_unlock_all(index) |
198 | # define btr_search_info_update(index, cursor) |
199 | # define btr_search_move_or_delete_hash_entries(new_block, block) |
200 | # define btr_search_update_hash_on_insert(cursor, ahi_latch) |
201 | # define btr_search_update_hash_on_delete(cursor) |
202 | # define btr_search_sys_resize(hash_size) |
203 | #endif /* BTR_CUR_HASH_ADAPT */ |
204 | |
205 | #ifdef BTR_CUR_ADAPT |
206 | /** Create and initialize search info. |
207 | @param[in,out] heap heap where created |
208 | @return own: search info struct */ |
209 | static inline btr_search_t* btr_search_info_create(mem_heap_t* heap) |
210 | MY_ATTRIBUTE((nonnull, warn_unused_result)); |
211 | |
212 | /** @return the search info of an index */ |
213 | static inline btr_search_t* btr_search_get_info(dict_index_t* index) |
214 | { |
215 | return(index->search_info); |
216 | } |
217 | #endif /* BTR_CUR_ADAPT */ |
218 | |
219 | /** The search info struct in an index */ |
220 | struct btr_search_t{ |
221 | /* @{ The following fields are not protected by any latch. |
222 | Unfortunately, this means that they must be aligned to |
223 | the machine word, i.e., they cannot be turned into bit-fields. */ |
224 | buf_block_t* root_guess;/*!< the root page frame when it was last time |
225 | fetched, or NULL */ |
226 | ulint withdraw_clock; /*!< the withdraw clock value of the buffer |
227 | pool when root_guess was stored */ |
228 | #ifdef BTR_CUR_HASH_ADAPT |
229 | ulint hash_analysis; /*!< when this exceeds |
230 | BTR_SEARCH_HASH_ANALYSIS, the hash |
231 | analysis starts; this is reset if no |
232 | success noticed */ |
233 | ibool last_hash_succ; /*!< TRUE if the last search would have |
234 | succeeded, or did succeed, using the hash |
235 | index; NOTE that the value here is not exact: |
236 | it is not calculated for every search, and the |
237 | calculation itself is not always accurate! */ |
238 | ulint n_hash_potential; |
239 | /*!< number of consecutive searches |
240 | which would have succeeded, or did succeed, |
241 | using the hash index; |
242 | the range is 0 .. BTR_SEARCH_BUILD_LIMIT + 5 */ |
243 | /* @} */ |
244 | ulint ref_count; /*!< Number of blocks in this index tree |
245 | that have search index built |
246 | i.e. block->index points to this index. |
247 | Protected by search latch except |
248 | when during initialization in |
249 | btr_search_info_create(). */ |
250 | |
251 | /*---------------------- @{ */ |
252 | ulint n_fields; /*!< recommended prefix length for hash search: |
253 | number of full fields */ |
254 | ulint n_bytes; /*!< recommended prefix: number of bytes in |
255 | an incomplete field |
256 | @see BTR_PAGE_MAX_REC_SIZE */ |
257 | bool left_side; /*!< true or false, depending on whether |
258 | the leftmost record of several records with |
259 | the same prefix should be indexed in the |
260 | hash index */ |
261 | /*---------------------- @} */ |
262 | #ifdef UNIV_SEARCH_PERF_STAT |
263 | ulint n_hash_succ; /*!< number of successful hash searches thus |
264 | far */ |
265 | ulint n_hash_fail; /*!< number of failed hash searches */ |
266 | ulint n_patt_succ; /*!< number of successful pattern searches thus |
267 | far */ |
268 | ulint n_searches; /*!< number of searches */ |
269 | #endif /* UNIV_SEARCH_PERF_STAT */ |
270 | #endif /* BTR_CUR_HASH_ADAPT */ |
271 | #ifdef UNIV_DEBUG |
272 | ulint magic_n; /*!< magic number @see BTR_SEARCH_MAGIC_N */ |
273 | /** value of btr_search_t::magic_n, used in assertions */ |
274 | # define BTR_SEARCH_MAGIC_N 1112765 |
275 | #endif /* UNIV_DEBUG */ |
276 | }; |
277 | |
278 | #ifdef BTR_CUR_HASH_ADAPT |
279 | /** The hash index system */ |
280 | struct btr_search_sys_t{ |
281 | hash_table_t** hash_tables; /*!< the adaptive hash tables, |
282 | mapping dtuple_fold values |
283 | to rec_t pointers on index pages */ |
284 | }; |
285 | |
286 | /** Latches protecting access to adaptive hash index. */ |
287 | extern rw_lock_t** btr_search_latches; |
288 | |
289 | /** The adaptive hash index */ |
290 | extern btr_search_sys_t* btr_search_sys; |
291 | |
292 | #ifdef UNIV_SEARCH_PERF_STAT |
293 | /** Number of successful adaptive hash index lookups */ |
294 | extern ulint btr_search_n_succ; |
295 | /** Number of failed adaptive hash index lookups */ |
296 | extern ulint btr_search_n_hash_fail; |
297 | #endif /* UNIV_SEARCH_PERF_STAT */ |
298 | |
299 | /** After change in n_fields or n_bytes in info, this many rounds are waited |
300 | before starting the hash analysis again: this is to save CPU time when there |
301 | is no hope in building a hash index. */ |
302 | #define BTR_SEARCH_HASH_ANALYSIS 17 |
303 | |
304 | /** Limit of consecutive searches for trying a search shortcut on the search |
305 | pattern */ |
306 | #define BTR_SEARCH_ON_PATTERN_LIMIT 3 |
307 | |
308 | /** Limit of consecutive searches for trying a search shortcut using |
309 | the hash index */ |
310 | #define BTR_SEARCH_ON_HASH_LIMIT 3 |
311 | |
312 | /** We do this many searches before trying to keep the search latch |
313 | over calls from MySQL. If we notice someone waiting for the latch, we |
314 | again set this much timeout. This is to reduce contention. */ |
315 | #define BTR_SEA_TIMEOUT 10000 |
316 | #endif /* BTR_CUR_HASH_ADAPT */ |
317 | |
318 | #include "btr0sea.ic" |
319 | |
320 | #endif |
321 | |