Commit 8fb8584e authored by marko's avatar marko

branches/zip: row_ext: Fetch the BLOB prefixes already at row_ext_create().

Only add indexed BLOBs to row_ext.

trx_undo_rec_get_partial_row(): Move the BLOB fetching to row_ext_create().

row_build(): Pass only those BLOBs to row_ext_create() that are referenced by
ordering columns of some indexes, similar to trx_undo_rec_get_partial_row().

row_ext_create(): Add the parameter "tuple".  Move the implementation
from row0ext.ic to row0ext.c.

row_ext_lookup_ith(), row_ext_lookup(): Return a const pointer.  Remove
the parameters "field" and "f_len".  Make the row_ext_t* parameter const.

row_ext_t: Remove the field zip_size.

field_ref_zero[]: Declare in btr0types.h instead of btr0cur.h.

row_ext_lookup_low(): Rename to row_ext_cache_fill() and change the
signature.
parent 962ed523
...@@ -716,11 +716,6 @@ extern ulint btr_cur_n_sea; ...@@ -716,11 +716,6 @@ extern ulint btr_cur_n_sea;
extern ulint btr_cur_n_non_sea_old; extern ulint btr_cur_n_non_sea_old;
extern ulint btr_cur_n_sea_old; extern ulint btr_cur_n_sea_old;
/* A BLOB field reference full of zero, for use in assertions and tests.
Initially, BLOB field references are set to zero, in
dtuple_convert_big_rec(). */
extern const byte field_ref_zero[BTR_EXTERN_FIELD_REF_SIZE];
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "btr0cur.ic" #include "btr0cur.ic"
#endif #endif
......
...@@ -23,4 +23,9 @@ The reference is stored at the end of the prefix of the field ...@@ -23,4 +23,9 @@ The reference is stored at the end of the prefix of the field
in the index record. */ in the index record. */
#define BTR_EXTERN_FIELD_REF_SIZE 20 #define BTR_EXTERN_FIELD_REF_SIZE 20
/* A BLOB field reference full of zero, for use in assertions and tests.
Initially, BLOB field references are set to zero, in
dtuple_convert_big_rec(). */
extern const byte field_ref_zero[BTR_EXTERN_FIELD_REF_SIZE];
#endif #endif
...@@ -11,11 +11,12 @@ Created September 2006 Marko Makela ...@@ -11,11 +11,12 @@ Created September 2006 Marko Makela
#include "univ.i" #include "univ.i"
#include "row0types.h" #include "row0types.h"
#include "data0types.h"
#include "mem0mem.h" #include "mem0mem.h"
/************************************************************************ /************************************************************************
Creates a cache of column prefixes of externally stored columns. */ Creates a cache of column prefixes of externally stored columns. */
UNIV_INLINE
row_ext_t* row_ext_t*
row_ext_create( row_ext_create(
/*===========*/ /*===========*/
...@@ -25,50 +26,48 @@ row_ext_create( ...@@ -25,50 +26,48 @@ row_ext_create(
in the InnoDB table object, as reported by in the InnoDB table object, as reported by
dict_col_get_no(); NOT relative to the records dict_col_get_no(); NOT relative to the records
in the clustered index */ in the clustered index */
ulint zip_size,/* compressed page size, or 0 */ const dtuple_t* tuple, /* in: data tuple containing the field
references of the externally stored columns;
must be indexed by col_no */
ulint zip_size,/* compressed page size in bytes, or 0 */
mem_heap_t* heap); /* in: heap where created */ mem_heap_t* heap); /* in: heap where created */
/************************************************************************ /************************************************************************
Looks up a column prefix of an externally stored column. */ Looks up a column prefix of an externally stored column. */
UNIV_INLINE UNIV_INLINE
byte* const byte*
row_ext_lookup_ith( row_ext_lookup_ith(
/*===============*/ /*===============*/
/* out: column prefix, or NULL if /* out: column prefix, or NULL if
the column is not stored externally, the column is not stored externally,
or pointer to field_ref_zero or pointer to field_ref_zero
if the BLOB pointer is unset */ if the BLOB pointer is unset */
row_ext_t* ext, /* in/out: column prefix cache */ const row_ext_t* ext, /* in/out: column prefix cache */
ulint i, /* in: ith element of ext */ ulint i, /* in: index of ext->ext[] */
const byte* field, /* in: locally stored part of the column */ ulint* len); /* out: length of prefix, in bytes,
ulint f_len, /* in: length of field, in bytes */ at most REC_MAX_INDEX_COL_LEN */
ulint* len); /* out: length of prefix, in bytes,
at most REC_MAX_INDEX_COL_LEN */
/************************************************************************ /************************************************************************
Looks up a column prefix of an externally stored column. */ Looks up a column prefix of an externally stored column. */
UNIV_INLINE UNIV_INLINE
byte* const byte*
row_ext_lookup( row_ext_lookup(
/*===========*/ /*===========*/
/* out: column prefix, or NULL if /* out: column prefix, or NULL if
the column is not stored externally, the column is not stored externally,
or pointer to field_ref_zero or pointer to field_ref_zero
if the BLOB pointer is unset */ if the BLOB pointer is unset */
row_ext_t* ext, /* in/out: column prefix cache */ const row_ext_t* ext, /* in: column prefix cache */
ulint col, /* in: column number in the InnoDB ulint col, /* in: column number in the InnoDB
table object, as reported by table object, as reported by
dict_col_get_no(); NOT relative to the dict_col_get_no(); NOT relative to the
records in the clustered index */ records in the clustered index */
const byte* field, /* in: locally stored part of the column */ ulint* len); /* out: length of prefix, in bytes,
ulint f_len, /* in: length of field, in bytes */ at most REC_MAX_INDEX_COL_LEN */
ulint* len); /* out: length of prefix, in bytes,
at most REC_MAX_INDEX_COL_LEN */
/* Prefixes of externally stored columns */ /* Prefixes of externally stored columns */
struct row_ext_struct{ struct row_ext_struct{
ulint n_ext; /* number of externally stored columns */ ulint n_ext; /* number of externally stored columns */
const ulint* ext; /* col_no's of externally stored columns */ const ulint* ext; /* col_no's of externally stored columns */
ulint zip_size;/* compressed page size, or 0 */
byte* buf; /* backing store of the column prefix cache */ byte* buf; /* backing store of the column prefix cache */
ulint len[1]; /* prefix lengths; 0 if not cached */ ulint len[1]; /* prefix lengths; 0 if not cached */
}; };
......
...@@ -7,118 +7,63 @@ Created September 2006 Marko Makela ...@@ -7,118 +7,63 @@ Created September 2006 Marko Makela
*******************************************************/ *******************************************************/
#include "rem0types.h" #include "rem0types.h"
#include "btr0types.h"
/************************************************************************
Looks up and caches a column prefix of an externally stored column. */
byte*
row_ext_lookup_low(
/*===============*/
/* out: column prefix, or
pointer to field_ref_zero
if the BLOB pointer is unset */
row_ext_t* ext, /* in/out: column prefix cache */
ulint i, /* in: index of ext->ext[] */
const byte* field, /* in: locally stored part of the column */
ulint f_len, /* in: length of field, in bytes */
ulint* len); /* out: length of prefix, in bytes,
at most REC_MAX_INDEX_COL_LEN */
/************************************************************************
Creates a cache of column prefixes of externally stored columns. */
UNIV_INLINE
row_ext_t*
row_ext_create(
/*===========*/
/* out,own: column prefix cache */
ulint n_ext, /* in: number of externally stored columns */
const ulint* ext, /* in: col_no's of externally stored columns
in the InnoDB table object, as reported by
dict_col_get_no(); NOT relative to the records
in the clustered index */
ulint zip_size,/* compressed page size, or 0 */
mem_heap_t* heap) /* in: heap where created */
{
row_ext_t* ret = mem_heap_alloc(heap, (sizeof *ret)
+ (n_ext - 1) * sizeof ret->len);
ut_ad(ut_is_2pow(zip_size));
ret->n_ext = n_ext;
ret->ext = ext;
ret->zip_size = zip_size;
ret->buf = mem_heap_alloc(heap, n_ext * REC_MAX_INDEX_COL_LEN);
#ifdef UNIV_DEBUG
memset(ret->buf, 0xaa, n_ext * REC_MAX_INDEX_COL_LEN);
UNIV_MEM_ALLOC(ret->buf, n_ext * REC_MAX_INDEX_COL_LEN);
#endif
memset(ret->len, 0, n_ext * sizeof *ret->len);
return(ret);
}
/************************************************************************ /************************************************************************
Looks up a column prefix of an externally stored column. */ Looks up a column prefix of an externally stored column. */
UNIV_INLINE UNIV_INLINE
byte* const byte*
row_ext_lookup_ith( row_ext_lookup_ith(
/*===============*/ /*===============*/
/* out: column prefix, or NULL if /* out: column prefix, or NULL if
the column is not stored externally, the column is not stored externally,
or pointer to field_ref_zero or pointer to field_ref_zero
if the BLOB pointer is unset */ if the BLOB pointer is unset */
row_ext_t* ext, /* in/out: column prefix cache */ const row_ext_t* ext, /* in/out: column prefix cache */
ulint i, /* in: index of ext->ext[] */ ulint i, /* in: index of ext->ext[] */
const byte* field, /* in: locally stored part of the column */ ulint* len) /* out: length of prefix, in bytes,
ulint f_len, /* in: length of field, in bytes */ at most REC_MAX_INDEX_COL_LEN */
ulint* len) /* out: length of prefix, in bytes,
at most REC_MAX_INDEX_COL_LEN */
{ {
ut_ad(ext); ut_ad(ext);
ut_ad(field);
ut_ad(len); ut_ad(len);
ut_ad(i < ext->n_ext); ut_ad(i < ext->n_ext);
/* Return from the cache if found */ *len = ext->len[i];
if (ext->len[i]) {
*len = ext->len[i]; if (UNIV_UNLIKELY(*len == 0)) {
ut_ad(*len > f_len); /* The BLOB could not be fetched to the cache. */
return(field_ref_zero);
} else {
return(ext->buf + i * REC_MAX_INDEX_COL_LEN); return(ext->buf + i * REC_MAX_INDEX_COL_LEN);
} }
/* Update the cache */
return(row_ext_lookup_low(ext, i, field, f_len, len));
} }
/************************************************************************ /************************************************************************
Looks up a column prefix of an externally stored column. */ Looks up a column prefix of an externally stored column. */
UNIV_INLINE UNIV_INLINE
byte* const byte*
row_ext_lookup( row_ext_lookup(
/*===========*/ /*===========*/
/* out: column prefix, or NULL if /* out: column prefix, or NULL if
the column is not stored externally, the column is not stored externally,
or pointer to field_ref_zero or pointer to field_ref_zero
if the BLOB pointer is unset */ if the BLOB pointer is unset */
row_ext_t* ext, /* in/out: column prefix cache */ const row_ext_t* ext, /* in: column prefix cache */
ulint col, /* in: column number in the InnoDB ulint col, /* in: column number in the InnoDB
table object, as reported by table object, as reported by
dict_col_get_no(); NOT relative to the dict_col_get_no(); NOT relative to the
records in the clustered index */ records in the clustered index */
const byte* field, /* in: locally stored part of the column */ ulint* len) /* out: length of prefix, in bytes,
ulint f_len, /* in: length of field, in bytes */ at most REC_MAX_INDEX_COL_LEN */
ulint* len) /* out: length of prefix, in bytes,
at most REC_MAX_INDEX_COL_LEN */
{ {
ulint i; ulint i;
ut_ad(ext); ut_ad(ext);
ut_ad(field);
ut_ad(len); ut_ad(len);
for (i = 0; i < ext->n_ext; i++) { for (i = 0; i < ext->n_ext; i++) {
if (col == ext->ext[i]) { if (col == ext->ext[i]) {
return(row_ext_lookup_ith(ext, i, field, f_len, len)); return(row_ext_lookup_ith(ext, i, len));
} }
} }
......
...@@ -15,36 +15,78 @@ Created September 2006 Marko Makela ...@@ -15,36 +15,78 @@ Created September 2006 Marko Makela
#include "btr0cur.h" #include "btr0cur.h"
/************************************************************************ /************************************************************************
Looks up and caches a column prefix of an externally stored column. */ Fills the column prefix cache of an externally stored column. */
static
byte* void
row_ext_lookup_low( row_ext_cache_fill(
/*===============*/ /*===============*/
/* out: column prefix, or
pointer to field_ref_zero
if the BLOB pointer is unset */
row_ext_t* ext, /* in/out: column prefix cache */ row_ext_t* ext, /* in/out: column prefix cache */
ulint i, /* in: index of ext->ext[] */ ulint i, /* in: index of ext->ext[] */
const byte* field, /* in: locally stored part of the column */ ulint zip_size,/* compressed page size in bytes, or 0 */
ulint f_len, /* in: length of field, in bytes */ const dfield_t* dfield) /* in: data field */
ulint* len) /* out: length of prefix, in bytes,
at most REC_MAX_INDEX_COL_LEN */
{ {
byte* buf = ext->buf + i * REC_MAX_INDEX_COL_LEN; const byte* field = dfield_get_data(dfield);
ulint f_len = dfield_get_len(dfield);
byte* buf = ext->buf + i * REC_MAX_INDEX_COL_LEN;
ut_ad(i < ext->n_ext); ut_ad(i < ext->n_ext);
ut_ad(dfield_is_ext(dfield));
ut_a(f_len >= BTR_EXTERN_FIELD_REF_SIZE); ut_a(f_len >= BTR_EXTERN_FIELD_REF_SIZE);
if (UNIV_UNLIKELY(!memcmp(field_ref_zero, if (UNIV_UNLIKELY(!memcmp(field_ref_zero,
field + f_len - BTR_EXTERN_FIELD_REF_SIZE, field + f_len - BTR_EXTERN_FIELD_REF_SIZE,
BTR_EXTERN_FIELD_REF_SIZE))) { BTR_EXTERN_FIELD_REF_SIZE))) {
/* The BLOB pointer is not set: we cannot fetch it */ /* The BLOB pointer is not set: we cannot fetch it */
*len = 0; ext->len[i] = 0;
return((byte*) field_ref_zero);
} }
*len = ext->len[i] = btr_copy_externally_stored_field_prefix( ext->len[i] = btr_copy_externally_stored_field_prefix(
buf, buf,
REC_MAX_INDEX_COL_LEN, ext->zip_size, field, f_len); REC_MAX_INDEX_COL_LEN, zip_size, field, f_len);
return(buf); }
/************************************************************************
Creates a cache of column prefixes of externally stored columns. */
UNIV_INLINE
row_ext_t*
row_ext_create(
/*===========*/
/* out,own: column prefix cache */
ulint n_ext, /* in: number of externally stored columns */
const ulint* ext, /* in: col_no's of externally stored columns
in the InnoDB table object, as reported by
dict_col_get_no(); NOT relative to the records
in the clustered index */
const dtuple_t* tuple, /* in: data tuple containing the field
references of the externally stored columns;
must be indexed by col_no */
ulint zip_size,/* compressed page size in bytes, or 0 */
mem_heap_t* heap) /* in: heap where created */
{
ulint i;
row_ext_t* ret = mem_heap_alloc(heap, (sizeof *ret)
+ (n_ext - 1) * sizeof ret->len);
ut_ad(ut_is_2pow(zip_size));
ut_ad(zip_size <= UNIV_PAGE_SIZE);
ret->n_ext = n_ext;
ret->ext = ext;
ret->buf = mem_heap_alloc(heap, n_ext * REC_MAX_INDEX_COL_LEN);
#ifdef UNIV_DEBUG
memset(ret->buf, 0xaa, n_ext * REC_MAX_INDEX_COL_LEN);
UNIV_MEM_ALLOC(ret->buf, n_ext * REC_MAX_INDEX_COL_LEN);
#endif
/* Fetch the BLOB prefixes */
for (i = 0; i < n_ext; i++) {
const dfield_t* dfield;
ulint len;
byte* b;
dfield = dtuple_get_nth_field(tuple, ext[i]);
row_ext_cache_fill(ret, i, zip_size, dfield);
}
return(ret);
} }
...@@ -261,7 +261,6 @@ row_merge_buf_add( ...@@ -261,7 +261,6 @@ row_merge_buf_add(
ulint col_no; ulint col_no;
const dfield_t* row_field; const dfield_t* row_field;
ulint len; ulint len;
const void* field_data;
ifield = dict_index_get_nth_field(index, i); ifield = dict_index_get_nth_field(index, i);
col = ifield->col; col = ifield->col;
...@@ -269,17 +268,15 @@ row_merge_buf_add( ...@@ -269,17 +268,15 @@ row_merge_buf_add(
row_field = dtuple_get_nth_field(row, col_no); row_field = dtuple_get_nth_field(row, col_no);
dfield_copy(field, row_field); dfield_copy(field, row_field);
len = dfield_get_len(field); len = dfield_get_len(field);
field_data = dfield_get_data(field);
if (dfield_is_null(field)) { if (dfield_is_null(field)) {
ut_ad(!(col->prtype & DATA_NOT_NULL)); ut_ad(!(col->prtype & DATA_NOT_NULL));
ut_ad(field_data == NULL);
continue; continue;
} else if (UNIV_LIKELY(!ext)) { } else if (UNIV_LIKELY(!ext)) {
} else if (dict_index_is_clust(index)) { } else if (dict_index_is_clust(index)) {
/* Flag externally stored fields. */ /* Flag externally stored fields. */
byte* buf = row_ext_lookup(ext, col_no, const byte* buf = row_ext_lookup(ext, col_no,
field_data, len, &len); &len);
if (UNIV_LIKELY_NULL(buf)) { if (UNIV_LIKELY_NULL(buf)) {
ut_a(buf != field_ref_zero); ut_a(buf != field_ref_zero);
if (i < dict_index_get_n_unique(index)) { if (i < dict_index_get_n_unique(index)) {
...@@ -290,8 +287,8 @@ row_merge_buf_add( ...@@ -290,8 +287,8 @@ row_merge_buf_add(
} }
} }
} else { } else {
byte* buf = row_ext_lookup(ext, col_no, const byte* buf = row_ext_lookup(ext, col_no,
field_data, len, &len); &len);
if (UNIV_LIKELY_NULL(buf)) { if (UNIV_LIKELY_NULL(buf)) {
ut_a(buf != field_ref_zero); ut_a(buf != field_ref_zero);
dfield_set_data(field, buf, len); dfield_set_data(field, buf, len);
......
...@@ -121,9 +121,8 @@ row_build_index_entry( ...@@ -121,9 +121,8 @@ row_build_index_entry(
if (UNIV_LIKELY_NULL(ext) && !dfield_is_null(dfield)) { if (UNIV_LIKELY_NULL(ext) && !dfield_is_null(dfield)) {
/* See if the column is stored externally. */ /* See if the column is stored externally. */
byte* buf = row_ext_lookup(ext, col_no, const byte* buf = row_ext_lookup(ext, col_no,
dfield_get_data(dfield), &len);
len, &len);
if (UNIV_LIKELY_NULL(buf)) { if (UNIV_LIKELY_NULL(buf)) {
if (UNIV_UNLIKELY(buf == field_ref_zero)) { if (UNIV_UNLIKELY(buf == field_ref_zero)) {
return(NULL); return(NULL);
...@@ -229,8 +228,10 @@ row_build( ...@@ -229,8 +228,10 @@ row_build(
= dict_index_get_nth_field(index, i); = dict_index_get_nth_field(index, i);
const dict_col_t* col const dict_col_t* col
= dict_field_get_col(ind_field); = dict_field_get_col(ind_field);
ulint col_no
= dict_col_get_no(col);
dfield_t* dfield dfield_t* dfield
= dtuple_get_nth_field(row, dict_col_get_no(col)); = dtuple_get_nth_field(row, col_no);
if (ind_field->prefix_len == 0) { if (ind_field->prefix_len == 0) {
...@@ -241,16 +242,20 @@ row_build( ...@@ -241,16 +242,20 @@ row_build(
} }
if (rec_offs_nth_extern(offsets, i)) { if (rec_offs_nth_extern(offsets, i)) {
ext_cols[j++] = dict_col_get_no(col);
dfield_set_ext(dfield); dfield_set_ext(dfield);
if (col->ord_part) {
/* We will have to fetch prefixes of
externally stored columns that are
referenced by column prefixes. */
ext_cols[j++] = col_no;
}
} }
} }
ut_ad(j == n_ext_cols);
ut_ad(dtuple_check_typed(row)); ut_ad(dtuple_check_typed(row));
if (n_ext_cols) { if (j) {
*ext = row_ext_create(n_ext_cols, ext_cols, *ext = row_ext_create(j, ext_cols, row,
dict_table_zip_size(index->table), dict_table_zip_size(index->table),
heap); heap);
} else { } else {
......
...@@ -945,30 +945,9 @@ trx_undo_rec_get_partial_row( ...@@ -945,30 +945,9 @@ trx_undo_rec_get_partial_row(
} }
if (n_ext_cols) { if (n_ext_cols) {
ulint i; *ext = row_ext_create(n_ext_cols, ext_cols, *row,
*ext = row_ext_create(n_ext_cols, ext_cols,
dict_table_zip_size(index->table), dict_table_zip_size(index->table),
heap); heap);
/* Fetch the BLOB prefixes, because the clustered
index record (and the BLOBs) may have been deleted by
the time row_ext_lookup() is called later in the purge
thread. */
for (i = 0; i < n_ext_cols; i++) {
const dfield_t* dfield;
ulint len;
byte* b;
dfield = dtuple_get_nth_field(*row, ext_cols[i]);
b = row_ext_lookup_ith(*ext, i,
dfield_get_data(dfield),
dfield_get_len(dfield),
&len);
ut_a(b);
ut_a(b != field_ref_zero);
}
} else { } else {
*ext = NULL; *ext = NULL;
} }
......
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