1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, MariaDB Corporation. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /**************************************************//** |
21 | @file fsp/fsp0space.cc |
22 | Shared tablespace implementation. |
23 | |
24 | Created 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 */ |
38 | bool |
39 | Tablespace::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. */ |
55 | void |
56 | Tablespace::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 */ |
70 | void |
71 | Tablespace::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 */ |
85 | dberr_t |
86 | Tablespace::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 */ |
148 | bool |
149 | Tablespace::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. */ |
162 | void |
163 | Tablespace::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 |
181 | front of m_files. |
182 | Parse the datafile path into a path and a filename with extension 'ibd'. |
183 | This datafile_path provided may or may not be an absolute path, but it |
184 | must end with the extension .ibd and have a basename of at least 1 byte. |
185 | |
186 | Set tablespace m_path member and add a Datafile with the filename. |
187 | @param[in] datafile_path full path of the tablespace file. */ |
188 | dberr_t |
189 | Tablespace::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 | |