1/*****************************************************************************
2
3Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2017, 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 fsp/fsp0space.cc
22Shared tablespace implementation.
23
24Created 2012-11-16 by Sunny Bains as srv/srv0space.cc
25*******************************************************/
26
27#include "ha_prototypes.h"
28
29#include "fsp0space.h"
30#include "fsp0sysspace.h"
31#include "fsp0fsp.h"
32#include "os0file.h"
33#include "my_sys.h"
34
35/** Check if two tablespaces have common data file names.
36@param other_space Tablespace to check against this.
37@return true if they have the same data filenames and paths */
38bool
39Tablespace::intersection(
40 const Tablespace* other_space)
41{
42 for (files_t::const_iterator it(other_space->begin()),
43 end(other_space->end()); it != end; ++it) {
44
45 if (find(it->m_filename)) {
46
47 return(true);
48 }
49 }
50
51 return(false);
52}
53
54/** Frees the memory allocated by the SysTablespace object. */
55void
56Tablespace::shutdown()
57{
58 for (iterator it = begin(); it != end(); ++it) {
59 it->shutdown();
60 }
61
62 m_files.clear();
63 ut_free(m_path);
64 m_path = NULL;
65 m_space_id = ULINT_UNDEFINED;
66}
67
68/** Note that the data file was found.
69@param[in,out] file Data file object to set */
70void
71Tablespace::file_found(Datafile& file)
72{
73 /* Note that the file exists and can be opened
74 in the appropriate mode. */
75 file.m_exists = true;
76
77 file.set_open_flags(
78 &file == &m_files.front()
79 ? OS_FILE_OPEN_RETRY : OS_FILE_OPEN);
80}
81
82/** Open or Create the data files if they do not exist.
83@param[in] is_temp whether this is a temporary tablespace
84@return DB_SUCCESS or error code */
85dberr_t
86Tablespace::open_or_create(bool is_temp)
87{
88 fil_space_t* space = NULL;
89 dberr_t err = DB_SUCCESS;
90
91 ut_ad(!m_files.empty());
92
93 for (iterator it = begin(); it != end(); ++it) {
94
95 if (it->m_exists) {
96 err = it->open_or_create(
97 m_ignore_read_only
98 ? false : srv_read_only_mode);
99 } else {
100 err = it->open_or_create(
101 m_ignore_read_only
102 ? false : srv_read_only_mode);
103
104 /* Set the correct open flags now that we have
105 successfully created the file. */
106 if (err == DB_SUCCESS) {
107 file_found(*it);
108 }
109 }
110
111 if (err != DB_SUCCESS) {
112 break;
113 }
114
115 /* We can close the handle now and open the tablespace
116 the proper way. */
117 it->close();
118
119 if (it == begin()) {
120 /* First data file. */
121
122 /* Create the tablespace entry for the multi-file
123 tablespace in the tablespace manager. */
124 space = fil_space_create(
125 m_name, m_space_id, FSP_FLAGS_PAGE_SSIZE(),
126 is_temp
127 ? FIL_TYPE_TEMPORARY : FIL_TYPE_TABLESPACE,
128 NULL);
129 }
130
131 ut_a(fil_validate());
132
133 /* Create the tablespace node entry for this data file. */
134 if (!fil_node_create(
135 it->m_filepath, it->m_size, space, false,
136 TRUE)) {
137
138 err = DB_ERROR;
139 break;
140 }
141 }
142
143 return(err);
144}
145
146/** Find a filename in the list of Datafiles for a tablespace
147@return true if the filename exists in the data files */
148bool
149Tablespace::find(const char* filename) const
150{
151 for (const_iterator it = begin(); it != end(); ++it) {
152
153 if (innobase_strcasecmp(filename, it->m_filename) == 0) {
154 return(true);
155 }
156 }
157
158 return(false);
159}
160
161/** Delete all the data files. */
162void
163Tablespace::delete_files()
164{
165 for (iterator it = begin(); it != end(); ++it) {
166
167 it->close();
168
169 bool file_pre_exists;
170 bool success = os_file_delete_if_exists(
171 innodb_data_file_key, it->m_filepath, &file_pre_exists);
172
173 if (success && file_pre_exists) {
174 ib::info() << "Removed temporary tablespace data"
175 " file: \"" << it->m_name << "\"";
176 }
177 }
178}
179
180/** Use the ADD DATAFILE path to create a Datafile object and add it to the
181front of m_files.
182Parse the datafile path into a path and a filename with extension 'ibd'.
183This datafile_path provided may or may not be an absolute path, but it
184must end with the extension .ibd and have a basename of at least 1 byte.
185
186Set tablespace m_path member and add a Datafile with the filename.
187@param[in] datafile_path full path of the tablespace file. */
188dberr_t
189Tablespace::add_datafile(
190 const char* datafile_added)
191{
192 /* The path provided ends in ".ibd". This was assured by
193 validate_create_tablespace_info() */
194 ut_d(const char* dot = strrchr(datafile_added, '.'));
195 ut_ad(dot != NULL && 0 == strcmp(dot, DOT_IBD));
196
197 char* filepath = mem_strdup(datafile_added);
198 os_normalize_path(filepath);
199
200 /* If the path is an absolute path, separate it onto m_path and a
201 basename. For relative paths, make the whole thing a basename so that
202 it can be appended to the datadir. */
203 bool is_abs_path = is_absolute_path(filepath);
204 size_t dirlen = (is_abs_path ? dirname_length(filepath) : 0);
205 const char* basename = filepath + dirlen;
206
207 /* If the pathname contains a directory separator, fill the
208 m_path member which is the default directory for files in this
209 tablespace. Leave it null otherwise. */
210 if (dirlen > 0) {
211 set_path(filepath, dirlen);
212 }
213
214 /* Now add a new Datafile and set the filepath
215 using the m_path created above. */
216 m_files.push_back(Datafile(m_name, m_flags,
217 FIL_IBD_FILE_INITIAL_SIZE, 0));
218 Datafile* datafile = &m_files.back();
219 datafile->make_filepath(m_path, basename, IBD);
220
221 ut_free(filepath);
222
223 return(DB_SUCCESS);
224}
225