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,176 +1630,349 @@ page_zip_apply_log( ...@@ -1630,176 +1630,349 @@ 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;
}
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. */
mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
heap_status += 1 << REC_HEAP_NO_SHIFT;
/* Read the offsets. The status bits are needed here. */
offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap);
/* Non-leaf nodes should not have any externally
stored columns. */
ut_ad(!rec_offs_any_extern(offsets));
/* Decompress the data bytes, except node_ptr. */
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;
}
/* Clear the node pointer in case the record
will be deleted and the space will be reallocated
to a smaller record. */
memset(d_stream->next_out, 0, REC_NODE_PTR_SIZE);
d_stream->next_out += REC_NODE_PTR_SIZE;
ut_ad(d_stream->next_out == rec_get_end(rec, offsets));
} }
heap = mem_heap_create(n_dense * (3 * sizeof *recs)); /* Decompress any trailing garbage, in case the last record was
recs = mem_heap_alloc(heap, n_dense * (2 * sizeof *recs)); allocated from an originally longer space 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)) {
#ifdef UNIV_ZIP_DEBUG goto zlib_error;
/* 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(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
if (UNIV_UNLIKELY zlib_error:
(!page_zip_dir_decode(page_zip, page, inflateEnd(d_stream);
recs, recs + n_dense, n_dense))) {
mem_heap_free(heap);
return(FALSE); return(FALSE);
} }
/* Copy the infimum and supremum records. */ /* Note that d_stream->avail_out > 0 may hold here
memcpy(page + (PAGE_NEW_INFIMUM - REC_N_NEW_EXTRA_BYTES), if the modification log is nonempty. */
infimum_extra, sizeof infimum_extra);
if (UNIV_UNLIKELY(!page_get_n_recs(page))) { zlib_done:
rec_set_next_offs_new(page + PAGE_NEW_INFIMUM, if (UNIV_UNLIKELY(inflateEnd(d_stream) != Z_OK)) {
PAGE_NEW_SUPREMUM); ut_error;
} else {
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; {
d_stream.zfree = page_zip_free; page_t* page = page_align(d_stream->next_out);
d_stream.opaque = (voidpf) 0;
if (UNIV_UNLIKELY(inflateInit(&d_stream) != Z_OK)) { /* Clear the unused heap space on the uncompressed page. */
ut_error; memset(d_stream->next_out, 0,
page_dir_get_nth_slot(page,
page_dir_get_n_slots(page) - 1)
- d_stream->next_out);
} }
d_stream.next_in = page_zip->data + PAGE_DATA; page_zip->m_start = PAGE_DATA + d_stream->total_in;
/* 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; /* Apply the modification log. */
d_stream.avail_out = UNIV_PAGE_SIZE - PAGE_ZIP_START; {
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);
/* Decode the zlib header and the index information. */ if (UNIV_UNLIKELY(!mod_log_ptr)) {
if (UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK) return(FALSE);
|| UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)) { }
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);
}
goto zlib_error; /* Restore the uncompressed columns in heap_no order. */
storage = page_zip->data + page_zip->size
- n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
for (slot = 0; slot < n_dense; slot++) {
rec_t* rec = recs[slot];
offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap);
/* Non-leaf nodes should not have any externally
stored columns. */
ut_ad(!rec_offs_any_extern(offsets));
storage -= REC_NODE_PTR_SIZE;
memcpy(rec_get_end(rec, offsets) - REC_NODE_PTR_SIZE,
storage, REC_NODE_PTR_SIZE);
} }
index = page_zip_fields_decode( return(TRUE);
page + PAGE_ZIP_START, d_stream.next_out, }
page_is_leaf(page) ? &trx_id_col : NULL);
if (UNIV_UNLIKELY(!index)) { /**************************************************************************
Decompress the records of a leaf node of a secondary index. */
static
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;
/* Subtract the space reserved for uncompressed data. */
d_stream->avail_in -= n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
for (slot = 0; slot < n_dense; slot++) {
rec_t* rec = recs[slot];
/* Decompress everything up to this record. */
d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
- d_stream->next_out;
if (UNIV_LIKELY(d_stream->avail_out)) {
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;
}
}
ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
/* Skip the REC_N_NEW_EXTRA_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;
}
/* Decompress the data of the last record and any trailing garbage,
in case the last record was allocated from an originally longer space
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)) {
goto zlib_error; goto zlib_error;
} }
/* Decompress the user records. */ if (UNIV_UNLIKELY(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
d_stream.next_out = page + PAGE_ZIP_START; zlib_error:
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;
}
{ {
/* Pre-allocate the offsets page_t* page = page_align(d_stream->next_out);
for rec_get_offsets_reverse(). */
ulint n;
if (page_is_leaf(page)) {
n = dict_index_get_n_fields(index);
heap_status = REC_STATUS_ORDINARY
| 2 << REC_HEAP_NO_SHIFT;
/* Subtract the space reserved
for uncompressed data. */
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
(mach_read_from_4(page + FIL_PAGE_PREV)
== FIL_NULL)) {
info_bits = REC_INFO_MIN_REC_FLAG;
}
/* Subtract the space reserved /* Clear the unused heap space on the uncompressed page. */
for uncompressed data. */ memset(d_stream->next_out, 0,
d_stream.avail_in -= n_dense page_dir_get_nth_slot(page,
* (PAGE_ZIP_DIR_SLOT_SIZE + REC_NODE_PTR_SIZE); page_dir_get_n_slots(page) - 1)
} - d_stream->next_out);
}
n += 1 + REC_OFFS_HEADER_SIZE; page_zip->m_start = PAGE_DATA + d_stream->total_in;
offsets = mem_heap_alloc(heap, n * sizeof(ulint));
*offsets = n; /* 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);
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. */ /* 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 d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
- d_stream.next_out; - d_stream->next_out;
ut_ad(d_stream.avail_out < UNIV_PAGE_SIZE ut_ad(d_stream->avail_out < UNIV_PAGE_SIZE
- PAGE_ZIP_START - PAGE_DIR); - PAGE_ZIP_START - PAGE_DIR);
switch (inflate(&d_stream, Z_SYNC_FLUSH)) { err = inflate(d_stream, Z_SYNC_FLUSH);
switch (err) {
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 (UNIV_LIKELY(!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); ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
/* Prepare to decompress the data bytes. */ /* Prepare to decompress the data bytes. */
d_stream.next_out = rec; 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;
...@@ -1808,299 +1981,384 @@ page_zip_decompress( ...@@ -1808,299 +1981,384 @@ page_zip_decompress(
offsets = rec_get_offsets(rec, index, offsets, offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap); ULINT_UNDEFINED, &heap);
if (!page_is_leaf(page)) { /* This is a leaf page in a clustered index. */
/* Non-leaf nodes should not have any externally ulint i;
stored columns. */
ut_ad(!rec_offs_any_extern(offsets));
/* Decompress the data bytes, except node_ptr. */
d_stream.avail_out = rec_offs_data_size(offsets)
- REC_NODE_PTR_SIZE;
switch (inflate(&d_stream, Z_SYNC_FLUSH)) { /* Check if there are any externally stored columns.
case Z_STREAM_END: For each externally stored column, restore the
case Z_OK: BTR_EXTERN_FIELD_REF separately. */
case Z_BUF_ERROR:
if (!d_stream.avail_out) {
break;
}
/* fall through */
default:
goto zlib_error;
}
/* Clear the node pointer in case the record for (i = 0; i < rec_offs_n_fields(offsets); i++) {
will be deleted and the space will be reallocated ulint len;
to a smaller record. */ byte* dst;
memset(d_stream.next_out, 0, REC_NODE_PTR_SIZE);
d_stream.next_out += REC_NODE_PTR_SIZE;
} else if (UNIV_LIKELY(trx_id_col == ULINT_UNDEFINED)) {
/* This is a leaf page in a non-clustered index. */
goto decompress_tail;
} else {
/* This is a leaf page in a clustered index. */
ulint i;
/* Check if there are any externally stored columns. if (UNIV_UNLIKELY(i == trx_id_col)) {
For each externally stored column, restore the /* Skip trx_id and roll_ptr */
BTR_EXTERN_FIELD_REF separately. */ dst = rec_get_nth_field(rec, offsets, i, &len);
if (UNIV_UNLIKELY(len < DATA_TRX_ID_LEN
+ DATA_ROLL_PTR_LEN)
|| rec_offs_nth_extern(offsets, i)) {
for (i = 0; i < rec_offs_n_fields(offsets); i++) { goto zlib_error;
ulint len; }
byte* dst;
if (UNIV_UNLIKELY(i == trx_id_col)) { d_stream->avail_out = dst - d_stream->next_out;
/* Skip trx_id and roll_ptr */
dst = rec_get_nth_field(rec, offsets,
i, &len);
if (UNIV_UNLIKELY(len < DATA_TRX_ID_LEN
+ DATA_ROLL_PTR_LEN)
|| rec_offs_nth_extern(offsets,
i)) {
goto zlib_error; switch (inflate(d_stream, Z_SYNC_FLUSH)) {
case Z_STREAM_END:
case Z_OK:
case Z_BUF_ERROR:
if (!d_stream->avail_out) {
break;
} }
/* fall through */
default:
goto zlib_error;
}
d_stream.avail_out = dst ut_ad(d_stream->next_out == dst);
- d_stream.next_out;
switch (inflate(&d_stream,
Z_SYNC_FLUSH)) {
case Z_STREAM_END:
case Z_OK:
case Z_BUF_ERROR:
if (!d_stream.avail_out) {
break;
}
/* fall through */
default:
goto zlib_error;
}
ut_ad(d_stream.next_out == dst); d_stream->next_out += DATA_TRX_ID_LEN
+ DATA_ROLL_PTR_LEN;
} else if (rec_offs_nth_extern(offsets, i)) {
dst = rec_get_nth_field(rec, offsets, i, &len);
ut_ad(len > BTR_EXTERN_FIELD_REF_SIZE);
dst += len - BTR_EXTERN_FIELD_REF_SIZE;
d_stream.next_out += DATA_TRX_ID_LEN d_stream->avail_out = dst - d_stream->next_out;
+ DATA_ROLL_PTR_LEN; switch (inflate(d_stream,
} else if (rec_offs_nth_extern(offsets, i)) { Z_SYNC_FLUSH)) {
dst = rec_get_nth_field(rec, offsets, case Z_STREAM_END:
i, &len); case Z_OK:
ut_ad(len > BTR_EXTERN_FIELD_REF_SIZE); case Z_BUF_ERROR:
dst += len - BTR_EXTERN_FIELD_REF_SIZE; if (!d_stream->avail_out) {
break;
d_stream.avail_out = dst
- d_stream.next_out;
switch (inflate(&d_stream,
Z_SYNC_FLUSH)) {
case Z_STREAM_END:
case Z_OK:
case Z_BUF_ERROR:
if (!d_stream.avail_out) {
break;
}
/* fall through */
default:
goto zlib_error;
} }
/* fall through */
default:
goto zlib_error;
}
ut_ad(d_stream.next_out == dst); ut_ad(d_stream->next_out == dst);
/* Reserve space for the data at
the end of the space reserved for
the compressed data and the
page modification log. */
if (UNIV_UNLIKELY /* Reserve space for the data at
(d_stream.avail_in the end of the space reserved for
<= BTR_EXTERN_FIELD_REF_SIZE)) { the compressed data and the
/* out of space */ page modification log. */
goto zlib_error;
}
/* Clear the BLOB pointer in case if (UNIV_UNLIKELY
the record will be deleted and the (d_stream->avail_in
space will not be reused. Note that <= BTR_EXTERN_FIELD_REF_SIZE)) {
the final initialization of the BLOB /* out of space */
pointers (copying from "externs" goto zlib_error;
or clearing) will have to take place
only after the page modification log
has been applied. Otherwise, we
could end up with an uninitialized
BLOB pointer when a record is deleted,
reallocated and deleted. */
memset(d_stream.next_out, 0,
BTR_EXTERN_FIELD_REF_SIZE);
d_stream.next_out
+= BTR_EXTERN_FIELD_REF_SIZE;
} }
/* Clear the BLOB pointer in case
the record will be deleted and the
space will not be reused. Note that
the final initialization of the BLOB
pointers (copying from "externs"
or clearing) will have to take place
only after the page modification log
has been applied. Otherwise, we
could end up with an uninitialized
BLOB pointer when a record is deleted,
reallocated and deleted. */
memset(d_stream->next_out, 0,
BTR_EXTERN_FIELD_REF_SIZE);
d_stream->next_out
+= 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 */
default:
goto zlib_error;
} }
/* fall through */
default:
goto zlib_error;
} }
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. */
memset(d_stream.next_out, 0,
page_dir_get_nth_slot(page, page_dir_get_n_slots(page) - 1)
- d_stream.next_out);
/* The dense directory excludes the infimum and supremum records. */ /* Clear the unused heap space on the uncompressed page. */
n_dense = page_dir_get_n_heap(page) - 2; 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->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, storage = page_zip->data + page_zip->size
info_bits))) { - n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
err_exit:
page_zip_fields_free(index); externs = storage - n_dense
* (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
/* Restore the uncompressed columns in heap_no order. */
for (slot = 0; slot < n_dense; slot++) {
ulint i;
ulint len;
byte* dst;
rec_t* rec = recs[slot];
ibool exists = !page_zip_dir_find_free(
page_zip, page_offset(rec));
offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap);
dst = rec_get_nth_field(rec, offsets,
trx_id_col, &len);
ut_ad(len >= DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
storage -= DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
memcpy(dst, storage,
DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
/* Check if there are any externally stored
columns in this record. For each externally
stored column, restore or clear the
BTR_EXTERN_FIELD_REF. */
for (i = 0; i < rec_offs_n_fields(offsets); i++) {
if (!rec_offs_nth_extern(offsets, i)) {
continue;
}
dst = rec_get_nth_field(rec, offsets, i, &len);
ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
dst += len - BTR_EXTERN_FIELD_REF_SIZE;
if (UNIV_LIKELY(exists)) {
/* Existing record:
restore the BLOB pointer */
externs -= BTR_EXTERN_FIELD_REF_SIZE;
memcpy(dst, externs,
BTR_EXTERN_FIELD_REF_SIZE);
page_zip->n_blobs++;
} else {
/* Deleted record:
clear the BLOB pointer */
memset(dst, 0,
BTR_EXTERN_FIELD_REF_SIZE);
}
}
}
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); mem_heap_free(heap);
return(FALSE); return(FALSE);
} }
/* Copy the uncompressed fields. */ /* 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 {
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);
storage = page_zip->data + page_zip->size d_stream.zalloc = page_zip_malloc;
- n_dense * PAGE_ZIP_DIR_SLOT_SIZE; d_stream.zfree = page_zip_free;
d_stream.opaque = (voidpf) 0;
if (UNIV_UNLIKELY(!n_dense)) { if (UNIV_UNLIKELY(inflateInit(&d_stream) != Z_OK)) {
goto recs_done; ut_error;
} }
/* Restore the uncompressed columns in heap_no order. */ 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);
if (page_is_leaf(page)) { d_stream.next_out = page + PAGE_ZIP_START;
const byte* externs = storage - n_dense d_stream.avail_out = UNIV_PAGE_SIZE - PAGE_ZIP_START;
* (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
do { /* Decode the zlib header and the index information. */
ulint i; if (UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)
ulint len; || UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)) {
byte* dst;
rec_t* rec = *recs++;
ibool exists = !page_zip_dir_find_free(
page_zip, page_offset(rec));
offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap);
if (UNIV_UNLIKELY(trx_id_col != ULINT_UNDEFINED)) {
dst = rec_get_nth_field(rec, offsets,
trx_id_col, &len);
ut_ad(len >= DATA_TRX_ID_LEN
+ DATA_ROLL_PTR_LEN);
storage -= DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
memcpy(dst, storage,
DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
}
/* Check if there are any externally stored goto zlib_error;
columns in this record. For each externally }
stored column, restore or clear the
BTR_EXTERN_FIELD_REF. */
for (i = 0; i < rec_offs_n_fields(offsets); i++) { index = page_zip_fields_decode(
if (!rec_offs_nth_extern(offsets, i)) { page + PAGE_ZIP_START, d_stream.next_out,
continue; page_is_leaf(page) ? &trx_id_col : NULL);
}
dst = rec_get_nth_field(rec, offsets, i, &len);
ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
dst += len - BTR_EXTERN_FIELD_REF_SIZE;
if (UNIV_LIKELY(exists)) { if (UNIV_UNLIKELY(!index)) {
/* Existing record:
restore the BLOB pointer */
externs -= BTR_EXTERN_FIELD_REF_SIZE;
memcpy(dst, externs, goto zlib_error;
BTR_EXTERN_FIELD_REF_SIZE); }
page_zip->n_blobs++; /* Decompress the user records. */
} else { page_zip->n_blobs = 0;
/* Deleted record: d_stream.next_out = page + PAGE_ZIP_START;
clear the BLOB pointer */
memset(dst, 0,
BTR_EXTERN_FIELD_REF_SIZE);
}
}
} while (--n_dense);
} else {
do {
rec_t* rec = *recs++;
offsets = rec_get_offsets(rec, index, offsets, {
ULINT_UNDEFINED, &heap); /* Pre-allocate the offsets for rec_get_offsets_reverse(). */
/* Non-leaf nodes should not have any externally ulint n = 1 + 1/* node ptr */ + REC_OFFS_HEADER_SIZE
stored columns. */ + dict_index_get_n_fields(index);
ut_ad(!rec_offs_any_extern(offsets)); offsets = mem_heap_alloc(heap, n * sizeof(ulint));
storage -= REC_NODE_PTR_SIZE; *offsets = n;
}
/* Decompress the records in heap_no order. */
if (!page_is_leaf(page)) {
/* This is a node pointer page. */
ulint info_bits;
memcpy(rec_get_end(rec, offsets) - REC_NODE_PTR_SIZE, if (UNIV_UNLIKELY
storage, REC_NODE_PTR_SIZE); (!page_zip_decompress_node_ptrs(page_zip, &d_stream,
} while (--n_dense); 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