1 /*****************************************************************************
2 
3 Copyright (c) 2013, 2020, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License, version 2.0, as published by the
7 Free Software Foundation.
8 
9 This program is also distributed with certain software (including but not
10 limited to OpenSSL) that is licensed under separate terms, as designated in a
11 particular file or component or in included license documentation. The authors
12 of MySQL hereby grant you an additional permission to link the program and
13 your derivative works with the separately licensed software that they have
14 included with MySQL.
15 
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19 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 St, Fifth Floor, Boston, MA 02110-1301  USA
24 
25 *****************************************************************************/
26 
27 /** @file include/fsp0file.h
28  Tablespace data file implementation.
29 
30  Created 2013-7-26 by Kevin Lewis
31  *******************************************************/
32 
33 #ifndef fsp0file_h
34 #define fsp0file_h
35 
36 #include <vector>
37 #include "fil0fil.h" /* SPACE_UNKNOWN */
38 #include "ha_prototypes.h"
39 #include "log0log.h"
40 #include "mem0mem.h"
41 #include "os0file.h"
42 
43 #ifdef UNIV_HOTBACKUP
44 #include "fil0fil.h"
45 #include "fsp0types.h"
46 
47 /** MEB routine to get the master key. MEB will extract
48 the key from the keyring encrypted file stored in backup.
49 @param[in]	key_id		the id of the master key
50 @param[in]	key_type	master key type
51 @param[out]	key		the master key being returned
52 @param[out]	key_length	the length of the returned key
53 @retval	0 if the key is being returned, 1 otherwise. */
54 extern int meb_key_fetch(const char *key_id, char **key_type,
55                          const char *user_id, void **key, size_t *key_length);
56 #endif /* UNIV_HOTBACKUP */
57 
58 /** Types of raw partitions in innodb_data_file_path */
59 enum device_t {
60 
61   /** Not a raw partition */
62   SRV_NOT_RAW = 0,
63 
64   /** A 'newraw' partition, only to be initialized */
65   SRV_NEW_RAW,
66 
67   /** An initialized raw partition */
68   SRV_OLD_RAW
69 };
70 
71 /** Data file control information. */
72 class Datafile {
73   friend class Tablespace;
74   friend class SysTablespace;
75 
76  public:
Datafile()77   Datafile()
78       : m_name(),
79         m_filename(),
80         m_open_flags(OS_FILE_OPEN),
81         m_size(),
82         m_order(),
83         m_type(SRV_NOT_RAW),
84         m_space_id(SPACE_UNKNOWN),
85         m_flags(),
86         m_exists(),
87         m_is_valid(),
88         m_first_page_buf(),
89         m_first_page(),
90         m_atomic_write(),
91         m_filepath(),
92         m_last_os_error(),
93         m_file_info(),
94         m_encryption_key(),
95         m_encryption_iv(),
96         m_encryption_op_in_progress(NONE) {
97     m_handle.m_file = OS_FILE_CLOSED;
98   }
99 
Datafile(const char * name,uint32_t flags,page_no_t size,ulint order)100   Datafile(const char *name, uint32_t flags, page_no_t size, ulint order)
101       : m_name(mem_strdup(name)),
102         m_filename(),
103         m_open_flags(OS_FILE_OPEN),
104         m_size(size),
105         m_order(order),
106         m_type(SRV_NOT_RAW),
107         m_space_id(SPACE_UNKNOWN),
108         m_flags(flags),
109         m_exists(),
110         m_is_valid(),
111         m_first_page_buf(),
112         m_first_page(),
113         m_atomic_write(),
114         m_filepath(),
115         m_last_os_error(),
116         m_file_info(),
117         m_encryption_key(),
118         m_encryption_iv(),
119         m_encryption_op_in_progress(NONE) {
120     ut_ad(m_name != nullptr);
121     m_handle.m_file = OS_FILE_CLOSED;
122     /* No op */
123   }
124 
Datafile(const Datafile & file)125   Datafile(const Datafile &file)
126       : m_handle(file.m_handle),
127         m_open_flags(file.m_open_flags),
128         m_size(file.m_size),
129         m_order(file.m_order),
130         m_type(file.m_type),
131         m_space_id(file.m_space_id),
132         m_flags(file.m_flags),
133         m_exists(file.m_exists),
134         m_is_valid(file.m_is_valid),
135         m_first_page_buf(),
136         m_first_page(),
137         m_atomic_write(file.m_atomic_write),
138         m_last_os_error(),
139         m_file_info(),
140         m_encryption_key(),
141         m_encryption_iv(),
142         m_encryption_op_in_progress(NONE) {
143     m_name = mem_strdup(file.m_name);
144     ut_ad(m_name != nullptr);
145 
146     if (file.m_filepath != nullptr) {
147       m_filepath = mem_strdup(file.m_filepath);
148       ut_a(m_filepath != nullptr);
149       set_filename();
150     } else {
151       m_filepath = nullptr;
152       m_filename = nullptr;
153     }
154   }
155 
~Datafile()156   ~Datafile() { shutdown(); }
157 
158   Datafile &operator=(const Datafile &file) {
159     ut_a(this != &file);
160 
161     ut_ad(m_name == nullptr);
162     m_name = mem_strdup(file.m_name);
163     ut_a(m_name != nullptr);
164 
165     m_size = file.m_size;
166     m_order = file.m_order;
167     m_type = file.m_type;
168 
169     ut_a(m_handle.m_file == OS_FILE_CLOSED);
170     m_handle = file.m_handle;
171 
172     m_exists = file.m_exists;
173     m_is_valid = file.m_is_valid;
174     m_open_flags = file.m_open_flags;
175     m_space_id = file.m_space_id;
176     m_flags = file.m_flags;
177     m_last_os_error = 0;
178 
179     if (m_filepath != nullptr) {
180       ut_free(m_filepath);
181       m_filepath = nullptr;
182       m_filename = nullptr;
183     }
184 
185     if (file.m_filepath != nullptr) {
186       m_filepath = mem_strdup(file.m_filepath);
187       ut_a(m_filepath != nullptr);
188       set_filename();
189     }
190 
191     /* Do not make a copy of the first page,
192     it should be reread if needed */
193     m_first_page_buf = nullptr;
194     m_first_page = nullptr;
195     m_encryption_key = nullptr;
196     m_encryption_iv = nullptr;
197     m_encryption_op_in_progress = NONE;
198 
199     m_atomic_write = file.m_atomic_write;
200 
201     return (*this);
202   }
203 
204   /** Initialize the name and flags of this datafile.
205   @param[in]	name	tablespace name, will be copied
206   @param[in]	flags	tablespace flags */
207   void init(const char *name, uint32_t flags);
208 
209   /** Release the resources. */
210   void shutdown();
211 
212   /** Open a data file in read-only mode to check if it exists
213   so that it can be validated.
214   @param[in]	strict	whether to issue error messages
215   @return DB_SUCCESS or error code */
216   dberr_t open_read_only(bool strict) MY_ATTRIBUTE((warn_unused_result));
217 
218   /** Open a data file in read-write mode during start-up so that
219   doublewrite pages can be restored and then it can be validated.
220   @param[in]	read_only_mode	if true, then readonly mode checks
221                                   are enforced.
222   @return DB_SUCCESS or error code */
223   dberr_t open_read_write(bool read_only_mode)
224       MY_ATTRIBUTE((warn_unused_result));
225 
226   /** Initialize OS specific file info. */
227   void init_file_info();
228 
229   /** Close a data file.
230   @return DB_SUCCESS or error code */
231   dberr_t close();
232 
233   /** Make a full filepath from a directory path and a filename.
234   Prepend the dirpath to filename using the extension given.
235   If dirpath is nullptr, prepend the default datadir to filepath.
236   Store the result in m_filepath.
237   @param[in]	dirpath		directory path
238   @param[in]	filename	filename or filepath
239   @param[in]	ext		filename extension */
240   void make_filepath(const char *dirpath, const char *filename,
241                      ib_file_suffix ext);
242 
243   /** Set the filepath by duplicating the filepath sent in */
244   void set_filepath(const char *filepath);
245 
246   /** Allocate and set the datafile or tablespace name in m_name.
247   If a name is provided, use it; else if the datafile is file-per-table,
248   extract a file-per-table tablespace name from m_filepath; else it is a
249   general tablespace, so just call it that for now. The value of m_name
250   will be freed in the destructor.
251   @param[in]	name	Tablespace Name if known, nullptr if not */
252   void set_name(const char *name);
253 
254   /** Validates the datafile and checks that it conforms with
255   the expected space ID and flags.  The file should exist and be
256   successfully opened in order for this function to validate it.
257   @param[in]	space_id	The expected tablespace ID.
258   @param[in]	flags		The expected tablespace flags.
259   @param[in]	for_import	is it for importing
260   @retval DB_SUCCESS if tablespace is valid, DB_ERROR if not.
261   m_is_valid is also set true on success, else false. */
262   dberr_t validate_to_dd(space_id_t space_id, uint32_t flags, bool for_import)
263       MY_ATTRIBUTE((warn_unused_result));
264 
265   /** Validates this datafile for the purpose of recovery.
266   The file should exist and be successfully opened. We initially
267   open it in read-only mode because we just want to read the SpaceID.
268   However, if the first page is corrupt and needs to be restored
269   from the doublewrite buffer, we will reopen it in write mode and
270   ry to restore that page.
271   @param[in]	space_id	Expected space ID
272   @retval DB_SUCCESS on success
273   m_is_valid is also set true on success, else false. */
274   dberr_t validate_for_recovery(space_id_t space_id)
275       MY_ATTRIBUTE((warn_unused_result));
276 
277   /** Checks the consistency of the first page of a datafile when the
278   tablespace is opened.  This occurs before the fil_space_t is created
279   so the Space ID found here must not already be open.
280   m_is_valid is set true on success, else false.
281   @param[in]	space_id	Expected space ID
282   @param[out]	flush_lsn	contents of FIL_PAGE_FILE_FLUSH_LSN
283   @param[in]	for_import	if it is for importing
284   (only valid for the first file of the system tablespace)
285   @retval DB_WRONG_FILE_NAME tablespace in file header doesn't match
286           expected value
287   @retval DB_SUCCESS on if the datafile is valid
288   @retval DB_CORRUPTION if the datafile is not readable
289   @retval DB_INVALID_ENCRYPTION_META if the encrypption meta data
290           is not readable
291   @retval DB_TABLESPACE_EXISTS if there is a duplicate space_id */
292   dberr_t validate_first_page(space_id_t space_id, lsn_t *flush_lsn,
293                               bool for_import)
294       MY_ATTRIBUTE((warn_unused_result));
295 
296   /** Get Datafile::m_name.
297   @return m_name */
name()298   const char *name() const { return (m_name); }
299 
300   /** Get Datafile::m_filepath.
301   @return m_filepath */
filepath()302   const char *filepath() const { return (m_filepath); }
303 
304   /** Get Datafile::m_handle.
305   @return m_handle */
handle()306   pfs_os_file_t handle() const { return (m_handle); }
307 
308   /** Get Datafile::m_order.
309   @return m_order */
order()310   ulint order() const { return (m_order); }
311 
312   /** Get Datafile::m_server_version.
313   @return m_server_version */
server_version()314   ulint server_version() const { return (m_server_version); }
315 
316   /** Get Datafile::m_space_version.
317   @return m_space_version */
space_version()318   ulint space_version() const { return (m_space_version); }
319 
320   /** Get Datafile::m_space_id.
321   @return m_space_id */
space_id()322   space_id_t space_id() const { return (m_space_id); }
323 
324   /** Get Datafile::m_flags.
325   @return m_flags */
flags()326   uint32_t flags() const { return (m_flags); }
327 
328   /**
329   @return true if m_handle is open, false if not */
is_open()330   bool is_open() const { return (m_handle.m_file != OS_FILE_CLOSED); }
331 
332   /** Get Datafile::m_is_valid.
333   @return m_is_valid */
is_valid()334   bool is_valid() const { return (m_is_valid); }
335 
336   /** Get the last OS error reported
337   @return m_last_os_error */
last_os_error()338   ulint last_os_error() const { return (m_last_os_error); }
339 
340   /** Test if the filepath provided looks the same as this filepath
341   by string comparison. If they are two different paths to the same
342   file, same_as() will be used to show that after the files are opened.
343   @param[in]	other	filepath to compare with
344   @retval true if it is the same filename by char comparison
345   @retval false if it looks different */
346   bool same_filepath_as(const char *other) const;
347 
348   /** Test if another opened datafile is the same file as this object.
349   @param[in]	other	Datafile to compare with
350   @return true if it is the same file, else false */
351   bool same_as(const Datafile &other) const;
352 
353   /** Determine the space id of the given file descriptor by reading
354   a few pages from the beginning of the .ibd file.
355   @return DB_SUCCESS if space id was successfully identified,
356   else DB_ERROR. */
357   dberr_t find_space_id();
358 
359   /** @return file size in number of pages */
size()360   page_no_t size() const { return (m_size); }
361 
362 #if defined(UNIV_HOTBACKUP) || defined(XTRABACKUP)
363   /** Set the tablespace ID.
364   @param[in]	space_id	Tablespace ID to set */
set_space_id(space_id_t space_id)365   void set_space_id(space_id_t space_id) {
366     ut_ad(space_id <= 0xFFFFFFFFU);
367     m_space_id = space_id;
368   }
369 
370   /** Set th tablespace flags
371   @param[in]	flags	Tablespace flags */
set_flags(uint32_t flags)372   void set_flags(uint32_t flags) { m_flags = flags; }
373 #endif /* UNIV_HOTBACKUP || XTRABACKUP*/
374 
375  private:
376   /** Free the filepath buffer. */
377   void free_filepath();
378 
379   /** Set the filename pointer to the start of the file name
380   in the filepath. */
set_filename()381   void set_filename() {
382     if (m_filepath == nullptr) {
383       return;
384     }
385 
386     char *last_slash = strrchr(m_filepath, OS_PATH_SEPARATOR);
387 
388     m_filename = last_slash ? last_slash + 1 : m_filepath;
389   }
390 
391   /** Create/open a data file.
392   @param[in]	read_only_mode	if true, then readonly mode checks
393                                   are enforced.
394   @return DB_SUCCESS or error code */
395   dberr_t open_or_create(bool read_only_mode)
396       MY_ATTRIBUTE((warn_unused_result));
397 
398   /** Reads a few significant fields from the first page of the
399   datafile, which must already be open.
400   @param[in]	read_only_mode	if true, then readonly mode checks
401                                   are enforced.
402   @return DB_SUCCESS or DB_IO_ERROR if page cannot be read */
403   dberr_t read_first_page(bool read_only_mode)
404       MY_ATTRIBUTE((warn_unused_result));
405 
406   /** Free the first page from memory when it is no longer needed. */
407   void free_first_page();
408 
409   /** Set the Datafile::m_open_flags.
410   @param open_flags	The Open flags to set. */
set_open_flags(os_file_create_t open_flags)411   void set_open_flags(os_file_create_t open_flags) {
412     m_open_flags = open_flags;
413   }
414 
415   /** Finds a given page of the given space id from the double write
416   buffer and copies it to the corresponding .ibd file.
417   @param[in]	restore_page_no		Page number to restore
418   @return DB_SUCCESS if page was restored, else DB_ERROR */
419   dberr_t restore_from_doublewrite(page_no_t restore_page_no);
420 
421  private:
422   /** Datafile name at the tablespace location.
423   This is either the basename of the file if an absolute path
424   was entered, or it is the relative path to the datadir or
425   Tablespace::m_path. */
426   char *m_name;
427 
428   /** Points into m_filepath to the file name with extension */
429   char *m_filename;
430 
431   /** Open file handle */
432   pfs_os_file_t m_handle;
433 
434   /** Flags to use for opening the data file */
435   os_file_create_t m_open_flags;
436 
437   /** size in pages */
438   page_no_t m_size;
439 
440   /** ordinal position of this datafile in the tablespace */
441   ulint m_order;
442 
443   /** The type of the data file */
444   device_t m_type;
445 
446   /** Tablespace ID. Contained in the datafile header.
447   If this is a system tablespace, FSP_SPACE_ID is only valid
448   in the first datafile. */
449   space_id_t m_space_id;
450 
451   /** Server version */
452   uint32 m_server_version;
453 
454   /** Space version */
455   uint32 m_space_version;
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   uint32_t 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   /** Physical file path with base name and extension */
479   char *m_filepath;
480 
481   /** Last OS error received so it can be reported if needed. */
482   ulint m_last_os_error;
483 
484  public:
485   /** Use the following to determine the uniqueness of this datafile. */
486 #ifdef _WIN32
487   using WIN32_FILE_INFO = BY_HANDLE_FILE_INFORMATION;
488 
489   /** Use fields dwVolumeSerialNumber, nFileIndexLow, nFileIndexHigh. */
490   WIN32_FILE_INFO m_file_info;
491 #else
492   /** Use field st_ino. */
493   struct stat m_file_info;
494 #endif /* WIN32 */
495 
496   /** Encryption key read from first page */
497   byte *m_encryption_key;
498 
499   /** Encryption iv read from first page */
500   byte *m_encryption_iv;
501 
502   /** Encryption operation in progress */
503   encryption_op_type m_encryption_op_in_progress;
504 };
505 #endif /* fsp0file_h */
506