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