1 /*****************************************************************************
2 
3 Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2016, 2021, MariaDB Corporation.
5 
6 This program is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free Software
8 Foundation; version 2 of the License.
9 
10 This program is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17 
18 *****************************************************************************/
19 
20 /**************************************************//**
21 @file fsp/fsp0space.cc
22 Multi file, shared, system tablespace implementation.
23 
24 Created 2012-11-16 by Sunny Bains as srv/srv0space.cc
25 Refactored 2013-7-26 by Kevin Lewis
26 *******************************************************/
27 
28 #include "fsp0sysspace.h"
29 #include "srv0start.h"
30 #include "trx0sys.h"
31 #include "dict0load.h"
32 #include "mem0mem.h"
33 #include "os0file.h"
34 #include "row0mysql.h"
35 
36 /** The server header file is included to access opt_initialize global variable.
37 If server passes the option for create/open DB to SE, we should remove such
38 direct reference to server header and global variable */
39 #include "mysqld.h"
40 
41 /** The control info of the system tablespace. */
42 SysTablespace srv_sys_space;
43 
44 /** The control info of a temporary table shared tablespace. */
45 SysTablespace srv_tmp_space;
46 
47 /** If the last data file is auto-extended, we add this many pages to it
48 at a time. We have to make this public because it is a config variable. */
49 ulong sys_tablespace_auto_extend_increment;
50 
51 /** Convert a numeric string that optionally ends in G or M or K,
52     to a number containing megabytes.
53 @param[in]	str	String with a quantity in bytes
54 @param[out]	megs	The number in megabytes
55 @return next character in string */
56 char*
parse_units(char * ptr,ulint * megs)57 SysTablespace::parse_units(
58 	char*	ptr,
59 	ulint*	megs)
60 {
61 	char*		endp;
62 
63 	*megs = strtoul(ptr, &endp, 10);
64 
65 	ptr = endp;
66 
67 	switch (*ptr) {
68 	case 'G': case 'g':
69 		*megs *= 1024;
70 		/* fall through */
71 	case 'M': case 'm':
72 		++ptr;
73 		break;
74 	case 'K': case 'k':
75 		*megs /= 1024;
76 		++ptr;
77 		break;
78 	default:
79 		*megs /= 1024 * 1024;
80 		break;
81 	}
82 
83 	return(ptr);
84 }
85 
86 /** Parse the input params and populate member variables.
87 @param[in]	filepath	path to data files
88 @param[in]	supports_raw	true if the tablespace supports raw devices
89 @return true on success parse */
90 bool
parse_params(const char * filepath_spec,bool supports_raw)91 SysTablespace::parse_params(
92 	const char*	filepath_spec,
93 	bool		supports_raw)
94 {
95 	char*	filepath;
96 	ulint	size;
97 	char*	input_str;
98 	ulint	n_files = 0;
99 
100 	ut_ad(m_last_file_size_max == 0);
101 	ut_ad(!m_auto_extend_last_file);
102 
103 	char*	new_str = mem_strdup(filepath_spec);
104 	char*	str = new_str;
105 
106 	input_str = str;
107 
108 	/*---------------------- PASS 1 ---------------------------*/
109 	/* First calculate the number of data files and check syntax:
110 	filepath:size[K |M | G];filepath:size[K |M | G]... .
111 	Note that a Windows path may contain a drive name and a ':'. */
112 	while (*str != '\0') {
113 		filepath = str;
114 
115 		while ((*str != ':' && *str != '\0')
116 		       || (*str == ':'
117 			   && (*(str + 1) == '\\' || *(str + 1) == '/'
118 			       || *(str + 1) == ':'))) {
119 			str++;
120 		}
121 
122 		if (*str == '\0') {
123 			ut_free(new_str);
124 
125 			ib::error()
126 				<< "syntax error in file path or size"
127 				" specified is less than 1 megabyte";
128 			return(false);
129 		}
130 
131 		str++;
132 
133 		str = parse_units(str, &size);
134 
135 		if (0 == strncmp(str, ":autoextend",
136 				 (sizeof ":autoextend") - 1)) {
137 
138 			str += (sizeof ":autoextend") - 1;
139 
140 			if (0 == strncmp(str, ":max:",
141 					 (sizeof ":max:") - 1)) {
142 
143 				str += (sizeof ":max:") - 1;
144 
145 				str = parse_units(str, &size);
146 			}
147 
148 			if (*str != '\0') {
149 				ut_free(new_str);
150 				ib::error()
151 					<< "syntax error in file path or"
152 					<< " size specified is less than"
153 					<< " 1 megabyte";
154 				return(false);
155 			}
156 		}
157 
158 		if (::strlen(str) >= 6
159 		    && *str == 'n'
160 		    && *(str + 1) == 'e'
161 		    && *(str + 2) == 'w') {
162 
163 			if (!supports_raw) {
164 				ib::error()
165 					<< "Tablespace doesn't support raw"
166 					" devices";
167 				ut_free(new_str);
168 				return(false);
169 			}
170 
171 			str += 3;
172 		}
173 
174 		if (*str == 'r' && *(str + 1) == 'a' && *(str + 2) == 'w') {
175 			str += 3;
176 
177 			if (!supports_raw) {
178 				ib::error()
179 					<< "Tablespace doesn't support raw"
180 					" devices";
181 				ut_free(new_str);
182 				return(false);
183 			}
184 		}
185 
186 		if (size == 0) {
187 
188 			ut_free(new_str);
189 
190 			ib::error()
191 				<< "syntax error in file path or size"
192 				" specified is less than 1 megabyte";
193 
194 			return(false);
195 		}
196 
197 		++n_files;
198 
199 		if (*str == ';') {
200 			str++;
201 		} else if (*str != '\0') {
202 			ut_free(new_str);
203 
204 			ib::error()
205 				<< "syntax error in file path or size"
206 				" specified is less than 1 megabyte";
207 			return(false);
208 		}
209 	}
210 
211 	if (n_files == 0) {
212 
213 		/* filepath_spec must contain at least one data file
214 		definition */
215 
216 		ut_free(new_str);
217 
218 		ib::error()
219 			<< "syntax error in file path or size specified"
220 			" is less than 1 megabyte";
221 
222 		return(false);
223 	}
224 
225 	/*---------------------- PASS 2 ---------------------------*/
226 	/* Then store the actual values to our arrays */
227 	str = input_str;
228 	ulint order = 0;
229 
230 	while (*str != '\0') {
231 		filepath = str;
232 
233 		/* Note that we must step over the ':' in a Windows filepath;
234 		a Windows path normally looks like C:\ibdata\ibdata1:1G, but
235 		a Windows raw partition may have a specification like
236 		\\.\C::1Gnewraw or \\.\PHYSICALDRIVE2:1Gnewraw */
237 
238 		while ((*str != ':' && *str != '\0')
239 		       || (*str == ':'
240 			   && (*(str + 1) == '\\' || *(str + 1) == '/'
241 			       || *(str + 1) == ':'))) {
242 			str++;
243 		}
244 
245 		if (*str == ':') {
246 			/* Make filepath a null-terminated string */
247 			*str = '\0';
248 			str++;
249 		}
250 
251 		str = parse_units(str, &size);
252 
253 		if (0 == strncmp(str, ":autoextend",
254 				 (sizeof ":autoextend") - 1)) {
255 
256 			m_auto_extend_last_file = true;
257 
258 			str += (sizeof ":autoextend") - 1;
259 
260 			if (0 == strncmp(str, ":max:",
261 					 (sizeof ":max:") - 1)) {
262 
263 				str += (sizeof ":max:") - 1;
264 
265 				str = parse_units(str, &m_last_file_size_max);
266 			}
267 
268 			if (*str != '\0') {
269 				ut_free(new_str);
270 				ib::error() << "syntax error in file path or"
271 					" size specified is less than 1"
272 					" megabyte";
273 				return(false);
274 			}
275 		}
276 
277 		m_files.push_back(Datafile(filepath, flags(), size, order));
278 		Datafile* datafile = &m_files.back();
279 		datafile->make_filepath(path(), filepath, NO_EXT);
280 
281 		if (::strlen(str) >= 6
282 		    && *str == 'n'
283 		    && *(str + 1) == 'e'
284 		    && *(str + 2) == 'w') {
285 
286 			ut_a(supports_raw);
287 
288 			str += 3;
289 
290 			/* Initialize new raw device only during initialize */
291 			/* JAN: TODO: MySQL 5.7 used opt_initialize */
292 			m_files.back().m_type =
293 			opt_bootstrap ? SRV_NEW_RAW : SRV_OLD_RAW;
294 		}
295 
296 		if (*str == 'r' && *(str + 1) == 'a' && *(str + 2) == 'w') {
297 
298 			ut_a(supports_raw);
299 
300 			str += 3;
301 
302 			/* Initialize new raw device only during initialize */
303 			if (m_files.back().m_type == SRV_NOT_RAW) {
304 				/* JAN: TODO: MySQL 5.7 used opt_initialize */
305 				m_files.back().m_type =
306 				opt_bootstrap ? SRV_NEW_RAW : SRV_OLD_RAW;
307 			}
308 		}
309 
310 		if (*str == ';') {
311 			++str;
312 		}
313 		order++;
314 	}
315 
316 	ut_ad(n_files == ulint(m_files.size()));
317 
318 	ut_free(new_str);
319 
320 	return(true);
321 }
322 
323 /** Frees the memory allocated by the parse method. */
324 void
shutdown()325 SysTablespace::shutdown()
326 {
327 	Tablespace::shutdown();
328 
329 	m_auto_extend_last_file = 0;
330 	m_last_file_size_max = 0;
331 	m_created_new_raw = 0;
332 	m_is_tablespace_full = false;
333 	m_sanity_checks_done = false;
334 }
335 
336 /** Verify the size of the physical file.
337 @param[in]	file	data file object
338 @return DB_SUCCESS if OK else error code. */
339 dberr_t
check_size(Datafile & file)340 SysTablespace::check_size(
341 	Datafile&	file)
342 {
343 	os_offset_t	size = os_file_get_size(file.m_handle);
344 	ut_a(size != (os_offset_t) -1);
345 
346 	/* Under some error conditions like disk full scenarios
347 	or file size reaching filesystem limit the data file
348 	could contain an incomplete extent at the end. When we
349 	extend a data file and if some failure happens, then
350 	also the data file could contain an incomplete extent.
351 	So we need to round the size downward to a  megabyte.*/
352 
353 	const ulint	rounded_size_pages = static_cast<ulint>(
354 		size >> srv_page_size_shift);
355 
356 	/* If last file */
357 	if (&file == &m_files.back() && m_auto_extend_last_file) {
358 
359 		if (file.m_size > rounded_size_pages
360 		    || (m_last_file_size_max > 0
361 			&& m_last_file_size_max < rounded_size_pages)) {
362 			ib::error() << "The Auto-extending " << name()
363 				<< " data file '" << file.filepath() << "' is"
364 				" of a different size " << rounded_size_pages
365 				<< " pages than specified"
366 				" in the .cnf file: initial " << file.m_size
367 				<< " pages, max " << m_last_file_size_max
368 				<< " (relevant if non-zero) pages!";
369 			return(DB_ERROR);
370 		}
371 
372 		file.m_size = rounded_size_pages;
373 	}
374 
375 	if (rounded_size_pages != file.m_size) {
376 		ib::error() << "The " << name() << " data file '"
377 			<< file.filepath() << "' is of a different size "
378 			<< rounded_size_pages << " pages"
379 			" than the " << file.m_size << " pages specified in"
380 			" the .cnf file!";
381 		return(DB_ERROR);
382 	}
383 
384 	return(DB_SUCCESS);
385 }
386 
387 /** Set the size of the file.
388 @param[in]	file	data file object
389 @return DB_SUCCESS or error code */
390 dberr_t
set_size(Datafile & file)391 SysTablespace::set_size(
392 	Datafile&	file)
393 {
394 	ut_a(!srv_read_only_mode || m_ignore_read_only);
395 
396 	/* We created the data file and now write it full of zeros */
397 	ib::info() << "Setting file '" << file.filepath() << "' size to "
398 		<< (file.m_size >> (20U - srv_page_size_shift)) << " MB."
399 		" Physically writing the file full; Please wait ...";
400 
401 	bool	success = os_file_set_size(
402 		file.m_filepath, file.m_handle,
403 		static_cast<os_offset_t>(file.m_size) << srv_page_size_shift);
404 
405 	if (success) {
406 		ib::info() << "File '" << file.filepath() << "' size is now "
407 			<< (file.m_size >> (20U - srv_page_size_shift))
408 			<< " MB.";
409 	} else {
410 		ib::error() << "Could not set the file size of '"
411 			<< file.filepath() << "'. Probably out of disk space";
412 
413 		return(DB_ERROR);
414 	}
415 
416 	return(DB_SUCCESS);
417 }
418 
419 /** Create a data file.
420 @param[in]	file	data file object
421 @return DB_SUCCESS or error code */
422 dberr_t
create_file(Datafile & file)423 SysTablespace::create_file(
424 	Datafile&	file)
425 {
426 	dberr_t	err = DB_SUCCESS;
427 
428 	ut_a(!file.m_exists);
429 	ut_a(!srv_read_only_mode || m_ignore_read_only);
430 
431 	switch (file.m_type) {
432 	case SRV_NEW_RAW:
433 
434 		/* The partition is opened, not created; then it is
435 		written over */
436 		m_created_new_raw = true;
437 
438 		/* Fall through. */
439 
440 	case SRV_OLD_RAW:
441 
442 		srv_start_raw_disk_in_use = TRUE;
443 
444 		/* Fall through. */
445 
446 	case SRV_NOT_RAW:
447 		err = file.open_or_create(
448 			m_ignore_read_only ? false : srv_read_only_mode);
449 		break;
450 	}
451 
452 
453 	if (err == DB_SUCCESS && file.m_type != SRV_OLD_RAW) {
454 		err = set_size(file);
455 	}
456 
457 	return(err);
458 }
459 
460 /** Open a data file.
461 @param[in]	file	data file object
462 @return DB_SUCCESS or error code */
463 dberr_t
open_file(Datafile & file)464 SysTablespace::open_file(
465 	Datafile&	file)
466 {
467 	dberr_t	err = DB_SUCCESS;
468 
469 	ut_a(file.m_exists);
470 
471 	switch (file.m_type) {
472 	case SRV_NEW_RAW:
473 		/* The partition is opened, not created; then it is
474 		written over */
475 		m_created_new_raw = true;
476 
477 		/* Fall through */
478 
479 	case SRV_OLD_RAW:
480 		srv_start_raw_disk_in_use = TRUE;
481 
482 		if (srv_read_only_mode && !m_ignore_read_only) {
483 			ib::error() << "Can't open a raw device '"
484 				<< file.m_filepath << "' when"
485 				" --innodb-read-only is set";
486 
487 			return(DB_ERROR);
488 		}
489 
490 		/* Fall through */
491 
492 	case SRV_NOT_RAW:
493 		err = file.open_or_create(
494 			m_ignore_read_only ? false : srv_read_only_mode);
495 
496 		if (err != DB_SUCCESS) {
497 			return(err);
498 		}
499 		break;
500 	}
501 
502 	switch (file.m_type) {
503 	case SRV_NEW_RAW:
504 		/* Set file size for new raw device. */
505 		err = set_size(file);
506 		break;
507 
508 	case SRV_NOT_RAW:
509 		/* Check file size for existing file. */
510 		err = check_size(file);
511 		break;
512 
513 	case SRV_OLD_RAW:
514 		err = DB_SUCCESS;
515 		break;
516 
517 	}
518 
519 	if (err != DB_SUCCESS) {
520 		file.close();
521 	}
522 
523 	return(err);
524 }
525 
526 /** Check the tablespace header for this tablespace.
527 @param[out]	flushed_lsn	the value of FIL_PAGE_FILE_FLUSH_LSN
528 @return DB_SUCCESS or error code */
529 dberr_t
read_lsn_and_check_flags(lsn_t * flushed_lsn)530 SysTablespace::read_lsn_and_check_flags(lsn_t* flushed_lsn)
531 {
532 	dberr_t	err;
533 
534 	/* Only relevant for the system tablespace. */
535 	ut_ad(space_id() == TRX_SYS_SPACE);
536 
537 	files_t::iterator it = m_files.begin();
538 
539 	ut_a(it->m_exists);
540 
541 	if (it->m_handle == OS_FILE_CLOSED) {
542 
543 		err = it->open_or_create(
544 			m_ignore_read_only ?  false : srv_read_only_mode);
545 
546 		if (err != DB_SUCCESS) {
547 			return(err);
548 		}
549 	}
550 
551 	err = it->read_first_page(
552 		m_ignore_read_only ?  false : srv_read_only_mode);
553 
554 	if (err != DB_SUCCESS) {
555 		return(err);
556 	}
557 
558 	ut_a(it->order() == 0);
559 
560 	if (srv_operation == SRV_OPERATION_NORMAL) {
561 		buf_dblwr_init_or_load_pages(it->handle(), it->filepath());
562 	}
563 
564 	/* Check the contents of the first page of the
565 	first datafile. */
566 	for (int retry = 0; retry < 2; ++retry) {
567 
568 		err = it->validate_first_page(flushed_lsn);
569 
570 		if (err != DB_SUCCESS
571 		    && (retry == 1
572 			|| it->restore_from_doublewrite())) {
573 
574 			it->close();
575 
576 			return(err);
577 		}
578 	}
579 
580 	/* Make sure the tablespace space ID matches the
581 	space ID on the first page of the first datafile. */
582 	if (space_id() != it->m_space_id) {
583 
584 		ib::error()
585 			<< "The " << name() << " data file '" << it->name()
586 			<< "' has the wrong space ID. It should be "
587 			<< space_id() << ", but " << it->m_space_id
588 			<< " was found";
589 
590 		it->close();
591 
592 		return(err);
593 	}
594 
595 	it->close();
596 
597 	return(DB_SUCCESS);
598 }
599 
600 /** Check if a file can be opened in the correct mode.
601 @param[in]	file	data file object
602 @param[out]	reason	exact reason if file_status check failed.
603 @return DB_SUCCESS or error code. */
604 dberr_t
check_file_status(const Datafile & file,file_status_t & reason)605 SysTablespace::check_file_status(
606 	const Datafile&		file,
607 	file_status_t&		reason)
608 {
609 	os_file_stat_t	stat;
610 
611 	memset(&stat, 0x0, sizeof(stat));
612 
613 	dberr_t	err = os_file_get_status(
614 		file.m_filepath, &stat, true,
615 		m_ignore_read_only ? false : srv_read_only_mode);
616 
617 	reason = FILE_STATUS_VOID;
618 	/* File exists but we can't read the rw-permission settings. */
619 	switch (err) {
620 	case DB_FAIL:
621 		ib::error() << "os_file_get_status() failed on '"
622 			<< file.filepath()
623 			<< "'. Can't determine file permissions";
624 		err = DB_ERROR;
625 		reason = FILE_STATUS_RW_PERMISSION_ERROR;
626 		break;
627 
628 	case DB_SUCCESS:
629 
630 		/* Note: stat.rw_perm is only valid for "regular" files */
631 
632 		if (stat.type == OS_FILE_TYPE_FILE) {
633 
634 			if (!stat.rw_perm) {
635 				const char	*p = (!srv_read_only_mode
636 						      || m_ignore_read_only)
637 						     ? "writable"
638 						     : "readable";
639 
640 				ib::error() << "The " << name() << " data file"
641 					<< " '" << file.name() << "' must be "
642 					<< p;
643 
644 				err = DB_ERROR;
645 				reason = FILE_STATUS_READ_WRITE_ERROR;
646 			}
647 
648 		} else {
649 			/* Not a regular file, bail out. */
650 			ib::error() << "The " << name() << " data file '"
651 				<< file.name() << "' is not a regular"
652 				" InnoDB data file.";
653 
654 			err = DB_ERROR;
655 			reason = FILE_STATUS_NOT_REGULAR_FILE_ERROR;
656 		}
657 		break;
658 
659 	case DB_NOT_FOUND:
660 		break;
661 
662 	default:
663 		ut_ad(0);
664 	}
665 
666 	return(err);
667 }
668 
669 /** Note that the data file was not found.
670 @param[in]	file		data file object
671 @param[out]	create_new_db	true if a new instance to be created
672 @return DB_SUCESS or error code */
673 dberr_t
file_not_found(Datafile & file,bool * create_new_db)674 SysTablespace::file_not_found(
675 	Datafile&	file,
676 	bool*	create_new_db)
677 {
678 	file.m_exists = false;
679 
680 	if (m_ignore_read_only) {
681 	} else if (srv_read_only_mode) {
682 		ib::error() << "Can't create file '" << file.filepath()
683 			<< "' when --innodb-read-only is set";
684 		return(DB_ERROR);
685 	} else if (srv_force_recovery && space_id() == TRX_SYS_SPACE) {
686 		ib::error() << "Can't create file '" << file.filepath()
687 			<< "' when --innodb-force-recovery is set";
688 		return DB_ERROR;
689 	}
690 
691 	if (&file == &m_files.front()) {
692 
693 		/* First data file. */
694 		ut_a(!*create_new_db);
695 		*create_new_db = TRUE;
696 
697 		if (space_id() == TRX_SYS_SPACE) {
698 			ib::info() << "The first " << name() << " data file '"
699 				<< file.name() << "' did not exist."
700 				" A new tablespace will be created!";
701 		}
702 
703 	} else {
704 		ib::info() << "Need to create a new " << name()
705 			<< " data file '" << file.name() << "'.";
706 	}
707 
708 	/* Set the file create mode. */
709 	switch (file.m_type) {
710 	case SRV_NOT_RAW:
711 		file.set_open_flags(OS_FILE_CREATE);
712 		break;
713 
714 	case SRV_NEW_RAW:
715 	case SRV_OLD_RAW:
716 		file.set_open_flags(OS_FILE_OPEN_RAW);
717 		break;
718 	}
719 
720 	return(DB_SUCCESS);
721 }
722 
723 /** Note that the data file was found.
724 @param[in,out]	file	data file object
725 @return true if a new instance to be created */
726 bool
file_found(Datafile & file)727 SysTablespace::file_found(
728 	Datafile&	file)
729 {
730 	/* Note that the file exists and can be opened
731 	in the appropriate mode. */
732 	file.m_exists = true;
733 
734 	/* Set the file open mode */
735 	switch (file.m_type) {
736 	case SRV_NOT_RAW:
737 		file.set_open_flags(
738 			&file == &m_files.front()
739 			? OS_FILE_OPEN_RETRY : OS_FILE_OPEN);
740 		break;
741 
742 	case SRV_NEW_RAW:
743 	case SRV_OLD_RAW:
744 		file.set_open_flags(OS_FILE_OPEN_RAW);
745 		break;
746 	}
747 
748 	/* Need to create the system tablespace for new raw device. */
749 	return(file.m_type == SRV_NEW_RAW);
750 }
751 
752 /** Check the data file specification.
753 @param[out] create_new_db	true if a new database is to be created
754 @param[in] min_expected_size	Minimum expected tablespace size in bytes
755 @return DB_SUCCESS if all OK else error code */
756 dberr_t
check_file_spec(bool * create_new_db,ulint min_expected_size)757 SysTablespace::check_file_spec(
758 	bool*	create_new_db,
759 	ulint	min_expected_size)
760 {
761 	*create_new_db = FALSE;
762 
763 	if (m_files.size() >= 1000) {
764 		ib::error() << "There must be < 1000 data files in "
765 			<< name() << " but " << m_files.size() << " have been"
766 			" defined.";
767 
768 		return(DB_ERROR);
769 	}
770 
771 	if (!m_auto_extend_last_file
772 	    && get_sum_of_sizes()
773 	    < (min_expected_size >> srv_page_size_shift)) {
774 		ib::error() << "Tablespace size must be at least "
775 			<< (min_expected_size >> 20) << " MB";
776 		return(DB_ERROR);
777 	}
778 
779 	dberr_t	err = DB_SUCCESS;
780 
781 	ut_a(!m_files.empty());
782 
783 	/* If there is more than one data file and the last data file
784 	doesn't exist, that is OK. We allow adding of new data files. */
785 
786 	files_t::iterator	begin = m_files.begin();
787 	files_t::iterator	end = m_files.end();
788 
789 	for (files_t::iterator it = begin; it != end; ++it) {
790 
791 		file_status_t reason_if_failed;
792 		err = check_file_status(*it, reason_if_failed);
793 
794 		if (err == DB_NOT_FOUND) {
795 
796 			err = file_not_found(*it, create_new_db);
797 
798 			if (err != DB_SUCCESS) {
799 				break;
800 			}
801 
802 		} else if (err != DB_SUCCESS) {
803 			if (reason_if_failed == FILE_STATUS_READ_WRITE_ERROR) {
804 				const char*	p = (!srv_read_only_mode
805 						     || m_ignore_read_only)
806 						    ? "writable" : "readable";
807 				ib::error() << "The " << name() << " data file"
808 					<< " '" << it->name() << "' must be "
809 					<< p;
810 			}
811 
812 			ut_a(err != DB_FAIL);
813 			break;
814 
815 		} else if (*create_new_db) {
816 			ib::error() << "The " << name() << " data file '"
817 				<< begin->m_name << "' was not found but"
818 				" one of the other data files '" << it->m_name
819 				<< "' exists.";
820 
821 			err = DB_ERROR;
822 			break;
823 
824 		} else {
825 			*create_new_db = file_found(*it);
826 		}
827 	}
828 
829 	return(err);
830 }
831 
832 /** Open or create the data files
833 @param[in]  is_temp		whether this is a temporary tablespace
834 @param[in]  create_new_db	whether we are creating a new database
835 @param[out] sum_new_sizes	sum of sizes of the new files added
836 @param[out] flush_lsn		FIL_PAGE_FILE_FLUSH_LSN of first file
837 @return DB_SUCCESS or error code */
838 dberr_t
open_or_create(bool is_temp,bool create_new_db,ulint * sum_new_sizes,lsn_t * flush_lsn)839 SysTablespace::open_or_create(
840 	bool	is_temp,
841 	bool	create_new_db,
842 	ulint*	sum_new_sizes,
843 	lsn_t*	flush_lsn)
844 {
845 	dberr_t		err	= DB_SUCCESS;
846 	fil_space_t*	space	= NULL;
847 
848 	ut_ad(!m_files.empty());
849 
850 	if (sum_new_sizes) {
851 		*sum_new_sizes = 0;
852 	}
853 
854 	files_t::iterator	begin = m_files.begin();
855 	files_t::iterator	end = m_files.end();
856 
857 	ut_ad(begin->order() == 0);
858 
859 	for (files_t::iterator it = begin; it != end; ++it) {
860 
861 		if (it->m_exists) {
862 			err = open_file(*it);
863 
864 			/* For new raw device increment new size. */
865 			if (sum_new_sizes && it->m_type == SRV_NEW_RAW) {
866 
867 				*sum_new_sizes += it->m_size;
868 			}
869 
870 		} else {
871 			err = create_file(*it);
872 
873 			if (sum_new_sizes) {
874 				*sum_new_sizes += it->m_size;
875 			}
876 
877 			/* Set the correct open flags now that we have
878 			successfully created the file. */
879 			if (err == DB_SUCCESS) {
880 				/* We ignore new_db OUT parameter here
881 				as the information is known at this stage */
882 				file_found(*it);
883 			}
884 		}
885 
886 		if (err != DB_SUCCESS) {
887 			return(err);
888 		}
889 
890 	}
891 
892 	if (!create_new_db && flush_lsn) {
893 		/* Validate the header page in the first datafile
894 		and read LSNs fom the others. */
895 		err = read_lsn_and_check_flags(flush_lsn);
896 		if (err != DB_SUCCESS) {
897 			return(err);
898 		}
899 	}
900 
901 	/* Close the curent handles, add space and file info to the
902 	fil_system cache and the Data Dictionary, and re-open them
903 	in file_system cache so that they stay open until shutdown. */
904 	ulint	node_counter = 0;
905 	for (files_t::iterator it = begin; it != end; ++it) {
906 		it->close();
907 		it->m_exists = true;
908 
909 		if (it != begin) {
910 		} else if (is_temp) {
911 			ut_ad(!fil_system.temp_space);
912 			ut_ad(space_id() == SRV_TMP_SPACE_ID);
913 			space = fil_space_create(
914 				name(), SRV_TMP_SPACE_ID, flags(),
915 				FIL_TYPE_TEMPORARY, NULL);
916 
917 			mutex_enter(&fil_system.mutex);
918 			fil_system.temp_space = space;
919 			mutex_exit(&fil_system.mutex);
920 			if (!space) {
921 				return DB_ERROR;
922 			}
923 		} else {
924 			ut_ad(!fil_system.sys_space);
925 			ut_ad(space_id() == TRX_SYS_SPACE);
926 			space = fil_space_create(
927 				name(), TRX_SYS_SPACE, it->flags(),
928 				FIL_TYPE_TABLESPACE, NULL);
929 
930 			mutex_enter(&fil_system.mutex);
931 			fil_system.sys_space = space;
932 			mutex_exit(&fil_system.mutex);
933 			if (!space) {
934 				return DB_ERROR;
935 			}
936 		}
937 
938 		ut_a(fil_validate());
939 
940 		ulint	max_size = (++node_counter == m_files.size()
941 				    ? (m_last_file_size_max == 0
942 				       ? ULINT_MAX
943 				       : m_last_file_size_max)
944 				    : it->m_size);
945 
946 		space->add(it->m_filepath, OS_FILE_CLOSED, it->m_size,
947 			   it->m_type != SRV_NOT_RAW, true, max_size);
948 	}
949 
950 	return(err);
951 }
952 
953 /** Normalize the file size, convert from megabytes to number of pages. */
954 void
normalize_size()955 SysTablespace::normalize_size()
956 {
957 	files_t::iterator	end = m_files.end();
958 
959 	for (files_t::iterator it = m_files.begin(); it != end; ++it) {
960 
961 		it->m_size <<= (20U - srv_page_size_shift);
962 	}
963 
964 	m_last_file_size_max <<= (20U - srv_page_size_shift);
965 }
966 
967 
968 /**
969 @return next increment size */
970 ulint
get_increment() const971 SysTablespace::get_increment() const
972 {
973 	ulint	increment;
974 
975 	if (m_last_file_size_max == 0) {
976 		increment = get_autoextend_increment();
977 	} else {
978 
979 		if (!is_valid_size()) {
980 			ib::error() << "The last data file in " << name()
981 				<< " has a size of " << last_file_size()
982 				<< " but the max size allowed is "
983 				<< m_last_file_size_max;
984 		}
985 
986 		increment = m_last_file_size_max - last_file_size();
987 	}
988 
989 	if (increment > get_autoextend_increment()) {
990 		increment = get_autoextend_increment();
991 	}
992 
993 	return(increment);
994 }
995 
996 
997 /**
998 @return true if configured to use raw devices */
999 bool
has_raw_device()1000 SysTablespace::has_raw_device()
1001 {
1002 	files_t::iterator	end = m_files.end();
1003 
1004 	for (files_t::iterator it = m_files.begin(); it != end; ++it) {
1005 
1006 		if (it->is_raw_device()) {
1007 			return(true);
1008 		}
1009 	}
1010 
1011 	return(false);
1012 }
1013