1
/**********************************************************************
2
File-based list utilities
6
Created 11/28/1995 Heikki Tuuri
7
***********************************************************************/
16
#include "page0page.h"
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_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
36
ut_ad(mtr_memo_contains_page(mtr, node, MTR_MEMO_PAGE_X_FIX));
37
len = flst_get_len(base, mtr);
40
buf_ptr_get_fsp_addr(node, &space, &node_addr);
42
/* Update first and last fields of base node */
43
flst_write_addr(base + FLST_FIRST, node_addr, mtr);
44
flst_write_addr(base + FLST_LAST, node_addr, mtr);
46
/* Set prev and next fields of node to add */
47
flst_write_addr(node + FLST_PREV, fil_addr_null, mtr);
48
flst_write_addr(node + FLST_NEXT, fil_addr_null, mtr);
50
/* Update len of base node */
51
mlog_write_ulint(base + FLST_LEN, len + 1, MLOG_4BYTES, mtr);
54
/************************************************************************
55
Adds a node as the last node in a list. */
60
flst_base_node_t* base, /* in: pointer to base node of list */
61
flst_node_t* node, /* in: node to add */
62
mtr_t* mtr) /* in: mini-transaction handle */
68
flst_node_t* last_node;
70
ut_ad(mtr && base && node);
72
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
73
ut_ad(mtr_memo_contains_page(mtr, node, MTR_MEMO_PAGE_X_FIX));
74
len = flst_get_len(base, mtr);
75
last_addr = flst_get_last(base, mtr);
77
buf_ptr_get_fsp_addr(node, &space, &node_addr);
79
/* If the list is not empty, call flst_insert_after */
81
if (last_addr.page == node_addr.page) {
82
last_node = page_align(node) + last_addr.boffset;
84
ulint zip_size = fil_space_get_zip_size(space);
86
last_node = fut_get_ptr(space, zip_size, last_addr,
90
flst_insert_after(base, last_node, node, mtr);
92
/* else call flst_add_to_empty */
93
flst_add_to_empty(base, node, mtr);
97
/************************************************************************
98
Adds a node as the first node in a list. */
103
flst_base_node_t* base, /* in: pointer to base node of list */
104
flst_node_t* node, /* in: node to add */
105
mtr_t* mtr) /* in: mini-transaction handle */
108
fil_addr_t node_addr;
110
fil_addr_t first_addr;
111
flst_node_t* first_node;
113
ut_ad(mtr && base && node);
115
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
116
ut_ad(mtr_memo_contains_page(mtr, node, MTR_MEMO_PAGE_X_FIX));
117
len = flst_get_len(base, mtr);
118
first_addr = flst_get_first(base, mtr);
120
buf_ptr_get_fsp_addr(node, &space, &node_addr);
122
/* If the list is not empty, call flst_insert_before */
124
if (first_addr.page == node_addr.page) {
125
first_node = page_align(node) + first_addr.boffset;
127
ulint zip_size = fil_space_get_zip_size(space);
129
first_node = fut_get_ptr(space, zip_size, first_addr,
133
flst_insert_before(base, node, first_node, mtr);
135
/* else call flst_add_to_empty */
136
flst_add_to_empty(base, node, mtr);
140
/************************************************************************
141
Inserts a node after another in a list. */
146
flst_base_node_t* base, /* in: pointer to base node of list */
147
flst_node_t* node1, /* in: node to insert after */
148
flst_node_t* node2, /* in: node to add */
149
mtr_t* mtr) /* in: mini-transaction handle */
152
fil_addr_t node1_addr;
153
fil_addr_t node2_addr;
155
fil_addr_t node3_addr;
158
ut_ad(mtr && node1 && node2 && base);
159
ut_ad(base != node1);
160
ut_ad(base != node2);
161
ut_ad(node2 != node1);
162
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
163
ut_ad(mtr_memo_contains_page(mtr, node1, MTR_MEMO_PAGE_X_FIX));
164
ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
166
buf_ptr_get_fsp_addr(node1, &space, &node1_addr);
167
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
169
node3_addr = flst_get_next_addr(node1, mtr);
171
/* Set prev and next fields of node2 */
172
flst_write_addr(node2 + FLST_PREV, node1_addr, mtr);
173
flst_write_addr(node2 + FLST_NEXT, node3_addr, mtr);
175
if (!fil_addr_is_null(node3_addr)) {
176
/* Update prev field of node3 */
177
ulint zip_size = fil_space_get_zip_size(space);
179
node3 = fut_get_ptr(space, zip_size,
180
node3_addr, RW_X_LATCH, mtr);
181
flst_write_addr(node3 + FLST_PREV, node2_addr, mtr);
183
/* node1 was last in list: update last field in base */
184
flst_write_addr(base + FLST_LAST, node2_addr, mtr);
187
/* Set next field of node1 */
188
flst_write_addr(node1 + FLST_NEXT, node2_addr, mtr);
190
/* Update len of base node */
191
len = flst_get_len(base, mtr);
192
mlog_write_ulint(base + FLST_LEN, len + 1, MLOG_4BYTES, mtr);
195
/************************************************************************
196
Inserts a node before another in a list. */
201
flst_base_node_t* base, /* in: pointer to base node of list */
202
flst_node_t* node2, /* in: node to insert */
203
flst_node_t* node3, /* in: node to insert before */
204
mtr_t* mtr) /* in: mini-transaction handle */
208
fil_addr_t node1_addr;
209
fil_addr_t node2_addr;
210
fil_addr_t node3_addr;
213
ut_ad(mtr && node2 && node3 && base);
214
ut_ad(base != node2);
215
ut_ad(base != node3);
216
ut_ad(node2 != node3);
217
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
218
ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
219
ut_ad(mtr_memo_contains_page(mtr, node3, MTR_MEMO_PAGE_X_FIX));
221
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
222
buf_ptr_get_fsp_addr(node3, &space, &node3_addr);
224
node1_addr = flst_get_prev_addr(node3, mtr);
226
/* Set prev and next fields of node2 */
227
flst_write_addr(node2 + FLST_PREV, node1_addr, mtr);
228
flst_write_addr(node2 + FLST_NEXT, node3_addr, mtr);
230
if (!fil_addr_is_null(node1_addr)) {
231
ulint zip_size = fil_space_get_zip_size(space);
232
/* Update next field of node1 */
233
node1 = fut_get_ptr(space, zip_size, node1_addr,
235
flst_write_addr(node1 + FLST_NEXT, node2_addr, mtr);
237
/* node3 was first in list: update first field in base */
238
flst_write_addr(base + FLST_FIRST, node2_addr, mtr);
241
/* Set prev field of node3 */
242
flst_write_addr(node3 + FLST_PREV, node2_addr, mtr);
244
/* Update len of base node */
245
len = flst_get_len(base, mtr);
246
mlog_write_ulint(base + FLST_LEN, len + 1, MLOG_4BYTES, mtr);
249
/************************************************************************
255
flst_base_node_t* base, /* in: pointer to base node of list */
256
flst_node_t* node2, /* in: node to remove */
257
mtr_t* mtr) /* in: mini-transaction handle */
262
fil_addr_t node1_addr;
263
fil_addr_t node2_addr;
265
fil_addr_t node3_addr;
268
ut_ad(mtr && node2 && base);
269
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
270
ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
272
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
273
zip_size = fil_space_get_zip_size(space);
275
node1_addr = flst_get_prev_addr(node2, mtr);
276
node3_addr = flst_get_next_addr(node2, mtr);
278
if (!fil_addr_is_null(node1_addr)) {
280
/* Update next field of node1 */
282
if (node1_addr.page == node2_addr.page) {
284
node1 = page_align(node2) + node1_addr.boffset;
286
node1 = fut_get_ptr(space, zip_size,
287
node1_addr, RW_X_LATCH, mtr);
290
ut_ad(node1 != node2);
292
flst_write_addr(node1 + FLST_NEXT, node3_addr, mtr);
294
/* node2 was first in list: update first field in base */
295
flst_write_addr(base + FLST_FIRST, node3_addr, mtr);
298
if (!fil_addr_is_null(node3_addr)) {
299
/* Update prev field of node3 */
301
if (node3_addr.page == node2_addr.page) {
303
node3 = page_align(node2) + node3_addr.boffset;
305
node3 = fut_get_ptr(space, zip_size,
306
node3_addr, RW_X_LATCH, mtr);
309
ut_ad(node2 != node3);
311
flst_write_addr(node3 + FLST_PREV, node1_addr, mtr);
313
/* node2 was last in list: update last field in base */
314
flst_write_addr(base + FLST_LAST, node1_addr, mtr);
317
/* Update len of base node */
318
len = flst_get_len(base, mtr);
321
mlog_write_ulint(base + FLST_LEN, len - 1, MLOG_4BYTES, mtr);
324
/************************************************************************
325
Cuts off the tail of the list, including the node given. The number of
326
nodes which will be removed must be provided by the caller, as this function
327
does not measure the length of the tail. */
332
flst_base_node_t* base, /* in: pointer to base node of list */
333
flst_node_t* node2, /* in: first node to remove */
334
ulint n_nodes,/* in: number of nodes to remove,
336
mtr_t* mtr) /* in: mini-transaction handle */
340
fil_addr_t node1_addr;
341
fil_addr_t node2_addr;
344
ut_ad(mtr && node2 && base);
345
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
346
ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
349
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
351
node1_addr = flst_get_prev_addr(node2, mtr);
353
if (!fil_addr_is_null(node1_addr)) {
355
/* Update next field of node1 */
357
if (node1_addr.page == node2_addr.page) {
359
node1 = page_align(node2) + node1_addr.boffset;
361
node1 = fut_get_ptr(space,
362
fil_space_get_zip_size(space),
363
node1_addr, RW_X_LATCH, mtr);
366
flst_write_addr(node1 + FLST_NEXT, fil_addr_null, mtr);
368
/* node2 was first in list: update the field in base */
369
flst_write_addr(base + FLST_FIRST, fil_addr_null, mtr);
372
flst_write_addr(base + FLST_LAST, node1_addr, mtr);
374
/* Update len of base node */
375
len = flst_get_len(base, mtr);
376
ut_ad(len >= n_nodes);
378
mlog_write_ulint(base + FLST_LEN, len - n_nodes, MLOG_4BYTES, mtr);
381
/************************************************************************
382
Cuts off the tail of the list, not including the given node. The number of
383
nodes which will be removed must be provided by the caller, as this function
384
does not measure the length of the tail. */
389
flst_base_node_t* base, /* in: pointer to base node of list */
390
flst_node_t* node2, /* in: first node not to remove */
391
ulint n_nodes,/* in: number of nodes to remove */
392
mtr_t* mtr) /* in: mini-transaction handle */
394
fil_addr_t node2_addr;
398
ut_ad(mtr && node2 && base);
399
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
400
ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
403
ut_ad(fil_addr_is_null(flst_get_next_addr(node2, mtr)));
408
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
410
/* Update next field of node2 */
411
flst_write_addr(node2 + FLST_NEXT, fil_addr_null, mtr);
413
flst_write_addr(base + FLST_LAST, node2_addr, mtr);
415
/* Update len of base node */
416
len = flst_get_len(base, mtr);
417
ut_ad(len >= n_nodes);
419
mlog_write_ulint(base + FLST_LEN, len - n_nodes, MLOG_4BYTES, mtr);
422
/************************************************************************
423
Validates a file-based list. */
428
/* out: TRUE if ok */
429
const flst_base_node_t* base, /* in: pointer to base node of list */
430
mtr_t* mtr1) /* in: mtr */
434
const flst_node_t* node;
435
fil_addr_t node_addr;
436
fil_addr_t base_addr;
442
ut_ad(mtr_memo_contains_page(mtr1, base, MTR_MEMO_PAGE_X_FIX));
444
/* We use two mini-transaction handles: the first is used to
445
lock the base node, and prevent other threads from modifying the
446
list. The second is used to traverse the list. We cannot run the
447
second mtr without committing it at times, because if the list
448
is long, then the x-locked pages could fill the buffer resulting
451
/* Find out the space id */
452
buf_ptr_get_fsp_addr(base, &space, &base_addr);
453
zip_size = fil_space_get_zip_size(space);
455
len = flst_get_len(base, mtr1);
456
node_addr = flst_get_first(base, mtr1);
458
for (i = 0; i < len; i++) {
461
node = fut_get_ptr(space, zip_size,
462
node_addr, RW_X_LATCH, &mtr2);
463
node_addr = flst_get_next_addr(node, &mtr2);
465
mtr_commit(&mtr2); /* Commit mtr2 each round to prevent buffer
469
ut_a(fil_addr_is_null(node_addr));
471
node_addr = flst_get_last(base, mtr1);
473
for (i = 0; i < len; i++) {
476
node = fut_get_ptr(space, zip_size,
477
node_addr, RW_X_LATCH, &mtr2);
478
node_addr = flst_get_prev_addr(node, &mtr2);
480
mtr_commit(&mtr2); /* Commit mtr2 each round to prevent buffer
484
ut_a(fil_addr_is_null(node_addr));
489
/************************************************************************
490
Prints info of a file-based list. */
495
const flst_base_node_t* base, /* in: pointer to base node of list */
496
mtr_t* mtr) /* in: mtr */
498
const buf_frame_t* frame;
502
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
503
frame = page_align((byte*) base);
505
len = flst_get_len(base, mtr);
509
"Base node in space %lu page %lu byte offset %lu; len %lu\n",
510
(ulong) page_get_space_id(frame),
511
(ulong) page_get_page_no(frame),
512
(ulong) page_offset(base), (ulong) len);