1 /***************************************************************************** 2 3 Copyright (c) 2005, 2019, Oracle and/or its affiliates. All Rights Reserved. 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License, version 2.0, as published by the 7 Free Software Foundation. 8 9 This program is also distributed with certain software (including but not 10 limited to OpenSSL) that is licensed under separate terms, as designated in a 11 particular file or component or in included license documentation. The authors 12 of MySQL hereby grant you an additional permission to link the program and 13 your derivative works with the separately licensed software that they have 14 included with MySQL. 15 16 This program is distributed in the hope that it will be useful, but WITHOUT 17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, 19 for more details. 20 21 You should have received a copy of the GNU General Public License along with 22 this program; if not, write to the Free Software Foundation, Inc., 23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 25 *****************************************************************************/ 26 27 /** @file include/row0merge.h 28 Index build routines using a merge sort 29 30 Created 13/06/2005 Jan Lindstrom 31 *******************************************************/ 32 33 #ifndef row0merge_h 34 #define row0merge_h 35 36 #include "btr0types.h" 37 #include "data0data.h" 38 #include "dict0types.h" 39 #include "lock0types.h" 40 #include "mtr0mtr.h" 41 #include "que0types.h" 42 #include "rem0rec.h" 43 #include "rem0types.h" 44 #include "row0mysql.h" 45 #include "srv0srv.h" 46 #include "trx0types.h" 47 #include "univ.i" 48 #include "ut0stage.h" 49 50 // Forward declaration 51 struct ib_sequence_t; 52 53 /** @brief Block size for I/O operations in merge sort. 54 55 The minimum is UNIV_PAGE_SIZE, or page_get_free_space_of_empty() 56 rounded to a power of 2. 57 58 When not creating a PRIMARY KEY that contains column prefixes, this 59 can be set as small as UNIV_PAGE_SIZE / 2. */ 60 typedef byte row_merge_block_t; 61 62 /** @brief Secondary buffer for I/O operations of merge records. 63 64 This buffer is used for writing or reading a record that spans two 65 row_merge_block_t. Thus, it must be able to hold one merge record, 66 whose maximum size is the same as the minimum size of 67 row_merge_block_t. */ 68 typedef byte mrec_buf_t[UNIV_PAGE_SIZE_MAX]; 69 70 /** @brief Merge record in row_merge_block_t. 71 72 The format is the same as a record in ROW_FORMAT=COMPACT with the 73 exception that the REC_N_NEW_EXTRA_BYTES are omitted. */ 74 typedef byte mrec_t; 75 76 /** Merge record in row_merge_buf_t */ 77 struct mtuple_t { 78 dfield_t *fields; /*!< data fields */ 79 }; 80 81 /** Buffer for sorting in main memory. */ 82 struct row_merge_buf_t { 83 mem_heap_t *heap; /*!< memory heap where allocated */ 84 dict_index_t *index; /*!< the index the tuples belong to */ 85 ulint total_size; /*!< total amount of data bytes */ 86 ulint n_tuples; /*!< number of data tuples */ 87 ulint max_tuples; /*!< maximum number of data tuples */ 88 mtuple_t *tuples; /*!< array of data tuples */ 89 mtuple_t *tmp_tuples; /*!< temporary copy of tuples, 90 for sorting */ 91 }; 92 93 /** Information about temporary files used in merge sort */ 94 struct merge_file_t { 95 int fd; /*!< file descriptor */ 96 ulint offset; /*!< file offset (end of file) */ 97 ib_uint64_t n_rec; /*!< number of records in the file */ 98 }; 99 100 /** Index field definition */ 101 struct index_field_t { 102 ulint col_no; /*!< column offset */ 103 ulint prefix_len; /*!< column prefix length, or 0 104 if indexing the whole column */ 105 bool is_v_col; /*!< whether this is a virtual column */ 106 bool is_multi_value; /*!< whether it has multi-value */ 107 bool is_ascending; /*!< true=ASC, false=DESC */ 108 }; 109 110 /** Definition of an index being created */ 111 struct index_def_t { 112 const char *name; /*!< index name */ 113 bool rebuild; /*!< whether the table is rebuilt */ 114 ulint ind_type; /*!< 0, DICT_UNIQUE, 115 or DICT_CLUSTERED */ 116 ulint key_number; /*!< MySQL key number, 117 or ULINT_UNDEFINED if none */ 118 ulint n_fields; /*!< number of fields in index */ 119 index_field_t *fields; /*!< field definitions */ 120 st_mysql_ftparser *parser; /*!< fulltext parser plugin */ 121 bool is_ngram; /*!< true if it's ngram parser */ 122 bool srid_is_valid; /*!< true if we want to check SRID 123 while inserting to index */ 124 uint32_t srid; /*!< SRID obtained from dd column */ 125 }; 126 127 /** Structure for reporting duplicate records. */ 128 struct row_merge_dup_t { 129 dict_index_t *index; /*!< index being sorted */ 130 struct TABLE *table; /*!< MySQL table object */ 131 const ulint *col_map; /*!< mapping of column numbers 132 in table to the rebuilt table 133 (index->table), or NULL if not 134 rebuilding table */ 135 ulint n_dup; /*!< number of duplicates */ 136 }; 137 138 /** Report a duplicate key. */ 139 void row_merge_dup_report( 140 row_merge_dup_t *dup, /*!< in/out: for reporting duplicates */ 141 const dfield_t *entry); /*!< in: duplicate index entry */ 142 /** Sets an exclusive lock on a table, for the duration of creating indexes. 143 @return error code or DB_SUCCESS */ 144 dberr_t row_merge_lock_table(trx_t *trx, /*!< in/out: transaction */ 145 dict_table_t *table, /*!< in: table to lock */ 146 enum lock_mode mode) /*!< in: LOCK_X or LOCK_S */ 147 MY_ATTRIBUTE((warn_unused_result)); 148 /** Drop those indexes which were created before an error occurred. 149 The data dictionary must have been locked exclusively by the caller, 150 because the transaction will not be committed. */ 151 void row_merge_drop_indexes( 152 trx_t *trx, /*!< in/out: transaction */ 153 dict_table_t *table, /*!< in/out: table containing the indexes */ 154 ibool locked); /*!< in: TRUE=table locked, 155 FALSE=may need to do a lazy drop */ 156 157 /**Create temporary merge files in the given paramater path, and if 158 UNIV_PFS_IO defined, register the file descriptor with Performance Schema. 159 @param[in] path location for creating temporary merge files. 160 @return File descriptor */ 161 int row_merge_file_create_low(const char *path) 162 MY_ATTRIBUTE((warn_unused_result)); 163 164 /** Destroy a merge file. And de-register the file from Performance Schema 165 if UNIV_PFS_IO is defined. */ 166 void row_merge_file_destroy_low(int fd); /*!< in: merge file descriptor */ 167 168 /** Provide a new pathname for a table that is being renamed if it belongs to 169 a file-per-table tablespace. The caller is responsible for freeing the 170 memory allocated for the return value. 171 @return new pathname of tablespace file, or NULL if space = 0 */ 172 char *row_make_new_pathname(dict_table_t *table, /*!< in: table to be renamed */ 173 const char *new_name); /*!< in: new name */ 174 /** Rename the tables in the data dictionary. The data dictionary must 175 have been locked exclusively by the caller, because the transaction 176 will not be committed. 177 @return error code or DB_SUCCESS */ 178 dberr_t row_merge_rename_tables_dict( 179 dict_table_t *old_table, /*!< in/out: old table, renamed to 180 tmp_name */ 181 dict_table_t *new_table, /*!< in/out: new table, renamed to 182 old_table->name */ 183 const char *tmp_name, /*!< in: new name for old_table */ 184 trx_t *trx) /*!< in/out: dictionary transaction */ 185 MY_ATTRIBUTE((warn_unused_result)); 186 187 /** Create the index and load in to the dictionary. 188 @param[in,out] trx trx (sets error_state) 189 @param[in,out] table the index is on this table 190 @param[in] index_def the index definition 191 @param[in] add_v new virtual columns added along with add 192 index call 193 @return index, or NULL on error */ 194 dict_index_t *row_merge_create_index(trx_t *trx, dict_table_t *table, 195 const index_def_t *index_def, 196 const dict_add_v_col_t *add_v); 197 198 /** Drop a table. The caller must have ensured that the background stats 199 thread is not processing the table. This can be done by calling 200 dict_stats_wait_bg_to_stop_using_table() after locking the dictionary and 201 before calling this function. 202 @return DB_SUCCESS or error code */ 203 dberr_t row_merge_drop_table( 204 trx_t *trx, /*!< in: transaction */ 205 dict_table_t *table); /*!< in: table instance to drop */ 206 207 /** Build indexes on a table by reading a clustered index, creating a temporary 208 file containing index entries, merge sorting these index entries and inserting 209 sorted index entries to indexes. 210 @param[in] trx transaction 211 @param[in] old_table table where rows are read from 212 @param[in] new_table table where indexes are created; identical to 213 old_table unless creating a PRIMARY KEY 214 @param[in] online true if creating indexes online 215 @param[in] indexes indexes to be created 216 @param[in] key_numbers MySQL key numbers 217 @param[in] n_indexes size of indexes[] 218 @param[in,out] table MySQL table, for reporting erroneous key value 219 if applicable 220 @param[in] add_cols default values of added columns, or NULL 221 @param[in] col_map mapping of old column numbers to new ones, or 222 NULL if old_table == new_table 223 @param[in] add_autoinc number of added AUTO_INCREMENT columns, or 224 ULINT_UNDEFINED if none is added 225 @param[in,out] sequence autoinc sequence 226 @param[in] skip_pk_sort whether the new PRIMARY KEY will follow 227 existing order 228 @param[in,out] stage performance schema accounting object, used by 229 ALTER TABLE. stage->begin_phase_read_pk() will be called at the beginning of 230 this function and it will be passed to other functions for further accounting. 231 @param[in] add_v new virtual columns added along with indexes 232 @param[in] eval_table mysql table used to evaluate virtual column 233 value, see innobase_get_computed_value(). 234 @return DB_SUCCESS or error code */ 235 dberr_t row_merge_build_indexes( 236 trx_t *trx, dict_table_t *old_table, dict_table_t *new_table, bool online, 237 dict_index_t **indexes, const ulint *key_numbers, ulint n_indexes, 238 struct TABLE *table, const dtuple_t *add_cols, const ulint *col_map, 239 ulint add_autoinc, ib_sequence_t &sequence, bool skip_pk_sort, 240 ut_stage_alter_t *stage, const dict_add_v_col_t *add_v, 241 struct TABLE *eval_table) MY_ATTRIBUTE((warn_unused_result)); 242 243 /** Write a buffer to a block. 244 @param[in] buf sorted buffer 245 @param[in] of output file 246 @param[out] block buffer for writing to file */ 247 void row_merge_buf_write(const row_merge_buf_t *buf, const merge_file_t *of, 248 row_merge_block_t *block); 249 250 /** Sort a buffer. */ 251 void row_merge_buf_sort( 252 row_merge_buf_t *buf, /*!< in/out: sort buffer */ 253 row_merge_dup_t *dup); /*!< in/out: reporter of duplicates 254 (NULL if non-unique index) */ 255 /** Write a merge block to the file system. 256 @return true if request was successful, false if fail */ 257 ibool row_merge_write(int fd, /*!< in: file descriptor */ 258 ulint offset, /*!< in: offset where to write, 259 in number of row_merge_block_t elements */ 260 const void *buf); /*!< in: data */ 261 /** Empty a sort buffer. 262 @return sort buffer */ 263 row_merge_buf_t *row_merge_buf_empty( 264 row_merge_buf_t *buf) /*!< in,own: sort buffer */ 265 MY_ATTRIBUTE((warn_unused_result)); 266 267 /** Create a merge file int the given location. 268 @param[out] merge_file merge file structure 269 @param[in] path location for creating temporary file 270 @return file descriptor, or -1 on failure */ 271 int row_merge_file_create(merge_file_t *merge_file, const char *path); 272 273 /** Merge disk files. 274 @param[in] trx transaction 275 @param[in] dup descriptor of index being created 276 @param[in,out] file file containing index entries 277 @param[in,out] block 3 buffers 278 @param[in,out] tmpfd temporary file handle 279 @param[in,out] stage performance schema accounting object, used by 280 ALTER TABLE. If not NULL, stage->begin_phase_sort() will be called initially 281 and then stage->inc() will be called for each record processed. 282 @return DB_SUCCESS or error code */ 283 dberr_t row_merge_sort(trx_t *trx, const row_merge_dup_t *dup, 284 merge_file_t *file, row_merge_block_t *block, int *tmpfd, 285 ut_stage_alter_t *stage = nullptr); 286 287 /** Allocate a sort buffer. 288 @return own: sort buffer */ 289 row_merge_buf_t *row_merge_buf_create( 290 dict_index_t *index) /*!< in: secondary index */ 291 MY_ATTRIBUTE((warn_unused_result, malloc)); 292 /** Deallocate a sort buffer. */ 293 void row_merge_buf_free( 294 row_merge_buf_t *buf); /*!< in,own: sort buffer to be freed */ 295 /** Destroy a merge file. */ 296 void row_merge_file_destroy( 297 merge_file_t *merge_file); /*!< in/out: merge file structure */ 298 /** Read a merge block from the file system. 299 @return true if request was successful, false if fail */ 300 ibool row_merge_read(int fd, /*!< in: file descriptor */ 301 ulint offset, /*!< in: offset where to read 302 in number of row_merge_block_t 303 elements */ 304 row_merge_block_t *buf); /*!< out: data */ 305 /** Read a merge record. 306 @return pointer to next record, or NULL on I/O error or end of list */ 307 const byte *row_merge_read_rec( 308 row_merge_block_t *block, /*!< in/out: file buffer */ 309 mrec_buf_t *buf, /*!< in/out: secondary buffer */ 310 const byte *b, /*!< in: pointer to record */ 311 const dict_index_t *index, /*!< in: index of the record */ 312 int fd, /*!< in: file descriptor */ 313 ulint *foffs, /*!< in/out: file offset */ 314 const mrec_t **mrec, /*!< out: pointer to merge record, 315 or NULL on end of list 316 (non-NULL on I/O error) */ 317 ulint *offsets) /*!< out: offsets of mrec */ 318 MY_ATTRIBUTE((warn_unused_result)); 319 #endif /* row0merge.h */ 320