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