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);