Commit 4a7bd430 authored by marko's avatar marko

branches/innodb+: Refuse to buffer deletes if that could lead to B-tree

pages becoming empty.  Remove work-arounds for empty pages.  This fixes
Issue #82.

ibuf_get_volume_buffered(): Add the output parameter n_recs, for returning
the minimum number of records on the page.

ibuf_insert_low(): Refuse to buffer IBUF_OP_DELETE if the page could
become empty.

btr_page_get_father_node_ptr(): Remove the work-around for the page
being empty.

page_zip_dir_delete(): Revert to the version from branches/zip.
Always invoke page_zip_clear_rec().
parent 70f11286
......@@ -603,18 +603,7 @@ btr_page_get_father_node_ptr(
level = btr_page_get_level(btr_cur_get_page(cursor), mtr);
page = btr_cur_get_page(cursor);
if (UNIV_UNLIKELY(page_get_n_recs(page) == 0)) {
/* Empty pages can result from buffered delete operations.
The first record from the free list can be used to find the
father node. */
user_rec = page_header_get_ptr(page, PAGE_FREE);
/* TODO: make sure that empty pages are never recompressed. */
ut_a(user_rec);
} else {
user_rec = btr_cur_get_rec(cursor);
}
ut_a(page_rec_is_user_rec(user_rec));
tuple = dict_index_build_node_ptr(index, user_rec, 0, heap, level);
......
......@@ -658,9 +658,6 @@ btr_cur_search_to_nth_level(
page_mode = mode;
}
/* TO DO: if the page is empty, advance to the next page.
There may be a match on the first nonempty right sibling. */
page_cur_search_with_match(
block, index, tuple, page_mode, &up_match, &up_bytes,
&low_match, &low_bytes, page_cursor);
......
......@@ -2542,6 +2542,8 @@ ibuf_get_volume_buffered(
or BTR_MODIFY_TREE */
ulint space, /* in: space id */
ulint page_no,/* in: page number of an index page */
ulint* n_recs, /* out: minimum number of records on the page
after the buffered changes have been applied */
mtr_t* mtr) /* in: mtr */
{
ulint volume;
......@@ -2561,6 +2563,7 @@ ibuf_get_volume_buffered(
pcur */
volume = 0;
*n_recs = 0;
rec = btr_pcur_get_rec(pcur);
page = page_align(rec);
......@@ -2657,6 +2660,20 @@ ibuf_get_volume_buffered(
volume += ibuf_rec_get_volume(rec);
switch (ibuf_rec_get_op_type(rec)) {
case IBUF_OP_INSERT:
case IBUF_OP_DELETE_MARK:
(*n_recs)++;
break;
case IBUF_OP_DELETE:
if (*n_recs > 0) {
(*n_recs)--;
}
break;
default:
ut_error;
}
rec = page_rec_get_next(rec);
}
......@@ -2704,6 +2721,20 @@ ibuf_get_volume_buffered(
volume += ibuf_rec_get_volume(rec);
switch (ibuf_rec_get_op_type(rec)) {
case IBUF_OP_INSERT:
case IBUF_OP_DELETE_MARK:
(*n_recs)++;
break;
case IBUF_OP_DELETE:
if (*n_recs > 0) {
(*n_recs)--;
}
break;
default:
ut_error;
}
rec = page_rec_get_next(rec);
}
}
......@@ -2986,6 +3017,7 @@ ibuf_insert_low(
dtuple_t* ibuf_entry;
mem_heap_t* heap;
ulint buffered;
ulint min_n_recs;
rec_t* ins_rec;
ibool old_bit_value;
page_t* bitmap_page;
......@@ -3091,7 +3123,16 @@ ibuf_insert_low(
/* Find out the volume of already buffered inserts for the same index
page */
buffered = ibuf_get_volume_buffered(&pcur, space, page_no, &mtr);
buffered = ibuf_get_volume_buffered(&pcur, space, page_no,
&min_n_recs, &mtr);
if (op == IBUF_OP_DELETE && min_n_recs == 0) {
/* The page could become empty after the record is
deleted. Refuse to buffer the operation. */
err = DB_STRONG_FAIL;
goto function_exit;
}
#ifdef UNIV_IBUF_COUNT_DEBUG
ut_a((buffered == 0) || ibuf_count_get(space, page_no));
......
......@@ -4116,29 +4116,9 @@ page_zip_dir_delete(
The "owned" and "deleted" flags will be cleared. */
mach_write_to_2(slot_free, page_offset(rec));
/* The compression algorithm expects info_bits and n_owned
to be 0 for deleted records. */
rec[-REC_N_NEW_EXTRA_BYTES] = 0; /* info_bits and n_owned */
if (!page_is_leaf(page)) {
if (!page_is_leaf(page) || !dict_index_is_clust(index)) {
ut_ad(!rec_offs_any_extern(offsets));
goto clear_rec;
}
if (!dict_index_is_clust(index)) {
ut_ad(!rec_offs_any_extern(offsets));
/* Do not clear the last record on a secondary index
leaf page, because that could break delete
buffering. */
if (!page_get_n_recs(page)) {
#ifdef UNIV_ZIP_DEBUG
ut_a(page_zip_validate(page_zip, page));
#endif /* UNIV_ZIP_DEBUG */
return;
}
goto clear_rec;
goto skip_blobs;
}
n_ext = rec_offs_n_extern(offsets);
......@@ -4168,7 +4148,11 @@ page_zip_dir_delete(
memset(ext_end, 0, n_ext * BTR_EXTERN_FIELD_REF_SIZE);
}
clear_rec:
skip_blobs:
/* The compression algorithm expects info_bits and n_owned
to be 0 for deleted records. */
rec[-REC_N_NEW_EXTRA_BYTES] = 0; /* info_bits and n_owned */
page_zip_clear_rec(page_zip, rec, index, offsets);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment