Commit 65dfefe2 authored by marko's avatar marko

branches/zip: Implement in-place updates of BLOB pointers.

There are still some bugs in the code.

btr_store_big_rec_extern_fields(): Remove assertion on dict_table_is_zip()
to ease testing.

btr_free_externally_stored_field(): Test page_zip instead of
dict_table_is_zip().

page_zip_write_rec(): Add parameter "create".  Try to handle externally
stored columns.

rec_offs_any_extern(): Correct the function comment.

Add rec_offs_n_extern() and page_zip_get_n_prev_extern().

page_zip_dir_decode(): Replace assertion with if (...) return(FALSE).

page_zip_decompress(): Do not clear page_zip->n_blobs after counting the
BLOBs.

page_zip_write_blob_ptr(): Use page_zip_get_n_prev_extern().
Correct an off-by-one error in memcpy().
parent 23d19f8f
...@@ -3512,7 +3512,6 @@ btr_store_big_rec_extern_fields( ...@@ -3512,7 +3512,6 @@ btr_store_big_rec_extern_fields(
space_id = buf_frame_get_space_id(rec); space_id = buf_frame_get_space_id(rec);
page_zip = buf_block_get_page_zip(buf_block_align(rec)); page_zip = buf_block_get_page_zip(buf_block_align(rec));
ut_ad(!page_zip == !dict_table_is_zip(index->table));
if (UNIV_LIKELY_NULL(page_zip)) { if (UNIV_LIKELY_NULL(page_zip)) {
int err; int err;
...@@ -3848,7 +3847,7 @@ btr_free_externally_stored_field( ...@@ -3848,7 +3847,7 @@ btr_free_externally_stored_field(
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
buf_page_dbg_add_level(page, SYNC_EXTERN_STORAGE); buf_page_dbg_add_level(page, SYNC_EXTERN_STORAGE);
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
if (dict_table_is_zip(index->table)) { if (UNIV_LIKELY_NULL(page_zip)) {
next_page_no = mach_read_from_4(page); next_page_no = mach_read_from_4(page);
btr_page_free_low(index->tree, page, btr_page_free_low(index->tree, page,
...@@ -3860,10 +3859,8 @@ btr_free_externally_stored_field( ...@@ -3860,10 +3859,8 @@ btr_free_externally_stored_field(
mlog_write_ulint(field_ref + BTR_EXTERN_LEN + 4, mlog_write_ulint(field_ref + BTR_EXTERN_LEN + 4,
0, 0,
MLOG_4BYTES, &mtr); MLOG_4BYTES, &mtr);
if (UNIV_LIKELY_NULL(page_zip)) { page_zip_write_blob_ptr(page_zip,
page_zip_write_blob_ptr(page_zip,
rec, index, offsets, i, &mtr); rec, index, offsets, i, &mtr);
}
} else { } else {
ulint extern_len = mach_read_from_4( ulint extern_len = mach_read_from_4(
field_ref + BTR_EXTERN_LEN + 4); field_ref + BTR_EXTERN_LEN + 4);
......
...@@ -113,7 +113,8 @@ page_zip_write_rec( ...@@ -113,7 +113,8 @@ page_zip_write_rec(
page_zip_des_t* page_zip,/* in/out: compressed page */ page_zip_des_t* page_zip,/* in/out: compressed page */
const byte* rec, /* in: record being written */ const byte* rec, /* in: record being written */
dict_index_t* index, /* in: the index the record belongs to */ dict_index_t* index, /* in: the index the record belongs to */
const ulint* offsets)/* in: rec_get_offsets(rec, index) */ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
ulint create) /* in: nonzero=insert, zero=update */
__attribute__((nonnull)); __attribute__((nonnull));
/************************************************************************** /**************************************************************************
......
...@@ -447,13 +447,21 @@ rec_offs_nth_size( ...@@ -447,13 +447,21 @@ rec_offs_nth_size(
/********************************************************** /**********************************************************
Returns TRUE if the extern bit is set in any of the fields Returns TRUE if the extern bit is set in any of the fields
of rec. */ of a record. */
UNIV_INLINE UNIV_INLINE
ibool ibool
rec_offs_any_extern( rec_offs_any_extern(
/*================*/ /*================*/
/* out: TRUE if a field is stored externally */ /* out: TRUE if a field is stored externally */
const ulint* offsets);/* in: array returned by rec_get_offsets() */ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/**********************************************************
Returns the number of extern bits set in a record. */
UNIV_INLINE
ulint
rec_offs_n_extern(
/*==============*/
/* out: number of externally stored fields */
const ulint* offsets);/* in: array returned by rec_get_offsets() */
/*************************************************************** /***************************************************************
Sets TRUE the extern storage bits of fields mentioned in an array. */ Sets TRUE the extern storage bits of fields mentioned in an array. */
......
...@@ -1080,7 +1080,7 @@ rec_offs_nth_size( ...@@ -1080,7 +1080,7 @@ rec_offs_nth_size(
/********************************************************** /**********************************************************
Returns TRUE if the extern bit is set in any of the fields Returns TRUE if the extern bit is set in any of the fields
of an old-style record. */ of a record. */
UNIV_INLINE UNIV_INLINE
ibool ibool
rec_offs_any_extern( rec_offs_any_extern(
...@@ -1097,6 +1097,25 @@ rec_offs_any_extern( ...@@ -1097,6 +1097,25 @@ rec_offs_any_extern(
return(FALSE); return(FALSE);
} }
/**********************************************************
Returns the number of extern bits set in a record. */
UNIV_INLINE
ulint
rec_offs_n_extern(
/*==============*/
/* out: number of externally stored fields */
const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
ulint i;
ulint n = 0;
for (i = rec_offs_n_fields(offsets); i--; ) {
if (rec_offs_nth_extern(offsets, i)) {
n++;
}
}
return(n);
}
/********************************************************** /**********************************************************
Returns the offset of n - 1th field end if the record is stored in the 1-byte Returns the offset of n - 1th field end if the record is stored in the 1-byte
offsets form. If the field is SQL null, the flag is ORed in the returned offsets form. If the field is SQL null, the flag is ORed in the returned
......
...@@ -1104,7 +1104,7 @@ page_cur_insert_rec_low( ...@@ -1104,7 +1104,7 @@ page_cur_insert_rec_low(
/* TODO: something similar to page_zip_dir_delete() */ /* TODO: something similar to page_zip_dir_delete() */
page_zip_dir_rewrite(page_zip, page); page_zip_dir_rewrite(page_zip, page);
page_zip_write_rec(page_zip, insert_rec, index, offsets); page_zip_write_rec(page_zip, insert_rec, index, offsets, 1);
} }
/* 9. Write log record of the insert */ /* 9. Write log record of the insert */
......
...@@ -160,6 +160,46 @@ page_zip_dir_get( ...@@ -160,6 +160,46 @@ page_zip_dir_get(
- PAGE_ZIP_DIR_SLOT_SIZE * (slot + 1))); - PAGE_ZIP_DIR_SLOT_SIZE * (slot + 1)));
} }
/**********************************************************
Determine how many externally stored columns are contained
in previous records on the page of rec. */
UNIV_INLINE
ulint
page_zip_get_n_prev_extern(
/*=======================*/
const rec_t* rec, /* in: compact physical record
on a B-tree leaf page */
dict_index_t* index) /* in: record descriptor */
{
page_t* page = ut_align_down((byte*) rec, UNIV_PAGE_SIZE);
ulint n_ext;
ulint next_offs;
ut_ad(page_is_leaf(page));
ut_ad(page_is_comp(page));
ut_ad(dict_table_is_comp(index->table));
n_ext = 0;
next_offs = rec_get_next_offs(page + PAGE_NEW_INFIMUM, TRUE);
ut_a(next_offs >= PAGE_NEW_SUPREMUM_END);
do {
rec_t* r = page + next_offs;
if (r == rec) {
return(n_ext);
}
n_ext += rec_get_n_extern_new(r, index, ULINT_UNDEFINED);
next_offs = rec_get_next_offs(r, TRUE);
ut_a(next_offs > 0);
} while (next_offs != PAGE_NEW_SUPREMUM);
ut_error;
return(0);
}
/************************************************************************** /**************************************************************************
Encode the length of a fixed-length column. */ Encode the length of a fixed-length column. */
static static
...@@ -980,8 +1020,10 @@ page_zip_dir_decode( ...@@ -980,8 +1020,10 @@ page_zip_dir_decode(
UNIV_PREFETCH_RW(slot); UNIV_PREFETCH_RW(slot);
} }
ut_ad((offs & PAGE_ZIP_DIR_SLOT_MASK) if (UNIV_UNLIKELY((offs & PAGE_ZIP_DIR_SLOT_MASK)
>= PAGE_ZIP_START + REC_N_NEW_EXTRA_BYTES); < PAGE_ZIP_START + REC_N_NEW_EXTRA_BYTES)) {
return(FALSE);
}
recs[i] = page + (offs & PAGE_ZIP_DIR_SLOT_MASK); recs[i] = page + (offs & PAGE_ZIP_DIR_SLOT_MASK);
} }
...@@ -1628,7 +1670,7 @@ page_zip_decompress( ...@@ -1628,7 +1670,7 @@ page_zip_decompress(
} else { } else {
externs = storage; externs = storage;
} }
page_zip->n_blobs = 0;
recsc = recs; recsc = recs;
while (n_dense--) { while (n_dense--) {
...@@ -1732,7 +1774,8 @@ page_zip_write_rec( ...@@ -1732,7 +1774,8 @@ page_zip_write_rec(
page_zip_des_t* page_zip,/* in/out: compressed page */ page_zip_des_t* page_zip,/* in/out: compressed page */
const byte* rec, /* in: record being written */ const byte* rec, /* in: record being written */
dict_index_t* index, /* in: the index the record belongs to */ dict_index_t* index, /* in: the index the record belongs to */
const ulint* offsets)/* in: rec_get_offsets(rec, index) */ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
ulint create) /* in: nonzero=insert, zero=update */
{ {
page_t* page; page_t* page;
byte* data; byte* data;
...@@ -1794,33 +1837,64 @@ page_zip_write_rec( ...@@ -1794,33 +1837,64 @@ page_zip_write_rec(
if (page_is_leaf(page)) { if (page_is_leaf(page)) {
ulint i; ulint i;
ulint len; ulint len;
const byte* start = rec; const byte* start = rec;
byte* externs;
ulint trx_id_col; ulint trx_id_col;
ulint n_ext = rec_offs_n_extern(offsets);
if (dict_index_is_clust(index)) { if (dict_index_is_clust(index)) {
trx_id_col = dict_index_get_sys_col_pos( trx_id_col = dict_index_get_sys_col_pos(
index, DATA_TRX_ID); index, DATA_TRX_ID);
ut_ad(trx_id_col != ULINT_UNDEFINED); ut_ad(trx_id_col != ULINT_UNDEFINED);
/* Do not assert on page_zip->n_blobs, because
it may change later in this function. */ externs = storage
ut_ad(data + rec_offs_data_size(offsets)
- (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN) - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
< storage * (page_dir_get_n_heap(page) - 2);
/* Note that this will not take into account
the BLOB columns of rec if create==TRUE */
ut_ad(data + rec_offs_data_size(offsets)
- (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN) - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
* (page_dir_get_n_heap(page) - 2)); - n_ext * BTR_EXTERN_FIELD_REF_SIZE
< externs
- BTR_EXTERN_FIELD_REF_SIZE
* page_zip->n_blobs);
} else { } else {
trx_id_col = ULINT_UNDEFINED; trx_id_col = ULINT_UNDEFINED;
ut_ad(dict_index_get_sys_col_pos( ut_ad(dict_index_get_sys_col_pos(
index, DATA_TRX_ID) index, DATA_TRX_ID)
== ULINT_UNDEFINED); == ULINT_UNDEFINED);
/* Do not assert on page_zip->n_blobs, because externs = storage;
it may change later in this function. */ /* Note that this will not take into account
ut_ad(data + rec_offs_data_size(offsets) < storage); the BLOB columns of rec if create==TRUE */
ut_ad(data + rec_offs_data_size(offsets)
- n_ext * BTR_EXTERN_FIELD_REF_SIZE
< externs
- BTR_EXTERN_FIELD_REF_SIZE
* page_zip->n_blobs);
}
if (UNIV_UNLIKELY(n_ext)) {
ulint blob_no = page_zip_get_n_prev_extern(
rec, index);
byte* ext_end = externs - page_zip->n_blobs
* BTR_EXTERN_FIELD_REF_SIZE;
ut_ad(blob_no <= page_zip->n_blobs);
externs -= blob_no * BTR_EXTERN_FIELD_REF_SIZE;
if (create) {
page_zip->n_blobs += n_ext;
memmove(ext_end - n_ext
* BTR_EXTERN_FIELD_REF_SIZE,
ext_end,
externs - ext_end);
}
ut_a(blob_no + n_ext <= page_zip->n_blobs);
} }
/* Check if there are any externally stored columns. /* Store separately trx_id, roll_ptr and
For each externally stored column, store the the BTR_EXTERN_FIELD_REF of each BLOB column._*/
BTR_EXTERN_FIELD_REF separately._*/
for (i = 0; i < rec_offs_n_fields(offsets); i++) { for (i = 0; i < rec_offs_n_fields(offsets); i++) {
const byte* src; const byte* src;
...@@ -1861,11 +1935,11 @@ page_zip_write_rec( ...@@ -1861,11 +1935,11 @@ page_zip_write_rec(
data += src - start; data += src - start;
start = src + BTR_EXTERN_FIELD_REF_SIZE; start = src + BTR_EXTERN_FIELD_REF_SIZE;
/* TODO: copy the BLOB pointer to /* Store the BLOB pointer separately. */
the appropriate place in the externs -= BTR_EXTERN_FIELD_REF_SIZE;
uncompressed BLOB pointer array */ ut_ad(data < externs);
memcpy(externs, src,
/* TODO: update page_zip->n_blobs */ BTR_EXTERN_FIELD_REF_SIZE);
} }
} }
...@@ -1923,9 +1997,8 @@ page_zip_write_blob_ptr( ...@@ -1923,9 +1997,8 @@ page_zip_write_blob_ptr(
{ {
byte* field; byte* field;
byte* externs; byte* externs;
page_t* page = buf_frame_align((byte*) rec); page_t* page = ut_align_down((byte*) rec, UNIV_PAGE_SIZE);
ulint blob_no; ulint blob_no;
ulint next_offs;
ulint len; ulint len;
ut_ad(buf_block_get_page_zip(buf_block_align((byte*)rec)) == page_zip); ut_ad(buf_block_get_page_zip(buf_block_align((byte*)rec)) == page_zip);
...@@ -1940,28 +2013,9 @@ page_zip_write_blob_ptr( ...@@ -1940,28 +2013,9 @@ page_zip_write_blob_ptr(
ut_ad(page_is_leaf(page)); ut_ad(page_is_leaf(page));
blob_no = 0; blob_no = page_zip_get_n_prev_extern(rec, index)
next_offs = rec_get_next_offs(page + PAGE_NEW_INFIMUM, TRUE); + rec_get_n_extern_new(rec, index, n);
ut_a(next_offs > PAGE_NEW_SUPREMUM_END); ut_a(blob_no <= page_zip->n_blobs);
do {
rec_t* r = page + next_offs;
if (r == rec) {
goto found;
}
blob_no += rec_get_n_extern_new(r, index, ULINT_UNDEFINED);
next_offs = rec_get_next_offs(r, TRUE);
ut_a(next_offs > 0);
} while (next_offs != PAGE_NEW_SUPREMUM);
ut_error;
found:
blob_no += rec_get_n_extern_new(rec, index, n);
ut_a(blob_no < page_zip->n_blobs);
/* The heap number of the first user record is 2. */ /* The heap number of the first user record is 2. */
if (dict_index_is_clust(index)) { if (dict_index_is_clust(index)) {
...@@ -1977,7 +2031,7 @@ page_zip_write_blob_ptr( ...@@ -1977,7 +2031,7 @@ page_zip_write_blob_ptr(
field = rec_get_nth_field((rec_t*) rec, offsets, n, &len); field = rec_get_nth_field((rec_t*) rec, offsets, n, &len);
memcpy(externs - blob_no * BTR_EXTERN_FIELD_REF_SIZE, memcpy(externs - (blob_no + 1) * BTR_EXTERN_FIELD_REF_SIZE,
field + len - BTR_EXTERN_FIELD_REF_SIZE, field + len - BTR_EXTERN_FIELD_REF_SIZE,
BTR_EXTERN_FIELD_REF_SIZE); BTR_EXTERN_FIELD_REF_SIZE);
...@@ -2119,7 +2173,7 @@ page_zip_clear_rec( ...@@ -2119,7 +2173,7 @@ page_zip_clear_rec(
memset(rec, 0, rec_offs_data_size(offsets)); memset(rec, 0, rec_offs_data_size(offsets));
/* Log that the data was zeroed out. */ /* Log that the data was zeroed out. */
page_zip_write_rec(page_zip, rec, index, offsets); page_zip_write_rec(page_zip, rec, index, offsets, 0);
} else { } else {
/* There is not enough space to log the clearing. /* There is not enough space to log the clearing.
Try to clear the block and to recompress the page. */ Try to clear the block and to recompress the page. */
......
...@@ -477,7 +477,7 @@ row_upd_rec_in_place( ...@@ -477,7 +477,7 @@ row_upd_rec_in_place(
} }
if (UNIV_LIKELY_NULL(page_zip)) { if (UNIV_LIKELY_NULL(page_zip)) {
page_zip_write_rec(page_zip, rec, index, offsets); page_zip_write_rec(page_zip, rec, index, offsets, 0);
} }
} }
......
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