summaryrefslogtreecommitdiff
path: root/storage/innobase/row/row0row.cc
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2018-09-21 09:17:33 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2018-09-21 09:27:06 +0300
commitbc7d40d0324f4062f44214e9db4dfd9c347700b0 (patch)
treebfa2cd1d7e066dc74de450fdc9ce535bbdcd21ec /storage/innobase/row/row0row.cc
parent90b292ce31170be33796b07723ffcef56bf8a679 (diff)
downloadmariadb-git-bc7d40d0324f4062f44214e9db4dfd9c347700b0.tar.gz
Clean up some SPATIAL INDEX code
Clarify some comments about accessing an externally stored column on which a spatial index has been defined. Add a TODO comment that we should actually write the minimum bounding rectangle (MBR) to the undo log record, so that we can avoid fetching BLOBs and recomputing MBR. row_build_spatial_index_key(): Split from row_build_index_entry_low().
Diffstat (limited to 'storage/innobase/row/row0row.cc')
-rw-r--r--storage/innobase/row/row0row.cc246
1 files changed, 134 insertions, 112 deletions
diff --git a/storage/innobase/row/row0row.cc b/storage/innobase/row/row0row.cc
index 04af5646e6b..ffd8f48503d 100644
--- a/storage/innobase/row/row0row.cc
+++ b/storage/innobase/row/row0row.cc
@@ -46,6 +46,136 @@ Created 4/20/1996 Heikki Tuuri
#include "gis0geo.h"
#include "row0mysql.h"
+/** Build a spatial index key.
+@param[in] index spatial index
+@param[in] ext externally stored column prefixes, or NULL
+@param[in,out] dfield field of the tuple to be copied
+@param[in] dfield2 field of the tuple to copy
+@param[in] flag ROW_BUILD_NORMAL, ROW_BUILD_FOR_PURGE or
+ ROW_BUILD_FOR_UNDO
+@param[in,out] heap memory heap from which the memory
+ of the field entry is allocated.
+@retval false if undo log is logged before spatial index creation. */
+static bool row_build_spatial_index_key(
+ dict_index_t* index,
+ const row_ext_t* ext,
+ dfield_t* dfield,
+ const dfield_t* dfield2,
+ ulint flag,
+ mem_heap_t* heap)
+{
+ double* mbr;
+
+ dfield_copy(dfield, dfield2);
+ dfield->type.prtype |= DATA_GIS_MBR;
+
+ /* Allocate memory for mbr field */
+ mbr = static_cast<double*>(mem_heap_alloc(heap, DATA_MBR_LEN));
+
+ /* Set mbr field data. */
+ dfield_set_data(dfield, mbr, DATA_MBR_LEN);
+
+ const fil_space_t* space = index->table->space;
+
+ if (UNIV_UNLIKELY(!dfield2->data || !space)) {
+ /* FIXME: dfield contains uninitialized data,
+ but row_build_index_entry_low() will not return NULL.
+ This bug is inherited from MySQL 5.7.5
+ commit b66ad511b61fffe75c58d0a607cdb837c6e6c821. */
+ return true;
+ }
+
+ uchar* dptr = NULL;
+ ulint dlen = 0;
+ ulint flen = 0;
+ double tmp_mbr[SPDIMS * 2];
+ mem_heap_t* temp_heap = NULL;
+
+ if (!dfield_is_ext(dfield2)) {
+ dptr = static_cast<uchar*>(dfield_get_data(dfield2));
+ dlen = dfield_get_len(dfield2);
+ goto write_mbr;
+ }
+
+ if (flag == ROW_BUILD_FOR_PURGE) {
+ byte* ptr = static_cast<byte*>(dfield_get_data(dfield2));
+
+ switch (dfield_get_spatial_status(dfield2)) {
+ case SPATIAL_ONLY:
+ ut_ad(dfield_get_len(dfield2) == DATA_MBR_LEN);
+ break;
+
+ case SPATIAL_MIXED:
+ ptr += dfield_get_len(dfield2);
+ break;
+
+ case SPATIAL_UNKNOWN:
+ ut_ad(0);
+ /* fall through */
+ case SPATIAL_NONE:
+ /* Undo record is logged before
+ spatial index is created.*/
+ return false;
+ }
+
+ memcpy(mbr, ptr, DATA_MBR_LEN);
+ return true;
+ }
+
+ if (flag == ROW_BUILD_FOR_UNDO
+ && dict_table_has_atomic_blobs(index->table)) {
+ /* For ROW_FORMAT=DYNAMIC or COMPRESSED, a prefix of
+ off-page records is stored in the undo log record (for
+ any column prefix indexes). For SPATIAL INDEX, we
+ must ignore this prefix. The full column value is
+ stored in the BLOB. For non-spatial index, we would
+ have already fetched a necessary prefix of the BLOB,
+ available in the "ext" parameter.
+
+ Here, for SPATIAL INDEX, we are fetching the full
+ column, which is potentially wasting a lot of I/O,
+ memory, and possibly involving a concurrency problem,
+ similar to ones that existed before the introduction
+ of row_ext_t.
+
+ MDEV-11657 FIXME: write the MBR directly to the undo
+ log record, and avoid recomputing it here! */
+ flen = BTR_EXTERN_FIELD_REF_SIZE;
+ ut_ad(dfield_get_len(dfield2) >= BTR_EXTERN_FIELD_REF_SIZE);
+ dptr = static_cast<byte*>(dfield_get_data(dfield2))
+ + dfield_get_len(dfield2)
+ - BTR_EXTERN_FIELD_REF_SIZE;
+ } else {
+ flen = dfield_get_len(dfield2);
+ dptr = static_cast<byte*>(dfield_get_data(dfield2));
+ }
+
+ temp_heap = mem_heap_create(1000);
+
+ dptr = btr_copy_externally_stored_field(
+ &dlen, dptr, ext ? ext->page_size : page_size_t(space->flags),
+ flen, temp_heap);
+
+write_mbr:
+ if (dlen <= GEO_DATA_HEADER_SIZE) {
+ for (uint i = 0; i < SPDIMS; i += 2) {
+ tmp_mbr[i] = DBL_MAX;
+ tmp_mbr[i + 1] = -DBL_MAX;
+ }
+ } else {
+ rtree_mbr_from_wkb(dptr + GEO_DATA_HEADER_SIZE,
+ uint(dlen - GEO_DATA_HEADER_SIZE),
+ SPDIMS, tmp_mbr);
+ }
+
+ dfield_write_mbr(dfield, tmp_mbr);
+ if (temp_heap) {
+ mem_heap_free(temp_heap);
+ }
+
+ return true;
+}
+
/*****************************************************************//**
When an insert or purge to a table is performed, this function builds
the entry to be inserted into or purged from an index on the table.
@@ -149,119 +279,11 @@ row_build_index_entry_low(
/* Special handle spatial index, set the first field
which is for store MBR. */
if (dict_index_is_spatial(index) && i == 0) {
- double* mbr;
-
- dfield_copy(dfield, dfield2);
- dfield->type.prtype |= DATA_GIS_MBR;
-
- /* Allocate memory for mbr field */
- ulint mbr_len = DATA_MBR_LEN;
- mbr = static_cast<double*>(mem_heap_alloc(heap, mbr_len));
-
- /* Set mbr field data. */
- dfield_set_data(dfield, mbr, mbr_len);
-
- if (dfield2->data) {
- uchar* dptr = NULL;
- ulint dlen = 0;
- ulint flen = 0;
- double tmp_mbr[SPDIMS * 2];
- mem_heap_t* temp_heap = NULL;
-
- if (dfield_is_ext(dfield2)) {
- if (flag == ROW_BUILD_FOR_PURGE) {
- byte* ptr = NULL;
-
- spatial_status_t spatial_status;
- spatial_status =
- dfield_get_spatial_status(
- dfield2);
-
- switch (spatial_status) {
- case SPATIAL_ONLY:
- ptr = static_cast<byte*>(
- dfield_get_data(
- dfield2));
- ut_ad(dfield_get_len(dfield2)
- == DATA_MBR_LEN);
- break;
-
- case SPATIAL_MIXED:
- ptr = static_cast<byte*>(
- dfield_get_data(
- dfield2))
- + dfield_get_len(
- dfield2);
- break;
-
- case SPATIAL_UNKNOWN:
- ut_ad(0);
- /* fall through */
- case SPATIAL_NONE:
- /* Undo record is logged before
- spatial index is created.*/
- return(NULL);
- }
-
- memcpy(mbr, ptr, DATA_MBR_LEN);
- continue;
- }
-
- if (flag == ROW_BUILD_FOR_UNDO
- && dict_table_has_atomic_blobs(
- index->table)) {
- /* For build entry for undo, and
- the table is Barrcuda, we need
- to skip the prefix data. */
- flen = BTR_EXTERN_FIELD_REF_SIZE;
- ut_ad(dfield_get_len(dfield2) >=
- BTR_EXTERN_FIELD_REF_SIZE);
- dptr = static_cast<byte*>(
- dfield_get_data(dfield2))
- + dfield_get_len(dfield2)
- - BTR_EXTERN_FIELD_REF_SIZE;
- } else {
- flen = dfield_get_len(dfield2);
- dptr = static_cast<byte*>(
- dfield_get_data(dfield2));
- }
-
- temp_heap = mem_heap_create(1000);
-
- const page_size_t page_size
- = (ext != NULL)
- ? ext->page_size
- : dict_table_page_size(
- index->table);
-
- dptr = btr_copy_externally_stored_field(
- &dlen, dptr,
- page_size,
- flen,
- temp_heap);
- } else {
- dptr = static_cast<uchar*>(
- dfield_get_data(dfield2));
- dlen = dfield_get_len(dfield2);
-
- }
-
- if (dlen <= GEO_DATA_HEADER_SIZE) {
- for (uint i = 0; i < SPDIMS; ++i) {
- tmp_mbr[i * 2] = DBL_MAX;
- tmp_mbr[i * 2 + 1] = -DBL_MAX;
- }
- } else {
- rtree_mbr_from_wkb(dptr + GEO_DATA_HEADER_SIZE,
- static_cast<uint>(dlen
- - GEO_DATA_HEADER_SIZE),
- SPDIMS, tmp_mbr);
- }
- dfield_write_mbr(dfield, tmp_mbr);
- if (temp_heap) {
- mem_heap_free(temp_heap);
- }
+ if (!row_build_spatial_index_key(
+ index, ext, dfield, dfield2, flag, heap)) {
+ return NULL;
}
+
continue;
}