Commit ab7b4937 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 a5bd2496
......@@ -716,11 +716,6 @@ extern ulint btr_cur_n_sea;
extern ulint btr_cur_n_non_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
#include "btr0cur.ic"
#endif
......
......@@ -23,4 +23,9 @@ The reference is stored at the end of the prefix of the field
in the index record. */
#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
......@@ -11,11 +11,12 @@ Created September 2006 Marko Makela
#include "univ.i"
#include "row0types.h"
#include "data0types.h"
#include "mem0mem.h"
/************************************************************************
Creates a cache of column prefixes of externally stored columns. */
UNIV_INLINE
row_ext_t*
row_ext_create(
/*===========*/
......@@ -25,50 +26,48 @@ row_ext_create(
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 */
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 */
/************************************************************************
Looks up a column prefix of an externally stored column. */
UNIV_INLINE
byte*
const byte*
row_ext_lookup_ith(
/*===============*/
/* out: column prefix, or NULL if
the column is not stored externally,
or pointer to field_ref_zero
if the BLOB pointer is unset */
row_ext_t* ext, /* in/out: column prefix cache */
ulint i, /* in: ith element of 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 */
/* out: column prefix, or NULL if
the column is not stored externally,
or pointer to field_ref_zero
if the BLOB pointer is unset */
const row_ext_t* ext, /* in/out: column prefix cache */
ulint i, /* in: index of ext->ext[] */
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. */
UNIV_INLINE
byte*
const byte*
row_ext_lookup(
/*===========*/
/* out: column prefix, or NULL if
the column is not stored externally,
or pointer to field_ref_zero
if the BLOB pointer is unset */
row_ext_t* ext, /* in/out: column prefix cache */
ulint col, /* in: column number in the InnoDB
table object, as reported by
dict_col_get_no(); NOT relative to the
records in the clustered index */
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 */
/* out: column prefix, or NULL if
the column is not stored externally,
or pointer to field_ref_zero
if the BLOB pointer is unset */
const row_ext_t* ext, /* in: column prefix cache */
ulint col, /* in: column number in the InnoDB
table object, as reported by
dict_col_get_no(); NOT relative to the
records in the clustered index */
ulint* len); /* out: length of prefix, in bytes,
at most REC_MAX_INDEX_COL_LEN */
/* Prefixes of externally stored columns */
struct row_ext_struct{
ulint n_ext; /* number 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 */
ulint len[1]; /* prefix lengths; 0 if not cached */
};
......
......@@ -7,118 +7,63 @@ Created September 2006 Marko Makela
*******************************************************/
#include "rem0types.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);
}
#include "btr0types.h"
/************************************************************************
Looks up a column prefix of an externally stored column. */
UNIV_INLINE
byte*
const byte*
row_ext_lookup_ith(
/*===============*/
/* out: column prefix, or NULL if
the column is not stored externally,
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 */
/* out: column prefix, or NULL if
the column is not stored externally,
or pointer to field_ref_zero
if the BLOB pointer is unset */
const row_ext_t* ext, /* in/out: column prefix cache */
ulint i, /* in: index of ext->ext[] */
ulint* len) /* out: length of prefix, in bytes,
at most REC_MAX_INDEX_COL_LEN */
{
ut_ad(ext);
ut_ad(field);
ut_ad(len);
ut_ad(i < ext->n_ext);
/* Return from the cache if found */
if (ext->len[i]) {
*len = ext->len[i];
ut_ad(*len > f_len);
*len = ext->len[i];
if (UNIV_UNLIKELY(*len == 0)) {
/* The BLOB could not be fetched to the cache. */
return(field_ref_zero);
} else {
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. */
UNIV_INLINE
byte*
const byte*
row_ext_lookup(
/*===========*/
/* out: column prefix, or NULL if
the column is not stored externally,
or pointer to field_ref_zero
if the BLOB pointer is unset */
row_ext_t* ext, /* in/out: column prefix cache */
ulint col, /* in: column number in the InnoDB
table object, as reported by
dict_col_get_no(); NOT relative to the
records in the clustered index */
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 */
/* out: column prefix, or NULL if
the column is not stored externally,
or pointer to field_ref_zero
if the BLOB pointer is unset */
const row_ext_t* ext, /* in: column prefix cache */
ulint col, /* in: column number in the InnoDB
table object, as reported by
dict_col_get_no(); NOT relative to the
records in the clustered index */
ulint* len) /* out: length of prefix, in bytes,
at most REC_MAX_INDEX_COL_LEN */
{
ulint i;
ut_ad(ext);
ut_ad(field);
ut_ad(len);
for (i = 0; i < ext->n_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
#include "btr0cur.h"
/************************************************************************
Looks up and caches a column prefix of an externally stored column. */
byte*
row_ext_lookup_low(
Fills the column prefix cache of an externally stored column. */
static
void
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 */
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 */
ulint zip_size,/* compressed page size in bytes, or 0 */
const dfield_t* dfield) /* in: data field */
{
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(dfield_is_ext(dfield));
ut_a(f_len >= BTR_EXTERN_FIELD_REF_SIZE);
if (UNIV_UNLIKELY(!memcmp(field_ref_zero,
field + f_len - BTR_EXTERN_FIELD_REF_SIZE,
BTR_EXTERN_FIELD_REF_SIZE))) {
/* The BLOB pointer is not set: we cannot fetch it */
*len = 0;
return((byte*) field_ref_zero);
ext->len[i] = 0;
}
*len = ext->len[i] = btr_copy_externally_stored_field_prefix(
ext->len[i] = btr_copy_externally_stored_field_prefix(
buf,
REC_MAX_INDEX_COL_LEN, ext->zip_size, field, f_len);
return(buf);
REC_MAX_INDEX_COL_LEN, zip_size, field, f_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 */
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(
ulint col_no;
const dfield_t* row_field;
ulint len;
const void* field_data;
ifield = dict_index_get_nth_field(index, i);
col = ifield->col;
......@@ -269,17 +268,15 @@ row_merge_buf_add(
row_field = dtuple_get_nth_field(row, col_no);
dfield_copy(field, row_field);
len = dfield_get_len(field);
field_data = dfield_get_data(field);
if (dfield_is_null(field)) {
ut_ad(!(col->prtype & DATA_NOT_NULL));
ut_ad(field_data == NULL);
continue;
} else if (UNIV_LIKELY(!ext)) {
} else if (dict_index_is_clust(index)) {
/* Flag externally stored fields. */
byte* buf = row_ext_lookup(ext, col_no,
field_data, len, &len);
const byte* buf = row_ext_lookup(ext, col_no,
&len);
if (UNIV_LIKELY_NULL(buf)) {
ut_a(buf != field_ref_zero);
if (i < dict_index_get_n_unique(index)) {
......@@ -290,8 +287,8 @@ row_merge_buf_add(
}
}
} else {
byte* buf = row_ext_lookup(ext, col_no,
field_data, len, &len);
const byte* buf = row_ext_lookup(ext, col_no,
&len);
if (UNIV_LIKELY_NULL(buf)) {
ut_a(buf != field_ref_zero);
dfield_set_data(field, buf, len);
......
......@@ -121,9 +121,8 @@ row_build_index_entry(
if (UNIV_LIKELY_NULL(ext) && !dfield_is_null(dfield)) {
/* See if the column is stored externally. */
byte* buf = row_ext_lookup(ext, col_no,
dfield_get_data(dfield),
len, &len);
const byte* buf = row_ext_lookup(ext, col_no,
&len);
if (UNIV_LIKELY_NULL(buf)) {
if (UNIV_UNLIKELY(buf == field_ref_zero)) {
return(NULL);
......@@ -229,8 +228,10 @@ row_build(
= dict_index_get_nth_field(index, i);
const dict_col_t* col
= dict_field_get_col(ind_field);
ulint col_no
= dict_col_get_no(col);
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) {
......@@ -241,16 +242,20 @@ row_build(
}
if (rec_offs_nth_extern(offsets, i)) {
ext_cols[j++] = dict_col_get_no(col);
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));
if (n_ext_cols) {
*ext = row_ext_create(n_ext_cols, ext_cols,
if (j) {
*ext = row_ext_create(j, ext_cols, row,
dict_table_zip_size(index->table),
heap);
} else {
......
......@@ -945,30 +945,9 @@ trx_undo_rec_get_partial_row(
}
if (n_ext_cols) {
ulint i;
*ext = row_ext_create(n_ext_cols, ext_cols,
*ext = row_ext_create(n_ext_cols, ext_cols, *row,
dict_table_zip_size(index->table),
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 {
*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