mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / innobase / fut / fut0lst.c
blob75fa8bf5552f6ad53f1ef8b901a08a9f7dd71ad8
1 /**********************************************************************
2 File-based list utilities
4 (c) 1995 Innobase Oy
6 Created 11/28/1995 Heikki Tuuri
7 ***********************************************************************/
9 #include "fut0lst.h"
11 #ifdef UNIV_NONINL
12 #include "fut0lst.ic"
13 #endif
15 #include "buf0buf.h"
18 /************************************************************************
19 Adds a node to an empty list. */
20 static
21 void
22 flst_add_to_empty(
23 /*==============*/
24 flst_base_node_t* base, /* in: pointer to base node of
25 empty list */
26 flst_node_t* node, /* in: node to add */
27 mtr_t* mtr) /* in: mini-transaction handle */
29 ulint space;
30 fil_addr_t node_addr;
31 ulint len;
33 ut_ad(mtr && base && node);
34 ut_ad(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);
40 ut_a(len == 0);
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. */
59 void
60 flst_add_last(
61 /*==========*/
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 */
66 ulint space;
67 fil_addr_t node_addr;
68 ulint len;
69 fil_addr_t last_addr;
70 flst_node_t* last_node;
72 ut_ad(mtr && base && node);
73 ut_ad(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 */
84 if (len != 0) {
85 if (last_addr.page == node_addr.page) {
86 last_node = buf_frame_align(node) + last_addr.boffset;
87 } else {
88 last_node = fut_get_ptr(space, last_addr, RW_X_LATCH,
89 mtr);
92 flst_insert_after(base, last_node, node, mtr);
93 } else {
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. */
102 void
103 flst_add_first(
104 /*===========*/
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 */
109 ulint space;
110 fil_addr_t node_addr;
111 ulint len;
112 fil_addr_t first_addr;
113 flst_node_t* first_node;
115 ut_ad(mtr && base && node);
116 ut_ad(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 */
127 if (len != 0) {
128 if (first_addr.page == node_addr.page) {
129 first_node = buf_frame_align(node)
130 + first_addr.boffset;
131 } else {
132 first_node = fut_get_ptr(space, first_addr,
133 RW_X_LATCH, mtr);
136 flst_insert_before(base, node, first_node, mtr);
137 } else {
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. */
146 void
147 flst_insert_after(
148 /*==============*/
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 */
154 ulint space;
155 fil_addr_t node1_addr;
156 fil_addr_t node2_addr;
157 flst_node_t* node3;
158 fil_addr_t node3_addr;
159 ulint len;
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);
185 } else {
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. */
201 void
202 flst_insert_before(
203 /*===============*/
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 */
209 ulint space;
210 flst_node_t* node1;
211 fil_addr_t node1_addr;
212 fil_addr_t node2_addr;
213 fil_addr_t node3_addr;
214 ulint len;
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);
240 } else {
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 /************************************************************************
254 Removes a node. */
256 void
257 flst_remove(
258 /*========*/
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 */
263 ulint space;
264 flst_node_t* node1;
265 fil_addr_t node1_addr;
266 fil_addr_t node2_addr;
267 flst_node_t* node3;
268 fil_addr_t node3_addr;
269 ulint len;
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;
289 } else {
290 node1 = fut_get_ptr(space, node1_addr, RW_X_LATCH,
291 mtr);
294 ut_ad(node1 != node2);
296 flst_write_addr(node1 + FLST_NEXT, node3_addr, mtr);
297 } else {
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;
308 } else {
309 node3 = fut_get_ptr(space, node3_addr, RW_X_LATCH,
310 mtr);
313 ut_ad(node2 != node3);
315 flst_write_addr(node3 + FLST_PREV, node1_addr, mtr);
316 } else {
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);
323 ut_ad(len > 0);
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. */
333 void
334 flst_cut_end(
335 /*=========*/
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,
339 must be >= 1 */
340 mtr_t* mtr) /* in: mini-transaction handle */
342 ulint space;
343 flst_node_t* node1;
344 fil_addr_t node1_addr;
345 fil_addr_t node2_addr;
346 ulint len;
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));
353 ut_ad(n_nodes > 0);
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;
366 } else {
367 node1 = fut_get_ptr(space, node1_addr, RW_X_LATCH,
368 mtr);
371 flst_write_addr(node1 + FLST_NEXT, fil_addr_null, mtr);
372 } else {
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. */
391 void
392 flst_truncate_end(
393 /*==============*/
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;
400 ulint len;
401 ulint space;
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));
408 if (n_nodes == 0) {
410 ut_ad(fil_addr_is_null(flst_get_next_addr(node2, mtr)));
412 return;
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. */
432 ibool
433 flst_validate(
434 /*==========*/
435 /* out: TRUE if ok */
436 flst_base_node_t* base, /* in: pointer to base node of list */
437 mtr_t* mtr1) /* in: mtr */
439 ulint space;
440 flst_node_t* node;
441 fil_addr_t node_addr;
442 fil_addr_t base_addr;
443 ulint len;
444 ulint i;
445 mtr_t mtr2;
447 ut_ad(base);
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
456 in a deadlock. */
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++) {
465 mtr_start(&mtr2);
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
471 becoming full */
474 ut_a(fil_addr_is_null(node_addr));
476 node_addr = flst_get_last(base, mtr1);
478 for (i = 0; i < len; i++) {
479 mtr_start(&mtr2);
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
485 becoming full */
488 ut_a(fil_addr_is_null(node_addr));
490 return(TRUE);
493 /************************************************************************
494 Prints info of a file-based list. */
496 void
497 flst_print(
498 /*=======*/
499 flst_base_node_t* base, /* in: pointer to base node of list */
500 mtr_t* mtr) /* in: mtr */
502 buf_frame_t* frame;
503 ulint len;
505 ut_ad(base && 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);
512 fprintf(stderr,
513 "FILE-BASED LIST:\n"
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);