1 /**********************************************************************
2 File-based list utilities
6 Created 11/28/1995 Heikki Tuuri
7 ***********************************************************************/
18 /************************************************************************
19 Adds a node to an empty list. */
24 flst_base_node_t
* base
, /* in: pointer to base node of
26 flst_node_t
* node
, /* in: node to add */
27 mtr_t
* mtr
) /* in: mini-transaction handle */
33 ut_ad(mtr
&& base
&& node
);
35 ut_ad(mtr_memo_contains(mtr
, buf_block_align(base
),
36 MTR_MEMO_PAGE_X_FIX
));
37 ut_ad(mtr_memo_contains(mtr
, buf_block_align(node
),
38 MTR_MEMO_PAGE_X_FIX
));
39 len
= flst_get_len(base
, mtr
);
42 buf_ptr_get_fsp_addr(node
, &space
, &node_addr
);
44 /* Update first and last fields of base node */
45 flst_write_addr(base
+ FLST_FIRST
, node_addr
, mtr
);
46 flst_write_addr(base
+ FLST_LAST
, node_addr
, mtr
);
48 /* Set prev and next fields of node to add */
49 flst_write_addr(node
+ FLST_PREV
, fil_addr_null
, mtr
);
50 flst_write_addr(node
+ FLST_NEXT
, fil_addr_null
, mtr
);
52 /* Update len of base node */
53 mlog_write_ulint(base
+ FLST_LEN
, len
+ 1, MLOG_4BYTES
, mtr
);
56 /************************************************************************
57 Adds a node as the last node in a list. */
62 flst_base_node_t
* base
, /* in: pointer to base node of list */
63 flst_node_t
* node
, /* in: node to add */
64 mtr_t
* mtr
) /* in: mini-transaction handle */
70 flst_node_t
* last_node
;
72 ut_ad(mtr
&& base
&& node
);
74 ut_ad(mtr_memo_contains(mtr
, buf_block_align(base
),
75 MTR_MEMO_PAGE_X_FIX
));
76 ut_ad(mtr_memo_contains(mtr
, buf_block_align(node
),
77 MTR_MEMO_PAGE_X_FIX
));
78 len
= flst_get_len(base
, mtr
);
79 last_addr
= flst_get_last(base
, mtr
);
81 buf_ptr_get_fsp_addr(node
, &space
, &node_addr
);
83 /* If the list is not empty, call flst_insert_after */
85 if (last_addr
.page
== node_addr
.page
) {
86 last_node
= buf_frame_align(node
) + last_addr
.boffset
;
88 last_node
= fut_get_ptr(space
, last_addr
, RW_X_LATCH
,
92 flst_insert_after(base
, last_node
, node
, mtr
);
94 /* else call flst_add_to_empty */
95 flst_add_to_empty(base
, node
, mtr
);
99 /************************************************************************
100 Adds a node as the first node in a list. */
105 flst_base_node_t
* base
, /* in: pointer to base node of list */
106 flst_node_t
* node
, /* in: node to add */
107 mtr_t
* mtr
) /* in: mini-transaction handle */
110 fil_addr_t node_addr
;
112 fil_addr_t first_addr
;
113 flst_node_t
* first_node
;
115 ut_ad(mtr
&& base
&& node
);
117 ut_ad(mtr_memo_contains(mtr
, buf_block_align(base
),
118 MTR_MEMO_PAGE_X_FIX
));
119 ut_ad(mtr_memo_contains(mtr
, buf_block_align(node
),
120 MTR_MEMO_PAGE_X_FIX
));
121 len
= flst_get_len(base
, mtr
);
122 first_addr
= flst_get_first(base
, mtr
);
124 buf_ptr_get_fsp_addr(node
, &space
, &node_addr
);
126 /* If the list is not empty, call flst_insert_before */
128 if (first_addr
.page
== node_addr
.page
) {
129 first_node
= buf_frame_align(node
)
130 + first_addr
.boffset
;
132 first_node
= fut_get_ptr(space
, first_addr
,
136 flst_insert_before(base
, node
, first_node
, mtr
);
138 /* else call flst_add_to_empty */
139 flst_add_to_empty(base
, node
, mtr
);
143 /************************************************************************
144 Inserts a node after another in a list. */
149 flst_base_node_t
* base
, /* in: pointer to base node of list */
150 flst_node_t
* node1
, /* in: node to insert after */
151 flst_node_t
* node2
, /* in: node to add */
152 mtr_t
* mtr
) /* in: mini-transaction handle */
155 fil_addr_t node1_addr
;
156 fil_addr_t node2_addr
;
158 fil_addr_t node3_addr
;
161 ut_ad(mtr
&& node1
&& node2
&& base
);
162 ut_ad(base
!= node1
);
163 ut_ad(base
!= node2
);
164 ut_ad(node2
!= node1
);
165 ut_ad(mtr_memo_contains(mtr
, buf_block_align(base
),
166 MTR_MEMO_PAGE_X_FIX
));
167 ut_ad(mtr_memo_contains(mtr
, buf_block_align(node1
),
168 MTR_MEMO_PAGE_X_FIX
));
169 ut_ad(mtr_memo_contains(mtr
, buf_block_align(node2
),
170 MTR_MEMO_PAGE_X_FIX
));
172 buf_ptr_get_fsp_addr(node1
, &space
, &node1_addr
);
173 buf_ptr_get_fsp_addr(node2
, &space
, &node2_addr
);
175 node3_addr
= flst_get_next_addr(node1
, mtr
);
177 /* Set prev and next fields of node2 */
178 flst_write_addr(node2
+ FLST_PREV
, node1_addr
, mtr
);
179 flst_write_addr(node2
+ FLST_NEXT
, node3_addr
, mtr
);
181 if (!fil_addr_is_null(node3_addr
)) {
182 /* Update prev field of node3 */
183 node3
= fut_get_ptr(space
, node3_addr
, RW_X_LATCH
, mtr
);
184 flst_write_addr(node3
+ FLST_PREV
, node2_addr
, mtr
);
186 /* node1 was last in list: update last field in base */
187 flst_write_addr(base
+ FLST_LAST
, node2_addr
, mtr
);
190 /* Set next field of node1 */
191 flst_write_addr(node1
+ FLST_NEXT
, node2_addr
, mtr
);
193 /* Update len of base node */
194 len
= flst_get_len(base
, mtr
);
195 mlog_write_ulint(base
+ FLST_LEN
, len
+ 1, MLOG_4BYTES
, mtr
);
198 /************************************************************************
199 Inserts a node before another in a list. */
204 flst_base_node_t
* base
, /* in: pointer to base node of list */
205 flst_node_t
* node2
, /* in: node to insert */
206 flst_node_t
* node3
, /* in: node to insert before */
207 mtr_t
* mtr
) /* in: mini-transaction handle */
211 fil_addr_t node1_addr
;
212 fil_addr_t node2_addr
;
213 fil_addr_t node3_addr
;
216 ut_ad(mtr
&& node2
&& node3
&& base
);
217 ut_ad(base
!= node2
);
218 ut_ad(base
!= node3
);
219 ut_ad(node2
!= node3
);
220 ut_ad(mtr_memo_contains(mtr
, buf_block_align(base
),
221 MTR_MEMO_PAGE_X_FIX
));
222 ut_ad(mtr_memo_contains(mtr
, buf_block_align(node2
),
223 MTR_MEMO_PAGE_X_FIX
));
224 ut_ad(mtr_memo_contains(mtr
, buf_block_align(node3
),
225 MTR_MEMO_PAGE_X_FIX
));
227 buf_ptr_get_fsp_addr(node2
, &space
, &node2_addr
);
228 buf_ptr_get_fsp_addr(node3
, &space
, &node3_addr
);
230 node1_addr
= flst_get_prev_addr(node3
, mtr
);
232 /* Set prev and next fields of node2 */
233 flst_write_addr(node2
+ FLST_PREV
, node1_addr
, mtr
);
234 flst_write_addr(node2
+ FLST_NEXT
, node3_addr
, mtr
);
236 if (!fil_addr_is_null(node1_addr
)) {
237 /* Update next field of node1 */
238 node1
= fut_get_ptr(space
, node1_addr
, RW_X_LATCH
, mtr
);
239 flst_write_addr(node1
+ FLST_NEXT
, node2_addr
, mtr
);
241 /* node3 was first in list: update first field in base */
242 flst_write_addr(base
+ FLST_FIRST
, node2_addr
, mtr
);
245 /* Set prev field of node3 */
246 flst_write_addr(node3
+ FLST_PREV
, node2_addr
, mtr
);
248 /* Update len of base node */
249 len
= flst_get_len(base
, mtr
);
250 mlog_write_ulint(base
+ FLST_LEN
, len
+ 1, MLOG_4BYTES
, mtr
);
253 /************************************************************************
259 flst_base_node_t
* base
, /* in: pointer to base node of list */
260 flst_node_t
* node2
, /* in: node to remove */
261 mtr_t
* mtr
) /* in: mini-transaction handle */
265 fil_addr_t node1_addr
;
266 fil_addr_t node2_addr
;
268 fil_addr_t node3_addr
;
271 ut_ad(mtr
&& node2
&& base
);
272 ut_ad(mtr_memo_contains(mtr
, buf_block_align(base
),
273 MTR_MEMO_PAGE_X_FIX
));
274 ut_ad(mtr_memo_contains(mtr
, buf_block_align(node2
),
275 MTR_MEMO_PAGE_X_FIX
));
277 buf_ptr_get_fsp_addr(node2
, &space
, &node2_addr
);
279 node1_addr
= flst_get_prev_addr(node2
, mtr
);
280 node3_addr
= flst_get_next_addr(node2
, mtr
);
282 if (!fil_addr_is_null(node1_addr
)) {
284 /* Update next field of node1 */
286 if (node1_addr
.page
== node2_addr
.page
) {
288 node1
= buf_frame_align(node2
) + node1_addr
.boffset
;
290 node1
= fut_get_ptr(space
, node1_addr
, RW_X_LATCH
,
294 ut_ad(node1
!= node2
);
296 flst_write_addr(node1
+ FLST_NEXT
, node3_addr
, mtr
);
298 /* node2 was first in list: update first field in base */
299 flst_write_addr(base
+ FLST_FIRST
, node3_addr
, mtr
);
302 if (!fil_addr_is_null(node3_addr
)) {
303 /* Update prev field of node3 */
305 if (node3_addr
.page
== node2_addr
.page
) {
307 node3
= buf_frame_align(node2
) + node3_addr
.boffset
;
309 node3
= fut_get_ptr(space
, node3_addr
, RW_X_LATCH
,
313 ut_ad(node2
!= node3
);
315 flst_write_addr(node3
+ FLST_PREV
, node1_addr
, mtr
);
317 /* node2 was last in list: update last field in base */
318 flst_write_addr(base
+ FLST_LAST
, node1_addr
, mtr
);
321 /* Update len of base node */
322 len
= flst_get_len(base
, mtr
);
325 mlog_write_ulint(base
+ FLST_LEN
, len
- 1, MLOG_4BYTES
, mtr
);
328 /************************************************************************
329 Cuts off the tail of the list, including the node given. The number of
330 nodes which will be removed must be provided by the caller, as this function
331 does not measure the length of the tail. */
336 flst_base_node_t
* base
, /* in: pointer to base node of list */
337 flst_node_t
* node2
, /* in: first node to remove */
338 ulint n_nodes
,/* in: number of nodes to remove,
340 mtr_t
* mtr
) /* in: mini-transaction handle */
344 fil_addr_t node1_addr
;
345 fil_addr_t node2_addr
;
348 ut_ad(mtr
&& node2
&& base
);
349 ut_ad(mtr_memo_contains(mtr
, buf_block_align(base
),
350 MTR_MEMO_PAGE_X_FIX
));
351 ut_ad(mtr_memo_contains(mtr
, buf_block_align(node2
),
352 MTR_MEMO_PAGE_X_FIX
));
355 buf_ptr_get_fsp_addr(node2
, &space
, &node2_addr
);
357 node1_addr
= flst_get_prev_addr(node2
, mtr
);
359 if (!fil_addr_is_null(node1_addr
)) {
361 /* Update next field of node1 */
363 if (node1_addr
.page
== node2_addr
.page
) {
365 node1
= buf_frame_align(node2
) + node1_addr
.boffset
;
367 node1
= fut_get_ptr(space
, node1_addr
, RW_X_LATCH
,
371 flst_write_addr(node1
+ FLST_NEXT
, fil_addr_null
, mtr
);
373 /* node2 was first in list: update the field in base */
374 flst_write_addr(base
+ FLST_FIRST
, fil_addr_null
, mtr
);
377 flst_write_addr(base
+ FLST_LAST
, node1_addr
, mtr
);
379 /* Update len of base node */
380 len
= flst_get_len(base
, mtr
);
381 ut_ad(len
>= n_nodes
);
383 mlog_write_ulint(base
+ FLST_LEN
, len
- n_nodes
, MLOG_4BYTES
, mtr
);
386 /************************************************************************
387 Cuts off the tail of the list, not including the given node. The number of
388 nodes which will be removed must be provided by the caller, as this function
389 does not measure the length of the tail. */
394 flst_base_node_t
* base
, /* in: pointer to base node of list */
395 flst_node_t
* node2
, /* in: first node not to remove */
396 ulint n_nodes
,/* in: number of nodes to remove */
397 mtr_t
* mtr
) /* in: mini-transaction handle */
399 fil_addr_t node2_addr
;
403 ut_ad(mtr
&& node2
&& base
);
404 ut_ad(mtr_memo_contains(mtr
, buf_block_align(base
),
405 MTR_MEMO_PAGE_X_FIX
));
406 ut_ad(mtr_memo_contains(mtr
, buf_block_align(node2
),
407 MTR_MEMO_PAGE_X_FIX
));
410 ut_ad(fil_addr_is_null(flst_get_next_addr(node2
, mtr
)));
415 buf_ptr_get_fsp_addr(node2
, &space
, &node2_addr
);
417 /* Update next field of node2 */
418 flst_write_addr(node2
+ FLST_NEXT
, fil_addr_null
, mtr
);
420 flst_write_addr(base
+ FLST_LAST
, node2_addr
, mtr
);
422 /* Update len of base node */
423 len
= flst_get_len(base
, mtr
);
424 ut_ad(len
>= n_nodes
);
426 mlog_write_ulint(base
+ FLST_LEN
, len
- n_nodes
, MLOG_4BYTES
, mtr
);
429 /************************************************************************
430 Validates a file-based list. */
435 /* out: TRUE if ok */
436 flst_base_node_t
* base
, /* in: pointer to base node of list */
437 mtr_t
* mtr1
) /* in: mtr */
441 fil_addr_t node_addr
;
442 fil_addr_t base_addr
;
448 ut_ad(mtr_memo_contains(mtr1
, buf_block_align(base
),
449 MTR_MEMO_PAGE_X_FIX
));
451 /* We use two mini-transaction handles: the first is used to
452 lock the base node, and prevent other threads from modifying the
453 list. The second is used to traverse the list. We cannot run the
454 second mtr without committing it at times, because if the list
455 is long, then the x-locked pages could fill the buffer resulting
458 /* Find out the space id */
459 buf_ptr_get_fsp_addr(base
, &space
, &base_addr
);
461 len
= flst_get_len(base
, mtr1
);
462 node_addr
= flst_get_first(base
, mtr1
);
464 for (i
= 0; i
< len
; i
++) {
467 node
= fut_get_ptr(space
, node_addr
, RW_X_LATCH
, &mtr2
);
468 node_addr
= flst_get_next_addr(node
, &mtr2
);
470 mtr_commit(&mtr2
); /* Commit mtr2 each round to prevent buffer
474 ut_a(fil_addr_is_null(node_addr
));
476 node_addr
= flst_get_last(base
, mtr1
);
478 for (i
= 0; i
< len
; i
++) {
481 node
= fut_get_ptr(space
, node_addr
, RW_X_LATCH
, &mtr2
);
482 node_addr
= flst_get_prev_addr(node
, &mtr2
);
484 mtr_commit(&mtr2
); /* Commit mtr2 each round to prevent buffer
488 ut_a(fil_addr_is_null(node_addr
));
493 /************************************************************************
494 Prints info of a file-based list. */
499 flst_base_node_t
* base
, /* in: pointer to base node of list */
500 mtr_t
* mtr
) /* in: mtr */
506 ut_ad(mtr_memo_contains(mtr
, buf_block_align(base
),
507 MTR_MEMO_PAGE_X_FIX
));
508 frame
= buf_frame_align(base
);
510 len
= flst_get_len(base
, mtr
);
514 "Base node in space %lu page %lu byte offset %lu; len %lu\n",
515 (ulong
) buf_frame_get_space_id(frame
),
516 (ulong
) buf_frame_get_page_no(frame
),
517 (ulong
) (base
- frame
), (ulong
) len
);