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 /** Validates the datafile and checks that it conforms with 245 the expected space ID and flags. The file should exist and be 246 successfully opened in order for this function to validate it. 247 @param[in] space_id The expected tablespace ID. 248 @param[in] flags The expected tablespace flags. 249 @param[in] for_import is it for importing 250 @retval DB_SUCCESS if tablespace is valid, DB_ERROR if not. 251 m_is_valid is also set true on success, else false. */ 252 dberr_t validate_to_dd( 253 ulint space_id, 254 ulint flags, 255 bool for_import) 256 MY_ATTRIBUTE((warn_unused_result)); 257 258 /** Validates this datafile for the purpose of recovery. 259 The file should exist and be successfully opened. We initially 260 open it in read-only mode because we just want to read the SpaceID. 261 However, if the first page is corrupt and needs to be restored 262 from the doublewrite buffer, we will reopen it in write mode and 263 ry to restore that page. 264 @retval DB_SUCCESS if tablespace is valid, DB_ERROR if not. 265 m_is_valid is also set true on success, else false. */ 266 dberr_t validate_for_recovery() 267 MY_ATTRIBUTE((warn_unused_result)); 268 269 /** Checks the consistency of the first page of a datafile when the 270 tablespace is opened. This occurs before the fil_space_t is created 271 so the Space ID found here must not already be open. 272 m_is_valid is set true on success, else false. 273 @param[out] flush_lsn contents of FIL_PAGE_FILE_FLUSH_LSN 274 @param[in] for_import if it is for importing 275 (only valid for the first file of the system tablespace) 276 @retval DB_SUCCESS on if the datafile is valid 277 @retval DB_CORRUPTION if the datafile is not readable 278 @retval DB_TABLESPACE_EXISTS if there is a duplicate space_id */ 279 dberr_t validate_first_page(lsn_t* flush_lsn, 280 bool for_import) 281 MY_ATTRIBUTE((warn_unused_result)); 282 283 /** Get Datafile::m_name. 284 @return m_name */ name()285 const char* name() const 286 { 287 return(m_name); 288 } 289 290 /** Get Datafile::m_filepath. 291 @return m_filepath */ filepath()292 const char* filepath() const 293 { 294 return(m_filepath); 295 } 296 297 /** Get Datafile::m_handle. 298 @return m_handle */ handle()299 pfs_os_file_t handle() const 300 { 301 return(m_handle); 302 } 303 304 /** Get Datafile::m_order. 305 @return m_order */ order()306 ulint order() const 307 { 308 return(m_order); 309 } 310 311 /** Get Datafile::m_space_id. 312 @return m_space_id */ space_id()313 ulint space_id() const 314 { 315 return(m_space_id); 316 } 317 318 /** Get Datafile::m_flags. 319 @return m_flags */ flags()320 ulint flags() const 321 { 322 return(m_flags); 323 } 324 325 /** 326 @return true if m_handle is open, false if not */ is_open()327 bool is_open() const 328 { 329 return(m_handle.m_file != OS_FILE_CLOSED); 330 } 331 332 /** Get Datafile::m_is_valid. 333 @return m_is_valid */ is_valid()334 bool is_valid() const 335 { 336 return(m_is_valid); 337 } 338 339 /** Get the last OS error reported 340 @return m_last_os_error */ last_os_error()341 ulint last_os_error() const 342 { 343 return(m_last_os_error); 344 } 345 346 /** Test if the filepath provided looks the same as this filepath 347 by string comparison. If they are two different paths to the same 348 file, same_as() will be used to show that after the files are opened. 349 @param[in] other filepath to compare with 350 @retval true if it is the same filename by char comparison 351 @retval false if it looks different */ 352 bool same_filepath_as(const char* other) const; 353 354 /** Test if another opened datafile is the same file as this object. 355 @param[in] other Datafile to compare with 356 @return true if it is the same file, else false */ 357 bool same_as(const Datafile& other) const; 358 359 private: 360 /** Free the filepath buffer. */ 361 void free_filepath(); 362 363 /** Set the filename pointer to the start of the file name 364 in the filepath. */ set_filename()365 void set_filename() 366 { 367 if (m_filepath == NULL) { 368 return; 369 } 370 371 char* last_slash = strrchr(m_filepath, OS_PATH_SEPARATOR); 372 373 m_filename = last_slash ? last_slash + 1 : m_filepath; 374 } 375 376 /** Create/open a data file. 377 @param[in] read_only_mode if true, then readonly mode checks 378 are enforced. 379 @return DB_SUCCESS or error code */ 380 dberr_t open_or_create(bool read_only_mode) 381 MY_ATTRIBUTE((warn_unused_result)); 382 383 /** Reads a few significant fields from the first page of the 384 datafile, which must already be open. 385 @param[in] read_only_mode if true, then readonly mode checks 386 are enforced. 387 @return DB_SUCCESS or DB_IO_ERROR if page cannot be read */ 388 dberr_t read_first_page(bool read_first_page) 389 MY_ATTRIBUTE((warn_unused_result)); 390 391 /** Free the first page from memory when it is no longer needed. */ 392 void free_first_page(); 393 394 /** Set the Datafile::m_open_flags. 395 @param open_flags The Open flags to set. */ set_open_flags(os_file_create_t open_flags)396 void set_open_flags(os_file_create_t open_flags) 397 { 398 m_open_flags = open_flags; 399 }; 400 401 /** Determine if this datafile is on a Raw Device 402 @return true if it is a RAW device. */ is_raw_device()403 bool is_raw_device() 404 { 405 return(m_type != SRV_NOT_RAW); 406 } 407 408 /* DATA MEMBERS */ 409 410 /** Datafile name at the tablespace location. 411 This is either the basename of the file if an absolute path 412 was entered, or it is the relative path to the datadir or 413 Tablespace::m_path. */ 414 char* m_name; 415 416 protected: 417 /** Physical file path with base name and extension */ 418 char* m_filepath; 419 420 private: 421 /** Determine the space id of the given file descriptor by reading 422 a few pages from the beginning of the .ibd file. 423 @return DB_SUCCESS if space id was successfully identified, 424 else DB_ERROR. */ 425 dberr_t find_space_id(); 426 427 /** Finds a given page of the given space id from the double write 428 buffer and copies it to the corresponding .ibd file. 429 @param[in] page_no Page number to restore 430 @return DB_SUCCESS if page was restored, else DB_ERROR */ 431 dberr_t restore_from_doublewrite( 432 ulint restore_page_no); 433 434 /** Points into m_filepath to the file name with extension */ 435 char* m_filename; 436 437 /** Open file handle */ 438 pfs_os_file_t m_handle; 439 440 /** Flags to use for opening the data file */ 441 os_file_create_t m_open_flags; 442 443 /** size in database pages */ 444 ulint m_size; 445 446 /** ordinal position of this datafile in the tablespace */ 447 ulint m_order; 448 449 /** The type of the data file */ 450 device_t m_type; 451 452 /** Tablespace ID. Contained in the datafile header. 453 If this is a system tablespace, FSP_SPACE_ID is only valid 454 in the first datafile. */ 455 ulint m_space_id; 456 457 /** Tablespace flags. Contained in the datafile header. 458 If this is a system tablespace, FSP_SPACE_FLAGS are only valid 459 in the first datafile. */ 460 ulint m_flags; 461 462 /** true if file already existed on startup */ 463 bool m_exists; 464 465 /* true if the tablespace is valid */ 466 bool m_is_valid; 467 468 /** Buffer to hold first page */ 469 byte* m_first_page_buf; 470 471 /** Pointer to the first page held in the buffer above */ 472 byte* m_first_page; 473 474 /** true if atomic writes enabled for this file */ 475 bool m_atomic_write; 476 477 protected: 478 /** Last OS error received so it can be reported if needed. */ 479 ulint m_last_os_error; 480 481 public: 482 /** Use the following to determine the uniqueness of this datafile. */ 483 #ifdef _WIN32 484 /* Use fields dwVolumeSerialNumber, nFileIndexLow, nFileIndexHigh. */ 485 BY_HANDLE_FILE_INFORMATION m_file_info; 486 #else 487 /* Use field st_ino. */ 488 struct stat m_file_info; 489 #endif /* WIN32 */ 490 491 /** Encryption key read from first page */ 492 byte* m_encryption_key; 493 494 /** Encryption iv read from first page */ 495 byte* m_encryption_iv; 496 497 }; 498 499 500 /** Data file control information. */ 501 class RemoteDatafile : public Datafile 502 { 503 private: 504 /** Link filename (full path) */ 505 char* m_link_filepath; 506 507 public: 508 RemoteDatafile()509 RemoteDatafile() 510 : 511 m_link_filepath() 512 { 513 /* No op - base constructor is called. */ 514 } 515 RemoteDatafile(const char * name,ulint size,ulint order)516 RemoteDatafile(const char* name, ulint size, ulint order) 517 : 518 m_link_filepath() 519 { 520 /* No op - base constructor is called. */ 521 } 522 ~RemoteDatafile()523 ~RemoteDatafile() 524 { 525 shutdown(); 526 } 527 528 /** Release the resources. */ 529 void shutdown(); 530 531 /** Get the link filepath. 532 @return m_link_filepath */ link_filepath()533 const char* link_filepath() const 534 { 535 return(m_link_filepath); 536 } 537 538 /** Set the link filepath. Use default datadir, the base name of 539 the path provided without its suffix, plus DOT_ISL. 540 @param[in] path filepath which contains a basename to use. 541 If NULL, use m_name as the basename. */ 542 void set_link_filepath(const char* path); 543 544 /** Create a link filename based on the contents of m_name, 545 open that file, and read the contents into m_filepath. 546 @retval DB_SUCCESS if remote linked tablespace file is opened and read. 547 @retval DB_CANNOT_OPEN_FILE if the link file does not exist. */ 548 dberr_t open_link_file(); 549 550 /** Delete an InnoDB Symbolic Link (ISL) file. */ 551 void delete_link_file(void); 552 553 /** Open a handle to the file linked to in an InnoDB Symbolic Link file 554 in read-only mode so that it can be validated. 555 @param[in] strict whether to issue error messages 556 @return DB_SUCCESS or error code */ 557 dberr_t open_read_only(bool strict); 558 559 /** Opens a handle to the file linked to in an InnoDB Symbolic Link 560 file in read-write mode so that it can be restored from doublewrite 561 and validated. 562 @param[in] read_only_mode If true, then readonly mode checks 563 are enforced. 564 @return DB_SUCCESS or error code */ 565 dberr_t open_read_write(bool read_only_mode) 566 MY_ATTRIBUTE((warn_unused_result)); 567 568 /****************************************************************** 569 Global Static Functions; Cannot refer to data members. 570 ******************************************************************/ 571 572 /** Creates a new InnoDB Symbolic Link (ISL) file. It is always 573 created under the 'datadir' of MySQL. The datadir is the directory 574 of a running mysqld program. We can refer to it by simply using 575 the path ".". 576 @param[in] name tablespace name 577 @param[in] filepath remote filepath of tablespace datafile 578 @param[in] is_shared true for general tablespace, 579 false for file-per-table 580 @return DB_SUCCESS or error code */ 581 static dberr_t create_link_file( 582 const char* name, 583 const char* filepath, 584 bool is_shared = false); 585 586 /** Delete an InnoDB Symbolic Link (ISL) file by name. 587 @param[in] name tablespace name */ 588 static void delete_link_file(const char* name); 589 590 /** Read an InnoDB Symbolic Link (ISL) file by name. 591 It is always created under the datadir of MySQL. 592 For file-per-table tablespaces, the isl file is expected to be 593 in a 'database' directory and called 'tablename.isl'. 594 For general tablespaces, there will be no 'database' directory. 595 The 'basename.isl' will be in the datadir. 596 The caller must free the memory returned if it is not null. 597 @param[in] link_filepath filepath of the ISL file 598 @return Filepath of the IBD file read from the ISL file */ 599 static char* read_link_file( 600 const char* link_filepath); 601 }; 602 #endif /* fsp0file_h */ 603