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