1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 2014, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, 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 gis0rtree.h |
22 | R-tree Inline code |
23 | |
24 | Created 2013/03/27 Jimmy Yang and Allen Lai |
25 | ***********************************************************************/ |
26 | |
27 | /**************************************************************//** |
28 | Sets the child node mbr in a node pointer. */ |
29 | UNIV_INLINE |
30 | void |
31 | rtr_page_cal_mbr( |
32 | /*=============*/ |
33 | const dict_index_t* index, /*!< in: index */ |
34 | const buf_block_t* block, /*!< in: buffer block */ |
35 | rtr_mbr_t* rtr_mbr,/*!< out: MBR encapsulates the page */ |
36 | mem_heap_t* heap) /*!< in: heap for the memory |
37 | allocation */ |
38 | { |
39 | page_t* page; |
40 | rec_t* rec; |
41 | const byte* field; |
42 | ulint len; |
43 | ulint* offsets = NULL; |
44 | double bmin, bmax; |
45 | double* amin; |
46 | double* amax; |
47 | ulint inc = 0; |
48 | double* mbr; |
49 | |
50 | rtr_mbr->xmin = DBL_MAX; |
51 | rtr_mbr->ymin = DBL_MAX; |
52 | rtr_mbr->xmax = -DBL_MAX; |
53 | rtr_mbr->ymax = -DBL_MAX; |
54 | |
55 | mbr = reinterpret_cast<double*>(rtr_mbr); |
56 | |
57 | page = buf_block_get_frame(block); |
58 | |
59 | rec = page_rec_get_next(page_get_infimum_rec(page)); |
60 | offsets = rec_get_offsets(rec, index, offsets, page_is_leaf(page), |
61 | ULINT_UNDEFINED, &heap); |
62 | |
63 | do { |
64 | /* The mbr address is in the first field. */ |
65 | field = rec_get_nth_field(rec, offsets, 0, &len); |
66 | |
67 | ut_ad(len == DATA_MBR_LEN); |
68 | inc = 0; |
69 | for (unsigned i = 0; i < SPDIMS; i++) { |
70 | bmin = mach_double_read(field + inc); |
71 | bmax = mach_double_read(field + inc + sizeof(double)); |
72 | |
73 | amin = mbr + i * SPDIMS; |
74 | amax = mbr + i * SPDIMS + 1; |
75 | |
76 | if (*amin > bmin) |
77 | *amin = bmin; |
78 | if (*amax < bmax) |
79 | *amax = bmax; |
80 | |
81 | inc += 2 * sizeof(double); |
82 | } |
83 | |
84 | rec = page_rec_get_next(rec); |
85 | |
86 | if (rec == NULL) { |
87 | break; |
88 | } |
89 | } while (!page_rec_is_supremum(rec)); |
90 | } |
91 | |
92 | /**************************************************************//** |
93 | push a nonleaf index node to the search path */ |
94 | UNIV_INLINE |
95 | void |
96 | rtr_non_leaf_stack_push( |
97 | /*====================*/ |
98 | rtr_node_path_t* path, /*!< in/out: search path */ |
99 | ulint pageno, /*!< in: pageno to insert */ |
100 | node_seq_t seq_no, /*!< in: Node sequence num */ |
101 | ulint level, /*!< in: index page level */ |
102 | ulint child_no, /*!< in: child page no */ |
103 | btr_pcur_t* cursor, /*!< in: position cursor */ |
104 | double mbr_inc) /*!< in: MBR needs to be |
105 | enlarged */ |
106 | { |
107 | node_visit_t insert_val; |
108 | |
109 | insert_val.page_no = pageno; |
110 | insert_val.seq_no = seq_no; |
111 | insert_val.level = level; |
112 | insert_val.child_no = child_no; |
113 | insert_val.cursor = cursor; |
114 | insert_val.mbr_inc = mbr_inc; |
115 | |
116 | path->push_back(insert_val); |
117 | |
118 | #ifdef RTR_SEARCH_DIAGNOSTIC |
119 | fprintf(stderr, "INNODB_RTR: Push page %d, level %d, seq %d" |
120 | " to search stack \n" , |
121 | static_cast<int>(pageno), static_cast<int>(level), |
122 | static_cast<int>(seq_no)); |
123 | #endif /* RTR_SEARCH_DIAGNOSTIC */ |
124 | } |
125 | |
126 | /*****************************************************************//** |
127 | Allocates a new Split Sequence Number. |
128 | @return new SSN id */ |
129 | UNIV_INLINE |
130 | node_seq_t |
131 | rtr_get_new_ssn_id( |
132 | /*===============*/ |
133 | dict_index_t* index) /*!< in/out: the index struct */ |
134 | { |
135 | node_seq_t ssn; |
136 | |
137 | mutex_enter(&(index->rtr_ssn.mutex)); |
138 | ssn = ++index->rtr_ssn.seq_no; |
139 | mutex_exit(&(index->rtr_ssn.mutex)); |
140 | |
141 | return(ssn); |
142 | } |
143 | /*****************************************************************//** |
144 | Get the current Split Sequence Number. |
145 | @return current SSN id */ |
146 | UNIV_INLINE |
147 | node_seq_t |
148 | rtr_get_current_ssn_id( |
149 | /*===================*/ |
150 | dict_index_t* index) /*!< in: index struct */ |
151 | { |
152 | node_seq_t ssn; |
153 | |
154 | mutex_enter(&(index->rtr_ssn.mutex)); |
155 | ssn = index->rtr_ssn.seq_no; |
156 | mutex_exit(&(index->rtr_ssn.mutex)); |
157 | |
158 | return(ssn); |
159 | } |
160 | |
161 | /*********************************************************************//** |
162 | Sets pointer to the data and length in a field. */ |
163 | UNIV_INLINE |
164 | void |
165 | rtr_write_mbr( |
166 | /*==========*/ |
167 | byte* data, /*!< out: data */ |
168 | const rtr_mbr_t* mbr) /*!< in: data */ |
169 | { |
170 | const double* my_mbr = reinterpret_cast<const double*>(mbr); |
171 | |
172 | for (unsigned i = 0; i < SPDIMS * 2; i++) { |
173 | mach_double_write(data + i * sizeof(double), my_mbr[i]); |
174 | } |
175 | } |
176 | |
177 | /*********************************************************************//** |
178 | Sets pointer to the data and length in a field. */ |
179 | UNIV_INLINE |
180 | void |
181 | rtr_read_mbr( |
182 | /*==========*/ |
183 | const byte* data, /*!< in: data */ |
184 | rtr_mbr_t* mbr) /*!< out: MBR */ |
185 | { |
186 | for (unsigned i = 0; i < SPDIMS * 2; i++) { |
187 | (reinterpret_cast<double*>(mbr))[i] = mach_double_read( |
188 | data |
189 | + i * sizeof(double)); |
190 | } |
191 | } |
192 | |
193 | /*********************************************************//** |
194 | Returns the R-Tree node stored in the parent search path |
195 | @return pointer to R-Tree cursor component in the parent path, |
196 | NULL if parent path is empty or index is larger than num of items contained */ |
197 | UNIV_INLINE |
198 | node_visit_t* |
199 | rtr_get_parent_node( |
200 | /*================*/ |
201 | btr_cur_t* btr_cur, /*!< in: persistent cursor */ |
202 | ulint level, /*!< in: index level of buffer page */ |
203 | ulint is_insert) /*!< in: whether it is insert */ |
204 | { |
205 | ulint num; |
206 | ulint tree_height = btr_cur->tree_height; |
207 | node_visit_t* found_node = NULL; |
208 | |
209 | if (level >= tree_height) { |
210 | return(NULL); |
211 | } |
212 | |
213 | mutex_enter(&btr_cur->rtr_info->rtr_path_mutex); |
214 | |
215 | num = btr_cur->rtr_info->parent_path->size(); |
216 | |
217 | if (!num) { |
218 | mutex_exit(&btr_cur->rtr_info->rtr_path_mutex); |
219 | return(NULL); |
220 | } |
221 | |
222 | if (is_insert) { |
223 | ulint idx = tree_height - level - 1; |
224 | ut_ad(idx < num); |
225 | |
226 | found_node = &(*btr_cur->rtr_info->parent_path)[idx]; |
227 | } else { |
228 | node_visit_t* node; |
229 | |
230 | while (num > 0) { |
231 | node = &(*btr_cur->rtr_info->parent_path)[num - 1]; |
232 | |
233 | if (node->level == level) { |
234 | found_node = node; |
235 | break; |
236 | } |
237 | num--; |
238 | } |
239 | } |
240 | |
241 | mutex_exit(&btr_cur->rtr_info->rtr_path_mutex); |
242 | |
243 | return(found_node); |
244 | } |
245 | |
246 | /*********************************************************//** |
247 | Returns the R-Tree cursor stored in the parent search path |
248 | @return pointer to R-Tree cursor component */ |
249 | UNIV_INLINE |
250 | btr_pcur_t* |
251 | rtr_get_parent_cursor( |
252 | /*==================*/ |
253 | btr_cur_t* btr_cur, /*!< in: persistent cursor */ |
254 | ulint level, /*!< in: index level of buffer page */ |
255 | ulint is_insert) /*!< in: whether insert operation */ |
256 | { |
257 | node_visit_t* found_node = rtr_get_parent_node( |
258 | btr_cur, level, is_insert); |
259 | |
260 | return((found_node) ? found_node->cursor : NULL); |
261 | } |
262 | |
263 | /********************************************************************//** |
264 | Reinitialize a R-Tree search info in btr_cur_t */ |
265 | UNIV_INLINE |
266 | void |
267 | rtr_info_reinit_in_cursor( |
268 | /************************/ |
269 | btr_cur_t* cursor, /*!< in/out: tree cursor */ |
270 | dict_index_t* index, /*!< in: index struct */ |
271 | bool need_prdt) /*!< in: Whether predicate lock is |
272 | needed */ |
273 | { |
274 | rtr_clean_rtr_info(cursor->rtr_info, false); |
275 | rtr_init_rtr_info(cursor->rtr_info, need_prdt, cursor, index, true); |
276 | } |
277 | |