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