1 /***************************************************************************** 2 3 Copyright (c) 2013, 2021, Oracle and/or its affiliates. 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/fsp0file.h 29 Tablespace data file implementation. 30 31 Created 2013-7-26 by Kevin Lewis 32 *******************************************************/ 33 34 #ifndef fsp0file_h 35 #define fsp0file_h 36 37 #include "ha_prototypes.h" 38 #include "log0log.h" 39 #include "mem0mem.h" 40 #include "os0file.h" 41 #include <vector> 42 43 /** Types of raw partitions in innodb_data_file_path */ 44 enum device_t { 45 SRV_NOT_RAW = 0, /*!< Not a raw partition */ 46 SRV_NEW_RAW, /*!< A 'newraw' partition, only to be 47 initialized */ 48 SRV_OLD_RAW /*!< An initialized raw partition */ 49 }; 50 51 /** Data file control information. */ 52 class Datafile { 53 54 friend class Tablespace; 55 friend class SysTablespace; 56 57 public: 58 Datafile()59 Datafile() 60 : 61 m_name(), 62 m_filepath(), 63 m_filename(), 64 m_open_flags(OS_FILE_OPEN), 65 m_size(), 66 m_order(), 67 m_type(SRV_NOT_RAW), 68 m_space_id(ULINT_UNDEFINED), 69 m_flags(), 70 m_exists(), 71 m_is_valid(), 72 m_first_page_buf(), 73 m_first_page(), 74 m_atomic_write(), 75 m_last_os_error(), 76 m_file_info(), 77 m_encryption_key(NULL), 78 m_encryption_iv(NULL) 79 { 80 81 m_handle.m_file = OS_FILE_CLOSED; 82 83 } 84 Datafile(const char * name,ulint flags,ulint size,ulint order)85 Datafile(const char* name, ulint flags, ulint size, ulint order) 86 : 87 m_name(mem_strdup(name)), 88 m_filepath(), 89 m_filename(), 90 m_open_flags(OS_FILE_OPEN), 91 m_size(size), 92 m_order(order), 93 m_type(SRV_NOT_RAW), 94 m_space_id(ULINT_UNDEFINED), 95 m_flags(flags), 96 m_exists(), 97 m_is_valid(), 98 m_first_page_buf(), 99 m_first_page(), 100 m_atomic_write(), 101 m_last_os_error(), 102 m_file_info(), 103 m_encryption_key(NULL), 104 m_encryption_iv(NULL) 105 { 106 ut_ad(m_name != NULL); 107 m_handle.m_file = OS_FILE_CLOSED; 108 109 } 110 Datafile(const Datafile & file)111 Datafile(const Datafile& file) 112 : 113 m_handle(file.m_handle), 114 m_open_flags(file.m_open_flags), 115 m_size(file.m_size), 116 m_order(file.m_order), 117 m_type(file.m_type), 118 m_space_id(file.m_space_id), 119 m_flags(file.m_flags), 120 m_exists(file.m_exists), 121 m_is_valid(file.m_is_valid), 122 m_first_page_buf(), 123 m_first_page(), 124 m_atomic_write(file.m_atomic_write), 125 m_last_os_error(), 126 m_file_info(), 127 m_encryption_key(NULL), 128 m_encryption_iv(NULL) 129 { 130 m_name = mem_strdup(file.m_name); 131 ut_ad(m_name != NULL); 132 133 if (file.m_filepath != NULL) { 134 m_filepath = mem_strdup(file.m_filepath); 135 ut_a(m_filepath != NULL); 136 set_filename(); 137 } else { 138 m_filepath = NULL; 139 m_filename = NULL; 140 } 141 } 142 ~Datafile()143 virtual ~Datafile() 144 { 145 shutdown(); 146 } 147 148 Datafile& operator=(const Datafile& file) 149 { 150 ut_a(this != &file); 151 152 ut_ad(m_name == NULL); 153 m_name = mem_strdup(file.m_name); 154 ut_a(m_name != NULL); 155 156 m_size = file.m_size; 157 m_order = file.m_order; 158 ut_a(m_handle.m_file == OS_FILE_CLOSED); 159 m_handle = file.m_handle; 160 161 m_exists = file.m_exists; 162 m_is_valid = file.m_is_valid; 163 m_open_flags = file.m_open_flags; 164 m_space_id = file.m_space_id; 165 m_flags = file.m_flags; 166 m_last_os_error = 0; 167 168 if (m_filepath != NULL) { 169 ut_free(m_filepath); 170 m_filepath = NULL; 171 m_filename = NULL; 172 } 173 174 if (file.m_filepath != NULL) { 175 m_filepath = mem_strdup(file.m_filepath); 176 ut_a(m_filepath != NULL); 177 set_filename(); 178 } 179 180 /* Do not make a copy of the first page, 181 it should be reread if needed */ 182 m_first_page_buf = NULL; 183 m_first_page = NULL; 184 m_encryption_key = NULL; 185 m_encryption_iv = NULL; 186 187 m_atomic_write = file.m_atomic_write; 188 189 return(*this); 190 } 191 192 /** Initialize the name and flags of this datafile. 193 @param[in] name tablespace name, will be copied 194 @param[in] flags tablespace flags */ 195 void init(const char* name, ulint flags); 196 197 /** Release the resources. */ 198 virtual void shutdown(); 199 200 /** Open a data file in read-only mode to check if it exists 201 so that it can be validated. 202 @param[in] strict whether to issue error messages 203 @return DB_SUCCESS or error code */ 204 virtual dberr_t open_read_only(bool strict); 205 206 /** Open a data file in read-write mode during start-up so that 207 doublewrite pages can be restored and then it can be validated. 208 @param[in] read_only_mode if true, then readonly mode checks 209 are enforced. 210 @return DB_SUCCESS or error code */ 211 virtual dberr_t open_read_write(bool read_only_mode) 212 MY_ATTRIBUTE((warn_unused_result)); 213 214 /** Initialize OS specific file info. */ 215 void init_file_info(); 216 217 /** Close a data file. 218 @return DB_SUCCESS or error code */ 219 dberr_t close(); 220 221 /** Make a full filepath from a directory path and a filename. 222 Prepend the dirpath to filename using the extension given. 223 If dirpath is NULL, prepend the default datadir to filepath. 224 Store the result in m_filepath. 225 @param[in] dirpath directory path 226 @param[in] filename filename or filepath 227 @param[in] ext filename extension */ 228 void make_filepath( 229 const char* dirpath, 230 const char* filename, 231 ib_extention ext); 232 233 /** Set the filepath by duplicating the filepath sent in */ 234 void set_filepath(const char* filepath); 235 236 /** Allocate and set the datafile or tablespace name in m_name. 237 If a name is provided, use it; else if the datafile is file-per-table, 238 extract a file-per-table tablespace name from m_filepath; else it is a 239 general tablespace, so just call it that for now. The value of m_name 240 will be freed in the destructor. 241 @param[in] name Tablespace Name if known, NULL if not */ 242 void set_name(const char* name); 243 244 struct ValidateOutput { ValidateOutputValidateOutput245 ValidateOutput() 246 : error(DB_ERROR) 247 , encryption_type(DO_NOT_KNOW) 248 {} 249 250 Keyring_encryption_info keyring_encryption_info; 251 252 enum EncryptionType { 253 DO_NOT_KNOW, /*error occured before we were able to read encryption type from first page*/ 254 NONE, 255 KEYRING, 256 MASTER_KEY 257 }; 258 dberr_t error; 259 EncryptionType encryption_type; 260 }; 261 262 /** Validates the datafile and checks that it conforms with 263 the expected space ID and flags. The file should exist and be 264 successfully opened in order for this function to validate it. 265 @param[in] space_id The expected tablespace ID. 266 @param[in] flags The expected tablespace flags. 267 @param[in] for_import is it for importing 268 @retval DB_SUCCESS if tablespace is valid, DB_ERROR if not. 269 m_is_valid is also set true on success, else false. */ 270 ValidateOutput validate_to_dd( 271 ulint space_id, 272 ulint flags, 273 bool for_import) 274 MY_ATTRIBUTE((warn_unused_result)); 275 276 /** Validates this datafile for the purpose of recovery. 277 The file should exist and be successfully opened. We initially 278 open it in read-only mode because we just want to read the SpaceID. 279 However, if the first page is corrupt and needs to be restored 280 from the doublewrite buffer, we will reopen it in write mode and 281 ry to restore that page. 282 @retval DB_SUCCESS if tablespace is valid, DB_ERROR if not. 283 m_is_valid is also set true on success, else false. */ 284 ValidateOutput validate_for_recovery() 285 MY_ATTRIBUTE((warn_unused_result)); 286 287 /** Checks the consistency of the first page of a datafile when the 288 tablespace is opened. This occurs before the fil_space_t is created 289 so the Space ID found here must not already be open. 290 m_is_valid is set true on success, else false. 291 @param[out] flush_lsn contents of FIL_PAGE_FILE_FLUSH_LSN 292 @param[in] for_import if it is for importing 293 (only valid for the first file of the system tablespace) 294 @retval DB_SUCCESS on if the datafile is valid 295 @retval DB_CORRUPTION if the datafile is not readable 296 @retval DB_TABLESPACE_EXISTS if there is a duplicate space_id */ 297 ValidateOutput validate_first_page(lsn_t* flush_lsn, 298 bool for_import) 299 MY_ATTRIBUTE((warn_unused_result)); 300 301 /** Get Datafile::m_name. 302 @return m_name */ name()303 const char* name() const 304 { 305 return(m_name); 306 } 307 308 /** Get Datafile::m_filepath. 309 @return m_filepath */ filepath()310 const char* filepath() const 311 { 312 return(m_filepath); 313 } 314 315 /** Get Datafile::m_handle. 316 @return m_handle */ handle()317 pfs_os_file_t handle() const 318 { 319 return(m_handle); 320 } 321 322 /** Get Datafile::m_order. 323 @return m_order */ order()324 ulint order() const 325 { 326 return(m_order); 327 } 328 329 /** Get Datafile::m_space_id. 330 @return m_space_id */ space_id()331 ulint space_id() const 332 { 333 return(m_space_id); 334 } 335 336 /** Get Datafile::m_flags. 337 @return m_flags */ flags()338 ulint flags() const 339 { 340 return(m_flags); 341 } 342 343 /** 344 @return true if m_handle is open, false if not */ is_open()345 bool is_open() const 346 { 347 return(m_handle.m_file != OS_FILE_CLOSED); 348 } 349 350 /** Get Datafile::m_is_valid. 351 @return m_is_valid */ is_valid()352 bool is_valid() const 353 { 354 return(m_is_valid); 355 } 356 357 /** Get the last OS error reported 358 @return m_last_os_error */ last_os_error()359 ulint last_os_error() const 360 { 361 return(m_last_os_error); 362 } 363 364 /** Test if the filepath provided looks the same as this filepath 365 by string comparison. If they are two different paths to the same 366 file, same_as() will be used to show that after the files are opened. 367 @param[in] other filepath to compare with 368 @retval true if it is the same filename by char comparison 369 @retval false if it looks different */ 370 bool same_filepath_as(const char* other) const; 371 372 /** Test if another opened datafile is the same file as this object. 373 @param[in] other Datafile to compare with 374 @return true if it is the same file, else false */ 375 bool same_as(const Datafile& other) const; 376 377 /** Get access to the first data page. 378 It is valid after open_read_only() succeeded. 379 @return the first data page */ get_first_page()380 const byte* get_first_page() const { return(m_first_page); } 381 382 private: 383 /** Free the filepath buffer. */ 384 void free_filepath(); 385 386 /** Set the filename pointer to the start of the file name 387 in the filepath. */ set_filename()388 void set_filename() 389 { 390 if (m_filepath == NULL) { 391 return; 392 } 393 394 char* last_slash = strrchr(m_filepath, OS_PATH_SEPARATOR); 395 396 m_filename = last_slash ? last_slash + 1 : m_filepath; 397 } 398 399 /** Create/open a data file. 400 @param[in] read_only_mode if true, then readonly mode checks 401 are enforced. 402 @return DB_SUCCESS or error code */ 403 dberr_t open_or_create(bool read_only_mode) 404 MY_ATTRIBUTE((warn_unused_result)); 405 406 /** Reads a few significant fields from the first page of the 407 datafile, which must already be open. 408 @param[in] read_only_mode if true, then readonly mode checks 409 are enforced. 410 @return DB_SUCCESS or DB_IO_ERROR if page cannot be read */ 411 dberr_t read_first_page(bool read_first_page) 412 MY_ATTRIBUTE((warn_unused_result)); 413 414 /** Free the first page from memory when it is no longer needed. */ 415 void free_first_page(); 416 417 /** Set the Datafile::m_open_flags. 418 @param open_flags The Open flags to set. */ set_open_flags(os_file_create_t open_flags)419 void set_open_flags(os_file_create_t open_flags) 420 { 421 m_open_flags = open_flags; 422 }; 423 424 /** Determine if this datafile is on a Raw Device 425 @return true if it is a RAW device. */ is_raw_device()426 bool is_raw_device() 427 { 428 return(m_type != SRV_NOT_RAW); 429 } 430 431 /* DATA MEMBERS */ 432 433 /** Datafile name at the tablespace location. 434 This is either the basename of the file if an absolute path 435 was entered, or it is the relative path to the datadir or 436 Tablespace::m_path. */ 437 char* m_name; 438 439 protected: 440 /** Physical file path with base name and extension */ 441 char* m_filepath; 442 443 private: 444 /** Determine the space id of the given file descriptor by reading 445 a few pages from the beginning of the .ibd file. 446 @return DB_SUCCESS if space id was successfully identified, 447 else DB_ERROR. */ 448 dberr_t find_space_id(); 449 450 /** Finds a given page of the given space id from the double write 451 buffer and copies it to the corresponding .ibd file. 452 @param[in] page_no Page number to restore 453 @return DB_SUCCESS if page was restored, else DB_ERROR */ 454 dberr_t restore_from_doublewrite( 455 ulint restore_page_no); 456 457 /** Points into m_filepath to the file name with extension */ 458 char* m_filename; 459 460 /** Open file handle */ 461 pfs_os_file_t m_handle; 462 463 /** Flags to use for opening the data file */ 464 os_file_create_t m_open_flags; 465 466 /** size in database pages */ 467 ulint m_size; 468 469 /** ordinal position of this datafile in the tablespace */ 470 ulint m_order; 471 472 /** The type of the data file */ 473 device_t m_type; 474 475 /** Tablespace ID. Contained in the datafile header. 476 If this is a system tablespace, FSP_SPACE_ID is only valid 477 in the first datafile. */ 478 ulint m_space_id; 479 480 /** Tablespace flags. Contained in the datafile header. 481 If this is a system tablespace, FSP_SPACE_FLAGS are only valid 482 in the first datafile. */ 483 ulint m_flags; 484 485 /** true if file already existed on startup */ 486 bool m_exists; 487 488 /* true if the tablespace is valid */ 489 bool m_is_valid; 490 491 /** Buffer to hold first page */ 492 byte* m_first_page_buf; 493 494 /** Pointer to the first page held in the buffer above */ 495 byte* m_first_page; 496 497 /** true if atomic writes enabled for this file */ 498 bool m_atomic_write; 499 500 protected: 501 /** Last OS error received so it can be reported if needed. */ 502 ulint m_last_os_error; 503 504 public: 505 /** Use the following to determine the uniqueness of this datafile. */ 506 #ifdef _WIN32 507 /* Use fields dwVolumeSerialNumber, nFileIndexLow, nFileIndexHigh. */ 508 BY_HANDLE_FILE_INFORMATION m_file_info; 509 #else 510 /* Use field st_ino. */ 511 struct stat m_file_info; 512 #endif /* WIN32 */ 513 514 /** Encryption key read from first page */ 515 byte* m_encryption_key; 516 517 /** Encryption iv read from first page */ 518 byte* m_encryption_iv; 519 520 }; 521 522 523 /** Data file control information. */ 524 class RemoteDatafile : public Datafile 525 { 526 private: 527 /** Link filename (full path) */ 528 char* m_link_filepath; 529 530 public: 531 RemoteDatafile()532 RemoteDatafile() 533 : 534 m_link_filepath() 535 { 536 /* No op - base constructor is called. */ 537 } 538 RemoteDatafile(const char * name,ulint size,ulint order)539 RemoteDatafile(const char* name, ulint size, ulint order) 540 : 541 m_link_filepath() 542 { 543 /* No op - base constructor is called. */ 544 } 545 ~RemoteDatafile()546 ~RemoteDatafile() 547 { 548 shutdown(); 549 } 550 551 /** Release the resources. */ 552 void shutdown(); 553 554 /** Get the link filepath. 555 @return m_link_filepath */ link_filepath()556 const char* link_filepath() const 557 { 558 return(m_link_filepath); 559 } 560 561 /** Set the link filepath. Use default datadir, the base name of 562 the path provided without its suffix, plus DOT_ISL. 563 @param[in] path filepath which contains a basename to use. 564 If NULL, use m_name as the basename. */ 565 void set_link_filepath(const char* path); 566 567 /** Create a link filename based on the contents of m_name, 568 open that file, and read the contents into m_filepath. 569 @retval DB_SUCCESS if remote linked tablespace file is opened and read. 570 @retval DB_CANNOT_OPEN_FILE if the link file does not exist. */ 571 dberr_t open_link_file(); 572 573 /** Delete an InnoDB Symbolic Link (ISL) file. */ 574 void delete_link_file(void); 575 576 /** Open a handle to the file linked to in an InnoDB Symbolic Link file 577 in read-only mode so that it can be validated. 578 @param[in] strict whether to issue error messages 579 @return DB_SUCCESS or error code */ 580 dberr_t open_read_only(bool strict); 581 582 /** Opens a handle to the file linked to in an InnoDB Symbolic Link 583 file in read-write mode so that it can be restored from doublewrite 584 and validated. 585 @param[in] read_only_mode If true, then readonly mode checks 586 are enforced. 587 @return DB_SUCCESS or error code */ 588 dberr_t open_read_write(bool read_only_mode) 589 MY_ATTRIBUTE((warn_unused_result)); 590 591 /****************************************************************** 592 Global Static Functions; Cannot refer to data members. 593 ******************************************************************/ 594 595 /** Creates a new InnoDB Symbolic Link (ISL) file. It is always 596 created under the 'datadir' of MySQL. The datadir is the directory 597 of a running mysqld program. We can refer to it by simply using 598 the path ".". 599 @param[in] name tablespace name 600 @param[in] filepath remote filepath of tablespace datafile 601 @param[in] is_shared true for general tablespace, 602 false for file-per-table 603 @return DB_SUCCESS or error code */ 604 static dberr_t create_link_file( 605 const char* name, 606 const char* filepath, 607 bool is_shared = false); 608 609 /** Delete an InnoDB Symbolic Link (ISL) file by name. 610 @param[in] name tablespace name */ 611 static void delete_link_file(const char* name); 612 613 /** Read an InnoDB Symbolic Link (ISL) file by name. 614 It is always created under the datadir of MySQL. 615 For file-per-table tablespaces, the isl file is expected to be 616 in a 'database' directory and called 'tablename.isl'. 617 For general tablespaces, there will be no 'database' directory. 618 The 'basename.isl' will be in the datadir. 619 The caller must free the memory returned if it is not null. 620 @param[in] link_filepath filepath of the ISL file 621 @return Filepath of the IBD file read from the ISL file */ 622 static char* read_link_file( 623 const char* link_filepath); 624 }; 625 #endif /* fsp0file_h */ 626