1 /***************************************************************************** 2 3 Copyright (c) 2005, 2016, Oracle and/or its affiliates. All Rights Reserved. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License, version 2.0, 7 as published by the Free Software Foundation. 8 9 This program is also distributed with certain software (including 10 but not limited to OpenSSL) that is licensed under separate terms, 11 as designated in a particular file or component or in included license 12 documentation. The authors of MySQL hereby grant you an additional 13 permission to link the program and your derivative works with the 14 separately licensed software that they have included with MySQL. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License, version 2.0, 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 Street, Suite 500, Boston, MA 02110-1335 USA 24 25 *****************************************************************************/ 26 27 /**************************************************//** 28 @file include/row0merge.h 29 Index build routines using a merge sort 30 31 Created 13/06/2005 Jan Lindstrom 32 *******************************************************/ 33 34 #ifndef row0merge_h 35 #define row0merge_h 36 37 #include "univ.i" 38 #include "data0data.h" 39 #include "dict0types.h" 40 #include "trx0types.h" 41 #include "que0types.h" 42 #include "mtr0mtr.h" 43 #include "rem0types.h" 44 #include "rem0rec.h" 45 #include "read0types.h" 46 #include "btr0types.h" 47 #include "row0mysql.h" 48 #include "lock0types.h" 49 #include "srv0srv.h" 50 51 // Forward declaration 52 struct ib_sequence_t; 53 54 /** @brief Block size for I/O operations in merge sort. 55 56 The minimum is UNIV_PAGE_SIZE, or page_get_free_space_of_empty() 57 rounded to a power of 2. 58 59 When not creating a PRIMARY KEY that contains column prefixes, this 60 can be set as small as UNIV_PAGE_SIZE / 2. */ 61 typedef byte row_merge_block_t; 62 63 /** @brief Secondary buffer for I/O operations of merge records. 64 65 This buffer is used for writing or reading a record that spans two 66 row_merge_block_t. Thus, it must be able to hold one merge record, 67 whose maximum size is the same as the minimum size of 68 row_merge_block_t. */ 69 typedef byte mrec_buf_t[UNIV_PAGE_SIZE_MAX]; 70 71 /** @brief Merge record in row_merge_block_t. 72 73 The format is the same as a record in ROW_FORMAT=COMPACT with the 74 exception that the REC_N_NEW_EXTRA_BYTES are omitted. */ 75 typedef byte mrec_t; 76 77 /** Merge record in row_merge_buf_t */ 78 struct mtuple_t { 79 dfield_t* fields; /*!< data fields */ 80 }; 81 82 /** Buffer for sorting in main memory. */ 83 struct row_merge_buf_t { 84 mem_heap_t* heap; /*!< memory heap where allocated */ 85 dict_index_t* index; /*!< the index the tuples belong to */ 86 ulint total_size; /*!< total amount of data bytes */ 87 ulint n_tuples; /*!< number of data tuples */ 88 ulint max_tuples; /*!< maximum number of data tuples */ 89 mtuple_t* tuples; /*!< array of data tuples */ 90 mtuple_t* tmp_tuples; /*!< temporary copy of tuples, 91 for sorting */ 92 }; 93 94 /** Information about temporary files used in merge sort */ 95 struct merge_file_t { 96 int fd; /*!< file descriptor */ 97 ulint offset; /*!< file offset (end of file) */ 98 ib_uint64_t n_rec; /*!< number of records in the file */ 99 }; 100 101 /** Index field definition */ 102 struct index_field_t { 103 ulint col_no; /*!< column offset */ 104 ulint prefix_len; /*!< column prefix length, or 0 105 if indexing the whole column */ 106 }; 107 108 /** Definition of an index being created */ 109 struct index_def_t { 110 const char* name; /*!< index name */ 111 ulint ind_type; /*!< 0, DICT_UNIQUE, 112 or DICT_CLUSTERED */ 113 ulint key_number; /*!< MySQL key number, 114 or ULINT_UNDEFINED if none */ 115 ulint n_fields; /*!< number of fields in index */ 116 index_field_t* fields; /*!< field definitions */ 117 }; 118 119 /** Structure for reporting duplicate records. */ 120 struct row_merge_dup_t { 121 dict_index_t* index; /*!< index being sorted */ 122 struct TABLE* table; /*!< MySQL table object */ 123 const ulint* col_map;/*!< mapping of column numbers 124 in table to the rebuilt table 125 (index->table), or NULL if not 126 rebuilding table */ 127 ulint n_dup; /*!< number of duplicates */ 128 }; 129 130 /*************************************************************//** 131 Report a duplicate key. */ 132 UNIV_INTERN 133 void 134 row_merge_dup_report( 135 /*=================*/ 136 row_merge_dup_t* dup, /*!< in/out: for reporting duplicates */ 137 const dfield_t* entry) /*!< in: duplicate index entry */ 138 MY_ATTRIBUTE((nonnull)); 139 /*********************************************************************//** 140 Sets an exclusive lock on a table, for the duration of creating indexes. 141 @return error code or DB_SUCCESS */ 142 UNIV_INTERN 143 dberr_t 144 row_merge_lock_table( 145 /*=================*/ 146 trx_t* trx, /*!< in/out: transaction */ 147 dict_table_t* table, /*!< in: table to lock */ 148 enum lock_mode mode) /*!< in: LOCK_X or LOCK_S */ 149 MY_ATTRIBUTE((nonnull, warn_unused_result)); 150 /*********************************************************************//** 151 Drop indexes that were created before an error occurred. 152 The data dictionary must have been locked exclusively by the caller, 153 because the transaction will not be committed. */ 154 UNIV_INTERN 155 void 156 row_merge_drop_indexes_dict( 157 /*========================*/ 158 trx_t* trx, /*!< in/out: dictionary transaction */ 159 table_id_t table_id)/*!< in: table identifier */ 160 MY_ATTRIBUTE((nonnull)); 161 /*********************************************************************//** 162 Drop those indexes which were created before an error occurred. 163 The data dictionary must have been locked exclusively by the caller, 164 because the transaction will not be committed. */ 165 UNIV_INTERN 166 void 167 row_merge_drop_indexes( 168 /*===================*/ 169 trx_t* trx, /*!< in/out: transaction */ 170 dict_table_t* table, /*!< in/out: table containing the indexes */ 171 ibool locked) /*!< in: TRUE=table locked, 172 FALSE=may need to do a lazy drop */ 173 MY_ATTRIBUTE((nonnull)); 174 /*********************************************************************//** 175 Drop all partially created indexes during crash recovery. */ 176 UNIV_INTERN 177 void 178 row_merge_drop_temp_indexes(void); 179 /*=============================*/ 180 181 /** Create temporary merge files in the given paramater path, and if 182 UNIV_PFS_IO defined, register the file descriptor with Performance Schema. 183 @param[in] path location for creating temporary merge files. 184 @return File descriptor */ 185 UNIV_INTERN 186 int 187 row_merge_file_create_low( 188 const char* path) 189 MY_ATTRIBUTE((warn_unused_result)); 190 /*********************************************************************//** 191 Destroy a merge file. And de-register the file from Performance Schema 192 if UNIV_PFS_IO is defined. */ 193 UNIV_INTERN 194 void 195 row_merge_file_destroy_low( 196 /*=======================*/ 197 int fd); /*!< in: merge file descriptor */ 198 199 /*********************************************************************//** 200 Provide a new pathname for a table that is being renamed if it belongs to 201 a file-per-table tablespace. The caller is responsible for freeing the 202 memory allocated for the return value. 203 @return new pathname of tablespace file, or NULL if space = 0 */ 204 UNIV_INTERN 205 char* 206 row_make_new_pathname( 207 /*==================*/ 208 dict_table_t* table, /*!< in: table to be renamed */ 209 const char* new_name); /*!< in: new name */ 210 /*********************************************************************//** 211 Rename the tables in the data dictionary. The data dictionary must 212 have been locked exclusively by the caller, because the transaction 213 will not be committed. 214 @return error code or DB_SUCCESS */ 215 UNIV_INTERN 216 dberr_t 217 row_merge_rename_tables_dict( 218 /*=========================*/ 219 dict_table_t* old_table, /*!< in/out: old table, renamed to 220 tmp_name */ 221 dict_table_t* new_table, /*!< in/out: new table, renamed to 222 old_table->name */ 223 const char* tmp_name, /*!< in: new name for old_table */ 224 trx_t* trx) /*!< in/out: dictionary transaction */ 225 MY_ATTRIBUTE((nonnull, warn_unused_result)); 226 227 /*********************************************************************//** 228 Rename an index in the dictionary that was created. The data 229 dictionary must have been locked exclusively by the caller, because 230 the transaction will not be committed. 231 @return DB_SUCCESS if all OK */ 232 UNIV_INTERN 233 dberr_t 234 row_merge_rename_index_to_add( 235 /*==========================*/ 236 trx_t* trx, /*!< in/out: transaction */ 237 table_id_t table_id, /*!< in: table identifier */ 238 index_id_t index_id) /*!< in: index identifier */ 239 MY_ATTRIBUTE((nonnull)); 240 /*********************************************************************//** 241 Rename an index in the dictionary that is to be dropped. The data 242 dictionary must have been locked exclusively by the caller, because 243 the transaction will not be committed. 244 @return DB_SUCCESS if all OK */ 245 UNIV_INTERN 246 dberr_t 247 row_merge_rename_index_to_drop( 248 /*===========================*/ 249 trx_t* trx, /*!< in/out: transaction */ 250 table_id_t table_id, /*!< in: table identifier */ 251 index_id_t index_id) /*!< in: index identifier */ 252 MY_ATTRIBUTE((nonnull)); 253 /*********************************************************************//** 254 Create the index and load in to the dictionary. 255 @return index, or NULL on error */ 256 UNIV_INTERN 257 dict_index_t* 258 row_merge_create_index( 259 /*===================*/ 260 trx_t* trx, /*!< in/out: trx (sets error_state) */ 261 dict_table_t* table, /*!< in: the index is on this table */ 262 const index_def_t* index_def); 263 /*!< in: the index definition */ 264 /*********************************************************************//** 265 Check if a transaction can use an index. 266 @return TRUE if index can be used by the transaction else FALSE */ 267 UNIV_INTERN 268 ibool 269 row_merge_is_index_usable( 270 /*======================*/ 271 const trx_t* trx, /*!< in: transaction */ 272 const dict_index_t* index); /*!< in: index to check */ 273 /*********************************************************************//** 274 Drop a table. The caller must have ensured that the background stats 275 thread is not processing the table. This can be done by calling 276 dict_stats_wait_bg_to_stop_using_table() after locking the dictionary and 277 before calling this function. 278 @return DB_SUCCESS or error code */ 279 UNIV_INTERN 280 dberr_t 281 row_merge_drop_table( 282 /*=================*/ 283 trx_t* trx, /*!< in: transaction */ 284 dict_table_t* table) /*!< in: table instance to drop */ 285 MY_ATTRIBUTE((nonnull)); 286 /*********************************************************************//** 287 Build indexes on a table by reading a clustered index, 288 creating a temporary file containing index entries, merge sorting 289 these index entries and inserting sorted index entries to indexes. 290 @return DB_SUCCESS or error code */ 291 UNIV_INTERN 292 dberr_t 293 row_merge_build_indexes( 294 /*====================*/ 295 trx_t* trx, /*!< in: transaction */ 296 dict_table_t* old_table, /*!< in: table where rows are 297 read from */ 298 dict_table_t* new_table, /*!< in: table where indexes are 299 created; identical to old_table 300 unless creating a PRIMARY KEY */ 301 bool online, /*!< in: true if creating indexes 302 online */ 303 dict_index_t** indexes, /*!< in: indexes to be created */ 304 const ulint* key_numbers, /*!< in: MySQL key numbers */ 305 ulint n_indexes, /*!< in: size of indexes[] */ 306 struct TABLE* table, /*!< in/out: MySQL table, for 307 reporting erroneous key value 308 if applicable */ 309 const dtuple_t* add_cols, /*!< in: default values of 310 added columns, or NULL */ 311 const ulint* col_map, /*!< in: mapping of old column 312 numbers to new ones, or NULL 313 if old_table == new_table */ 314 ulint add_autoinc, /*!< in: number of added 315 AUTO_INCREMENT column, or 316 ULINT_UNDEFINED if none is added */ 317 ib_sequence_t& sequence) /*!< in/out: autoinc sequence */ 318 MY_ATTRIBUTE((nonnull(1,2,3,5,6,8), warn_unused_result)); 319 /********************************************************************//** 320 Write a buffer to a block. */ 321 UNIV_INTERN 322 void 323 row_merge_buf_write( 324 /*================*/ 325 const row_merge_buf_t* buf, /*!< in: sorted buffer */ 326 const merge_file_t* of, /*!< in: output file */ 327 row_merge_block_t* block) /*!< out: buffer for writing to file */ 328 MY_ATTRIBUTE((nonnull)); 329 /********************************************************************//** 330 Sort a buffer. */ 331 UNIV_INTERN 332 void 333 row_merge_buf_sort( 334 /*===============*/ 335 row_merge_buf_t* buf, /*!< in/out: sort buffer */ 336 row_merge_dup_t* dup) /*!< in/out: reporter of duplicates 337 (NULL if non-unique index) */ 338 MY_ATTRIBUTE((nonnull(1))); 339 /********************************************************************//** 340 Write a merge block to the file system. 341 @return TRUE if request was successful, FALSE if fail */ 342 UNIV_INTERN 343 ibool 344 row_merge_write( 345 /*============*/ 346 int fd, /*!< in: file descriptor */ 347 ulint offset, /*!< in: offset where to write, 348 in number of row_merge_block_t elements */ 349 const void* buf); /*!< in: data */ 350 /********************************************************************//** 351 Empty a sort buffer. 352 @return sort buffer */ 353 UNIV_INTERN 354 row_merge_buf_t* 355 row_merge_buf_empty( 356 /*================*/ 357 row_merge_buf_t* buf) /*!< in,own: sort buffer */ 358 MY_ATTRIBUTE((warn_unused_result, nonnull)); 359 360 /** Create a merge file in the given location. 361 @param[out] merge_file merge file structure 362 @param[in] path location for creating temporary file 363 @return file descriptor, or -1 on failure */ 364 UNIV_INTERN 365 int 366 row_merge_file_create( 367 merge_file_t* merge_file, 368 const char* path); 369 370 /*********************************************************************//** 371 Merge disk files. 372 @return DB_SUCCESS or error code */ 373 UNIV_INTERN 374 dberr_t 375 row_merge_sort( 376 /*===========*/ 377 trx_t* trx, /*!< in: transaction */ 378 const row_merge_dup_t* dup, /*!< in: descriptor of 379 index being created */ 380 merge_file_t* file, /*!< in/out: file containing 381 index entries */ 382 row_merge_block_t* block, /*!< in/out: 3 buffers */ 383 int* tmpfd) /*!< in/out: temporary file handle */ 384 MY_ATTRIBUTE((nonnull)); 385 /*********************************************************************//** 386 Allocate a sort buffer. 387 @return own: sort buffer */ 388 UNIV_INTERN 389 row_merge_buf_t* 390 row_merge_buf_create( 391 /*=================*/ 392 dict_index_t* index) /*!< in: secondary index */ 393 MY_ATTRIBUTE((warn_unused_result, nonnull, malloc)); 394 /*********************************************************************//** 395 Deallocate a sort buffer. */ 396 UNIV_INTERN 397 void 398 row_merge_buf_free( 399 /*===============*/ 400 row_merge_buf_t* buf) /*!< in,own: sort buffer to be freed */ 401 MY_ATTRIBUTE((nonnull)); 402 /*********************************************************************//** 403 Destroy a merge file. */ 404 UNIV_INTERN 405 void 406 row_merge_file_destroy( 407 /*===================*/ 408 merge_file_t* merge_file) /*!< in/out: merge file structure */ 409 MY_ATTRIBUTE((nonnull)); 410 /********************************************************************//** 411 Read a merge block from the file system. 412 @return TRUE if request was successful, FALSE if fail */ 413 UNIV_INTERN 414 ibool 415 row_merge_read( 416 /*===========*/ 417 int fd, /*!< in: file descriptor */ 418 ulint offset, /*!< in: offset where to read 419 in number of row_merge_block_t 420 elements */ 421 row_merge_block_t* buf); /*!< out: data */ 422 /********************************************************************//** 423 Read a merge record. 424 @return pointer to next record, or NULL on I/O error or end of list */ 425 UNIV_INTERN 426 const byte* 427 row_merge_read_rec( 428 /*===============*/ 429 row_merge_block_t* block, /*!< in/out: file buffer */ 430 mrec_buf_t* buf, /*!< in/out: secondary buffer */ 431 const byte* b, /*!< in: pointer to record */ 432 const dict_index_t* index, /*!< in: index of the record */ 433 int fd, /*!< in: file descriptor */ 434 ulint* foffs, /*!< in/out: file offset */ 435 const mrec_t** mrec, /*!< out: pointer to merge record, 436 or NULL on end of list 437 (non-NULL on I/O error) */ 438 ulint* offsets)/*!< out: offsets of mrec */ 439 MY_ATTRIBUTE((nonnull, warn_unused_result)); 440 #endif /* row0merge.h */ 441