Commit 81a283f8 authored by marko's avatar marko

branches/zip: page_zip_decompress(): Split into

page_zip_decompress_node_ptrs(), page_zip_decompress_sec(), and
page_zip_decompress_clust().  See also r856.
parent edb0f042
...@@ -1630,198 +1630,339 @@ page_zip_apply_log( ...@@ -1630,198 +1630,339 @@ page_zip_apply_log(
} }
/************************************************************************** /**************************************************************************
Decompress a page. This function should tolerate errors on the compressed Decompress the records of a node pointer page. */
page. Instead of letting assertions fail, it will return FALSE if an static
inconsistency is detected. */
ibool ibool
page_zip_decompress( page_zip_decompress_node_ptrs(
/*================*/ /*==========================*/
/* out: TRUE on success, FALSE on failure */ /* out: TRUE on success,
page_zip_des_t* page_zip,/* in: data, size; FALSE on failure */
out: m_start, m_end, n_blobs */ page_zip_des_t* page_zip, /* in/out: compressed page */
page_t* page) /* out: uncompressed page, may be trashed */ z_stream* d_stream, /* in/out: compressed page stream */
rec_t** recs, /* in: dense page directory
sorted by address */
ulint n_dense, /* in: size of recs[] */
dict_index_t* index, /* in: the index of the page */
ulint* offsets, /* in/out: temporary offsets */
mem_heap_t* heap) /* in: temporary memory heap */
{ {
z_stream d_stream; ulint heap_status = REC_STATUS_NODE_PTR
dict_index_t* index = NULL; | 2 << REC_HEAP_NO_SHIFT;
rec_t** recs; /* dense page directory, sorted by address */
ulint slot; ulint slot;
ulint heap_status;/* heap_no and status bits */
ulint n_dense;/* number of user records on the page */
ulint trx_id_col = ULINT_UNDEFINED;
mem_heap_t* heap;
ulint* offsets = NULL;
ulint info_bits = 0;
const byte* storage; const byte* storage;
ut_ad(page_zip_simple_validate(page_zip)); /* Subtract the space reserved for uncompressed data. */
d_stream->avail_in -= n_dense
* (PAGE_ZIP_DIR_SLOT_SIZE + REC_NODE_PTR_SIZE);
/* The dense directory excludes the infimum and supremum records. */ /* Decompress the records in heap_no order. */
n_dense = page_dir_get_n_heap(page_zip->data) - 2; for (slot = 0; slot < n_dense; slot++) {
if (UNIV_UNLIKELY(n_dense * PAGE_ZIP_DIR_SLOT_SIZE rec_t* rec = recs[slot];
>= page_zip->size)) {
return(FALSE); d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
- d_stream->next_out;
ut_ad(d_stream->avail_out < UNIV_PAGE_SIZE
- PAGE_ZIP_START - PAGE_DIR);
switch (inflate(d_stream, Z_SYNC_FLUSH)) {
case Z_STREAM_END:
/* Apparently, n_dense has grown
since the time the page was last compressed. */
goto zlib_done;
case Z_OK:
case Z_BUF_ERROR:
if (!d_stream->avail_out) {
break;
}
/* fall through */
default:
goto zlib_error;
} }
heap = mem_heap_create(n_dense * (3 * sizeof *recs)); ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
recs = mem_heap_alloc(heap, n_dense * (2 * sizeof *recs)); /* Prepare to decompress the data bytes. */
d_stream->next_out = rec;
/* Set heap_no and the status bits. */
mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
heap_status += 1 << REC_HEAP_NO_SHIFT;
#ifdef UNIV_ZIP_DEBUG /* Read the offsets. The status bits are needed here. */
/* Clear the page. */ offsets = rec_get_offsets(rec, index, offsets,
memset(page, 0x55, UNIV_PAGE_SIZE); ULINT_UNDEFINED, &heap);
#endif /* UNIV_ZIP_DEBUG */
/* Copy the page header. */
memcpy(page, page_zip->data, PAGE_DATA);
/* Copy the page directory. */ /* Non-leaf nodes should not have any externally
if (UNIV_UNLIKELY stored columns. */
(!page_zip_dir_decode(page_zip, page, ut_ad(!rec_offs_any_extern(offsets));
recs, recs + n_dense, n_dense))) {
mem_heap_free(heap); /* Decompress the data bytes, except node_ptr. */
return(FALSE); d_stream->avail_out = rec_offs_data_size(offsets)
- REC_NODE_PTR_SIZE;
switch (inflate(d_stream, Z_SYNC_FLUSH)) {
case Z_STREAM_END:
goto zlib_done;
case Z_OK:
case Z_BUF_ERROR:
if (!d_stream->avail_out) {
break;
}
/* fall through */
default:
goto zlib_error;
} }
/* Copy the infimum and supremum records. */ /* Clear the node pointer in case the record
memcpy(page + (PAGE_NEW_INFIMUM - REC_N_NEW_EXTRA_BYTES), will be deleted and the space will be reallocated
infimum_extra, sizeof infimum_extra); to a smaller record. */
if (UNIV_UNLIKELY(!page_get_n_recs(page))) { memset(d_stream->next_out, 0, REC_NODE_PTR_SIZE);
rec_set_next_offs_new(page + PAGE_NEW_INFIMUM, d_stream->next_out += REC_NODE_PTR_SIZE;
PAGE_NEW_SUPREMUM);
} else { ut_ad(d_stream->next_out == rec_get_end(rec, offsets));
rec_set_next_offs_new(page + PAGE_NEW_INFIMUM,
page_zip_dir_get(page_zip, 0)
& PAGE_ZIP_DIR_SLOT_MASK);
} }
memcpy(page + PAGE_NEW_INFIMUM, infimum_data, sizeof infimum_data);
memcpy(page + (PAGE_NEW_SUPREMUM - REC_N_NEW_EXTRA_BYTES + 1),
supremum_extra_data, sizeof supremum_extra_data);
d_stream.zalloc = page_zip_malloc; /* Decompress any trailing garbage, in case the last record was
d_stream.zfree = page_zip_free; allocated from an originally longer space on the free list. */
d_stream.opaque = (voidpf) 0; d_stream->avail_out = page_header_get_field(page_zip->data,
PAGE_HEAP_TOP)
- page_offset(d_stream->next_out);
if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
- PAGE_ZIP_START - PAGE_DIR)) {
if (UNIV_UNLIKELY(inflateInit(&d_stream) != Z_OK)) { goto zlib_error;
ut_error;
} }
d_stream.next_in = page_zip->data + PAGE_DATA; if (UNIV_UNLIKELY(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
/* Subtract the space reserved for zlib_error:
the page header and the end marker of the modification log. */ inflateEnd(d_stream);
d_stream.avail_in = page_zip->size - (PAGE_DATA + 1); return(FALSE);
}
d_stream.next_out = page + PAGE_ZIP_START; /* Note that d_stream->avail_out > 0 may hold here
d_stream.avail_out = UNIV_PAGE_SIZE - PAGE_ZIP_START; if the modification log is nonempty. */
/* Decode the zlib header and the index information. */ zlib_done:
if (UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK) if (UNIV_UNLIKELY(inflateEnd(d_stream) != Z_OK)) {
|| UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)) { ut_error;
}
goto zlib_error; {
page_t* page = page_align(d_stream->next_out);
/* Clear the unused heap space on the uncompressed page. */
memset(d_stream->next_out, 0,
page_dir_get_nth_slot(page,
page_dir_get_n_slots(page) - 1)
- d_stream->next_out);
} }
index = page_zip_fields_decode( page_zip->m_start = PAGE_DATA + d_stream->total_in;
page + PAGE_ZIP_START, d_stream.next_out,
page_is_leaf(page) ? &trx_id_col : NULL);
if (UNIV_UNLIKELY(!index)) { /* Apply the modification log. */
{
const byte* mod_log_ptr;
mod_log_ptr = page_zip_apply_log(page_zip->data
+ page_zip->m_start,
d_stream->avail_in + 1,
recs, n_dense,
ULINT_UNDEFINED, heap_status,
index, offsets);
goto zlib_error; if (UNIV_UNLIKELY(!mod_log_ptr)) {
return(FALSE);
}
page_zip->m_end = mod_log_ptr - page_zip->data;
ut_a(page_zip_get_trailer_len(page_zip, index, NULL)
+ page_zip->m_end < page_zip->size);
} }
/* Decompress the user records. */ /* Restore the uncompressed columns in heap_no order. */
d_stream.next_out = page + PAGE_ZIP_START; storage = page_zip->data + page_zip->size
- n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
{ for (slot = 0; slot < n_dense; slot++) {
/* Pre-allocate the offsets rec_t* rec = recs[slot];
for rec_get_offsets_reverse(). */
ulint n;
if (page_is_leaf(page)) { offsets = rec_get_offsets(rec, index, offsets,
n = dict_index_get_n_fields(index); ULINT_UNDEFINED, &heap);
heap_status = REC_STATUS_ORDINARY /* Non-leaf nodes should not have any externally
| 2 << REC_HEAP_NO_SHIFT; stored columns. */
ut_ad(!rec_offs_any_extern(offsets));
storage -= REC_NODE_PTR_SIZE;
/* Subtract the space reserved memcpy(rec_get_end(rec, offsets) - REC_NODE_PTR_SIZE,
for uncompressed data. */ storage, REC_NODE_PTR_SIZE);
if (trx_id_col != ULINT_UNDEFINED) {
d_stream.avail_in -= n_dense
* (PAGE_ZIP_DIR_SLOT_SIZE
+ DATA_TRX_ID_LEN
+ DATA_ROLL_PTR_LEN);
} else {
d_stream.avail_in -= n_dense
* PAGE_ZIP_DIR_SLOT_SIZE;
} }
} else {
n = dict_index_get_n_unique_in_tree(index) + 1;
heap_status = REC_STATUS_NODE_PTR
| 2 << REC_HEAP_NO_SHIFT;
if (UNIV_UNLIKELY return(TRUE);
(mach_read_from_4(page + FIL_PAGE_PREV) }
== FIL_NULL)) {
info_bits = REC_INFO_MIN_REC_FLAG;
}
/* Subtract the space reserved /**************************************************************************
for uncompressed data. */ Decompress the records of a leaf node of a secondary index. */
d_stream.avail_in -= n_dense static
* (PAGE_ZIP_DIR_SLOT_SIZE + REC_NODE_PTR_SIZE); ibool
} page_zip_decompress_sec(
/*====================*/
/* out: TRUE on success,
FALSE on failure */
page_zip_des_t* page_zip, /* in/out: compressed page */
z_stream* d_stream, /* in/out: compressed page stream */
rec_t** recs, /* in: dense page directory
sorted by address */
ulint n_dense, /* in: size of recs[] */
dict_index_t* index, /* in: the index of the page */
ulint* offsets) /* in/out: temporary offsets */
{
ulint heap_status = REC_STATUS_ORDINARY | 2 << REC_HEAP_NO_SHIFT;
ulint slot;
n += 1 + REC_OFFS_HEADER_SIZE; /* Subtract the space reserved for uncompressed data. */
offsets = mem_heap_alloc(heap, n * sizeof(ulint)); d_stream->avail_in -= n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
*offsets = n;
}
/* Decompress the records in heap_no order. */
for (slot = 0; slot < n_dense; slot++) { for (slot = 0; slot < n_dense; slot++) {
rec_t* rec = recs[slot]; rec_t* rec = recs[slot];
d_stream.avail_out = rec - REC_N_NEW_EXTRA_BYTES /* Decompress everything up to this record. */
- d_stream.next_out; d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
- d_stream->next_out;
ut_ad(d_stream.avail_out < UNIV_PAGE_SIZE if (UNIV_LIKELY(d_stream->avail_out)) {
- PAGE_ZIP_START - PAGE_DIR); switch (inflate(d_stream, Z_SYNC_FLUSH)) {
switch (inflate(&d_stream, Z_SYNC_FLUSH)) {
case Z_STREAM_END: case Z_STREAM_END:
/* Apparently, n_dense has grown /* Apparently, n_dense has grown
since the time the page was last compressed. */ since the time the page was last compressed. */
goto zlib_done; goto zlib_done;
case Z_OK: case Z_OK:
case Z_BUF_ERROR: case Z_BUF_ERROR:
if (!d_stream.avail_out) { if (!d_stream->avail_out) {
break; break;
} }
/* fall through */
default: default:
goto zlib_error; goto zlib_error;
} }
}
ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
/* Skip the REC_N_NEW_EXTRA_BYTES. */
d_stream->next_out = rec;
ut_ad(d_stream.next_out == rec - REC_N_NEW_EXTRA_BYTES);
/* Prepare to decompress the data bytes. */
d_stream.next_out = rec;
/* Set heap_no and the status bits. */ /* Set heap_no and the status bits. */
mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status); mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
heap_status += 1 << REC_HEAP_NO_SHIFT; heap_status += 1 << REC_HEAP_NO_SHIFT;
}
/* Read the offsets. The status bits are needed here. */ /* Decompress the data of the last record and any trailing garbage,
offsets = rec_get_offsets(rec, index, offsets, in case the last record was allocated from an originally longer space
ULINT_UNDEFINED, &heap); on the free list. */
d_stream->avail_out = page_header_get_field(page_zip->data,
PAGE_HEAP_TOP)
- page_offset(d_stream->next_out);
if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
- PAGE_ZIP_START - PAGE_DIR)) {
if (!page_is_leaf(page)) { goto zlib_error;
/* Non-leaf nodes should not have any externally }
stored columns. */
ut_ad(!rec_offs_any_extern(offsets));
/* Decompress the data bytes, except node_ptr. */ if (UNIV_UNLIKELY(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
d_stream.avail_out = rec_offs_data_size(offsets) zlib_error:
- REC_NODE_PTR_SIZE; inflateEnd(d_stream);
return(FALSE);
}
/* Note that d_stream->avail_out > 0 may hold here
if the modification log is nonempty. */
zlib_done:
if (UNIV_UNLIKELY(inflateEnd(d_stream) != Z_OK)) {
ut_error;
}
{
page_t* page = page_align(d_stream->next_out);
/* Clear the unused heap space on the uncompressed page. */
memset(d_stream->next_out, 0,
page_dir_get_nth_slot(page,
page_dir_get_n_slots(page) - 1)
- d_stream->next_out);
}
page_zip->m_start = PAGE_DATA + d_stream->total_in;
/* Apply the modification log. */
{
const byte* mod_log_ptr;
mod_log_ptr = page_zip_apply_log(page_zip->data
+ page_zip->m_start,
d_stream->avail_in + 1,
recs, n_dense,
ULINT_UNDEFINED, heap_status,
index, offsets);
switch (inflate(&d_stream, Z_SYNC_FLUSH)) { if (UNIV_UNLIKELY(!mod_log_ptr)) {
return(FALSE);
}
page_zip->m_end = mod_log_ptr - page_zip->data;
ut_a(page_zip_get_trailer_len(page_zip, index, NULL)
+ page_zip->m_end < page_zip->size);
}
/* There are no uncompressed columns on leaf pages of
secondary indexes. */
return(TRUE);
}
/**************************************************************************
Compress the records of a leaf node of a clustered index. */
static
ibool
page_zip_decompress_clust(
/*======================*/
/* out: TRUE on success,
FALSE on failure */
page_zip_des_t* page_zip, /* in/out: compressed page */
z_stream* d_stream, /* in/out: compressed page stream */
rec_t** recs, /* in: dense page directory
sorted by address */
ulint n_dense, /* in: size of recs[] */
dict_index_t* index, /* in: the index of the page */
ulint trx_id_col, /* index of the trx_id column */
ulint* offsets, /* in/out: temporary offsets */
mem_heap_t* heap) /* in: temporary memory heap */
{
int err;
ulint slot;
ulint heap_status = REC_STATUS_ORDINARY
| 2 << REC_HEAP_NO_SHIFT;
const byte* storage;
const byte* externs;
/* Subtract the space reserved for uncompressed data. */
d_stream->avail_in -= n_dense * (PAGE_ZIP_DIR_SLOT_SIZE
+ DATA_TRX_ID_LEN
+ DATA_ROLL_PTR_LEN);
/* Decompress the records in heap_no order. */
for (slot = 0; slot < n_dense; slot++) {
rec_t* rec = recs[slot];
d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
- d_stream->next_out;
ut_ad(d_stream->avail_out < UNIV_PAGE_SIZE
- PAGE_ZIP_START - PAGE_DIR);
err = inflate(d_stream, Z_SYNC_FLUSH);
switch (err) {
case Z_STREAM_END: case Z_STREAM_END:
/* Apparently, n_dense has grown
since the time the page was last compressed. */
goto zlib_done;
case Z_OK: case Z_OK:
case Z_BUF_ERROR: case Z_BUF_ERROR:
if (!d_stream.avail_out) { if (UNIV_LIKELY(!d_stream->avail_out)) {
break; break;
} }
/* fall through */ /* fall through */
...@@ -1829,15 +1970,17 @@ page_zip_decompress( ...@@ -1829,15 +1970,17 @@ page_zip_decompress(
goto zlib_error; goto zlib_error;
} }
/* Clear the node pointer in case the record ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
will be deleted and the space will be reallocated /* Prepare to decompress the data bytes. */
to a smaller record. */ d_stream->next_out = rec;
memset(d_stream.next_out, 0, REC_NODE_PTR_SIZE); /* Set heap_no and the status bits. */
d_stream.next_out += REC_NODE_PTR_SIZE; mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
} else if (UNIV_LIKELY(trx_id_col == ULINT_UNDEFINED)) { heap_status += 1 << REC_HEAP_NO_SHIFT;
/* This is a leaf page in a non-clustered index. */
goto decompress_tail; /* Read the offsets. The status bits are needed here. */
} else { offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap);
/* This is a leaf page in a clustered index. */ /* This is a leaf page in a clustered index. */
ulint i; ulint i;
...@@ -1851,25 +1994,21 @@ page_zip_decompress( ...@@ -1851,25 +1994,21 @@ page_zip_decompress(
if (UNIV_UNLIKELY(i == trx_id_col)) { if (UNIV_UNLIKELY(i == trx_id_col)) {
/* Skip trx_id and roll_ptr */ /* Skip trx_id and roll_ptr */
dst = rec_get_nth_field(rec, offsets, dst = rec_get_nth_field(rec, offsets, i, &len);
i, &len);
if (UNIV_UNLIKELY(len < DATA_TRX_ID_LEN if (UNIV_UNLIKELY(len < DATA_TRX_ID_LEN
+ DATA_ROLL_PTR_LEN) + DATA_ROLL_PTR_LEN)
|| rec_offs_nth_extern(offsets, || rec_offs_nth_extern(offsets, i)) {
i)) {
goto zlib_error; goto zlib_error;
} }
d_stream.avail_out = dst d_stream->avail_out = dst - d_stream->next_out;
- d_stream.next_out;
switch (inflate(&d_stream, switch (inflate(d_stream, Z_SYNC_FLUSH)) {
Z_SYNC_FLUSH)) {
case Z_STREAM_END: case Z_STREAM_END:
case Z_OK: case Z_OK:
case Z_BUF_ERROR: case Z_BUF_ERROR:
if (!d_stream.avail_out) { if (!d_stream->avail_out) {
break; break;
} }
/* fall through */ /* fall through */
...@@ -1877,24 +2016,22 @@ page_zip_decompress( ...@@ -1877,24 +2016,22 @@ page_zip_decompress(
goto zlib_error; goto zlib_error;
} }
ut_ad(d_stream.next_out == dst); ut_ad(d_stream->next_out == dst);
d_stream.next_out += DATA_TRX_ID_LEN d_stream->next_out += DATA_TRX_ID_LEN
+ DATA_ROLL_PTR_LEN; + DATA_ROLL_PTR_LEN;
} else if (rec_offs_nth_extern(offsets, i)) { } else if (rec_offs_nth_extern(offsets, i)) {
dst = rec_get_nth_field(rec, offsets, dst = rec_get_nth_field(rec, offsets, i, &len);
i, &len);
ut_ad(len > BTR_EXTERN_FIELD_REF_SIZE); ut_ad(len > BTR_EXTERN_FIELD_REF_SIZE);
dst += len - BTR_EXTERN_FIELD_REF_SIZE; dst += len - BTR_EXTERN_FIELD_REF_SIZE;
d_stream.avail_out = dst d_stream->avail_out = dst - d_stream->next_out;
- d_stream.next_out; switch (inflate(d_stream,
switch (inflate(&d_stream,
Z_SYNC_FLUSH)) { Z_SYNC_FLUSH)) {
case Z_STREAM_END: case Z_STREAM_END:
case Z_OK: case Z_OK:
case Z_BUF_ERROR: case Z_BUF_ERROR:
if (!d_stream.avail_out) { if (!d_stream->avail_out) {
break; break;
} }
/* fall through */ /* fall through */
...@@ -1902,7 +2039,7 @@ page_zip_decompress( ...@@ -1902,7 +2039,7 @@ page_zip_decompress(
goto zlib_error; goto zlib_error;
} }
ut_ad(d_stream.next_out == dst); ut_ad(d_stream->next_out == dst);
/* Reserve space for the data at /* Reserve space for the data at
the end of the space reserved for the end of the space reserved for
...@@ -1910,7 +2047,7 @@ page_zip_decompress( ...@@ -1910,7 +2047,7 @@ page_zip_decompress(
page modification log. */ page modification log. */
if (UNIV_UNLIKELY if (UNIV_UNLIKELY
(d_stream.avail_in (d_stream->avail_in
<= BTR_EXTERN_FIELD_REF_SIZE)) { <= BTR_EXTERN_FIELD_REF_SIZE)) {
/* out of space */ /* out of space */
goto zlib_error; goto zlib_error;
...@@ -1927,23 +2064,22 @@ page_zip_decompress( ...@@ -1927,23 +2064,22 @@ page_zip_decompress(
could end up with an uninitialized could end up with an uninitialized
BLOB pointer when a record is deleted, BLOB pointer when a record is deleted,
reallocated and deleted. */ reallocated and deleted. */
memset(d_stream.next_out, 0, memset(d_stream->next_out, 0,
BTR_EXTERN_FIELD_REF_SIZE); BTR_EXTERN_FIELD_REF_SIZE);
d_stream.next_out d_stream->next_out
+= BTR_EXTERN_FIELD_REF_SIZE; += BTR_EXTERN_FIELD_REF_SIZE;
} }
} }
decompress_tail:
/* Decompress the last bytes of the record. */ /* Decompress the last bytes of the record. */
d_stream.avail_out = rec_get_end(rec, offsets) d_stream->avail_out = rec_get_end(rec, offsets)
- d_stream.next_out; - d_stream->next_out;
switch (inflate(&d_stream, Z_SYNC_FLUSH)) { switch (inflate(d_stream, Z_SYNC_FLUSH)) {
case Z_STREAM_END: case Z_STREAM_END:
case Z_OK: case Z_OK:
case Z_BUF_ERROR: case Z_BUF_ERROR:
if (!d_stream.avail_out) { if (!d_stream->avail_out) {
break; break;
} }
/* fall through */ /* fall through */
...@@ -1952,107 +2088,85 @@ decompress_tail: ...@@ -1952,107 +2088,85 @@ decompress_tail:
} }
} }
ut_ad(d_stream.next_out == rec_get_end(rec, offsets));
}
/* Decompress any trailing garbage, in case the last record was /* Decompress any trailing garbage, in case the last record was
allocated from an originally longer space on the free list. */ allocated from an originally longer space on the free list. */
d_stream.avail_out = page_header_get_field(page, PAGE_HEAP_TOP) d_stream->avail_out = page_header_get_field(page_zip->data,
- (d_stream.next_out - page); PAGE_HEAP_TOP)
if (UNIV_UNLIKELY(d_stream.avail_out > UNIV_PAGE_SIZE - page_offset(d_stream->next_out);
if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
- PAGE_ZIP_START - PAGE_DIR)) { - PAGE_ZIP_START - PAGE_DIR)) {
goto zlib_error; goto zlib_error;
} }
if (UNIV_UNLIKELY(inflate(&d_stream, Z_FINISH) != Z_STREAM_END)) { if (UNIV_UNLIKELY(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
zlib_error: zlib_error:
inflateEnd(&d_stream); inflateEnd(d_stream);
goto err_exit; return(FALSE);
} }
/* Note that d_stream.avail_out > 0 may hold here /* Note that d_stream->avail_out > 0 may hold here
if the modification log is nonempty. */ if the modification log is nonempty. */
zlib_done: zlib_done:
if (UNIV_UNLIKELY(inflateEnd(&d_stream) != Z_OK)) { if (UNIV_UNLIKELY(inflateEnd(d_stream) != Z_OK)) {
ut_error; ut_error;
} }
ut_ad(page_zip->data + PAGE_DATA + d_stream.total_in {
== d_stream.next_in); page_t* page = page_align(d_stream->next_out);
/* Clear the unused heap space on the uncompressed page. */ /* Clear the unused heap space on the uncompressed page. */
memset(d_stream.next_out, 0, memset(d_stream->next_out, 0,
page_dir_get_nth_slot(page, page_dir_get_n_slots(page) - 1) page_dir_get_nth_slot(page,
- d_stream.next_out); page_dir_get_n_slots(page) - 1)
- d_stream->next_out);
/* The dense directory excludes the infimum and supremum records. */ }
n_dense = page_dir_get_n_heap(page) - 2;
page_zip->n_blobs = 0; page_zip->m_start = PAGE_DATA + d_stream->total_in;
page_zip->m_start = PAGE_DATA + d_stream.total_in;
/* Apply the modification log. */ /* Apply the modification log. */
{ {
const byte* mod_log_ptr; const byte* mod_log_ptr;
mod_log_ptr = page_zip_apply_log(page_zip->data mod_log_ptr = page_zip_apply_log(page_zip->data
+ page_zip->m_start, + page_zip->m_start,
d_stream.avail_in + 1, d_stream->avail_in + 1,
recs, n_dense, recs, n_dense,
trx_id_col, heap_status, trx_id_col, heap_status,
index, offsets); index, offsets);
if (UNIV_UNLIKELY(!mod_log_ptr)) { if (UNIV_UNLIKELY(!mod_log_ptr)) {
goto err_exit; return(FALSE);
} }
page_zip->m_end = mod_log_ptr - page_zip->data; page_zip->m_end = mod_log_ptr - page_zip->data;
ut_a(page_zip_get_trailer_len(page_zip, index, NULL) ut_a(page_zip_get_trailer_len(page_zip, index, NULL)
+ page_zip->m_end < page_zip->size); + page_zip->m_end < page_zip->size);
} }
if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip, page,
info_bits))) {
err_exit:
page_zip_fields_free(index);
mem_heap_free(heap);
return(FALSE);
}
/* Copy the uncompressed fields. */
storage = page_zip->data + page_zip->size storage = page_zip->data + page_zip->size
- n_dense * PAGE_ZIP_DIR_SLOT_SIZE; - n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
if (UNIV_UNLIKELY(!n_dense)) { externs = storage - n_dense
goto recs_done; * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
}
/* Restore the uncompressed columns in heap_no order. */ /* Restore the uncompressed columns in heap_no order. */
if (page_is_leaf(page)) { for (slot = 0; slot < n_dense; slot++) {
const byte* externs = storage - n_dense
* (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
do {
ulint i; ulint i;
ulint len; ulint len;
byte* dst; byte* dst;
rec_t* rec = *recs++; rec_t* rec = recs[slot];
ibool exists = !page_zip_dir_find_free( ibool exists = !page_zip_dir_find_free(
page_zip, page_offset(rec)); page_zip, page_offset(rec));
offsets = rec_get_offsets(rec, index, offsets, offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap); ULINT_UNDEFINED, &heap);
if (UNIV_UNLIKELY(trx_id_col != ULINT_UNDEFINED)) {
dst = rec_get_nth_field(rec, offsets, dst = rec_get_nth_field(rec, offsets,
trx_id_col, &len); trx_id_col, &len);
ut_ad(len >= DATA_TRX_ID_LEN ut_ad(len >= DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
+ DATA_ROLL_PTR_LEN);
storage -= DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN; storage -= DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
memcpy(dst, storage, memcpy(dst, storage,
DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN); DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
}
/* Check if there are any externally stored /* Check if there are any externally stored
columns in this record. For each externally columns in this record. For each externally
...@@ -2083,24 +2197,168 @@ err_exit: ...@@ -2083,24 +2197,168 @@ err_exit:
BTR_EXTERN_FIELD_REF_SIZE); BTR_EXTERN_FIELD_REF_SIZE);
} }
} }
} while (--n_dense); }
return(TRUE);
}
/**************************************************************************
Decompress a page. This function should tolerate errors on the compressed
page. Instead of letting assertions fail, it will return FALSE if an
inconsistency is detected. */
ibool
page_zip_decompress(
/*================*/
/* out: TRUE on success, FALSE on failure */
page_zip_des_t* page_zip,/* in: data, size;
out: m_start, m_end, n_blobs */
page_t* page) /* out: uncompressed page, may be trashed */
{
z_stream d_stream;
dict_index_t* index = NULL;
rec_t** recs; /* dense page directory, sorted by address */
ulint n_dense;/* number of user records on the page */
ulint trx_id_col = ULINT_UNDEFINED;
mem_heap_t* heap;
ulint* offsets;
ut_ad(page_zip_simple_validate(page_zip));
/* The dense directory excludes the infimum and supremum records. */
n_dense = page_dir_get_n_heap(page_zip->data) - 2;
if (UNIV_UNLIKELY(n_dense * PAGE_ZIP_DIR_SLOT_SIZE
>= page_zip->size)) {
return(FALSE);
}
heap = mem_heap_create(n_dense * (3 * sizeof *recs));
recs = mem_heap_alloc(heap, n_dense * (2 * sizeof *recs));
#ifdef UNIV_ZIP_DEBUG
/* Clear the page. */
memset(page, 0x55, UNIV_PAGE_SIZE);
#endif /* UNIV_ZIP_DEBUG */
/* Copy the page header. */
memcpy(page, page_zip->data, PAGE_DATA);
/* Copy the page directory. */
if (UNIV_UNLIKELY(!page_zip_dir_decode(page_zip, page, recs,
recs + n_dense, n_dense))) {
zlib_error:
mem_heap_free(heap);
return(FALSE);
}
/* Copy the infimum and supremum records. */
memcpy(page + (PAGE_NEW_INFIMUM - REC_N_NEW_EXTRA_BYTES),
infimum_extra, sizeof infimum_extra);
if (UNIV_UNLIKELY(!page_get_n_recs(page))) {
rec_set_next_offs_new(page + PAGE_NEW_INFIMUM,
PAGE_NEW_SUPREMUM);
} else { } else {
do { rec_set_next_offs_new(page + PAGE_NEW_INFIMUM,
rec_t* rec = *recs++; page_zip_dir_get(page_zip, 0)
& PAGE_ZIP_DIR_SLOT_MASK);
}
memcpy(page + PAGE_NEW_INFIMUM, infimum_data, sizeof infimum_data);
memcpy(page + (PAGE_NEW_SUPREMUM - REC_N_NEW_EXTRA_BYTES + 1),
supremum_extra_data, sizeof supremum_extra_data);
offsets = rec_get_offsets(rec, index, offsets, d_stream.zalloc = page_zip_malloc;
ULINT_UNDEFINED, &heap); d_stream.zfree = page_zip_free;
/* Non-leaf nodes should not have any externally d_stream.opaque = (voidpf) 0;
stored columns. */
ut_ad(!rec_offs_any_extern(offsets));
storage -= REC_NODE_PTR_SIZE;
memcpy(rec_get_end(rec, offsets) - REC_NODE_PTR_SIZE, if (UNIV_UNLIKELY(inflateInit(&d_stream) != Z_OK)) {
storage, REC_NODE_PTR_SIZE); ut_error;
} while (--n_dense); }
d_stream.next_in = page_zip->data + PAGE_DATA;
/* Subtract the space reserved for
the page header and the end marker of the modification log. */
d_stream.avail_in = page_zip->size - (PAGE_DATA + 1);
d_stream.next_out = page + PAGE_ZIP_START;
d_stream.avail_out = UNIV_PAGE_SIZE - PAGE_ZIP_START;
/* Decode the zlib header and the index information. */
if (UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)
|| UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)) {
goto zlib_error;
}
index = page_zip_fields_decode(
page + PAGE_ZIP_START, d_stream.next_out,
page_is_leaf(page) ? &trx_id_col : NULL);
if (UNIV_UNLIKELY(!index)) {
goto zlib_error;
}
/* Decompress the user records. */
page_zip->n_blobs = 0;
d_stream.next_out = page + PAGE_ZIP_START;
{
/* Pre-allocate the offsets for rec_get_offsets_reverse(). */
ulint n = 1 + 1/* node ptr */ + REC_OFFS_HEADER_SIZE
+ dict_index_get_n_fields(index);
offsets = mem_heap_alloc(heap, n * sizeof(ulint));
*offsets = n;
}
/* Decompress the records in heap_no order. */
if (!page_is_leaf(page)) {
/* This is a node pointer page. */
ulint info_bits;
if (UNIV_UNLIKELY
(!page_zip_decompress_node_ptrs(page_zip, &d_stream,
recs, n_dense, index,
offsets, heap))) {
goto err_exit;
}
info_bits = mach_read_from_4(page + FIL_PAGE_PREV) == FIL_NULL
? REC_INFO_MIN_REC_FLAG : 0;
if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip, page,
info_bits))) {
goto err_exit;
}
} else if (UNIV_LIKELY(trx_id_col == ULINT_UNDEFINED)) {
/* This is a leaf page in a secondary index. */
if (UNIV_UNLIKELY(!page_zip_decompress_sec(page_zip, &d_stream,
recs, n_dense,
index, offsets))) {
goto err_exit;
}
if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip,
page, 0))) {
err_exit:
page_zip_fields_free(index);
mem_heap_free(heap);
return(FALSE);
}
} else {
/* This is a leaf page in a clustered index. */
if (UNIV_UNLIKELY(!page_zip_decompress_clust(page_zip,
&d_stream, recs,
n_dense, index,
trx_id_col,
offsets, heap))) {
goto err_exit;
}
if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip,
page, 0))) {
goto err_exit;
}
} }
recs_done:
ut_a(page_is_comp(page)); ut_a(page_is_comp(page));
page_zip_fields_free(index); page_zip_fields_free(index);
......
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