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