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