1 | /* Copyright (C) 2004-2008 MySQL AB & MySQL Finland AB & TCX DataKonsult AB |
2 | Copyright (C) 2008-2009 Sun Microsystems, Inc. |
3 | Copyright (c) 2009, 2017, MariaDB Corporation. |
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 as published by |
7 | the Free Software Foundation; version 2 of the License. |
8 | |
9 | This program is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License |
15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ |
17 | |
18 | |
19 | #ifdef USE_PRAGMA_IMPLEMENTATION |
20 | #pragma implementation // gcc: Class implementation |
21 | #endif |
22 | |
23 | #define MYSQL_SERVER 1 |
24 | #include <my_global.h> |
25 | #include <m_ctype.h> |
26 | #include <my_dir.h> |
27 | #include <myisampack.h> |
28 | #include <my_bit.h> |
29 | #include "ha_maria.h" |
30 | #include "trnman_public.h" |
31 | #include "trnman.h" |
32 | |
33 | C_MODE_START |
34 | #include "maria_def.h" |
35 | #include "ma_rt_index.h" |
36 | #include "ma_blockrec.h" |
37 | #include "ma_checkpoint.h" |
38 | #include "ma_recovery.h" |
39 | C_MODE_END |
40 | |
41 | //#include "sql_priv.h" |
42 | #include "protocol.h" |
43 | #include "sql_class.h" |
44 | #include "key.h" |
45 | #include "log.h" |
46 | #include "sql_parse.h" |
47 | |
48 | /* |
49 | Note that in future versions, only *transactional* Maria tables can |
50 | rollback, so this flag should be up or down conditionally. |
51 | */ |
52 | #ifdef MARIA_CANNOT_ROLLBACK |
53 | #define CANNOT_ROLLBACK_FLAG HA_NO_TRANSACTIONS |
54 | #define trans_register_ha(A, B, C) do { /* nothing */ } while(0) |
55 | #else |
56 | #define CANNOT_ROLLBACK_FLAG 0 |
57 | #endif |
58 | #define THD_TRN (*(TRN **)thd_ha_data(thd, maria_hton)) |
59 | |
60 | ulong pagecache_division_limit, pagecache_age_threshold, pagecache_file_hash_size; |
61 | ulonglong pagecache_buffer_size; |
62 | const char *zerofill_error_msg= |
63 | "Table is from another system and must be zerofilled or repaired to be " |
64 | "usable on this system" ; |
65 | |
66 | /** |
67 | As the auto-repair is initiated when opened from the SQL layer |
68 | (open_unireg_entry(), check_and_repair()), it does not happen when Maria's |
69 | Recovery internally opens the table to apply log records to it, which is |
70 | good. It would happen only after Recovery, if the table is still |
71 | corrupted. |
72 | */ |
73 | ulonglong maria_recover_options= HA_RECOVER_NONE; |
74 | handlerton *maria_hton; |
75 | |
76 | /* bits in maria_recover_options */ |
77 | const char *maria_recover_names[]= |
78 | { |
79 | /* |
80 | Compared to MyISAM, "default" was renamed to "normal" as it collided with |
81 | SET var=default which sets to the var's default i.e. what happens when the |
82 | var is not set i.e. HA_RECOVER_NONE. |
83 | OFF flag is ignored. |
84 | */ |
85 | "NORMAL" , "BACKUP" , "FORCE" , "QUICK" , "OFF" , NullS |
86 | }; |
87 | TYPELIB maria_recover_typelib= |
88 | { |
89 | array_elements(maria_recover_names) - 1, "" , |
90 | maria_recover_names, NULL |
91 | }; |
92 | |
93 | const char *maria_stats_method_names[]= |
94 | { |
95 | "nulls_unequal" , "nulls_equal" , |
96 | "nulls_ignored" , NullS |
97 | }; |
98 | TYPELIB maria_stats_method_typelib= |
99 | { |
100 | array_elements(maria_stats_method_names) - 1, "" , |
101 | maria_stats_method_names, NULL |
102 | }; |
103 | |
104 | /* transactions log purge mode */ |
105 | const char *maria_translog_purge_type_names[]= |
106 | { |
107 | "immediate" , "external" , "at_flush" , NullS |
108 | }; |
109 | TYPELIB maria_translog_purge_type_typelib= |
110 | { |
111 | array_elements(maria_translog_purge_type_names) - 1, "" , |
112 | maria_translog_purge_type_names, NULL |
113 | }; |
114 | |
115 | /* transactional log directory sync */ |
116 | const char *maria_sync_log_dir_names[]= |
117 | { |
118 | "NEVER" , "NEWFILE" , "ALWAYS" , NullS |
119 | }; |
120 | TYPELIB maria_sync_log_dir_typelib= |
121 | { |
122 | array_elements(maria_sync_log_dir_names) - 1, "" , |
123 | maria_sync_log_dir_names, NULL |
124 | }; |
125 | |
126 | /* transactional log group commit */ |
127 | const char *maria_group_commit_names[]= |
128 | { |
129 | "none" , "hard" , "soft" , NullS |
130 | }; |
131 | TYPELIB maria_group_commit_typelib= |
132 | { |
133 | array_elements(maria_group_commit_names) - 1, "" , |
134 | maria_group_commit_names, NULL |
135 | }; |
136 | |
137 | /** Interval between background checkpoints in seconds */ |
138 | static ulong checkpoint_interval; |
139 | static void update_checkpoint_interval(MYSQL_THD thd, |
140 | struct st_mysql_sys_var *var, |
141 | void *var_ptr, const void *save); |
142 | static void update_maria_group_commit(MYSQL_THD thd, |
143 | struct st_mysql_sys_var *var, |
144 | void *var_ptr, const void *save); |
145 | static void update_maria_group_commit_interval(MYSQL_THD thd, |
146 | struct st_mysql_sys_var *var, |
147 | void *var_ptr, const void *save); |
148 | /** After that many consecutive recovery failures, remove logs */ |
149 | static ulong force_start_after_recovery_failures; |
150 | static void update_log_file_size(MYSQL_THD thd, |
151 | struct st_mysql_sys_var *var, |
152 | void *var_ptr, const void *save); |
153 | |
154 | static MYSQL_SYSVAR_ULONG(block_size, maria_block_size, |
155 | PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, |
156 | "Block size to be used for Aria index pages." , 0, 0, |
157 | MARIA_KEY_BLOCK_LENGTH, MARIA_MIN_KEY_BLOCK_LENGTH, |
158 | MARIA_MAX_KEY_BLOCK_LENGTH, MARIA_MIN_KEY_BLOCK_LENGTH); |
159 | |
160 | static MYSQL_SYSVAR_ULONG(checkpoint_interval, checkpoint_interval, |
161 | PLUGIN_VAR_RQCMDARG, |
162 | "Interval between tries to do an automatic checkpoints. In seconds; 0 means" |
163 | " 'no automatic checkpoints' which makes sense only for testing." , |
164 | NULL, update_checkpoint_interval, 30, 0, UINT_MAX, 1); |
165 | |
166 | static MYSQL_SYSVAR_ULONG(checkpoint_log_activity, maria_checkpoint_min_log_activity, |
167 | PLUGIN_VAR_RQCMDARG, |
168 | "Number of bytes that the transaction log has to grow between checkpoints before a new " |
169 | "checkpoint is written to the log." , |
170 | NULL, NULL, 1024*1024, 0, UINT_MAX, 1); |
171 | |
172 | static MYSQL_SYSVAR_ULONG(force_start_after_recovery_failures, |
173 | force_start_after_recovery_failures, |
174 | /* |
175 | Read-only because setting it on the fly has no useful effect, |
176 | should be set on command-line. |
177 | */ |
178 | PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, |
179 | "Number of consecutive log recovery failures after which logs will be" |
180 | " automatically deleted to cure the problem; 0 (the default) disables" |
181 | " the feature." , NULL, NULL, 0, 0, UINT_MAX8, 1); |
182 | |
183 | static MYSQL_SYSVAR_BOOL(page_checksum, maria_page_checksums, 0, |
184 | "Maintain page checksums (can be overridden per table " |
185 | "with PAGE_CHECKSUM clause in CREATE TABLE)" , 0, 0, 1); |
186 | |
187 | /* It is only command line argument */ |
188 | static MYSQL_SYSVAR_STR(log_dir_path, maria_data_root, |
189 | PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, |
190 | "Path to the directory where to store transactional log" , |
191 | NULL, NULL, mysql_real_data_home); |
192 | |
193 | |
194 | static MYSQL_SYSVAR_ULONG(log_file_size, log_file_size, |
195 | PLUGIN_VAR_RQCMDARG, |
196 | "Limit for transaction log size" , |
197 | NULL, update_log_file_size, TRANSLOG_FILE_SIZE, |
198 | TRANSLOG_MIN_FILE_SIZE, 0xffffffffL, TRANSLOG_PAGE_SIZE); |
199 | |
200 | static MYSQL_SYSVAR_ENUM(group_commit, maria_group_commit, |
201 | PLUGIN_VAR_RQCMDARG, |
202 | "Specifies Aria group commit mode. " |
203 | "Possible values are \"none\" (no group commit), " |
204 | "\"hard\" (with waiting to actual commit), " |
205 | "\"soft\" (no wait for commit (DANGEROUS!!!))" , |
206 | NULL, update_maria_group_commit, |
207 | TRANSLOG_GCOMMIT_NONE, &maria_group_commit_typelib); |
208 | |
209 | static MYSQL_SYSVAR_ULONG(group_commit_interval, maria_group_commit_interval, |
210 | PLUGIN_VAR_RQCMDARG, |
211 | "Interval between commite in microseconds (1/1000000c)." |
212 | " 0 stands for no waiting" |
213 | " for other threads to come and do a commit in \"hard\" mode and no" |
214 | " sync()/commit at all in \"soft\" mode. Option has only an effect" |
215 | " if aria_group_commit is used" , |
216 | NULL, update_maria_group_commit_interval, 0, 0, UINT_MAX, 1); |
217 | |
218 | static MYSQL_SYSVAR_ENUM(log_purge_type, log_purge_type, |
219 | PLUGIN_VAR_RQCMDARG, |
220 | "Specifies how Aria transactional log will be purged" , |
221 | NULL, NULL, TRANSLOG_PURGE_IMMIDIATE, |
222 | &maria_translog_purge_type_typelib); |
223 | |
224 | static MYSQL_SYSVAR_ULONGLONG(max_sort_file_size, |
225 | maria_max_temp_length, PLUGIN_VAR_RQCMDARG, |
226 | "Don't use the fast sort index method to created index if the " |
227 | "temporary file would get bigger than this." , |
228 | 0, 0, MAX_FILE_SIZE & ~((ulonglong) (1*MB-1)), |
229 | 0, MAX_FILE_SIZE, 1*MB); |
230 | |
231 | static MYSQL_SYSVAR_ULONG(pagecache_age_threshold, |
232 | pagecache_age_threshold, PLUGIN_VAR_RQCMDARG, |
233 | "This characterizes the number of hits a hot block has to be untouched " |
234 | "until it is considered aged enough to be downgraded to a warm block. " |
235 | "This specifies the percentage ratio of that number of hits to the " |
236 | "total number of blocks in the page cache." , 0, 0, |
237 | 300, 100, ~ (ulong) 0L, 100); |
238 | |
239 | static MYSQL_SYSVAR_ULONGLONG(pagecache_buffer_size, pagecache_buffer_size, |
240 | PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, |
241 | "The size of the buffer used for index blocks for Aria tables. " |
242 | "Increase this to get better index handling (for all reads and " |
243 | "multiple writes) to as much as you can afford." , 0, 0, |
244 | KEY_CACHE_SIZE, 8192*16L, ~(ulonglong) 0, 1); |
245 | |
246 | static MYSQL_SYSVAR_ULONG(pagecache_division_limit, pagecache_division_limit, |
247 | PLUGIN_VAR_RQCMDARG, |
248 | "The minimum percentage of warm blocks in key cache" , 0, 0, |
249 | 100, 1, 100, 1); |
250 | |
251 | static MYSQL_SYSVAR_ULONG(pagecache_file_hash_size, pagecache_file_hash_size, |
252 | PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, |
253 | "Number of hash buckets for open and changed files. If you have a lot of Aria " |
254 | "files open you should increase this for faster flush of changes. A good " |
255 | "value is probably 1/10 of number of possible open Aria files." , 0,0, |
256 | 512, 128, 16384, 1); |
257 | |
258 | static MYSQL_SYSVAR_SET(recover_options, maria_recover_options, PLUGIN_VAR_OPCMDARG, |
259 | "Specifies how corrupted tables should be automatically repaired" , |
260 | NULL, NULL, HA_RECOVER_BACKUP|HA_RECOVER_QUICK, &maria_recover_typelib); |
261 | |
262 | static MYSQL_THDVAR_ULONG(repair_threads, PLUGIN_VAR_RQCMDARG, |
263 | "Number of threads to use when repairing Aria tables. The value of 1 " |
264 | "disables parallel repair." , |
265 | 0, 0, 1, 1, 128, 1); |
266 | |
267 | static MYSQL_THDVAR_ULONGLONG(sort_buffer_size, PLUGIN_VAR_RQCMDARG, |
268 | "The buffer that is allocated when sorting the index when doing a " |
269 | "REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE." , NULL, NULL, |
270 | SORT_BUFFER_INIT, MIN_SORT_BUFFER, SIZE_T_MAX, 1); |
271 | |
272 | static MYSQL_THDVAR_ENUM(stats_method, PLUGIN_VAR_RQCMDARG, |
273 | "Specifies how Aria index statistics collection code should treat " |
274 | "NULLs" , 0, 0, 0, &maria_stats_method_typelib); |
275 | |
276 | static MYSQL_SYSVAR_ENUM(sync_log_dir, sync_log_dir, PLUGIN_VAR_RQCMDARG, |
277 | "Controls syncing directory after log file growth and new file " |
278 | "creation" , NULL, NULL, TRANSLOG_SYNC_DIR_NEWFILE, |
279 | &maria_sync_log_dir_typelib); |
280 | |
281 | #ifdef USE_ARIA_FOR_TMP_TABLES |
282 | #define USE_ARIA_FOR_TMP_TABLES_VAL 1 |
283 | #else |
284 | #define USE_ARIA_FOR_TMP_TABLES_VAL 0 |
285 | #endif |
286 | my_bool use_maria_for_temp_tables= USE_ARIA_FOR_TMP_TABLES_VAL; |
287 | |
288 | static MYSQL_SYSVAR_BOOL(used_for_temp_tables, |
289 | use_maria_for_temp_tables, PLUGIN_VAR_READONLY | PLUGIN_VAR_NOCMDOPT, |
290 | "Whether temporary tables should be MyISAM or Aria" , 0, 0, |
291 | 1); |
292 | |
293 | static MYSQL_SYSVAR_BOOL(encrypt_tables, maria_encrypt_tables, PLUGIN_VAR_OPCMDARG, |
294 | "Encrypt tables (only for tables with ROW_FORMAT=PAGE (default) " |
295 | "and not FIXED/DYNAMIC)" , |
296 | 0, 0, 0); |
297 | |
298 | #ifdef HAVE_PSI_INTERFACE |
299 | |
300 | static PSI_mutex_info all_aria_mutexes[]= |
301 | { |
302 | { &key_THR_LOCK_maria, "THR_LOCK_maria" , PSI_FLAG_GLOBAL}, |
303 | { &key_LOCK_soft_sync, "LOCK_soft_sync" , PSI_FLAG_GLOBAL}, |
304 | { &key_LOCK_trn_list, "LOCK_trn_list" , PSI_FLAG_GLOBAL}, |
305 | { &key_SHARE_BITMAP_lock, "SHARE::bitmap::bitmap_lock" , 0}, |
306 | { &key_SORT_INFO_mutex, "SORT_INFO::mutex" , 0}, |
307 | { &key_TRANSLOG_BUFFER_mutex, "TRANSLOG_BUFFER::mutex" , 0}, |
308 | { &key_TRANSLOG_DESCRIPTOR_dirty_buffer_mask_lock, "TRANSLOG_DESCRIPTOR::dirty_buffer_mask_lock" , 0}, |
309 | { &key_TRANSLOG_DESCRIPTOR_sent_to_disk_lock, "TRANSLOG_DESCRIPTOR::sent_to_disk_lock" , 0}, |
310 | { &key_TRANSLOG_DESCRIPTOR_log_flush_lock, "TRANSLOG_DESCRIPTOR::log_flush_lock" , 0}, |
311 | { &key_TRANSLOG_DESCRIPTOR_file_header_lock, "TRANSLOG_DESCRIPTOR::file_header_lock" , 0}, |
312 | { &key_TRANSLOG_DESCRIPTOR_unfinished_files_lock, "TRANSLOG_DESCRIPTOR::unfinished_files_lock" , 0}, |
313 | { &key_TRANSLOG_DESCRIPTOR_purger_lock, "TRANSLOG_DESCRIPTOR::purger_lock" , 0}, |
314 | { &key_SHARE_intern_lock, "SHARE::intern_lock" , 0}, |
315 | { &key_SHARE_key_del_lock, "SHARE::key_del_lock" , 0}, |
316 | { &key_SHARE_close_lock, "SHARE::close_lock" , 0}, |
317 | { &key_SERVICE_THREAD_CONTROL_lock, "SERVICE_THREAD_CONTROL::LOCK_control" , 0}, |
318 | { &key_TRN_state_lock, "TRN::state_lock" , 0}, |
319 | { &key_PAGECACHE_cache_lock, "PAGECACHE::cache_lock" , 0} |
320 | }; |
321 | |
322 | static PSI_cond_info all_aria_conds[]= |
323 | { |
324 | { &key_COND_soft_sync, "COND_soft_sync" , PSI_FLAG_GLOBAL}, |
325 | { &key_SHARE_key_del_cond, "SHARE::key_del_cond" , 0}, |
326 | { &key_SERVICE_THREAD_CONTROL_cond, "SERVICE_THREAD_CONTROL::COND_control" , 0}, |
327 | { &key_SORT_INFO_cond, "SORT_INFO::cond" , 0}, |
328 | { &key_SHARE_BITMAP_cond, "BITMAP::bitmap_cond" , 0}, |
329 | { &key_TRANSLOG_BUFFER_waiting_filling_buffer, "TRANSLOG_BUFFER::waiting_filling_buffer" , 0}, |
330 | { &key_TRANSLOG_BUFFER_prev_sent_to_disk_cond, "TRANSLOG_BUFFER::prev_sent_to_disk_cond" , 0}, |
331 | { &key_TRANSLOG_DESCRIPTOR_log_flush_cond, "TRANSLOG_DESCRIPTOR::log_flush_cond" , 0}, |
332 | { &key_TRANSLOG_DESCRIPTOR_new_goal_cond, "TRANSLOG_DESCRIPTOR::new_goal_cond" , 0} |
333 | }; |
334 | |
335 | static PSI_rwlock_info all_aria_rwlocks[]= |
336 | { |
337 | { &key_KEYINFO_root_lock, "KEYINFO::root_lock" , 0}, |
338 | { &key_SHARE_mmap_lock, "SHARE::mmap_lock" , 0}, |
339 | { &key_TRANSLOG_DESCRIPTOR_open_files_lock, "TRANSLOG_DESCRIPTOR::open_files_lock" , 0} |
340 | }; |
341 | |
342 | static PSI_thread_info all_aria_threads[]= |
343 | { |
344 | { &key_thread_checkpoint, "checkpoint_background" , PSI_FLAG_GLOBAL}, |
345 | { &key_thread_soft_sync, "soft_sync_background" , PSI_FLAG_GLOBAL}, |
346 | { &key_thread_find_all_keys, "thr_find_all_keys" , 0} |
347 | }; |
348 | |
349 | static PSI_file_info all_aria_files[]= |
350 | { |
351 | { &key_file_translog, "translog" , 0}, |
352 | { &key_file_kfile, "MAI" , 0}, |
353 | { &key_file_dfile, "MAD" , 0}, |
354 | { &key_file_control, "control" , PSI_FLAG_GLOBAL} |
355 | }; |
356 | |
357 | static PSI_stage_info *all_aria_stages[]= |
358 | { |
359 | & stage_waiting_for_a_resource |
360 | }; |
361 | |
362 | static void init_aria_psi_keys(void) |
363 | { |
364 | const char* category= "aria" ; |
365 | int count; |
366 | |
367 | count= array_elements(all_aria_mutexes); |
368 | mysql_mutex_register(category, all_aria_mutexes, count); |
369 | |
370 | count= array_elements(all_aria_rwlocks); |
371 | mysql_rwlock_register(category, all_aria_rwlocks, count); |
372 | |
373 | count= array_elements(all_aria_conds); |
374 | mysql_cond_register(category, all_aria_conds, count); |
375 | |
376 | count= array_elements(all_aria_threads); |
377 | mysql_thread_register(category, all_aria_threads, count); |
378 | |
379 | count= array_elements(all_aria_files); |
380 | mysql_file_register(category, all_aria_files, count); |
381 | |
382 | count= array_elements(all_aria_stages); |
383 | mysql_stage_register(category, all_aria_stages, count); |
384 | } |
385 | #else |
386 | #define init_aria_psi_keys() /* no-op */ |
387 | #endif /* HAVE_PSI_INTERFACE */ |
388 | |
389 | /***************************************************************************** |
390 | ** MARIA tables |
391 | *****************************************************************************/ |
392 | |
393 | static handler *maria_create_handler(handlerton *hton, |
394 | TABLE_SHARE * table, |
395 | MEM_ROOT *mem_root) |
396 | { |
397 | return new (mem_root) ha_maria(hton, table); |
398 | } |
399 | |
400 | |
401 | // collect errors printed by maria_check routines |
402 | |
403 | static void _ma_check_print_msg(HA_CHECK *param, const char *msg_type, |
404 | const char *fmt, va_list args) |
405 | { |
406 | THD *thd= (THD *) param->thd; |
407 | Protocol *protocol= thd->protocol; |
408 | size_t length, msg_length; |
409 | char msgbuf[MYSQL_ERRMSG_SIZE]; |
410 | char name[NAME_LEN * 2 + 2]; |
411 | |
412 | if (param->testflag & T_SUPPRESS_ERR_HANDLING) |
413 | return; |
414 | |
415 | msg_length= my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); |
416 | msgbuf[sizeof(msgbuf) - 1]= 0; // healthy paranoia |
417 | |
418 | DBUG_PRINT(msg_type, ("message: %s" , msgbuf)); |
419 | |
420 | if (!thd->vio_ok()) |
421 | { |
422 | sql_print_error("%s.%s: %s" , param->db_name, param->table_name, msgbuf); |
423 | return; |
424 | } |
425 | |
426 | if (param->testflag & |
427 | (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR | T_AUTO_REPAIR)) |
428 | { |
429 | my_message(ER_NOT_KEYFILE, msgbuf, MYF(MY_WME)); |
430 | if (thd->variables.log_warnings > 2) |
431 | sql_print_error("%s.%s: %s" , param->db_name, param->table_name, msgbuf); |
432 | return; |
433 | } |
434 | length= (uint) (strxmov(name, param->db_name, "." , param->table_name, |
435 | NullS) - name); |
436 | /* |
437 | TODO: switch from protocol to push_warning here. The main reason we didn't |
438 | it yet is parallel repair, which threads have no THD object accessible via |
439 | current_thd. |
440 | |
441 | Also we likely need to lock mutex here (in both cases with protocol and |
442 | push_warning). |
443 | */ |
444 | protocol->prepare_for_resend(); |
445 | protocol->store(name, (uint)length, system_charset_info); |
446 | protocol->store(param->op_name, system_charset_info); |
447 | protocol->store(msg_type, system_charset_info); |
448 | protocol->store(msgbuf, (uint)msg_length, system_charset_info); |
449 | if (protocol->write()) |
450 | sql_print_error("Failed on my_net_write, writing to stderr instead: %s.%s: %s\n" , |
451 | param->db_name, param->table_name, msgbuf); |
452 | else if (thd->variables.log_warnings > 2) |
453 | sql_print_error("%s.%s: %s" , param->db_name, param->table_name, msgbuf); |
454 | |
455 | return; |
456 | } |
457 | |
458 | |
459 | /* |
460 | Convert TABLE object to Maria key and column definition |
461 | |
462 | SYNOPSIS |
463 | table2maria() |
464 | table_arg in TABLE object. |
465 | keydef_out out Maria key definition. |
466 | recinfo_out out Maria column definition. |
467 | records_out out Number of fields. |
468 | |
469 | DESCRIPTION |
470 | This function will allocate and initialize Maria key and column |
471 | definition for further use in ma_create or for a check for underlying |
472 | table conformance in merge engine. |
473 | |
474 | The caller needs to free *recinfo_out after use. Since *recinfo_out |
475 | and *keydef_out are allocated with a my_multi_malloc, *keydef_out |
476 | is freed automatically when *recinfo_out is freed. |
477 | |
478 | RETURN VALUE |
479 | 0 OK |
480 | # error code |
481 | */ |
482 | |
483 | static int table2maria(TABLE *table_arg, data_file_type row_type, |
484 | MARIA_KEYDEF **keydef_out, |
485 | MARIA_COLUMNDEF **recinfo_out, uint *records_out, |
486 | MARIA_CREATE_INFO *create_info) |
487 | { |
488 | uint i, j, recpos, minpos, fieldpos, temp_length, length; |
489 | enum ha_base_keytype type= HA_KEYTYPE_BINARY; |
490 | uchar *record; |
491 | KEY *pos; |
492 | MARIA_KEYDEF *keydef; |
493 | MARIA_COLUMNDEF *recinfo, *recinfo_pos; |
494 | HA_KEYSEG *keyseg; |
495 | TABLE_SHARE *share= table_arg->s; |
496 | uint options= share->db_options_in_use; |
497 | DBUG_ENTER("table2maria" ); |
498 | |
499 | if (row_type == BLOCK_RECORD) |
500 | options|= HA_OPTION_PACK_RECORD; |
501 | |
502 | if (!(my_multi_malloc(MYF(MY_WME), |
503 | recinfo_out, (share->fields * 2 + 2) * sizeof(MARIA_COLUMNDEF), |
504 | keydef_out, share->keys * sizeof(MARIA_KEYDEF), |
505 | &keyseg, |
506 | (share->key_parts + share->keys) * sizeof(HA_KEYSEG), |
507 | NullS))) |
508 | DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */ |
509 | keydef= *keydef_out; |
510 | recinfo= *recinfo_out; |
511 | pos= table_arg->key_info; |
512 | for (i= 0; i < share->keys; i++, pos++) |
513 | { |
514 | keydef[i].flag= (uint16) (pos->flags & (HA_NOSAME | HA_FULLTEXT | |
515 | HA_SPATIAL)); |
516 | keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ? |
517 | (pos->flags & HA_SPATIAL ? HA_KEY_ALG_RTREE : HA_KEY_ALG_BTREE) : |
518 | pos->algorithm; |
519 | keydef[i].block_length= pos->block_size; |
520 | keydef[i].seg= keyseg; |
521 | keydef[i].keysegs= pos->user_defined_key_parts; |
522 | for (j= 0; j < pos->user_defined_key_parts; j++) |
523 | { |
524 | Field *field= pos->key_part[j].field; |
525 | |
526 | if (!table_arg->field[field->field_index]->stored_in_db()) |
527 | { |
528 | my_free(*recinfo_out); |
529 | my_error(ER_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN, MYF(0)); |
530 | DBUG_RETURN(HA_ERR_UNSUPPORTED); |
531 | } |
532 | |
533 | type= field->key_type(); |
534 | keydef[i].seg[j].flag= pos->key_part[j].key_part_flag; |
535 | |
536 | if (options & HA_OPTION_PACK_KEYS || |
537 | (pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY | |
538 | HA_SPACE_PACK_USED))) |
539 | { |
540 | if (pos->key_part[j].length > 8 && |
541 | (type == HA_KEYTYPE_TEXT || |
542 | type == HA_KEYTYPE_NUM || |
543 | (type == HA_KEYTYPE_BINARY && !field->zero_pack()))) |
544 | { |
545 | /* No blobs here */ |
546 | if (j == 0) |
547 | keydef[i].flag|= HA_PACK_KEY; |
548 | if (!(field->flags & ZEROFILL_FLAG) && |
549 | (field->type() == MYSQL_TYPE_STRING || |
550 | field->type() == MYSQL_TYPE_VAR_STRING || |
551 | ((int) (pos->key_part[j].length - field->decimals())) >= 4)) |
552 | keydef[i].seg[j].flag|= HA_SPACE_PACK; |
553 | } |
554 | else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16)) |
555 | keydef[i].flag|= HA_BINARY_PACK_KEY; |
556 | } |
557 | keydef[i].seg[j].type= (int) type; |
558 | keydef[i].seg[j].start= pos->key_part[j].offset; |
559 | keydef[i].seg[j].length= pos->key_part[j].length; |
560 | keydef[i].seg[j].bit_start= keydef[i].seg[j].bit_length= 0; |
561 | keydef[i].seg[j].bit_pos= 0; |
562 | keydef[i].seg[j].language= field->charset()->number; |
563 | |
564 | if (field->null_ptr) |
565 | { |
566 | keydef[i].seg[j].null_bit= field->null_bit; |
567 | keydef[i].seg[j].null_pos= (uint) (field->null_ptr- |
568 | (uchar*) table_arg->record[0]); |
569 | } |
570 | else |
571 | { |
572 | keydef[i].seg[j].null_bit= 0; |
573 | keydef[i].seg[j].null_pos= 0; |
574 | } |
575 | if (field->type() == MYSQL_TYPE_BLOB || |
576 | field->type() == MYSQL_TYPE_GEOMETRY) |
577 | { |
578 | keydef[i].seg[j].flag|= HA_BLOB_PART; |
579 | /* save number of bytes used to pack length */ |
580 | keydef[i].seg[j].bit_start= (uint) (field->pack_length() - |
581 | portable_sizeof_char_ptr); |
582 | } |
583 | else if (field->type() == MYSQL_TYPE_BIT) |
584 | { |
585 | keydef[i].seg[j].bit_length= ((Field_bit *) field)->bit_len; |
586 | keydef[i].seg[j].bit_start= ((Field_bit *) field)->bit_ofs; |
587 | keydef[i].seg[j].bit_pos= (uint) (((Field_bit *) field)->bit_ptr - |
588 | (uchar*) table_arg->record[0]); |
589 | } |
590 | } |
591 | keyseg+= pos->user_defined_key_parts; |
592 | } |
593 | if (table_arg->found_next_number_field) |
594 | keydef[share->next_number_index].flag|= HA_AUTO_KEY; |
595 | record= table_arg->record[0]; |
596 | recpos= 0; |
597 | recinfo_pos= recinfo; |
598 | create_info->null_bytes= table_arg->s->null_bytes; |
599 | |
600 | while (recpos < (uint) share->stored_rec_length) |
601 | { |
602 | Field **field, *found= 0; |
603 | minpos= share->reclength; |
604 | length= 0; |
605 | |
606 | for (field= table_arg->field; *field; field++) |
607 | { |
608 | if ((fieldpos= (*field)->offset(record)) >= recpos && |
609 | fieldpos <= minpos) |
610 | { |
611 | /* skip null fields */ |
612 | if (!(temp_length= (*field)->pack_length_in_rec())) |
613 | continue; /* Skip null-fields */ |
614 | if (! found || fieldpos < minpos || |
615 | (fieldpos == minpos && temp_length < length)) |
616 | { |
617 | minpos= fieldpos; |
618 | found= *field; |
619 | length= temp_length; |
620 | } |
621 | } |
622 | } |
623 | DBUG_PRINT("loop" , ("found: %p recpos: %d minpos: %d length: %d" , |
624 | found, recpos, minpos, length)); |
625 | if (!found) |
626 | break; |
627 | |
628 | if (found->flags & BLOB_FLAG) |
629 | recinfo_pos->type= FIELD_BLOB; |
630 | else if (found->type() == MYSQL_TYPE_TIMESTAMP) |
631 | recinfo_pos->type= FIELD_NORMAL; |
632 | else if (found->type() == MYSQL_TYPE_VARCHAR) |
633 | recinfo_pos->type= FIELD_VARCHAR; |
634 | else if (!(options & HA_OPTION_PACK_RECORD) || |
635 | (found->zero_pack() && (found->flags & PRI_KEY_FLAG))) |
636 | recinfo_pos->type= FIELD_NORMAL; |
637 | else if (found->zero_pack()) |
638 | recinfo_pos->type= FIELD_SKIP_ZERO; |
639 | else |
640 | recinfo_pos->type= ((length <= 3 || |
641 | (found->flags & ZEROFILL_FLAG)) ? |
642 | FIELD_NORMAL : |
643 | found->type() == MYSQL_TYPE_STRING || |
644 | found->type() == MYSQL_TYPE_VAR_STRING ? |
645 | FIELD_SKIP_ENDSPACE : |
646 | FIELD_SKIP_PRESPACE); |
647 | if (found->null_ptr) |
648 | { |
649 | recinfo_pos->null_bit= found->null_bit; |
650 | recinfo_pos->null_pos= (uint) (found->null_ptr - |
651 | (uchar*) table_arg->record[0]); |
652 | } |
653 | else |
654 | { |
655 | recinfo_pos->null_bit= 0; |
656 | recinfo_pos->null_pos= 0; |
657 | } |
658 | (recinfo_pos++)->length= (uint16) length; |
659 | recpos= minpos + length; |
660 | DBUG_PRINT("loop" , ("length: %d type: %d" , |
661 | recinfo_pos[-1].length,recinfo_pos[-1].type)); |
662 | } |
663 | *records_out= (uint) (recinfo_pos - recinfo); |
664 | DBUG_RETURN(0); |
665 | } |
666 | |
667 | |
668 | /* |
669 | Check for underlying table conformance |
670 | |
671 | SYNOPSIS |
672 | maria_check_definition() |
673 | t1_keyinfo in First table key definition |
674 | t1_recinfo in First table record definition |
675 | t1_keys in Number of keys in first table |
676 | t1_recs in Number of records in first table |
677 | t2_keyinfo in Second table key definition |
678 | t2_recinfo in Second table record definition |
679 | t2_keys in Number of keys in second table |
680 | t2_recs in Number of records in second table |
681 | strict in Strict check switch |
682 | |
683 | DESCRIPTION |
684 | This function compares two Maria definitions. By intention it was done |
685 | to compare merge table definition against underlying table definition. |
686 | It may also be used to compare dot-frm and MAI definitions of Maria |
687 | table as well to compare different Maria table definitions. |
688 | |
689 | For merge table it is not required that number of keys in merge table |
690 | must exactly match number of keys in underlying table. When calling this |
691 | function for underlying table conformance check, 'strict' flag must be |
692 | set to false, and converted merge definition must be passed as t1_*. |
693 | |
694 | Otherwise 'strict' flag must be set to 1 and it is not required to pass |
695 | converted dot-frm definition as t1_*. |
696 | |
697 | RETURN VALUE |
698 | 0 - Equal definitions. |
699 | 1 - Different definitions. |
700 | |
701 | TODO |
702 | - compare FULLTEXT keys; |
703 | - compare SPATIAL keys; |
704 | - compare FIELD_SKIP_ZERO which is converted to FIELD_NORMAL correctly |
705 | (should be correctly detected in table2maria). |
706 | */ |
707 | |
708 | int maria_check_definition(MARIA_KEYDEF *t1_keyinfo, |
709 | MARIA_COLUMNDEF *t1_recinfo, |
710 | uint t1_keys, uint t1_recs, |
711 | MARIA_KEYDEF *t2_keyinfo, |
712 | MARIA_COLUMNDEF *t2_recinfo, |
713 | uint t2_keys, uint t2_recs, bool strict) |
714 | { |
715 | uint i, j; |
716 | DBUG_ENTER("maria_check_definition" ); |
717 | if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys)) |
718 | { |
719 | DBUG_PRINT("error" , ("Number of keys differs: t1_keys=%u, t2_keys=%u" , |
720 | t1_keys, t2_keys)); |
721 | DBUG_RETURN(1); |
722 | } |
723 | if (t1_recs != t2_recs) |
724 | { |
725 | DBUG_PRINT("error" , ("Number of recs differs: t1_recs=%u, t2_recs=%u" , |
726 | t1_recs, t2_recs)); |
727 | DBUG_RETURN(1); |
728 | } |
729 | for (i= 0; i < t1_keys; i++) |
730 | { |
731 | HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg; |
732 | HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg; |
733 | if (t1_keyinfo[i].flag & HA_FULLTEXT && t2_keyinfo[i].flag & HA_FULLTEXT) |
734 | continue; |
735 | else if (t1_keyinfo[i].flag & HA_FULLTEXT || |
736 | t2_keyinfo[i].flag & HA_FULLTEXT) |
737 | { |
738 | DBUG_PRINT("error" , ("Key %d has different definition" , i)); |
739 | DBUG_PRINT("error" , ("t1_fulltext= %d, t2_fulltext=%d" , |
740 | MY_TEST(t1_keyinfo[i].flag & HA_FULLTEXT), |
741 | MY_TEST(t2_keyinfo[i].flag & HA_FULLTEXT))); |
742 | DBUG_RETURN(1); |
743 | } |
744 | if (t1_keyinfo[i].flag & HA_SPATIAL && t2_keyinfo[i].flag & HA_SPATIAL) |
745 | continue; |
746 | else if (t1_keyinfo[i].flag & HA_SPATIAL || |
747 | t2_keyinfo[i].flag & HA_SPATIAL) |
748 | { |
749 | DBUG_PRINT("error" , ("Key %d has different definition" , i)); |
750 | DBUG_PRINT("error" , ("t1_spatial= %d, t2_spatial=%d" , |
751 | MY_TEST(t1_keyinfo[i].flag & HA_SPATIAL), |
752 | MY_TEST(t2_keyinfo[i].flag & HA_SPATIAL))); |
753 | DBUG_RETURN(1); |
754 | } |
755 | if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs || |
756 | t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg) |
757 | { |
758 | DBUG_PRINT("error" , ("Key %d has different definition" , i)); |
759 | DBUG_PRINT("error" , ("t1_keysegs=%d, t1_key_alg=%d" , |
760 | t1_keyinfo[i].keysegs, t1_keyinfo[i].key_alg)); |
761 | DBUG_PRINT("error" , ("t2_keysegs=%d, t2_key_alg=%d" , |
762 | t2_keyinfo[i].keysegs, t2_keyinfo[i].key_alg)); |
763 | DBUG_RETURN(1); |
764 | } |
765 | for (j= t1_keyinfo[i].keysegs; j--;) |
766 | { |
767 | uint8 t1_keysegs_j__type= t1_keysegs[j].type; |
768 | /* |
769 | Table migration from 4.1 to 5.1. In 5.1 a *TEXT key part is |
770 | always HA_KEYTYPE_VARTEXT2. In 4.1 we had only the equivalent of |
771 | HA_KEYTYPE_VARTEXT1. Since we treat both the same on MyISAM |
772 | level, we can ignore a mismatch between these types. |
773 | */ |
774 | if ((t1_keysegs[j].flag & HA_BLOB_PART) && |
775 | (t2_keysegs[j].flag & HA_BLOB_PART)) |
776 | { |
777 | if ((t1_keysegs_j__type == HA_KEYTYPE_VARTEXT2) && |
778 | (t2_keysegs[j].type == HA_KEYTYPE_VARTEXT1)) |
779 | t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1; /* purecov: tested */ |
780 | else if ((t1_keysegs_j__type == HA_KEYTYPE_VARBINARY2) && |
781 | (t2_keysegs[j].type == HA_KEYTYPE_VARBINARY1)) |
782 | t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1; /* purecov: inspected */ |
783 | } |
784 | |
785 | if (t1_keysegs_j__type != t2_keysegs[j].type || |
786 | t1_keysegs[j].language != t2_keysegs[j].language || |
787 | t1_keysegs[j].null_bit != t2_keysegs[j].null_bit || |
788 | t1_keysegs[j].length != t2_keysegs[j].length) |
789 | { |
790 | DBUG_PRINT("error" , ("Key segment %d (key %d) has different " |
791 | "definition" , j, i)); |
792 | DBUG_PRINT("error" , ("t1_type=%d, t1_language=%d, t1_null_bit=%d, " |
793 | "t1_length=%d" , |
794 | t1_keysegs[j].type, t1_keysegs[j].language, |
795 | t1_keysegs[j].null_bit, t1_keysegs[j].length)); |
796 | DBUG_PRINT("error" , ("t2_type=%d, t2_language=%d, t2_null_bit=%d, " |
797 | "t2_length=%d" , |
798 | t2_keysegs[j].type, t2_keysegs[j].language, |
799 | t2_keysegs[j].null_bit, t2_keysegs[j].length)); |
800 | |
801 | DBUG_RETURN(1); |
802 | } |
803 | } |
804 | } |
805 | |
806 | for (i= 0; i < t1_recs; i++) |
807 | { |
808 | MARIA_COLUMNDEF *t1_rec= &t1_recinfo[i]; |
809 | MARIA_COLUMNDEF *t2_rec= &t2_recinfo[i]; |
810 | /* |
811 | FIELD_SKIP_ZERO can be changed to FIELD_NORMAL in maria_create, |
812 | see NOTE1 in ma_create.c |
813 | */ |
814 | if ((t1_rec->type != t2_rec->type && |
815 | !(t1_rec->type == (int) FIELD_SKIP_ZERO && |
816 | t1_rec->length == 1 && |
817 | t2_rec->type == (int) FIELD_NORMAL)) || |
818 | t1_rec->length != t2_rec->length || |
819 | t1_rec->null_bit != t2_rec->null_bit) |
820 | { |
821 | DBUG_PRINT("error" , ("Field %d has different definition" , i)); |
822 | DBUG_PRINT("error" , ("t1_type=%d, t1_length=%d, t1_null_bit=%d" , |
823 | t1_rec->type, t1_rec->length, t1_rec->null_bit)); |
824 | DBUG_PRINT("error" , ("t2_type=%d, t2_length=%d, t2_null_bit=%d" , |
825 | t2_rec->type, t2_rec->length, t2_rec->null_bit)); |
826 | DBUG_RETURN(1); |
827 | } |
828 | } |
829 | DBUG_RETURN(0); |
830 | } |
831 | |
832 | |
833 | extern "C" { |
834 | |
835 | int _ma_killed_ptr(HA_CHECK *param) |
836 | { |
837 | if (likely(thd_killed((THD*)param->thd)) == 0) |
838 | return 0; |
839 | my_errno= HA_ERR_ABORTED_BY_USER; |
840 | return 1; |
841 | } |
842 | |
843 | |
844 | /* |
845 | Report progress to mysqld |
846 | |
847 | This is a bit more complex than what a normal progress report |
848 | function normally is. |
849 | |
850 | The reason is that this is called by enable_index/repair which |
851 | is one stage in ALTER TABLE and we can't use the external |
852 | stage/max_stage for this. |
853 | |
854 | thd_progress_init/thd_progress_next_stage is to be called by |
855 | high level commands like CHECK TABLE or REPAIR TABLE, not |
856 | by sub commands like enable_index(). |
857 | |
858 | In ma_check.c it's easier to work with stages than with a total |
859 | progress, so we use internal stage/max_stage here to keep the |
860 | code simple. |
861 | */ |
862 | |
863 | void _ma_report_progress(HA_CHECK *param, ulonglong progress, |
864 | ulonglong max_progress) |
865 | { |
866 | thd_progress_report((THD*)param->thd, |
867 | progress + max_progress * param->stage, |
868 | max_progress * param->max_stage); |
869 | } |
870 | |
871 | |
872 | void _ma_check_print_error(HA_CHECK *param, const char *fmt, ...) |
873 | { |
874 | va_list args; |
875 | DBUG_ENTER("_ma_check_print_error" ); |
876 | param->error_printed |= 1; |
877 | param->out_flag |= O_DATA_LOST; |
878 | if (param->testflag & T_SUPPRESS_ERR_HANDLING) |
879 | DBUG_VOID_RETURN; |
880 | va_start(args, fmt); |
881 | _ma_check_print_msg(param, "error" , fmt, args); |
882 | va_end(args); |
883 | DBUG_VOID_RETURN; |
884 | } |
885 | |
886 | |
887 | void _ma_check_print_info(HA_CHECK *param, const char *fmt, ...) |
888 | { |
889 | va_list args; |
890 | DBUG_ENTER("_ma_check_print_info" ); |
891 | va_start(args, fmt); |
892 | _ma_check_print_msg(param, "info" , fmt, args); |
893 | va_end(args); |
894 | DBUG_VOID_RETURN; |
895 | } |
896 | |
897 | |
898 | void _ma_check_print_warning(HA_CHECK *param, const char *fmt, ...) |
899 | { |
900 | va_list args; |
901 | DBUG_ENTER("_ma_check_print_warning" ); |
902 | param->warning_printed= 1; |
903 | param->out_flag |= O_DATA_LOST; |
904 | va_start(args, fmt); |
905 | _ma_check_print_msg(param, "warning" , fmt, args); |
906 | va_end(args); |
907 | DBUG_VOID_RETURN; |
908 | } |
909 | |
910 | /* |
911 | Create a transaction object |
912 | |
913 | SYNOPSIS |
914 | info Maria handler |
915 | |
916 | RETURN |
917 | 0 ok |
918 | # Error number (HA_ERR_OUT_OF_MEM) |
919 | */ |
920 | |
921 | static int maria_create_trn_for_mysql(MARIA_HA *info) |
922 | { |
923 | THD *thd= ((TABLE*) info->external_ref)->in_use; |
924 | TRN *trn= THD_TRN; |
925 | DBUG_ENTER("maria_create_trn_for_mysql" ); |
926 | |
927 | if (!trn) /* no transaction yet - open it now */ |
928 | { |
929 | trn= trnman_new_trn(& thd->transaction.wt); |
930 | if (unlikely(!trn)) |
931 | DBUG_RETURN(HA_ERR_OUT_OF_MEM); |
932 | THD_TRN= trn; |
933 | if (thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) |
934 | trans_register_ha(thd, TRUE, maria_hton); |
935 | } |
936 | _ma_set_trn_for_table(info, trn); |
937 | if (!trnman_increment_locked_tables(trn)) |
938 | { |
939 | trans_register_ha(thd, FALSE, maria_hton); |
940 | trnman_new_statement(trn); |
941 | } |
942 | #ifdef EXTRA_DEBUG |
943 | if (info->lock_type == F_WRLCK && |
944 | ! (trnman_get_flags(trn) & TRN_STATE_INFO_LOGGED)) |
945 | { |
946 | trnman_set_flags(trn, trnman_get_flags(trn) | TRN_STATE_INFO_LOGGED | |
947 | TRN_STATE_TABLES_CAN_CHANGE); |
948 | (void) translog_log_debug_info(trn, LOGREC_DEBUG_INFO_QUERY, |
949 | (uchar*) thd->query(), |
950 | thd->query_length()); |
951 | } |
952 | else |
953 | { |
954 | DBUG_PRINT("info" , ("lock_type: %d trnman_flags: %u" , |
955 | info->lock_type, trnman_get_flags(trn))); |
956 | } |
957 | |
958 | #endif |
959 | DBUG_RETURN(0); |
960 | } |
961 | |
962 | my_bool ma_killed_in_mariadb(MARIA_HA *info) |
963 | { |
964 | return (((TABLE*) (info->external_ref))->in_use->killed != 0); |
965 | } |
966 | |
967 | } /* extern "C" */ |
968 | |
969 | /** |
970 | Transactional table doing bulk insert with one single UNDO |
971 | (UNDO_BULK_INSERT) and with repair. |
972 | */ |
973 | #define BULK_INSERT_SINGLE_UNDO_AND_REPAIR 1 |
974 | /** |
975 | Transactional table doing bulk insert with one single UNDO |
976 | (UNDO_BULK_INSERT) and without repair. |
977 | */ |
978 | #define BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR 2 |
979 | /** |
980 | None of BULK_INSERT_SINGLE_UNDO_AND_REPAIR and |
981 | BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR. |
982 | */ |
983 | #define BULK_INSERT_NONE 0 |
984 | |
985 | ha_maria::ha_maria(handlerton *hton, TABLE_SHARE *table_arg): |
986 | handler(hton, table_arg), file(0), |
987 | int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | |
988 | HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | |
989 | HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY | |
990 | HA_FILE_BASED | HA_CAN_GEOMETRY | CANNOT_ROLLBACK_FLAG | |
991 | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS | HA_CAN_REPAIR | |
992 | HA_CAN_VIRTUAL_COLUMNS | HA_CAN_EXPORT | |
993 | HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT | |
994 | HA_CAN_TABLES_WITHOUT_ROLLBACK), |
995 | can_enable_indexes(1), bulk_insert_single_undo(BULK_INSERT_NONE) |
996 | {} |
997 | |
998 | |
999 | handler *ha_maria::clone(const char *name, MEM_ROOT *mem_root) |
1000 | { |
1001 | ha_maria *new_handler= static_cast <ha_maria *>(handler::clone(name, |
1002 | mem_root)); |
1003 | if (new_handler) |
1004 | { |
1005 | new_handler->file->state= file->state; |
1006 | /* maria_create_trn_for_mysql() is never called for clone() tables */ |
1007 | new_handler->file->trn= file->trn; |
1008 | } |
1009 | return new_handler; |
1010 | } |
1011 | |
1012 | |
1013 | static const char *ha_maria_exts[]= |
1014 | { |
1015 | MARIA_NAME_IEXT, |
1016 | MARIA_NAME_DEXT, |
1017 | NullS |
1018 | }; |
1019 | |
1020 | |
1021 | const char *ha_maria::index_type(uint key_number) |
1022 | { |
1023 | return ((table->key_info[key_number].flags & HA_FULLTEXT) ? |
1024 | "FULLTEXT" : |
1025 | (table->key_info[key_number].flags & HA_SPATIAL) ? |
1026 | "SPATIAL" : |
1027 | (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ? |
1028 | "RTREE" : "BTREE" ); |
1029 | } |
1030 | |
1031 | |
1032 | ulong ha_maria::index_flags(uint inx, uint part, bool all_parts) const |
1033 | { |
1034 | ulong flags; |
1035 | if (table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) |
1036 | flags= 0; |
1037 | else |
1038 | if ((table_share->key_info[inx].flags & HA_SPATIAL || |
1039 | table_share->key_info[inx].algorithm == HA_KEY_ALG_RTREE)) |
1040 | { |
1041 | /* All GIS scans are non-ROR scans. We also disable IndexConditionPushdown */ |
1042 | flags= HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | |
1043 | HA_READ_ORDER | HA_KEYREAD_ONLY | HA_KEY_SCAN_NOT_ROR; |
1044 | } |
1045 | else |
1046 | { |
1047 | flags= HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | |
1048 | HA_READ_ORDER | HA_KEYREAD_ONLY | HA_DO_INDEX_COND_PUSHDOWN; |
1049 | } |
1050 | return flags; |
1051 | } |
1052 | |
1053 | |
1054 | double ha_maria::scan_time() |
1055 | { |
1056 | if (file->s->data_file_type == BLOCK_RECORD) |
1057 | return ulonglong2double(stats.data_file_length - file->s->block_size) / MY_MAX(file->s->block_size / 2, IO_SIZE) + 2; |
1058 | return handler::scan_time(); |
1059 | } |
1060 | |
1061 | /* |
1062 | We need to be able to store at least 2 keys on an index page as the |
1063 | splitting algorithms depends on this. (With only one key on a page |
1064 | we also can't use any compression, which may make the index file much |
1065 | larger) |
1066 | We use HA_MAX_KEY_LENGTH as this is a stack restriction imposed by the |
1067 | handler interface. If we want to increase this, we have also to |
1068 | increase HA_MARIA_KEY_BUFF and MARIA_MAX_KEY_BUFF as the buffer needs |
1069 | to take be able to store the extra lenght bytes that is part of the stored |
1070 | key. |
1071 | |
1072 | We also need to reserve place for a record pointer (8) and 3 bytes |
1073 | per key segment to store the length of the segment + possible null bytes. |
1074 | These extra bytes are required here so that maria_create() will surely |
1075 | accept any keys created which the returned key data storage length. |
1076 | */ |
1077 | |
1078 | uint ha_maria::max_supported_key_length() const |
1079 | { |
1080 | return maria_max_key_length(); |
1081 | } |
1082 | |
1083 | |
1084 | #ifdef HAVE_REPLICATION |
1085 | int ha_maria::net_read_dump(NET * net) |
1086 | { |
1087 | int data_fd= file->dfile.file; |
1088 | int error= 0; |
1089 | |
1090 | mysql_file_seek(data_fd, 0L, MY_SEEK_SET, MYF(MY_WME)); |
1091 | for (;;) |
1092 | { |
1093 | ulong packet_len= my_net_read(net); |
1094 | if (!packet_len) |
1095 | break; // end of file |
1096 | if (packet_len == packet_error) |
1097 | { |
1098 | sql_print_error("ha_maria::net_read_dump - read error " ); |
1099 | error= -1; |
1100 | goto err; |
1101 | } |
1102 | if (mysql_file_write(data_fd, (uchar *) net->read_pos, (uint) packet_len, |
1103 | MYF(MY_WME | MY_FNABP))) |
1104 | { |
1105 | error= errno; |
1106 | goto err; |
1107 | } |
1108 | } |
1109 | err: |
1110 | return error; |
1111 | } |
1112 | |
1113 | |
1114 | int ha_maria::dump(THD * thd, int fd) |
1115 | { |
1116 | MARIA_SHARE *share= file->s; |
1117 | NET *net= &thd->net; |
1118 | uint block_size= share->block_size; |
1119 | my_off_t bytes_to_read= share->state.state.data_file_length; |
1120 | int data_fd= file->dfile.file; |
1121 | uchar *buf= (uchar *) my_malloc(block_size, MYF(MY_WME)); |
1122 | if (!buf) |
1123 | return ENOMEM; |
1124 | |
1125 | int error= 0; |
1126 | mysql_file_seek(data_fd, 0L, MY_SEEK_SET, MYF(MY_WME)); |
1127 | for (; bytes_to_read > 0;) |
1128 | { |
1129 | size_t bytes= mysql_file_read(data_fd, buf, block_size, MYF(MY_WME)); |
1130 | if (bytes == MY_FILE_ERROR) |
1131 | { |
1132 | error= errno; |
1133 | goto err; |
1134 | } |
1135 | |
1136 | if (fd >= 0) |
1137 | { |
1138 | if (mysql_file_write(fd, buf, bytes, MYF(MY_WME | MY_FNABP))) |
1139 | { |
1140 | error= errno ? errno : EPIPE; |
1141 | goto err; |
1142 | } |
1143 | } |
1144 | else |
1145 | { |
1146 | if (my_net_write(net, buf, bytes)) |
1147 | { |
1148 | error= errno ? errno : EPIPE; |
1149 | goto err; |
1150 | } |
1151 | } |
1152 | bytes_to_read -= bytes; |
1153 | } |
1154 | |
1155 | if (fd < 0) |
1156 | { |
1157 | if (my_net_write(net, (uchar*) "" , 0)) |
1158 | error= errno ? errno : EPIPE; |
1159 | net_flush(net); |
1160 | } |
1161 | |
1162 | err: |
1163 | my_free(buf); |
1164 | return error; |
1165 | } |
1166 | #endif /* HAVE_REPLICATION */ |
1167 | |
1168 | /* Name is here without an extension */ |
1169 | |
1170 | int ha_maria::open(const char *name, int mode, uint test_if_locked) |
1171 | { |
1172 | uint i; |
1173 | |
1174 | #ifdef NOT_USED |
1175 | /* |
1176 | If the user wants to have memory mapped data files, add an |
1177 | open_flag. Do not memory map temporary tables because they are |
1178 | expected to be inserted and thus extended a lot. Memory mapping is |
1179 | efficient for files that keep their size, but very inefficient for |
1180 | growing files. Using an open_flag instead of calling ma_extra(... |
1181 | HA_EXTRA_MMAP ...) after maxs_open() has the advantage that the |
1182 | mapping is not repeated for every open, but just done on the initial |
1183 | open, when the MyISAM share is created. Every time the server |
1184 | requires to open a new instance of a table it calls this method. We |
1185 | will always supply HA_OPEN_MMAP for a permanent table. However, the |
1186 | Maria storage engine will ignore this flag if this is a secondary |
1187 | open of a table that is in use by other threads already (if the |
1188 | Maria share exists already). |
1189 | */ |
1190 | if (!(test_if_locked & HA_OPEN_TMP_TABLE) && opt_maria_use_mmap) |
1191 | test_if_locked|= HA_OPEN_MMAP; |
1192 | #endif |
1193 | |
1194 | if (maria_recover_options & HA_RECOVER_ANY) |
1195 | { |
1196 | /* user asked to trigger a repair if table was not properly closed */ |
1197 | test_if_locked|= HA_OPEN_ABORT_IF_CRASHED; |
1198 | } |
1199 | |
1200 | if (!(file= maria_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER))) |
1201 | { |
1202 | if (my_errno == HA_ERR_OLD_FILE) |
1203 | { |
1204 | push_warning(current_thd, Sql_condition::WARN_LEVEL_NOTE, |
1205 | ER_CRASHED_ON_USAGE, |
1206 | zerofill_error_msg); |
1207 | } |
1208 | return (my_errno ? my_errno : -1); |
1209 | } |
1210 | |
1211 | file->s->chst_invalidator= query_cache_invalidate_by_MyISAM_filename_ref; |
1212 | /* Set external_ref, mainly for temporary tables */ |
1213 | file->external_ref= (void*) table; // For ma_killed() |
1214 | |
1215 | if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE)) |
1216 | maria_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0); |
1217 | |
1218 | info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST); |
1219 | if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED)) |
1220 | maria_extra(file, HA_EXTRA_WAIT_LOCK, 0); |
1221 | if ((data_file_type= file->s->data_file_type) != STATIC_RECORD) |
1222 | int_table_flags |= HA_REC_NOT_IN_SEQ; |
1223 | if (!file->s->base.born_transactional) |
1224 | { |
1225 | /* |
1226 | INSERT DELAYED cannot work with transactional tables (because it cannot |
1227 | stand up to "when client gets ok the data is safe on disk": the record |
1228 | may not even be inserted). In the future, we could enable it back (as a |
1229 | client doing INSERT DELAYED knows the specificities; but we then should |
1230 | make sure to regularly commit in the delayed_insert thread). |
1231 | */ |
1232 | int_table_flags|= HA_CAN_INSERT_DELAYED; |
1233 | } |
1234 | if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)) |
1235 | int_table_flags |= HA_HAS_NEW_CHECKSUM; |
1236 | |
1237 | /* |
1238 | For static size rows, tell MariaDB that we will access all bytes |
1239 | in the record when writing it. This signals MariaDB to initalize |
1240 | the full row to ensure we don't get any errors from valgrind and |
1241 | that all bytes in the row is properly reset. |
1242 | */ |
1243 | if (file->s->data_file_type == STATIC_RECORD && |
1244 | (file->s->has_varchar_fields | file->s->has_null_fields)) |
1245 | int_table_flags|= HA_RECORD_MUST_BE_CLEAN_ON_WRITE; |
1246 | |
1247 | for (i= 0; i < table->s->keys; i++) |
1248 | { |
1249 | plugin_ref parser= table->key_info[i].parser; |
1250 | if (table->key_info[i].flags & HA_USES_PARSER) |
1251 | file->s->keyinfo[i].parser= |
1252 | (struct st_mysql_ftparser *)plugin_decl(parser)->info; |
1253 | table->key_info[i].block_size= file->s->keyinfo[i].block_length; |
1254 | } |
1255 | my_errno= 0; |
1256 | |
1257 | /* Count statistics of usage for newly open normal files */ |
1258 | if (file->s->reopen == 1 && ! (test_if_locked & HA_OPEN_TMP_TABLE)) |
1259 | { |
1260 | if (file->s->delay_key_write) |
1261 | feature_files_opened_with_delayed_keys++; |
1262 | } |
1263 | |
1264 | return my_errno; |
1265 | } |
1266 | |
1267 | |
1268 | int ha_maria::close(void) |
1269 | { |
1270 | MARIA_HA *tmp= file; |
1271 | if (!tmp) |
1272 | return 0; |
1273 | file= 0; |
1274 | return maria_close(tmp); |
1275 | } |
1276 | |
1277 | |
1278 | int ha_maria::write_row(uchar * buf) |
1279 | { |
1280 | /* |
1281 | If we have an auto_increment column and we are writing a changed row |
1282 | or a new row, then update the auto_increment value in the record. |
1283 | */ |
1284 | if (table->next_number_field && buf == table->record[0]) |
1285 | { |
1286 | int error; |
1287 | if ((error= update_auto_increment())) |
1288 | return error; |
1289 | } |
1290 | return maria_write(file, buf); |
1291 | } |
1292 | |
1293 | |
1294 | int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt) |
1295 | { |
1296 | int error; |
1297 | HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param); |
1298 | MARIA_SHARE *share= file->s; |
1299 | const char *old_proc_info; |
1300 | TRN *old_trn= file->trn; |
1301 | |
1302 | if (!file || !param) return HA_ADMIN_INTERNAL_ERROR; |
1303 | |
1304 | maria_chk_init(param); |
1305 | param->thd= thd; |
1306 | param->op_name= "check" ; |
1307 | param->db_name= table->s->db.str; |
1308 | param->table_name= table->alias.c_ptr(); |
1309 | param->testflag= check_opt->flags | T_CHECK | T_SILENT; |
1310 | param->stats_method= (enum_handler_stats_method)THDVAR(thd,stats_method); |
1311 | |
1312 | if (!(table->db_stat & HA_READ_ONLY)) |
1313 | param->testflag |= T_STATISTICS; |
1314 | param->using_global_keycache= 1; |
1315 | |
1316 | if (!maria_is_crashed(file) && |
1317 | (((param->testflag & T_CHECK_ONLY_CHANGED) && |
1318 | !(share->state.changed & (STATE_CHANGED | STATE_CRASHED_FLAGS | |
1319 | STATE_IN_REPAIR)) && |
1320 | share->state.open_count == 0) || |
1321 | ((param->testflag & T_FAST) && (share->state.open_count == |
1322 | (uint) (share->global_changed ? 1 : |
1323 | 0))))) |
1324 | return HA_ADMIN_ALREADY_DONE; |
1325 | |
1326 | maria_chk_init_for_check(param, file); |
1327 | |
1328 | if ((file->s->state.changed & (STATE_CRASHED_FLAGS | STATE_MOVED)) == |
1329 | STATE_MOVED) |
1330 | { |
1331 | _ma_check_print_error(param, "%s" , zerofill_error_msg); |
1332 | return HA_ADMIN_CORRUPT; |
1333 | } |
1334 | |
1335 | old_proc_info= thd_proc_info(thd, "Checking status" ); |
1336 | thd_progress_init(thd, 3); |
1337 | error= maria_chk_status(param, file); // Not fatal |
1338 | /* maria_chk_size() will flush the page cache for this file */ |
1339 | if (maria_chk_size(param, file)) |
1340 | error= 1; |
1341 | if (!error) |
1342 | error|= maria_chk_del(param, file, param->testflag); |
1343 | thd_proc_info(thd, "Checking keys" ); |
1344 | thd_progress_next_stage(thd); |
1345 | if (!error) |
1346 | error= maria_chk_key(param, file); |
1347 | thd_proc_info(thd, "Checking data" ); |
1348 | thd_progress_next_stage(thd); |
1349 | if (!error) |
1350 | { |
1351 | if ((!(param->testflag & T_QUICK) && |
1352 | ((share->options & |
1353 | (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) || |
1354 | (param->testflag & (T_EXTEND | T_MEDIUM)))) || maria_is_crashed(file)) |
1355 | { |
1356 | ulonglong old_testflag= param->testflag; |
1357 | param->testflag |= T_MEDIUM; |
1358 | if (!(error= init_io_cache(¶m->read_cache, file->dfile.file, |
1359 | my_default_record_cache_size, READ_CACHE, |
1360 | share->pack.header_length, 1, MYF(MY_WME)))) |
1361 | { |
1362 | error= maria_chk_data_link(param, file, |
1363 | MY_TEST(param->testflag & T_EXTEND)); |
1364 | end_io_cache(¶m->read_cache); |
1365 | } |
1366 | param->testflag= old_testflag; |
1367 | } |
1368 | } |
1369 | if (!error) |
1370 | { |
1371 | if ((share->state.changed & (STATE_CHANGED | |
1372 | STATE_CRASHED_FLAGS | |
1373 | STATE_IN_REPAIR | STATE_NOT_ANALYZED)) || |
1374 | (param->testflag & T_STATISTICS) || maria_is_crashed(file)) |
1375 | { |
1376 | file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; |
1377 | mysql_mutex_lock(&share->intern_lock); |
1378 | DBUG_PRINT("info" , ("Reseting crashed state" )); |
1379 | share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED_FLAGS | |
1380 | STATE_IN_REPAIR); |
1381 | if (!(table->db_stat & HA_READ_ONLY)) |
1382 | error= maria_update_state_info(param, file, |
1383 | UPDATE_TIME | UPDATE_OPEN_COUNT | |
1384 | UPDATE_STAT); |
1385 | mysql_mutex_unlock(&share->intern_lock); |
1386 | info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE | |
1387 | HA_STATUS_CONST); |
1388 | } |
1389 | } |
1390 | else if (!maria_is_crashed(file) && !thd->killed) |
1391 | { |
1392 | maria_mark_crashed(file); |
1393 | file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; |
1394 | } |
1395 | |
1396 | /* Reset trn, that may have been set by repair */ |
1397 | _ma_set_trn_for_table(file, old_trn); |
1398 | thd_proc_info(thd, old_proc_info); |
1399 | thd_progress_end(thd); |
1400 | return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK; |
1401 | } |
1402 | |
1403 | |
1404 | /* |
1405 | Analyze the key distribution in the table |
1406 | As the table may be only locked for read, we have to take into account that |
1407 | two threads may do an analyze at the same time! |
1408 | */ |
1409 | |
1410 | int ha_maria::analyze(THD *thd, HA_CHECK_OPT * check_opt) |
1411 | { |
1412 | int error= 0; |
1413 | HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param); |
1414 | MARIA_SHARE *share= file->s; |
1415 | const char *old_proc_info; |
1416 | |
1417 | if (!param) |
1418 | return HA_ADMIN_INTERNAL_ERROR; |
1419 | |
1420 | maria_chk_init(param); |
1421 | param->thd= thd; |
1422 | param->op_name= "analyze" ; |
1423 | param->db_name= table->s->db.str; |
1424 | param->table_name= table->alias.c_ptr(); |
1425 | param->testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS | |
1426 | T_DONT_CHECK_CHECKSUM); |
1427 | param->using_global_keycache= 1; |
1428 | param->stats_method= (enum_handler_stats_method)THDVAR(thd,stats_method); |
1429 | |
1430 | if (!(share->state.changed & STATE_NOT_ANALYZED)) |
1431 | return HA_ADMIN_ALREADY_DONE; |
1432 | |
1433 | old_proc_info= thd_proc_info(thd, "Scanning" ); |
1434 | thd_progress_init(thd, 1); |
1435 | error= maria_chk_key(param, file); |
1436 | if (!error) |
1437 | { |
1438 | mysql_mutex_lock(&share->intern_lock); |
1439 | error= maria_update_state_info(param, file, UPDATE_STAT); |
1440 | mysql_mutex_unlock(&share->intern_lock); |
1441 | } |
1442 | else if (!maria_is_crashed(file) && !thd->killed) |
1443 | maria_mark_crashed(file); |
1444 | thd_proc_info(thd, old_proc_info); |
1445 | thd_progress_end(thd); |
1446 | return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK; |
1447 | } |
1448 | |
1449 | int ha_maria::repair(THD * thd, HA_CHECK_OPT *check_opt) |
1450 | { |
1451 | int error; |
1452 | HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param); |
1453 | ha_rows start_records; |
1454 | const char *old_proc_info; |
1455 | |
1456 | if (!file || !param) |
1457 | return HA_ADMIN_INTERNAL_ERROR; |
1458 | |
1459 | maria_chk_init(param); |
1460 | param->thd= thd; |
1461 | param->op_name= "repair" ; |
1462 | param->testflag= ((check_opt->flags & ~(T_EXTEND)) | |
1463 | T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM | |
1464 | (check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT)); |
1465 | param->sort_buffer_length= THDVAR(thd, sort_buffer_size); |
1466 | param->backup_time= check_opt->start_time; |
1467 | start_records= file->state->records; |
1468 | old_proc_info= thd_proc_info(thd, "Checking table" ); |
1469 | thd_progress_init(thd, 1); |
1470 | while ((error= repair(thd, param, 0)) && param->retry_repair) |
1471 | { |
1472 | param->retry_repair= 0; |
1473 | if (test_all_bits(param->testflag, |
1474 | (uint) (T_RETRY_WITHOUT_QUICK | T_QUICK))) |
1475 | { |
1476 | param->testflag&= ~(T_RETRY_WITHOUT_QUICK | T_QUICK); |
1477 | /* Ensure we don't loose any rows when retrying without quick */ |
1478 | param->testflag|= T_SAFE_REPAIR; |
1479 | if (thd->vio_ok()) |
1480 | _ma_check_print_info(param, "Retrying repair without quick" ); |
1481 | else |
1482 | sql_print_information("Retrying repair of: '%s' without quick" , |
1483 | table->s->path.str); |
1484 | continue; |
1485 | } |
1486 | param->testflag &= ~T_QUICK; |
1487 | if (param->testflag & T_REP_BY_SORT) |
1488 | { |
1489 | param->testflag= (param->testflag & ~T_REP_BY_SORT) | T_REP; |
1490 | if (thd->vio_ok()) |
1491 | _ma_check_print_info(param, "Retrying repair with keycache" ); |
1492 | sql_print_information("Retrying repair of: '%s' with keycache" , |
1493 | table->s->path.str); |
1494 | continue; |
1495 | } |
1496 | break; |
1497 | } |
1498 | if (!error && start_records != file->state->records && |
1499 | !(check_opt->flags & T_VERY_SILENT)) |
1500 | { |
1501 | char llbuff[22], llbuff2[22]; |
1502 | sql_print_information("Found %s of %s rows when repairing '%s'" , |
1503 | llstr(file->state->records, llbuff), |
1504 | llstr(start_records, llbuff2), |
1505 | table->s->path.str); |
1506 | } |
1507 | thd_proc_info(thd, old_proc_info); |
1508 | thd_progress_end(thd); |
1509 | return error; |
1510 | } |
1511 | |
1512 | int ha_maria::zerofill(THD * thd, HA_CHECK_OPT *check_opt) |
1513 | { |
1514 | int error; |
1515 | HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param); |
1516 | TRN *old_trn; |
1517 | MARIA_SHARE *share= file->s; |
1518 | |
1519 | if (!file || !param) |
1520 | return HA_ADMIN_INTERNAL_ERROR; |
1521 | |
1522 | old_trn= file->trn; |
1523 | maria_chk_init(param); |
1524 | param->thd= thd; |
1525 | param->op_name= "zerofill" ; |
1526 | param->testflag= check_opt->flags | T_SILENT | T_ZEROFILL; |
1527 | param->sort_buffer_length= THDVAR(thd, sort_buffer_size); |
1528 | error=maria_zerofill(param, file, share->open_file_name.str); |
1529 | |
1530 | /* Reset trn, that may have been set by repair */ |
1531 | _ma_set_trn_for_table(file, old_trn); |
1532 | |
1533 | if (!error) |
1534 | { |
1535 | TrID create_trid= trnman_get_min_safe_trid(); |
1536 | mysql_mutex_lock(&share->intern_lock); |
1537 | share->state.changed|= STATE_NOT_MOVABLE; |
1538 | maria_update_state_info(param, file, UPDATE_TIME | UPDATE_OPEN_COUNT); |
1539 | _ma_update_state_lsns_sub(share, LSN_IMPOSSIBLE, create_trid, |
1540 | TRUE, TRUE); |
1541 | mysql_mutex_unlock(&share->intern_lock); |
1542 | } |
1543 | return error; |
1544 | } |
1545 | |
1546 | int ha_maria::optimize(THD * thd, HA_CHECK_OPT *check_opt) |
1547 | { |
1548 | int error; |
1549 | HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param); |
1550 | |
1551 | if (!file || !param) |
1552 | return HA_ADMIN_INTERNAL_ERROR; |
1553 | |
1554 | maria_chk_init(param); |
1555 | param->thd= thd; |
1556 | param->op_name= "optimize" ; |
1557 | param->testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE | |
1558 | T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX); |
1559 | param->sort_buffer_length= THDVAR(thd, sort_buffer_size); |
1560 | thd_progress_init(thd, 1); |
1561 | if ((error= repair(thd, param, 1)) && param->retry_repair) |
1562 | { |
1563 | sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying" , |
1564 | my_errno, param->db_name, param->table_name); |
1565 | param->testflag &= ~T_REP_BY_SORT; |
1566 | error= repair(thd, param, 0); |
1567 | } |
1568 | thd_progress_end(thd); |
1569 | return error; |
1570 | } |
1571 | |
1572 | |
1573 | int ha_maria::repair(THD *thd, HA_CHECK *param, bool do_optimize) |
1574 | { |
1575 | int error= 0; |
1576 | ulonglong local_testflag= param->testflag; |
1577 | bool optimize_done= !do_optimize, statistics_done= 0, full_repair_done= 0; |
1578 | const char *old_proc_info= thd->proc_info; |
1579 | char fixed_name[FN_REFLEN]; |
1580 | MARIA_SHARE *share= file->s; |
1581 | ha_rows rows= file->state->records; |
1582 | TRN *old_trn= file->trn; |
1583 | my_bool locking= 0; |
1584 | DBUG_ENTER("ha_maria::repair" ); |
1585 | |
1586 | /* |
1587 | Normally this method is entered with a properly opened table. If the |
1588 | repair fails, it can be repeated with more elaborate options. Under |
1589 | special circumstances it can happen that a repair fails so that it |
1590 | closed the data file and cannot re-open it. In this case file->dfile |
1591 | is set to -1. We must not try another repair without an open data |
1592 | file. (Bug #25289) |
1593 | */ |
1594 | if (file->dfile.file == -1) |
1595 | { |
1596 | sql_print_information("Retrying repair of: '%s' failed. " |
1597 | "Please try REPAIR EXTENDED or aria_chk" , |
1598 | table->s->path.str); |
1599 | DBUG_RETURN(HA_ADMIN_FAILED); |
1600 | } |
1601 | |
1602 | /* |
1603 | If transactions was not enabled for a transactional table then |
1604 | file->s->status is not up to date. This is needed for repair_by_sort |
1605 | to work |
1606 | */ |
1607 | if (share->base.born_transactional && !share->now_transactional) |
1608 | _ma_copy_nontrans_state_information(file); |
1609 | |
1610 | param->db_name= table->s->db.str; |
1611 | param->table_name= table->alias.c_ptr(); |
1612 | param->tmpfile_createflag= O_RDWR | O_TRUNC; |
1613 | param->using_global_keycache= 1; |
1614 | param->thd= thd; |
1615 | param->tmpdir= &mysql_tmpdir_list; |
1616 | param->out_flag= 0; |
1617 | share->state.dupp_key= MI_MAX_KEY; |
1618 | strmov(fixed_name, share->open_file_name.str); |
1619 | |
1620 | /* |
1621 | Don't lock tables if we have used LOCK TABLE or if we come from |
1622 | enable_index() |
1623 | */ |
1624 | if (!thd->locked_tables_mode && ! (param->testflag & T_NO_LOCKS)) |
1625 | { |
1626 | locking= 1; |
1627 | if (maria_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK)) |
1628 | { |
1629 | _ma_check_print_error(param, ER_THD(thd, ER_CANT_LOCK), my_errno); |
1630 | DBUG_RETURN(HA_ADMIN_FAILED); |
1631 | } |
1632 | } |
1633 | |
1634 | if (!do_optimize || |
1635 | (((share->data_file_type == BLOCK_RECORD) ? |
1636 | (share->state.changed & STATE_NOT_OPTIMIZED_ROWS) : |
1637 | (file->state->del || |
1638 | share->state.split != file->state->records)) && |
1639 | (!(param->testflag & T_QUICK) || |
1640 | (share->state.changed & (STATE_NOT_OPTIMIZED_KEYS | |
1641 | STATE_NOT_OPTIMIZED_ROWS))))) |
1642 | { |
1643 | ulonglong key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ? |
1644 | maria_get_mask_all_keys_active(share->base.keys) : |
1645 | share->state.key_map); |
1646 | ulonglong save_testflag= param->testflag; |
1647 | if (maria_test_if_sort_rep(file, file->state->records, key_map, 0) && |
1648 | (local_testflag & T_REP_BY_SORT)) |
1649 | { |
1650 | local_testflag |= T_STATISTICS; |
1651 | param->testflag |= T_STATISTICS; // We get this for free |
1652 | statistics_done= 1; |
1653 | /* TODO: Remove BLOCK_RECORD test when parallel works with blocks */ |
1654 | if (THDVAR(thd,repair_threads) > 1 && |
1655 | share->data_file_type != BLOCK_RECORD) |
1656 | { |
1657 | char buf[40]; |
1658 | /* TODO: respect maria_repair_threads variable */ |
1659 | my_snprintf(buf, 40, "Repair with %d threads" , my_count_bits(key_map)); |
1660 | thd_proc_info(thd, buf); |
1661 | param->testflag|= T_REP_PARALLEL; |
1662 | error= maria_repair_parallel(param, file, fixed_name, |
1663 | MY_TEST(param->testflag & T_QUICK)); |
1664 | /* to reset proc_info, as it was pointing to local buffer */ |
1665 | thd_proc_info(thd, "Repair done" ); |
1666 | } |
1667 | else |
1668 | { |
1669 | thd_proc_info(thd, "Repair by sorting" ); |
1670 | param->testflag|= T_REP_BY_SORT; |
1671 | error= maria_repair_by_sort(param, file, fixed_name, |
1672 | MY_TEST(param->testflag & T_QUICK)); |
1673 | } |
1674 | if (error && file->create_unique_index_by_sort && |
1675 | share->state.dupp_key != MAX_KEY) |
1676 | { |
1677 | my_errno= HA_ERR_FOUND_DUPP_KEY; |
1678 | print_keydup_error(table, &table->key_info[share->state.dupp_key], |
1679 | MYF(0)); |
1680 | } |
1681 | } |
1682 | else |
1683 | { |
1684 | thd_proc_info(thd, "Repair with keycache" ); |
1685 | param->testflag &= ~(T_REP_BY_SORT | T_REP_PARALLEL); |
1686 | error= maria_repair(param, file, fixed_name, |
1687 | MY_TEST(param->testflag & T_QUICK)); |
1688 | } |
1689 | param->testflag= save_testflag | (param->testflag & T_RETRY_WITHOUT_QUICK); |
1690 | optimize_done= 1; |
1691 | /* |
1692 | set full_repair_done if we re-wrote all rows and all keys |
1693 | (and thus removed all transid's from the table |
1694 | */ |
1695 | full_repair_done= !MY_TEST(param->testflag & T_QUICK); |
1696 | } |
1697 | if (!error) |
1698 | { |
1699 | if ((local_testflag & T_SORT_INDEX) && |
1700 | (share->state.changed & STATE_NOT_SORTED_PAGES)) |
1701 | { |
1702 | optimize_done= 1; |
1703 | thd_proc_info(thd, "Sorting index" ); |
1704 | error= maria_sort_index(param, file, fixed_name); |
1705 | } |
1706 | if (!error && !statistics_done && (local_testflag & T_STATISTICS)) |
1707 | { |
1708 | if (share->state.changed & STATE_NOT_ANALYZED) |
1709 | { |
1710 | optimize_done= 1; |
1711 | thd_proc_info(thd, "Analyzing" ); |
1712 | error= maria_chk_key(param, file); |
1713 | } |
1714 | else |
1715 | local_testflag &= ~T_STATISTICS; // Don't update statistics |
1716 | } |
1717 | } |
1718 | thd_proc_info(thd, "Saving state" ); |
1719 | if (full_repair_done && !error && |
1720 | !(param->testflag & T_NO_CREATE_RENAME_LSN)) |
1721 | { |
1722 | /* Set trid (needed if the table was moved from another system) */ |
1723 | share->state.create_trid= trnman_get_min_safe_trid(); |
1724 | } |
1725 | mysql_mutex_lock(&share->intern_lock); |
1726 | if (!error) |
1727 | { |
1728 | if ((share->state.changed & STATE_CHANGED) || maria_is_crashed(file)) |
1729 | { |
1730 | DBUG_PRINT("info" , ("Reseting crashed state" )); |
1731 | share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED_FLAGS | |
1732 | STATE_IN_REPAIR | STATE_MOVED); |
1733 | file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; |
1734 | } |
1735 | /* |
1736 | repair updates share->state.state. Ensure that file->state is up to date |
1737 | */ |
1738 | if (file->state != &share->state.state) |
1739 | *file->state= share->state.state; |
1740 | |
1741 | if (share->base.auto_key) |
1742 | _ma_update_auto_increment_key(param, file, 1); |
1743 | if (optimize_done) |
1744 | error= maria_update_state_info(param, file, |
1745 | UPDATE_TIME | UPDATE_OPEN_COUNT | |
1746 | (local_testflag & |
1747 | T_STATISTICS ? UPDATE_STAT : 0)); |
1748 | /* File is repaired; Mark the file as moved to this system */ |
1749 | (void) _ma_set_uuid(share, 0); |
1750 | |
1751 | info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE | |
1752 | HA_STATUS_CONST); |
1753 | if (rows != file->state->records && !(param->testflag & T_VERY_SILENT)) |
1754 | { |
1755 | char llbuff[22], llbuff2[22]; |
1756 | _ma_check_print_warning(param, "Number of rows changed from %s to %s" , |
1757 | llstr(rows, llbuff), |
1758 | llstr(file->state->records, llbuff2)); |
1759 | } |
1760 | } |
1761 | else |
1762 | { |
1763 | maria_mark_crashed_on_repair(file); |
1764 | file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; |
1765 | maria_update_state_info(param, file, 0); |
1766 | } |
1767 | mysql_mutex_unlock(&share->intern_lock); |
1768 | thd_proc_info(thd, old_proc_info); |
1769 | thd_progress_end(thd); // Mark done |
1770 | if (locking) |
1771 | maria_lock_database(file, F_UNLCK); |
1772 | |
1773 | /* Reset trn, that may have been set by repair */ |
1774 | _ma_set_trn_for_table(file, old_trn); |
1775 | error= error ? HA_ADMIN_FAILED : |
1776 | (optimize_done ? |
1777 | (write_log_record_for_repair(param, file) ? HA_ADMIN_FAILED : |
1778 | HA_ADMIN_OK) : HA_ADMIN_ALREADY_DONE); |
1779 | DBUG_RETURN(error); |
1780 | } |
1781 | |
1782 | |
1783 | /* |
1784 | Assign table indexes to a specific key cache. |
1785 | */ |
1786 | |
1787 | int ha_maria::assign_to_keycache(THD * thd, HA_CHECK_OPT *check_opt) |
1788 | { |
1789 | #if 0 && NOT_IMPLEMENTED |
1790 | PAGECACHE *new_pagecache= check_opt->pagecache; |
1791 | const char *errmsg= 0; |
1792 | int error= HA_ADMIN_OK; |
1793 | ulonglong map; |
1794 | TABLE_LIST *table_list= table->pos_in_table_list; |
1795 | DBUG_ENTER("ha_maria::assign_to_keycache" ); |
1796 | |
1797 | |
1798 | table->keys_in_use_for_query.clear_all(); |
1799 | |
1800 | if (table_list->process_index_hints(table)) |
1801 | DBUG_RETURN(HA_ADMIN_FAILED); |
1802 | map= ~(ulonglong) 0; |
1803 | if (!table->keys_in_use_for_query.is_clear_all()) |
1804 | /* use all keys if there's no list specified by the user through hints */ |
1805 | map= table->keys_in_use_for_query.to_ulonglong(); |
1806 | |
1807 | if ((error= maria_assign_to_pagecache(file, map, new_pagecache))) |
1808 | { |
1809 | char buf[STRING_BUFFER_USUAL_SIZE]; |
1810 | my_snprintf(buf, sizeof(buf), |
1811 | "Failed to flush to index file (errno: %d)" , error); |
1812 | errmsg= buf; |
1813 | error= HA_ADMIN_CORRUPT; |
1814 | } |
1815 | |
1816 | if (error != HA_ADMIN_OK) |
1817 | { |
1818 | /* Send error to user */ |
1819 | HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param); |
1820 | if (!param) |
1821 | return HA_ADMIN_INTERNAL_ERROR; |
1822 | |
1823 | maria_chk_init(param); |
1824 | param->thd= thd; |
1825 | param->op_name= "assign_to_keycache" ; |
1826 | param->db_name= table->s->db.str; |
1827 | param->table_name= table->s->table_name.str; |
1828 | param->testflag= 0; |
1829 | _ma_check_print_error(param, errmsg); |
1830 | } |
1831 | DBUG_RETURN(error); |
1832 | #else |
1833 | return HA_ADMIN_NOT_IMPLEMENTED; |
1834 | #endif |
1835 | } |
1836 | |
1837 | |
1838 | /* |
1839 | Preload pages of the index file for a table into the key cache. |
1840 | */ |
1841 | |
1842 | int ha_maria::preload_keys(THD * thd, HA_CHECK_OPT *check_opt) |
1843 | { |
1844 | ulonglong map; |
1845 | TABLE_LIST *table_list= table->pos_in_table_list; |
1846 | |
1847 | DBUG_ENTER("ha_maria::preload_keys" ); |
1848 | |
1849 | table->keys_in_use_for_query.clear_all(); |
1850 | |
1851 | if (table_list->process_index_hints(table)) |
1852 | DBUG_RETURN(HA_ADMIN_FAILED); |
1853 | |
1854 | map= ~(ulonglong) 0; |
1855 | /* Check validity of the index references */ |
1856 | if (!table->keys_in_use_for_query.is_clear_all()) |
1857 | /* use all keys if there's no list specified by the user through hints */ |
1858 | map= table->keys_in_use_for_query.to_ulonglong(); |
1859 | |
1860 | maria_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE, |
1861 | (void*) &thd->variables.preload_buff_size); |
1862 | |
1863 | int error; |
1864 | |
1865 | if ((error= maria_preload(file, map, table_list->ignore_leaves))) |
1866 | { |
1867 | char buf[MYSQL_ERRMSG_SIZE+20]; |
1868 | const char *errmsg; |
1869 | |
1870 | switch (error) { |
1871 | case HA_ERR_NON_UNIQUE_BLOCK_SIZE: |
1872 | errmsg= "Indexes use different block sizes" ; |
1873 | break; |
1874 | case HA_ERR_OUT_OF_MEM: |
1875 | errmsg= "Failed to allocate buffer" ; |
1876 | break; |
1877 | default: |
1878 | my_snprintf(buf, sizeof(buf), |
1879 | "Failed to read from index file (errno: %d)" , my_errno); |
1880 | errmsg= buf; |
1881 | } |
1882 | |
1883 | HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param); |
1884 | if (!param) |
1885 | return HA_ADMIN_INTERNAL_ERROR; |
1886 | |
1887 | maria_chk_init(param); |
1888 | param->thd= thd; |
1889 | param->op_name= "preload_keys" ; |
1890 | param->db_name= table->s->db.str; |
1891 | param->table_name= table->s->table_name.str; |
1892 | param->testflag= 0; |
1893 | _ma_check_print_error(param, "%s" , errmsg); |
1894 | DBUG_RETURN(HA_ADMIN_FAILED); |
1895 | } |
1896 | DBUG_RETURN(HA_ADMIN_OK); |
1897 | } |
1898 | |
1899 | |
1900 | /* |
1901 | Disable indexes, making it persistent if requested. |
1902 | |
1903 | SYNOPSIS |
1904 | disable_indexes() |
1905 | mode mode of operation: |
1906 | HA_KEY_SWITCH_NONUNIQ disable all non-unique keys |
1907 | HA_KEY_SWITCH_ALL disable all keys |
1908 | HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent |
1909 | HA_KEY_SWITCH_ALL_SAVE dis. all keys and make persistent |
1910 | |
1911 | IMPLEMENTATION |
1912 | HA_KEY_SWITCH_NONUNIQ is not implemented. |
1913 | HA_KEY_SWITCH_ALL_SAVE is not implemented. |
1914 | |
1915 | RETURN |
1916 | 0 ok |
1917 | HA_ERR_WRONG_COMMAND mode not implemented. |
1918 | */ |
1919 | |
1920 | int ha_maria::disable_indexes(uint mode) |
1921 | { |
1922 | int error; |
1923 | |
1924 | if (mode == HA_KEY_SWITCH_ALL) |
1925 | { |
1926 | /* call a storage engine function to switch the key map */ |
1927 | error= maria_disable_indexes(file); |
1928 | } |
1929 | else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE) |
1930 | { |
1931 | maria_extra(file, HA_EXTRA_NO_KEYS, 0); |
1932 | info(HA_STATUS_CONST); // Read new key info |
1933 | error= 0; |
1934 | } |
1935 | else |
1936 | { |
1937 | /* mode not implemented */ |
1938 | error= HA_ERR_WRONG_COMMAND; |
1939 | } |
1940 | return error; |
1941 | } |
1942 | |
1943 | |
1944 | /* |
1945 | Enable indexes, making it persistent if requested. |
1946 | |
1947 | SYNOPSIS |
1948 | enable_indexes() |
1949 | mode mode of operation: |
1950 | HA_KEY_SWITCH_NONUNIQ enable all non-unique keys |
1951 | HA_KEY_SWITCH_ALL enable all keys |
1952 | HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent |
1953 | HA_KEY_SWITCH_ALL_SAVE en. all keys and make persistent |
1954 | |
1955 | DESCRIPTION |
1956 | Enable indexes, which might have been disabled by disable_index() before. |
1957 | The modes without _SAVE work only if both data and indexes are empty, |
1958 | since the MARIA repair would enable them persistently. |
1959 | To be sure in these cases, call handler::delete_all_rows() before. |
1960 | |
1961 | IMPLEMENTATION |
1962 | HA_KEY_SWITCH_NONUNIQ is not implemented. |
1963 | HA_KEY_SWITCH_ALL_SAVE is not implemented. |
1964 | |
1965 | RETURN |
1966 | 0 ok |
1967 | !=0 Error, among others: |
1968 | HA_ERR_CRASHED data or index is non-empty. Delete all rows and retry. |
1969 | HA_ERR_WRONG_COMMAND mode not implemented. |
1970 | */ |
1971 | |
1972 | int ha_maria::enable_indexes(uint mode) |
1973 | { |
1974 | int error; |
1975 | DBUG_PRINT("info" , ("ha_maria::enable_indexes mode: %d" , mode)); |
1976 | if (maria_is_all_keys_active(file->s->state.key_map, file->s->base.keys)) |
1977 | { |
1978 | /* All indexes are enabled already. */ |
1979 | return 0; |
1980 | } |
1981 | |
1982 | if (mode == HA_KEY_SWITCH_ALL) |
1983 | { |
1984 | error= maria_enable_indexes(file); |
1985 | /* |
1986 | Do not try to repair on error, |
1987 | as this could make the enabled state persistent, |
1988 | but mode==HA_KEY_SWITCH_ALL forbids it. |
1989 | */ |
1990 | } |
1991 | else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE) |
1992 | { |
1993 | THD *thd= table->in_use; |
1994 | HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param); |
1995 | if (!param) |
1996 | return HA_ADMIN_INTERNAL_ERROR; |
1997 | |
1998 | const char *save_proc_info= thd_proc_info(thd, "Creating index" ); |
1999 | |
2000 | maria_chk_init(param); |
2001 | param->op_name= "recreating_index" ; |
2002 | param->testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK | |
2003 | T_CREATE_MISSING_KEYS | T_SAFE_REPAIR); |
2004 | /* |
2005 | Don't lock and unlock table if it's locked. |
2006 | Normally table should be locked. This test is mostly for safety. |
2007 | */ |
2008 | if (likely(file->lock_type != F_UNLCK)) |
2009 | param->testflag|= T_NO_LOCKS; |
2010 | |
2011 | if (file->create_unique_index_by_sort) |
2012 | param->testflag|= T_CREATE_UNIQUE_BY_SORT; |
2013 | |
2014 | if (bulk_insert_single_undo == BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR) |
2015 | { |
2016 | bulk_insert_single_undo= BULK_INSERT_SINGLE_UNDO_AND_REPAIR; |
2017 | /* |
2018 | Don't bump create_rename_lsn, because UNDO_BULK_INSERT |
2019 | should not be skipped in case of crash during repair. |
2020 | */ |
2021 | param->testflag|= T_NO_CREATE_RENAME_LSN; |
2022 | } |
2023 | |
2024 | param->myf_rw &= ~MY_WAIT_IF_FULL; |
2025 | param->sort_buffer_length= THDVAR(thd,sort_buffer_size); |
2026 | param->stats_method= (enum_handler_stats_method)THDVAR(thd,stats_method); |
2027 | param->tmpdir= &mysql_tmpdir_list; |
2028 | if ((error= (repair(thd, param, 0) != HA_ADMIN_OK)) && param->retry_repair) |
2029 | { |
2030 | sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, " |
2031 | "retrying" , |
2032 | my_errno, param->db_name, param->table_name); |
2033 | /* This should never fail normally */ |
2034 | DBUG_ASSERT(thd->killed != 0); |
2035 | /* Repairing by sort failed. Now try standard repair method. */ |
2036 | param->testflag &= ~T_REP_BY_SORT; |
2037 | error= (repair(thd, param, 0) != HA_ADMIN_OK); |
2038 | /* |
2039 | If the standard repair succeeded, clear all error messages which |
2040 | might have been set by the first repair. They can still be seen |
2041 | with SHOW WARNINGS then. |
2042 | */ |
2043 | if (!error) |
2044 | thd->clear_error(); |
2045 | } |
2046 | info(HA_STATUS_CONST); |
2047 | thd_proc_info(thd, save_proc_info); |
2048 | } |
2049 | else |
2050 | { |
2051 | /* mode not implemented */ |
2052 | error= HA_ERR_WRONG_COMMAND; |
2053 | } |
2054 | DBUG_EXECUTE_IF("maria_flush_whole_log" , |
2055 | { |
2056 | DBUG_PRINT("maria_flush_whole_log" , ("now" )); |
2057 | translog_flush(translog_get_horizon()); |
2058 | }); |
2059 | DBUG_EXECUTE_IF("maria_crash_enable_index" , |
2060 | { |
2061 | DBUG_PRINT("maria_crash_enable_index" , ("now" )); |
2062 | DBUG_SUICIDE(); |
2063 | }); |
2064 | return error; |
2065 | } |
2066 | |
2067 | |
2068 | /* |
2069 | Test if indexes are disabled. |
2070 | |
2071 | |
2072 | SYNOPSIS |
2073 | indexes_are_disabled() |
2074 | no parameters |
2075 | |
2076 | |
2077 | RETURN |
2078 | 0 indexes are not disabled |
2079 | 1 all indexes are disabled |
2080 | [2 non-unique indexes are disabled - NOT YET IMPLEMENTED] |
2081 | */ |
2082 | |
2083 | int ha_maria::indexes_are_disabled(void) |
2084 | { |
2085 | return maria_indexes_are_disabled(file); |
2086 | } |
2087 | |
2088 | |
2089 | /* |
2090 | prepare for a many-rows insert operation |
2091 | e.g. - disable indexes (if they can be recreated fast) or |
2092 | activate special bulk-insert optimizations |
2093 | |
2094 | SYNOPSIS |
2095 | start_bulk_insert(rows, flags) |
2096 | rows Rows to be inserted |
2097 | 0 if we don't know |
2098 | flags Flags to control index creation |
2099 | |
2100 | NOTICE |
2101 | Do not forget to call end_bulk_insert() later! |
2102 | */ |
2103 | |
2104 | void ha_maria::start_bulk_insert(ha_rows rows, uint flags) |
2105 | { |
2106 | DBUG_ENTER("ha_maria::start_bulk_insert" ); |
2107 | THD *thd= table->in_use; |
2108 | MARIA_SHARE *share= file->s; |
2109 | DBUG_PRINT("info" , ("start_bulk_insert: rows %lu" , (ulong) rows)); |
2110 | |
2111 | /* don't enable row cache if too few rows */ |
2112 | if (!rows || (rows > MARIA_MIN_ROWS_TO_USE_WRITE_CACHE)) |
2113 | { |
2114 | ulonglong size= thd->variables.read_buff_size, tmp; |
2115 | if (rows) |
2116 | { |
2117 | if (file->state->records) |
2118 | { |
2119 | MARIA_INFO maria_info; |
2120 | maria_status(file, &maria_info, HA_STATUS_NO_LOCK |HA_STATUS_VARIABLE); |
2121 | set_if_smaller(size, maria_info.mean_reclength * rows); |
2122 | } |
2123 | else if (table->s->avg_row_length) |
2124 | set_if_smaller(size, (size_t) (table->s->avg_row_length * rows)); |
2125 | } |
2126 | tmp= (ulong) size; // Safe becasue of limits |
2127 | maria_extra(file, HA_EXTRA_WRITE_CACHE, (void*) &tmp); |
2128 | } |
2129 | |
2130 | can_enable_indexes= (maria_is_all_keys_active(share->state.key_map, |
2131 | share->base.keys)); |
2132 | bulk_insert_single_undo= BULK_INSERT_NONE; |
2133 | |
2134 | if (!(specialflag & SPECIAL_SAFE_MODE)) |
2135 | { |
2136 | /* |
2137 | Only disable old index if the table was empty and we are inserting |
2138 | a lot of rows. |
2139 | We should not do this for only a few rows as this is slower and |
2140 | we don't want to update the key statistics based of only a few rows. |
2141 | Index file rebuild requires an exclusive lock, so if versioning is on |
2142 | don't do it (see how ha_maria::store_lock() tries to predict repair). |
2143 | We can repair index only if we have an exclusive (TL_WRITE) lock or |
2144 | if this is inside an ALTER TABLE, in which case lock_type == TL_UNLOCK. |
2145 | |
2146 | To see if table is empty, we shouldn't rely on the old record |
2147 | count from our transaction's start (if that old count is 0 but |
2148 | now there are records in the table, we would wrongly destroy |
2149 | them). So we need to look at share->state.state.records. As a |
2150 | safety net for now, we don't remove the test of |
2151 | file->state->records, because there is uncertainty on what will |
2152 | happen during repair if the two states disagree. |
2153 | |
2154 | We also have to check in case of transactional tables that the |
2155 | user has not used LOCK TABLE on the table twice. |
2156 | */ |
2157 | if ((file->state->records == 0) && |
2158 | (share->state.state.records == 0) && can_enable_indexes && |
2159 | (!rows || rows >= MARIA_MIN_ROWS_TO_DISABLE_INDEXES) && |
2160 | (file->lock.type == TL_WRITE || file->lock.type == TL_UNLOCK) && |
2161 | (!share->have_versioning || !share->now_transactional || |
2162 | file->used_tables->use_count == 1)) |
2163 | { |
2164 | /** |
2165 | @todo for a single-row INSERT SELECT, we will go into repair, which |
2166 | is more costly (flushes, syncs) than a row write. |
2167 | */ |
2168 | if (file->open_flags & HA_OPEN_INTERNAL_TABLE) |
2169 | { |
2170 | /* Internal table; If we get a duplicate something is very wrong */ |
2171 | file->update|= HA_STATE_CHANGED; |
2172 | maria_clear_all_keys_active(file->s->state.key_map); |
2173 | } |
2174 | else |
2175 | { |
2176 | my_bool all_keys= MY_TEST(flags & HA_CREATE_UNIQUE_INDEX_BY_SORT); |
2177 | maria_disable_indexes_for_rebuild(file, rows, all_keys); |
2178 | } |
2179 | if (share->now_transactional) |
2180 | { |
2181 | bulk_insert_single_undo= BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR; |
2182 | write_log_record_for_bulk_insert(file); |
2183 | _ma_tmp_disable_logging_for_table(file, TRUE); |
2184 | /* |
2185 | Pages currently in the page cache have type PAGECACHE_LSN_PAGE, we |
2186 | are not allowed to overwrite them with PAGECACHE_PLAIN_PAGE, so |
2187 | throw them away. It is not losing data, because we just wrote and |
2188 | forced an UNDO which will for sure empty the table if we crash. The |
2189 | upcoming unique-key insertions however need a proper index, so we |
2190 | cannot leave the corrupted on-disk index file, thus we truncate it. |
2191 | */ |
2192 | maria_delete_all_rows(file); |
2193 | } |
2194 | } |
2195 | else if (!file->bulk_insert && |
2196 | (!rows || rows >= MARIA_MIN_ROWS_TO_USE_BULK_INSERT)) |
2197 | { |
2198 | maria_init_bulk_insert(file, |
2199 | (size_t) thd->variables.bulk_insert_buff_size, |
2200 | rows); |
2201 | } |
2202 | } |
2203 | DBUG_VOID_RETURN; |
2204 | } |
2205 | |
2206 | |
2207 | /* |
2208 | end special bulk-insert optimizations, |
2209 | which have been activated by start_bulk_insert(). |
2210 | |
2211 | SYNOPSIS |
2212 | end_bulk_insert() |
2213 | no arguments |
2214 | |
2215 | RETURN |
2216 | 0 OK |
2217 | != 0 Error |
2218 | */ |
2219 | |
2220 | int ha_maria::end_bulk_insert() |
2221 | { |
2222 | int first_error, error; |
2223 | my_bool abort= file->s->deleting; |
2224 | DBUG_ENTER("ha_maria::end_bulk_insert" ); |
2225 | |
2226 | if ((first_error= maria_end_bulk_insert(file, abort))) |
2227 | abort= 1; |
2228 | |
2229 | if ((error= maria_extra(file, HA_EXTRA_NO_CACHE, 0))) |
2230 | { |
2231 | first_error= first_error ? first_error : error; |
2232 | abort= 1; |
2233 | } |
2234 | |
2235 | if (!abort && can_enable_indexes) |
2236 | if ((error= enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE))) |
2237 | first_error= first_error ? first_error : error; |
2238 | |
2239 | if (bulk_insert_single_undo != BULK_INSERT_NONE) |
2240 | { |
2241 | DBUG_ASSERT(can_enable_indexes); |
2242 | /* |
2243 | Table was transactional just before start_bulk_insert(). |
2244 | No need to flush pages if we did a repair (which already flushed). |
2245 | */ |
2246 | if ((error= _ma_reenable_logging_for_table(file, |
2247 | bulk_insert_single_undo == |
2248 | BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR))) |
2249 | first_error= first_error ? first_error : error; |
2250 | bulk_insert_single_undo= BULK_INSERT_NONE; // Safety |
2251 | } |
2252 | DBUG_RETURN(first_error); |
2253 | } |
2254 | |
2255 | |
2256 | bool ha_maria::check_and_repair(THD *thd) |
2257 | { |
2258 | int error, crashed; |
2259 | HA_CHECK_OPT check_opt; |
2260 | const CSET_STRING query_backup= thd->query_string; |
2261 | DBUG_ENTER("ha_maria::check_and_repair" ); |
2262 | |
2263 | check_opt.init(); |
2264 | check_opt.flags= T_MEDIUM | T_AUTO_REPAIR; |
2265 | |
2266 | error= 1; |
2267 | if ((file->s->state.changed & (STATE_CRASHED_FLAGS | STATE_MOVED)) == |
2268 | STATE_MOVED) |
2269 | { |
2270 | /* Remove error about crashed table */ |
2271 | thd->get_stmt_da()->clear_warning_info(thd->query_id); |
2272 | push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, |
2273 | ER_CRASHED_ON_USAGE, |
2274 | "Zerofilling moved table %s" , table->s->path.str); |
2275 | sql_print_information("Zerofilling moved table: '%s'" , |
2276 | table->s->path.str); |
2277 | if (!(error= zerofill(thd, &check_opt))) |
2278 | DBUG_RETURN(0); |
2279 | } |
2280 | |
2281 | /* |
2282 | if we got this far - the table is crashed. |
2283 | but don't auto-repair if maria_recover_options is not set |
2284 | */ |
2285 | if (!maria_recover_options) |
2286 | DBUG_RETURN(error); |
2287 | |
2288 | error= 0; |
2289 | // Don't use quick if deleted rows |
2290 | if (!file->state->del && (maria_recover_options & HA_RECOVER_QUICK)) |
2291 | check_opt.flags |= T_QUICK; |
2292 | |
2293 | thd->set_query((char*) table->s->table_name.str, |
2294 | (uint) table->s->table_name.length, system_charset_info); |
2295 | |
2296 | if (!(crashed= maria_is_crashed(file))) |
2297 | { |
2298 | sql_print_warning("Checking table: '%s'" , table->s->path.str); |
2299 | crashed= check(thd, &check_opt); |
2300 | } |
2301 | |
2302 | if (crashed) |
2303 | { |
2304 | bool save_log_all_errors; |
2305 | sql_print_warning("Recovering table: '%s'" , table->s->path.str); |
2306 | save_log_all_errors= thd->log_all_errors; |
2307 | thd->log_all_errors|= (thd->variables.log_warnings > 2); |
2308 | check_opt.flags= |
2309 | ((maria_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) | |
2310 | (maria_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) | |
2311 | T_AUTO_REPAIR); |
2312 | if (repair(thd, &check_opt)) |
2313 | error= 1; |
2314 | thd->log_all_errors= save_log_all_errors; |
2315 | } |
2316 | thd->set_query(query_backup); |
2317 | DBUG_RETURN(error); |
2318 | } |
2319 | |
2320 | |
2321 | bool ha_maria::is_crashed() const |
2322 | { |
2323 | return (file->s->state.changed & (STATE_CRASHED_FLAGS | STATE_MOVED) || |
2324 | (my_disable_locking && file->s->state.open_count)); |
2325 | } |
2326 | |
2327 | #define CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING(msg) \ |
2328 | do { \ |
2329 | if (file->lock.type == TL_WRITE_CONCURRENT_INSERT && !table->s->sequence) \ |
2330 | { \ |
2331 | my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), msg); \ |
2332 | return 1; \ |
2333 | } \ |
2334 | } while(0) |
2335 | |
2336 | int ha_maria::update_row(const uchar * old_data, const uchar * new_data) |
2337 | { |
2338 | CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING("UPDATE in WRITE CONCURRENT" ); |
2339 | return maria_update(file, old_data, new_data); |
2340 | } |
2341 | |
2342 | |
2343 | int ha_maria::delete_row(const uchar * buf) |
2344 | { |
2345 | CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING("DELETE in WRITE CONCURRENT" ); |
2346 | return maria_delete(file, buf); |
2347 | } |
2348 | |
2349 | int ha_maria::index_read_map(uchar * buf, const uchar * key, |
2350 | key_part_map keypart_map, |
2351 | enum ha_rkey_function find_flag) |
2352 | { |
2353 | DBUG_ASSERT(inited == INDEX); |
2354 | int error= maria_rkey(file, buf, active_index, key, keypart_map, find_flag); |
2355 | return error; |
2356 | } |
2357 | |
2358 | |
2359 | int ha_maria::index_read_idx_map(uchar * buf, uint index, const uchar * key, |
2360 | key_part_map keypart_map, |
2361 | enum ha_rkey_function find_flag) |
2362 | { |
2363 | int error; |
2364 | /* Use the pushed index condition if it matches the index we're scanning */ |
2365 | end_range= NULL; |
2366 | if (index == pushed_idx_cond_keyno) |
2367 | ma_set_index_cond_func(file, handler_index_cond_check, this); |
2368 | |
2369 | error= maria_rkey(file, buf, index, key, keypart_map, find_flag); |
2370 | |
2371 | ma_set_index_cond_func(file, NULL, 0); |
2372 | return error; |
2373 | } |
2374 | |
2375 | |
2376 | int ha_maria::index_read_last_map(uchar * buf, const uchar * key, |
2377 | key_part_map keypart_map) |
2378 | { |
2379 | DBUG_ENTER("ha_maria::index_read_last_map" ); |
2380 | DBUG_ASSERT(inited == INDEX); |
2381 | int error= maria_rkey(file, buf, active_index, key, keypart_map, |
2382 | HA_READ_PREFIX_LAST); |
2383 | DBUG_RETURN(error); |
2384 | } |
2385 | |
2386 | |
2387 | int ha_maria::index_next(uchar * buf) |
2388 | { |
2389 | DBUG_ASSERT(inited == INDEX); |
2390 | int error= maria_rnext(file, buf, active_index); |
2391 | return error; |
2392 | } |
2393 | |
2394 | |
2395 | int ha_maria::index_prev(uchar * buf) |
2396 | { |
2397 | DBUG_ASSERT(inited == INDEX); |
2398 | int error= maria_rprev(file, buf, active_index); |
2399 | return error; |
2400 | } |
2401 | |
2402 | |
2403 | int ha_maria::index_first(uchar * buf) |
2404 | { |
2405 | DBUG_ASSERT(inited == INDEX); |
2406 | int error= maria_rfirst(file, buf, active_index); |
2407 | return error; |
2408 | } |
2409 | |
2410 | |
2411 | int ha_maria::index_last(uchar * buf) |
2412 | { |
2413 | DBUG_ASSERT(inited == INDEX); |
2414 | int error= maria_rlast(file, buf, active_index); |
2415 | return error; |
2416 | } |
2417 | |
2418 | |
2419 | int ha_maria::index_next_same(uchar * buf, |
2420 | const uchar *key __attribute__ ((unused)), |
2421 | uint length __attribute__ ((unused))) |
2422 | { |
2423 | int error; |
2424 | DBUG_ASSERT(inited == INDEX); |
2425 | /* |
2426 | TODO: Delete this loop in Maria 1.5 as versioning will ensure this never |
2427 | happens |
2428 | */ |
2429 | do |
2430 | { |
2431 | error= maria_rnext_same(file,buf); |
2432 | } while (error == HA_ERR_RECORD_DELETED); |
2433 | return error; |
2434 | } |
2435 | |
2436 | |
2437 | int ha_maria::index_init(uint idx, bool sorted) |
2438 | { |
2439 | active_index=idx; |
2440 | if (pushed_idx_cond_keyno == idx) |
2441 | ma_set_index_cond_func(file, handler_index_cond_check, this); |
2442 | return 0; |
2443 | } |
2444 | |
2445 | |
2446 | int ha_maria::index_end() |
2447 | { |
2448 | active_index=MAX_KEY; |
2449 | ma_set_index_cond_func(file, NULL, 0); |
2450 | in_range_check_pushed_down= FALSE; |
2451 | ds_mrr.dsmrr_close(); |
2452 | return 0; |
2453 | } |
2454 | |
2455 | |
2456 | int ha_maria::rnd_init(bool scan) |
2457 | { |
2458 | if (scan) |
2459 | return maria_scan_init(file); |
2460 | return maria_reset(file); // Free buffers |
2461 | } |
2462 | |
2463 | |
2464 | int ha_maria::rnd_end() |
2465 | { |
2466 | ds_mrr.dsmrr_close(); |
2467 | /* Safe to call even if we don't have started a scan */ |
2468 | maria_scan_end(file); |
2469 | return 0; |
2470 | } |
2471 | |
2472 | |
2473 | int ha_maria::rnd_next(uchar *buf) |
2474 | { |
2475 | int error= maria_scan(file, buf); |
2476 | return error; |
2477 | } |
2478 | |
2479 | |
2480 | int ha_maria::remember_rnd_pos() |
2481 | { |
2482 | return (*file->s->scan_remember_pos)(file, &remember_pos); |
2483 | } |
2484 | |
2485 | |
2486 | int ha_maria::restart_rnd_next(uchar *buf) |
2487 | { |
2488 | int error; |
2489 | if ((error= (*file->s->scan_restore_pos)(file, remember_pos))) |
2490 | return error; |
2491 | return rnd_next(buf); |
2492 | } |
2493 | |
2494 | |
2495 | int ha_maria::rnd_pos(uchar *buf, uchar *pos) |
2496 | { |
2497 | int error= maria_rrnd(file, buf, my_get_ptr(pos, ref_length)); |
2498 | return error; |
2499 | } |
2500 | |
2501 | |
2502 | void ha_maria::position(const uchar *record) |
2503 | { |
2504 | my_off_t row_position= maria_position(file); |
2505 | my_store_ptr(ref, ref_length, row_position); |
2506 | } |
2507 | |
2508 | |
2509 | int ha_maria::info(uint flag) |
2510 | { |
2511 | MARIA_INFO maria_info; |
2512 | char name_buff[FN_REFLEN]; |
2513 | |
2514 | (void) maria_status(file, &maria_info, flag); |
2515 | if (flag & HA_STATUS_VARIABLE) |
2516 | { |
2517 | stats.records= maria_info.records; |
2518 | stats.deleted= maria_info.deleted; |
2519 | stats.data_file_length= maria_info.data_file_length; |
2520 | stats.index_file_length= maria_info.index_file_length; |
2521 | stats.delete_length= maria_info.delete_length; |
2522 | stats.check_time= maria_info.check_time; |
2523 | stats.mean_rec_length= maria_info.mean_reclength; |
2524 | } |
2525 | if (flag & HA_STATUS_CONST) |
2526 | { |
2527 | TABLE_SHARE *share= table->s; |
2528 | stats.max_data_file_length= maria_info.max_data_file_length; |
2529 | stats.max_index_file_length= maria_info.max_index_file_length; |
2530 | stats.create_time= maria_info.create_time; |
2531 | ref_length= maria_info.reflength; |
2532 | share->db_options_in_use= maria_info.options; |
2533 | stats.block_size= maria_block_size; |
2534 | stats.mrr_length_per_rec= maria_info.reflength + 8; // 8 = MY_MAX(sizeof(void *)) |
2535 | |
2536 | /* Update share */ |
2537 | share->keys_in_use.set_prefix(share->keys); |
2538 | share->keys_in_use.intersect_extended(maria_info.key_map); |
2539 | share->keys_for_keyread.intersect(share->keys_in_use); |
2540 | share->db_record_offset= maria_info.record_offset; |
2541 | if (share->key_parts) |
2542 | { |
2543 | ulong *to= table->key_info[0].rec_per_key, *end; |
2544 | double *from= maria_info.rec_per_key; |
2545 | for (end= to+ share->key_parts ; to < end ; to++, from++) |
2546 | *to= (ulong) (*from + 0.5); |
2547 | } |
2548 | |
2549 | /* |
2550 | Set data_file_name and index_file_name to point at the symlink value |
2551 | if table is symlinked (Ie; Real name is not same as generated name) |
2552 | */ |
2553 | data_file_name= index_file_name= 0; |
2554 | fn_format(name_buff, file->s->open_file_name.str, "" , MARIA_NAME_DEXT, |
2555 | MY_APPEND_EXT | MY_UNPACK_FILENAME); |
2556 | if (strcmp(name_buff, maria_info.data_file_name)) |
2557 | data_file_name =maria_info.data_file_name; |
2558 | fn_format(name_buff, file->s->open_file_name.str, "" , MARIA_NAME_IEXT, |
2559 | MY_APPEND_EXT | MY_UNPACK_FILENAME); |
2560 | if (strcmp(name_buff, maria_info.index_file_name)) |
2561 | index_file_name=maria_info.index_file_name; |
2562 | } |
2563 | if (flag & HA_STATUS_ERRKEY) |
2564 | { |
2565 | errkey= maria_info.errkey; |
2566 | my_store_ptr(dup_ref, ref_length, maria_info.dup_key_pos); |
2567 | } |
2568 | if (flag & HA_STATUS_TIME) |
2569 | stats.update_time= maria_info.update_time; |
2570 | if (flag & HA_STATUS_AUTO) |
2571 | stats.auto_increment_value= maria_info.auto_increment; |
2572 | |
2573 | return 0; |
2574 | } |
2575 | |
2576 | |
2577 | int ha_maria::(enum ha_extra_function operation) |
2578 | { |
2579 | int tmp; |
2580 | TRN *old_trn= file->trn; |
2581 | if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_KEYREAD) |
2582 | return 0; |
2583 | #ifdef NOT_USED |
2584 | if (operation == HA_EXTRA_MMAP && !opt_maria_use_mmap) |
2585 | return 0; |
2586 | #endif |
2587 | |
2588 | /* |
2589 | We have to set file->trn here because in some cases we call |
2590 | extern_lock(F_UNLOCK) (which resets file->trn) followed by maria_close() |
2591 | without calling commit/rollback in between. If file->trn is not set |
2592 | we can't remove file->share from the transaction list in the extra() call. |
2593 | |
2594 | We also ensure that we set file->trn to 0 if THD_TRN is 0 as in |
2595 | this case we have already freed the trn. This can happen when one |
2596 | implicit_commit() is called as part of alter table. |
2597 | |
2598 | table->in_use is not set in the case this is a done as part of closefrm() |
2599 | as part of drop table. |
2600 | */ |
2601 | |
2602 | if (file->s->now_transactional && table->in_use && |
2603 | (operation == HA_EXTRA_PREPARE_FOR_DROP || |
2604 | operation == HA_EXTRA_PREPARE_FOR_RENAME || |
2605 | operation == HA_EXTRA_PREPARE_FOR_FORCED_CLOSE)) |
2606 | { |
2607 | THD *thd= table->in_use; |
2608 | TRN *trn= THD_TRN; |
2609 | _ma_set_trn_for_table(file, trn); |
2610 | } |
2611 | DBUG_ASSERT(file->s->base.born_transactional || file->trn == 0 || |
2612 | file->trn == &dummy_transaction_object); |
2613 | |
2614 | tmp= maria_extra(file, operation, 0); |
2615 | file->trn= old_trn; // Reset trn if was used |
2616 | return tmp; |
2617 | } |
2618 | |
2619 | int ha_maria::reset(void) |
2620 | { |
2621 | ma_set_index_cond_func(file, NULL, 0); |
2622 | ds_mrr.dsmrr_close(); |
2623 | if (file->trn) |
2624 | { |
2625 | /* Next statement is a new statement. Ensure it's logged */ |
2626 | trnman_set_flags(file->trn, |
2627 | trnman_get_flags(file->trn) & ~TRN_STATE_INFO_LOGGED); |
2628 | } |
2629 | return maria_reset(file); |
2630 | } |
2631 | |
2632 | /* To be used with WRITE_CACHE and EXTRA_CACHE */ |
2633 | |
2634 | int ha_maria::(enum ha_extra_function operation, ulong cache_size) |
2635 | { |
2636 | if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE) |
2637 | return 0; |
2638 | return maria_extra(file, operation, (void*) &cache_size); |
2639 | } |
2640 | |
2641 | |
2642 | int ha_maria::delete_all_rows() |
2643 | { |
2644 | THD *thd= table->in_use; |
2645 | TRN *trn= file->trn; |
2646 | CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING("TRUNCATE in WRITE CONCURRENT" ); |
2647 | #ifdef EXTRA_DEBUG |
2648 | if (trn && ! (trnman_get_flags(trn) & TRN_STATE_INFO_LOGGED)) |
2649 | { |
2650 | trnman_set_flags(trn, trnman_get_flags(trn) | TRN_STATE_INFO_LOGGED | |
2651 | TRN_STATE_TABLES_CAN_CHANGE); |
2652 | (void) translog_log_debug_info(trn, LOGREC_DEBUG_INFO_QUERY, |
2653 | (uchar*) thd->query(), thd->query_length()); |
2654 | } |
2655 | #endif |
2656 | /* |
2657 | If we are under LOCK TABLES, we have to do a commit as |
2658 | delete_all_rows() can't be rolled back |
2659 | */ |
2660 | if (table->in_use->locked_tables_mode && trn && |
2661 | trnman_has_locked_tables(trn)) |
2662 | { |
2663 | int error; |
2664 | if ((error= implicit_commit(thd, 1))) |
2665 | return error; |
2666 | } |
2667 | |
2668 | /* Note that this can't be rolled back */ |
2669 | return maria_delete_all_rows(file); |
2670 | } |
2671 | |
2672 | |
2673 | int ha_maria::delete_table(const char *name) |
2674 | { |
2675 | THD *thd= current_thd; |
2676 | (void) translog_log_debug_info(0, LOGREC_DEBUG_INFO_QUERY, |
2677 | (uchar*) thd->query(), thd->query_length()); |
2678 | return maria_delete_table(name); |
2679 | } |
2680 | |
2681 | |
2682 | /* This is mainly for temporary tables, so no logging necessary */ |
2683 | |
2684 | void ha_maria::drop_table(const char *name) |
2685 | { |
2686 | DBUG_ASSERT(file->s->temporary); |
2687 | (void) ha_close(); |
2688 | (void) maria_delete_table_files(name, 1, 0); |
2689 | } |
2690 | |
2691 | |
2692 | void ha_maria::change_table_ptr(TABLE *table_arg, TABLE_SHARE *share) |
2693 | { |
2694 | handler::change_table_ptr(table_arg, share); |
2695 | if (file) |
2696 | file->external_ref= table_arg; |
2697 | } |
2698 | |
2699 | |
2700 | int ha_maria::external_lock(THD *thd, int lock_type) |
2701 | { |
2702 | DBUG_ENTER("ha_maria::external_lock" ); |
2703 | file->external_ref= (void*) table; // For ma_killed() |
2704 | /* |
2705 | We don't test now_transactional because it may vary between lock/unlock |
2706 | and thus confuse our reference counting. |
2707 | It is critical to skip non-transactional tables: user-visible temporary |
2708 | tables get an external_lock() when read/written for the first time, but no |
2709 | corresponding unlock (they just stay locked and are later dropped while |
2710 | locked); if a tmp table was transactional, "SELECT FROM non_tmp, tmp" |
2711 | would never commit as its "locked_tables" count would stay 1. |
2712 | When Maria has has_transactions()==TRUE, open_temporary_table() |
2713 | (sql_base.cc) will use TRANSACTIONAL_TMP_TABLE and thus the |
2714 | external_lock(F_UNLCK) will happen and we can then allow the user to |
2715 | create transactional temporary tables. |
2716 | */ |
2717 | if (file->s->base.born_transactional) |
2718 | { |
2719 | /* Transactional table */ |
2720 | if (lock_type != F_UNLCK) |
2721 | { |
2722 | if (file->trn) |
2723 | { |
2724 | /* This can only happen with tables created with clone() */ |
2725 | trnman_increment_locked_tables(file->trn); |
2726 | } |
2727 | |
2728 | if (!thd->transaction.on) |
2729 | { |
2730 | /* |
2731 | No need to log REDOs/UNDOs. If this is an internal temporary table |
2732 | which will be renamed to a permanent table (like in ALTER TABLE), |
2733 | the rename happens after unlocking so will be durable (and the table |
2734 | will get its create_rename_lsn). |
2735 | Note: if we wanted to enable users to have an old backup and apply |
2736 | tons of archived logs to roll-forward, we could then not disable |
2737 | REDOs/UNDOs in this case. |
2738 | */ |
2739 | DBUG_PRINT("info" , ("Disabling logging for table" )); |
2740 | _ma_tmp_disable_logging_for_table(file, TRUE); |
2741 | } |
2742 | } |
2743 | else |
2744 | { |
2745 | TRN *trn= THD_TRN; |
2746 | /* End of transaction */ |
2747 | |
2748 | /* |
2749 | We always re-enable, don't rely on thd->transaction.on as it is |
2750 | sometimes reset to true after unlocking (see mysql_truncate() for a |
2751 | partitioned table based on Maria). |
2752 | Note that we can come here without having an exclusive lock on the |
2753 | table, for example in this case: |
2754 | external_lock(F_(WR|RD)LCK); thr_lock() which fails due to lock |
2755 | abortion; external_lock(F_UNLCK). Fortunately, the re-enabling happens |
2756 | only if we were the thread which disabled logging. |
2757 | */ |
2758 | if (_ma_reenable_logging_for_table(file, TRUE)) |
2759 | DBUG_RETURN(1); |
2760 | /** @todo zero file->trn also in commit and rollback */ |
2761 | _ma_set_trn_for_table(file, NULL); // Safety |
2762 | /* |
2763 | Ensure that file->state points to the current number of rows. This |
2764 | is needed if someone calls maria_info() without first doing an |
2765 | external lock of the table |
2766 | */ |
2767 | file->state= &file->s->state.state; |
2768 | if (trn) |
2769 | { |
2770 | DBUG_PRINT("info" , |
2771 | ("locked_tables: %u" , trnman_has_locked_tables(trn))); |
2772 | DBUG_ASSERT(trnman_has_locked_tables(trn) > 0); |
2773 | if (trnman_has_locked_tables(trn) && |
2774 | !trnman_decrement_locked_tables(trn)) |
2775 | { |
2776 | /* |
2777 | OK should not have been sent to client yet (ACID). |
2778 | This is a bit excessive, ACID requires this only if there are some |
2779 | changes to commit (rollback shouldn't be tested). |
2780 | */ |
2781 | DBUG_ASSERT(!thd->get_stmt_da()->is_sent() || |
2782 | thd->killed == KILL_CONNECTION); |
2783 | /* autocommit ? rollback a transaction */ |
2784 | #ifdef MARIA_CANNOT_ROLLBACK |
2785 | if (ma_commit(trn)) |
2786 | DBUG_RETURN(1); |
2787 | THD_TRN= 0; |
2788 | #else |
2789 | if (!(thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) |
2790 | { |
2791 | trnman_rollback_trn(trn); |
2792 | DBUG_PRINT("info" , ("THD_TRN set to 0x0" )); |
2793 | THD_TRN= 0; |
2794 | } |
2795 | #endif |
2796 | } |
2797 | trnman_set_flags(trn, trnman_get_flags(trn) & ~ TRN_STATE_INFO_LOGGED); |
2798 | } |
2799 | } |
2800 | } /* if transactional table */ |
2801 | DBUG_RETURN(maria_lock_database(file, !table->s->tmp_table ? |
2802 | lock_type : ((lock_type == F_UNLCK) ? |
2803 | F_UNLCK : F_EXTRA_LCK))); |
2804 | } |
2805 | |
2806 | int ha_maria::start_stmt(THD *thd, thr_lock_type lock_type) |
2807 | { |
2808 | TRN *trn; |
2809 | if (file->s->base.born_transactional) |
2810 | { |
2811 | trn= THD_TRN; |
2812 | DBUG_ASSERT(trn); // this may be called only after external_lock() |
2813 | DBUG_ASSERT(trnman_has_locked_tables(trn)); |
2814 | DBUG_ASSERT(lock_type != TL_UNLOCK); |
2815 | DBUG_ASSERT(file->trn == trn); |
2816 | |
2817 | /* |
2818 | If there was an implicit commit under this LOCK TABLES by a previous |
2819 | statement (like a DDL), at least if that previous statement was about a |
2820 | different ha_maria than 'this' then this->file->trn is a stale |
2821 | pointer. We fix it: |
2822 | */ |
2823 | _ma_set_trn_for_table(file, trn); |
2824 | /* |
2825 | As external_lock() was already called, don't increment locked_tables. |
2826 | Note that we call the function below possibly several times when |
2827 | statement starts (once per table). This is ok as long as that function |
2828 | does cheap operations. Otherwise, we will need to do it only on first |
2829 | call to start_stmt(). |
2830 | */ |
2831 | trnman_new_statement(trn); |
2832 | |
2833 | #ifdef EXTRA_DEBUG |
2834 | if (!(trnman_get_flags(trn) & TRN_STATE_INFO_LOGGED) && |
2835 | trnman_get_flags(trn) & TRN_STATE_TABLES_CAN_CHANGE) |
2836 | { |
2837 | trnman_set_flags(trn, trnman_get_flags(trn) | TRN_STATE_INFO_LOGGED); |
2838 | (void) translog_log_debug_info(trn, LOGREC_DEBUG_INFO_QUERY, |
2839 | (uchar*) thd->query(), |
2840 | thd->query_length()); |
2841 | } |
2842 | #endif |
2843 | } |
2844 | return 0; |
2845 | } |
2846 | |
2847 | |
2848 | /** |
2849 | Performs an implicit commit of the Maria transaction and creates a new |
2850 | one. |
2851 | |
2852 | This can be considered a hack. When Maria loses HA_NO_TRANSACTIONS it will |
2853 | be participant in the connection's transaction and so the implicit commits |
2854 | (ha_commit()) (like in end_active_trans()) will do the implicit commit |
2855 | without need to call this function which can then be removed. |
2856 | |
2857 | @param thd THD object |
2858 | @param new_trn if a new transaction should be created; a new |
2859 | transaction is not needed when we know that the |
2860 | tables will be unlocked very soon. |
2861 | */ |
2862 | |
2863 | int ha_maria::implicit_commit(THD *thd, bool new_trn) |
2864 | { |
2865 | #ifndef MARIA_CANNOT_ROLLBACK |
2866 | #error this method should be removed |
2867 | #endif |
2868 | TRN *trn; |
2869 | int error; |
2870 | uint locked_tables; |
2871 | DYNAMIC_ARRAY used_tables; |
2872 | extern my_bool plugins_are_initialized; |
2873 | |
2874 | DBUG_ENTER("ha_maria::implicit_commit" ); |
2875 | if (!maria_hton || !plugins_are_initialized || !(trn= THD_TRN)) |
2876 | DBUG_RETURN(0); |
2877 | if (!new_trn && (thd->locked_tables_mode == LTM_LOCK_TABLES || |
2878 | thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)) |
2879 | { |
2880 | /* |
2881 | No commit inside LOCK TABLES. |
2882 | |
2883 | Note that we come here only at the end of the top statement |
2884 | (dispatch_command()), we are never committing inside a sub-statement./ |
2885 | */ |
2886 | DBUG_PRINT("info" , ("locked_tables, skipping" )); |
2887 | DBUG_RETURN(0); |
2888 | } |
2889 | |
2890 | locked_tables= trnman_has_locked_tables(trn); |
2891 | |
2892 | if (new_trn && trn && trn->used_tables) |
2893 | { |
2894 | MARIA_USED_TABLES *tables; |
2895 | /* |
2896 | Save locked tables so that we can move them to another transaction |
2897 | We are using a dynamic array as locked_tables in some cases can be |
2898 | smaller than the used_tables list (for example when the server does |
2899 | early unlock of tables. |
2900 | */ |
2901 | |
2902 | my_init_dynamic_array2(&used_tables, sizeof(MARIA_SHARE*), (void*) 0, |
2903 | locked_tables, 8, MYF(MY_THREAD_SPECIFIC)); |
2904 | for (tables= (MARIA_USED_TABLES*) trn->used_tables; |
2905 | tables; |
2906 | tables= tables->next) |
2907 | { |
2908 | if (tables->share->base.born_transactional) |
2909 | { |
2910 | if (insert_dynamic(&used_tables, (uchar*) &tables->share)) |
2911 | { |
2912 | error= HA_ERR_OUT_OF_MEM; |
2913 | goto end_and_free; |
2914 | } |
2915 | } |
2916 | } |
2917 | } |
2918 | else |
2919 | bzero(&used_tables, sizeof(used_tables)); |
2920 | |
2921 | error= 0; |
2922 | if (unlikely(ma_commit(trn))) |
2923 | error= 1; |
2924 | if (!new_trn) |
2925 | { |
2926 | /* |
2927 | To be extra safe, we should also reset file->trn for all open |
2928 | tables as some calls, like extra() may access it. We take care |
2929 | of this in extra() by resetting file->trn if THD_TRN is 0. |
2930 | */ |
2931 | THD_TRN= NULL; |
2932 | goto end; |
2933 | } |
2934 | /* |
2935 | We need to create a new transaction and put it in THD_TRN. Indeed, |
2936 | tables may be under LOCK TABLES, and so they will start the next |
2937 | statement assuming they have a trn (see ha_maria::start_stmt()). |
2938 | */ |
2939 | trn= trnman_new_trn(& thd->transaction.wt); |
2940 | THD_TRN= trn; |
2941 | if (unlikely(trn == NULL)) |
2942 | { |
2943 | error= HA_ERR_OUT_OF_MEM; |
2944 | goto end_and_free; |
2945 | } |
2946 | /* |
2947 | Move all locked tables to the new transaction |
2948 | We must do it here as otherwise file->thd and file->state may be |
2949 | stale pointers. We can't do this in start_stmt() as we don't know |
2950 | when we should call _ma_setup_live_state() and in some cases, like |
2951 | in check table, we use the table without calling start_stmt(). |
2952 | */ |
2953 | |
2954 | uint i; |
2955 | for (i= 0 ; i < used_tables.elements ; i++) |
2956 | { |
2957 | MARIA_SHARE *share; |
2958 | LIST *handlers; |
2959 | |
2960 | share= *(dynamic_element(&used_tables, i, MARIA_SHARE**)); |
2961 | /* Find table instances that was used in this transaction */ |
2962 | for (handlers= share->open_list; handlers; handlers= handlers->next) |
2963 | { |
2964 | MARIA_HA *handler= (MARIA_HA*) handlers->data; |
2965 | if (handler->external_ref && |
2966 | ((TABLE*) handler->external_ref)->in_use == thd) |
2967 | { |
2968 | _ma_set_trn_for_table(handler, trn); |
2969 | /* If handler uses versioning */ |
2970 | if (handler->s->lock_key_trees) |
2971 | { |
2972 | if (_ma_setup_live_state(handler)) |
2973 | error= HA_ERR_OUT_OF_MEM; |
2974 | } |
2975 | } |
2976 | } |
2977 | } |
2978 | /* This is just a commit, tables stay locked if they were: */ |
2979 | trnman_reset_locked_tables(trn, locked_tables); |
2980 | |
2981 | end_and_free: |
2982 | delete_dynamic(&used_tables); |
2983 | end: |
2984 | DBUG_RETURN(error); |
2985 | } |
2986 | |
2987 | |
2988 | THR_LOCK_DATA **ha_maria::store_lock(THD *thd, |
2989 | THR_LOCK_DATA **to, |
2990 | enum thr_lock_type lock_type) |
2991 | { |
2992 | /* Test if we can fix test below */ |
2993 | DBUG_ASSERT(lock_type != TL_UNLOCK && |
2994 | (lock_type == TL_IGNORE || file->lock.type == TL_UNLOCK)); |
2995 | if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK) |
2996 | { |
2997 | const enum enum_sql_command sql_command= thd->lex->sql_command; |
2998 | /* |
2999 | We have to disable concurrent inserts for INSERT ... SELECT or |
3000 | INSERT/UPDATE/DELETE with sub queries if we are using statement based |
3001 | logging. We take the safe route here and disable this for all commands |
3002 | that only does reading that are not SELECT. |
3003 | */ |
3004 | if (lock_type <= TL_READ_HIGH_PRIORITY && |
3005 | !thd->is_current_stmt_binlog_format_row() && |
3006 | (sql_command != SQLCOM_SELECT && |
3007 | sql_command != SQLCOM_LOCK_TABLES) && |
3008 | (thd->variables.option_bits & OPTION_BIN_LOG) && |
3009 | mysql_bin_log.is_open()) |
3010 | lock_type= TL_READ_NO_INSERT; |
3011 | else if (lock_type == TL_WRITE_CONCURRENT_INSERT) |
3012 | { |
3013 | const enum enum_duplicates duplicates= thd->lex->duplicates; |
3014 | /* |
3015 | Explanation for the 3 conditions below, in order: |
3016 | |
3017 | - Bulk insert may use repair, which will cause problems if other |
3018 | threads try to read/insert to the table: disable versioning. |
3019 | Note that our read of file->state->records is incorrect, as such |
3020 | variable may have changed when we come to start_bulk_insert() (worse |
3021 | case: we see != 0 so allow versioning, start_bulk_insert() sees 0 and |
3022 | uses repair). This is prevented because start_bulk_insert() will not |
3023 | try repair if we enabled versioning. |
3024 | - INSERT SELECT ON DUPLICATE KEY UPDATE comes here with |
3025 | TL_WRITE_CONCURRENT_INSERT but shouldn't because it can do |
3026 | update/delete of a row and versioning doesn't support that |
3027 | - same for LOAD DATA CONCURRENT REPLACE. |
3028 | */ |
3029 | if ((file->state->records == 0) || |
3030 | (sql_command == SQLCOM_INSERT_SELECT && duplicates == DUP_UPDATE) || |
3031 | (sql_command == SQLCOM_LOAD && duplicates == DUP_REPLACE)) |
3032 | lock_type= TL_WRITE; |
3033 | } |
3034 | file->lock.type= lock_type; |
3035 | } |
3036 | *to++= &file->lock; |
3037 | return to; |
3038 | } |
3039 | |
3040 | |
3041 | void ha_maria::update_create_info(HA_CREATE_INFO *create_info) |
3042 | { |
3043 | ha_maria::info(HA_STATUS_AUTO | HA_STATUS_CONST); |
3044 | if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) |
3045 | { |
3046 | create_info->auto_increment_value= stats.auto_increment_value; |
3047 | } |
3048 | create_info->data_file_name= data_file_name; |
3049 | create_info->index_file_name= index_file_name; |
3050 | /* |
3051 | Keep user-specified row_type for ALTER, |
3052 | but show the actually used one in SHOW |
3053 | */ |
3054 | if (create_info->row_type != ROW_TYPE_DEFAULT && |
3055 | !(thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE)) |
3056 | create_info->row_type= get_row_type(); |
3057 | /* |
3058 | Show always page checksums, as this can be forced with |
3059 | maria_page_checksums variable |
3060 | */ |
3061 | if (create_info->page_checksum == HA_CHOICE_UNDEF) |
3062 | create_info->page_checksum= |
3063 | (file->s->options & HA_OPTION_PAGE_CHECKSUM) ? HA_CHOICE_YES : |
3064 | HA_CHOICE_NO; |
3065 | } |
3066 | |
3067 | |
3068 | enum row_type ha_maria::get_row_type() const |
3069 | { |
3070 | switch (file->s->data_file_type) { |
3071 | case STATIC_RECORD: return ROW_TYPE_FIXED; |
3072 | case DYNAMIC_RECORD: return ROW_TYPE_DYNAMIC; |
3073 | case BLOCK_RECORD: return ROW_TYPE_PAGE; |
3074 | case COMPRESSED_RECORD: return ROW_TYPE_COMPRESSED; |
3075 | default: return ROW_TYPE_NOT_USED; |
3076 | } |
3077 | } |
3078 | |
3079 | |
3080 | static enum data_file_type maria_row_type(HA_CREATE_INFO *info) |
3081 | { |
3082 | if (info->transactional == HA_CHOICE_YES) |
3083 | return BLOCK_RECORD; |
3084 | switch (info->row_type) { |
3085 | case ROW_TYPE_FIXED: return STATIC_RECORD; |
3086 | case ROW_TYPE_DYNAMIC: return DYNAMIC_RECORD; |
3087 | default: return BLOCK_RECORD; |
3088 | } |
3089 | } |
3090 | |
3091 | |
3092 | int ha_maria::create(const char *name, TABLE *table_arg, |
3093 | HA_CREATE_INFO *ha_create_info) |
3094 | { |
3095 | int error; |
3096 | uint create_flags= 0, record_count= 0, i; |
3097 | char buff[FN_REFLEN]; |
3098 | MARIA_KEYDEF *keydef; |
3099 | MARIA_COLUMNDEF *recinfo; |
3100 | MARIA_CREATE_INFO create_info; |
3101 | TABLE_SHARE *share= table_arg->s; |
3102 | uint options= share->db_options_in_use; |
3103 | enum data_file_type row_type; |
3104 | THD *thd= current_thd; |
3105 | DBUG_ENTER("ha_maria::create" ); |
3106 | |
3107 | for (i= 0; i < share->keys; i++) |
3108 | { |
3109 | if (table_arg->key_info[i].flags & HA_USES_PARSER) |
3110 | { |
3111 | create_flags|= HA_CREATE_RELIES_ON_SQL_LAYER; |
3112 | break; |
3113 | } |
3114 | } |
3115 | /* Note: BLOCK_RECORD is used if table is transactional */ |
3116 | row_type= maria_row_type(ha_create_info); |
3117 | if (ha_create_info->transactional == HA_CHOICE_YES && |
3118 | ha_create_info->row_type != ROW_TYPE_PAGE && |
3119 | ha_create_info->row_type != ROW_TYPE_NOT_USED && |
3120 | ha_create_info->row_type != ROW_TYPE_DEFAULT) |
3121 | push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, |
3122 | ER_ILLEGAL_HA_CREATE_OPTION, |
3123 | "Row format set to PAGE because of TRANSACTIONAL=1 option" ); |
3124 | |
3125 | if (share->table_type == TABLE_TYPE_SEQUENCE) |
3126 | { |
3127 | /* For sequences, the simples record type is appropriate */ |
3128 | row_type= STATIC_RECORD; |
3129 | ha_create_info->transactional= HA_CHOICE_NO; |
3130 | } |
3131 | |
3132 | bzero((char*) &create_info, sizeof(create_info)); |
3133 | if ((error= table2maria(table_arg, row_type, &keydef, &recinfo, |
3134 | &record_count, &create_info))) |
3135 | DBUG_RETURN(error); /* purecov: inspected */ |
3136 | create_info.max_rows= share->max_rows; |
3137 | create_info.reloc_rows= share->min_rows; |
3138 | create_info.with_auto_increment= share->next_number_key_offset == 0; |
3139 | create_info.auto_increment= (ha_create_info->auto_increment_value ? |
3140 | ha_create_info->auto_increment_value -1 : |
3141 | (ulonglong) 0); |
3142 | create_info.data_file_length= ((ulonglong) share->max_rows * |
3143 | share->avg_row_length); |
3144 | create_info.data_file_name= ha_create_info->data_file_name; |
3145 | create_info.index_file_name= ha_create_info->index_file_name; |
3146 | create_info.language= share->table_charset->number; |
3147 | |
3148 | /* |
3149 | Table is transactional: |
3150 | - If the user specify that table is transactional (in this case |
3151 | row type is forced to BLOCK_RECORD) |
3152 | - If they specify BLOCK_RECORD without specifying transactional behaviour |
3153 | |
3154 | Shouldn't this test be pushed down to maria_create()? Because currently, |
3155 | ma_test1 -T crashes: it creates a table with DYNAMIC_RECORD but has |
3156 | born_transactional==1, which confuses some recovery-related code. |
3157 | */ |
3158 | create_info.transactional= (row_type == BLOCK_RECORD && |
3159 | ha_create_info->transactional != HA_CHOICE_NO); |
3160 | |
3161 | if (ha_create_info->tmp_table()) |
3162 | { |
3163 | create_flags|= HA_CREATE_TMP_TABLE | HA_CREATE_DELAY_KEY_WRITE; |
3164 | create_info.transactional= 0; |
3165 | } |
3166 | if (ha_create_info->options & HA_CREATE_KEEP_FILES) |
3167 | create_flags|= HA_CREATE_KEEP_FILES; |
3168 | if (options & HA_OPTION_PACK_RECORD) |
3169 | create_flags|= HA_PACK_RECORD; |
3170 | if (options & HA_OPTION_CHECKSUM) |
3171 | create_flags|= HA_CREATE_CHECKSUM; |
3172 | if (options & HA_OPTION_DELAY_KEY_WRITE) |
3173 | create_flags|= HA_CREATE_DELAY_KEY_WRITE; |
3174 | if ((ha_create_info->page_checksum == HA_CHOICE_UNDEF && |
3175 | maria_page_checksums) || |
3176 | ha_create_info->page_checksum == HA_CHOICE_YES) |
3177 | create_flags|= HA_CREATE_PAGE_CHECKSUM; |
3178 | |
3179 | (void) translog_log_debug_info(0, LOGREC_DEBUG_INFO_QUERY, |
3180 | (uchar*) thd->query(), thd->query_length()); |
3181 | |
3182 | /* TODO: Check that the following fn_format is really needed */ |
3183 | error= |
3184 | maria_create(fn_format(buff, name, "" , "" , |
3185 | MY_UNPACK_FILENAME | MY_APPEND_EXT), |
3186 | row_type, share->keys, keydef, |
3187 | record_count, recinfo, |
3188 | 0, (MARIA_UNIQUEDEF *) 0, |
3189 | &create_info, create_flags); |
3190 | |
3191 | my_free(recinfo); |
3192 | DBUG_RETURN(error); |
3193 | } |
3194 | |
3195 | |
3196 | int ha_maria::rename_table(const char *from, const char *to) |
3197 | { |
3198 | THD *thd= current_thd; |
3199 | (void) translog_log_debug_info(0, LOGREC_DEBUG_INFO_QUERY, |
3200 | (uchar*) thd->query(), thd->query_length()); |
3201 | return maria_rename(from, to); |
3202 | } |
3203 | |
3204 | |
3205 | void ha_maria::get_auto_increment(ulonglong offset, ulonglong increment, |
3206 | ulonglong nb_desired_values, |
3207 | ulonglong *first_value, |
3208 | ulonglong *nb_reserved_values) |
3209 | { |
3210 | ulonglong nr; |
3211 | int error; |
3212 | uchar key[MARIA_MAX_KEY_BUFF]; |
3213 | |
3214 | if (!table->s->next_number_key_offset) |
3215 | { // Autoincrement at key-start |
3216 | ha_maria::info(HA_STATUS_AUTO); |
3217 | *first_value= stats.auto_increment_value; |
3218 | /* Maria has only table-level lock for now, so reserves to +inf */ |
3219 | *nb_reserved_values= ULONGLONG_MAX; |
3220 | return; |
3221 | } |
3222 | |
3223 | /* it's safe to call the following if bulk_insert isn't on */ |
3224 | maria_flush_bulk_insert(file, table->s->next_number_index); |
3225 | |
3226 | (void) extra(HA_EXTRA_KEYREAD); |
3227 | key_copy(key, table->record[0], |
3228 | table->key_info + table->s->next_number_index, |
3229 | table->s->next_number_key_offset); |
3230 | error= maria_rkey(file, table->record[1], (int) table->s->next_number_index, |
3231 | key, make_prev_keypart_map(table->s->next_number_keypart), |
3232 | HA_READ_PREFIX_LAST); |
3233 | if (error) |
3234 | nr= 1; |
3235 | else |
3236 | { |
3237 | /* Get data from record[1] */ |
3238 | nr= ((ulonglong) table->next_number_field-> |
3239 | val_int_offset(table->s->rec_buff_length) + 1); |
3240 | } |
3241 | extra(HA_EXTRA_NO_KEYREAD); |
3242 | *first_value= nr; |
3243 | /* |
3244 | MySQL needs to call us for next row: assume we are inserting ("a",null) |
3245 | here, we return 3, and next this statement will want to insert ("b",null): |
3246 | there is no reason why ("b",3+1) would be the good row to insert: maybe it |
3247 | already exists, maybe 3+1 is too large... |
3248 | */ |
3249 | *nb_reserved_values= 1; |
3250 | } |
3251 | |
3252 | |
3253 | /* |
3254 | Find out how many rows there is in the given range |
3255 | |
3256 | SYNOPSIS |
3257 | records_in_range() |
3258 | inx Index to use |
3259 | min_key Start of range. Null pointer if from first key |
3260 | max_key End of range. Null pointer if to last key |
3261 | |
3262 | NOTES |
3263 | min_key.flag can have one of the following values: |
3264 | HA_READ_KEY_EXACT Include the key in the range |
3265 | HA_READ_AFTER_KEY Don't include key in range |
3266 | |
3267 | max_key.flag can have one of the following values: |
3268 | HA_READ_BEFORE_KEY Don't include key in range |
3269 | HA_READ_AFTER_KEY Include all 'end_key' values in the range |
3270 | |
3271 | RETURN |
3272 | HA_POS_ERROR Something is wrong with the index tree. |
3273 | 0 There is no matching keys in the given range |
3274 | number > 0 There is approximately 'number' matching rows in |
3275 | the range. |
3276 | */ |
3277 | |
3278 | ha_rows ha_maria::records_in_range(uint inx, key_range *min_key, |
3279 | key_range *max_key) |
3280 | { |
3281 | return (ha_rows) maria_records_in_range(file, (int) inx, min_key, max_key); |
3282 | } |
3283 | |
3284 | |
3285 | int ha_maria::ft_read(uchar * buf) |
3286 | { |
3287 | int error; |
3288 | |
3289 | if (!ft_handler) |
3290 | return -1; |
3291 | |
3292 | thread_safe_increment(table->in_use->status_var.ha_read_next_count, |
3293 | &LOCK_status); // why ? |
3294 | |
3295 | error= ft_handler->please->read_next(ft_handler, (char*) buf); |
3296 | |
3297 | return error; |
3298 | } |
3299 | |
3300 | |
3301 | uint ha_maria::checksum() const |
3302 | { |
3303 | return (uint) file->state->checksum; |
3304 | } |
3305 | |
3306 | |
3307 | bool ha_maria::check_if_incompatible_data(HA_CREATE_INFO *create_info, |
3308 | uint table_changes) |
3309 | { |
3310 | DBUG_ENTER("check_if_incompatible_data" ); |
3311 | uint options= table->s->db_options_in_use; |
3312 | enum ha_choice page_checksum= table->s->page_checksum; |
3313 | |
3314 | if (page_checksum == HA_CHOICE_UNDEF) |
3315 | page_checksum= file->s->options & HA_OPTION_PAGE_CHECKSUM ? HA_CHOICE_YES |
3316 | : HA_CHOICE_NO; |
3317 | |
3318 | if (create_info->auto_increment_value != stats.auto_increment_value || |
3319 | create_info->data_file_name != data_file_name || |
3320 | create_info->index_file_name != index_file_name || |
3321 | create_info->page_checksum != page_checksum || |
3322 | create_info->transactional != table->s->transactional || |
3323 | (maria_row_type(create_info) != data_file_type && |
3324 | create_info->row_type != ROW_TYPE_DEFAULT) || |
3325 | table_changes == IS_EQUAL_NO || |
3326 | (table_changes & IS_EQUAL_PACK_LENGTH)) // Not implemented yet |
3327 | DBUG_RETURN(COMPATIBLE_DATA_NO); |
3328 | |
3329 | if ((options & (HA_OPTION_CHECKSUM | |
3330 | HA_OPTION_DELAY_KEY_WRITE)) != |
3331 | (create_info->table_options & (HA_OPTION_CHECKSUM | |
3332 | HA_OPTION_DELAY_KEY_WRITE))) |
3333 | DBUG_RETURN(COMPATIBLE_DATA_NO); |
3334 | DBUG_RETURN(COMPATIBLE_DATA_YES); |
3335 | } |
3336 | |
3337 | |
3338 | static int maria_hton_panic(handlerton *hton, ha_panic_function flag) |
3339 | { |
3340 | /* If no background checkpoints, we need to do one now */ |
3341 | int ret=0; |
3342 | |
3343 | if (!checkpoint_interval) |
3344 | ret= ma_checkpoint_execute(CHECKPOINT_FULL, FALSE); |
3345 | |
3346 | ret|= maria_panic(flag); |
3347 | |
3348 | maria_hton= 0; |
3349 | return ret; |
3350 | } |
3351 | |
3352 | |
3353 | static int maria_commit(handlerton *hton __attribute__ ((unused)), |
3354 | THD *thd, bool all) |
3355 | { |
3356 | TRN *trn= THD_TRN; |
3357 | DBUG_ENTER("maria_commit" ); |
3358 | trnman_reset_locked_tables(trn, 0); |
3359 | trnman_set_flags(trn, trnman_get_flags(trn) & ~TRN_STATE_INFO_LOGGED); |
3360 | |
3361 | /* statement or transaction ? */ |
3362 | if ((thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && !all) |
3363 | DBUG_RETURN(0); // end of statement |
3364 | DBUG_PRINT("info" , ("THD_TRN set to 0x0" )); |
3365 | THD_TRN= 0; |
3366 | DBUG_RETURN(ma_commit(trn)); // end of transaction |
3367 | } |
3368 | |
3369 | |
3370 | static int maria_rollback(handlerton *hton __attribute__ ((unused)), |
3371 | THD *thd, bool all) |
3372 | { |
3373 | TRN *trn= THD_TRN; |
3374 | DBUG_ENTER("maria_rollback" ); |
3375 | trnman_reset_locked_tables(trn, 0); |
3376 | /* statement or transaction ? */ |
3377 | if ((thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && !all) |
3378 | { |
3379 | trnman_rollback_statement(trn); |
3380 | DBUG_RETURN(0); // end of statement |
3381 | } |
3382 | DBUG_PRINT("info" , ("THD_TRN set to 0x0" )); |
3383 | THD_TRN= 0; |
3384 | DBUG_RETURN(trnman_rollback_trn(trn) ? |
3385 | HA_ERR_OUT_OF_MEM : 0); // end of transaction |
3386 | } |
3387 | |
3388 | |
3389 | |
3390 | /** |
3391 | @brief flush log handler |
3392 | |
3393 | @param hton maria handlerton (unused) |
3394 | |
3395 | @retval FALSE OK |
3396 | @retval TRUE Error |
3397 | */ |
3398 | |
3399 | bool maria_flush_logs(handlerton *hton) |
3400 | { |
3401 | return MY_TEST(translog_purge_at_flush()); |
3402 | } |
3403 | |
3404 | |
3405 | int maria_checkpoint_state(handlerton *hton, bool disabled) |
3406 | { |
3407 | maria_checkpoint_disabled= (my_bool) disabled; |
3408 | return 0; |
3409 | } |
3410 | |
3411 | |
3412 | |
3413 | #define SHOW_MSG_LEN (FN_REFLEN + 20) |
3414 | /** |
3415 | @brief show status handler |
3416 | |
3417 | @param hton maria handlerton |
3418 | @param thd thread handler |
3419 | @param print print function |
3420 | @param stat type of status |
3421 | */ |
3422 | |
3423 | bool maria_show_status(handlerton *hton, |
3424 | THD *thd, |
3425 | stat_print_fn *print, |
3426 | enum ha_stat_type stat) |
3427 | { |
3428 | const LEX_CSTRING *engine_name= hton_name(hton); |
3429 | switch (stat) { |
3430 | case HA_ENGINE_LOGS: |
3431 | { |
3432 | TRANSLOG_ADDRESS horizon= translog_get_horizon(); |
3433 | uint32 last_file= LSN_FILE_NO(horizon); |
3434 | uint32 first_needed= translog_get_first_needed_file(); |
3435 | uint32 first_file= translog_get_first_file(horizon); |
3436 | uint32 i; |
3437 | const char unknown[]= "unknown" ; |
3438 | const char needed[]= "in use" ; |
3439 | const char unneeded[]= "free" ; |
3440 | char path[FN_REFLEN]; |
3441 | |
3442 | if (first_file == 0) |
3443 | { |
3444 | const char error[]= "error" ; |
3445 | print(thd, engine_name->str, engine_name->length, |
3446 | STRING_WITH_LEN("" ), error, sizeof(error) - 1); |
3447 | break; |
3448 | } |
3449 | |
3450 | for (i= first_file; i <= last_file; i++) |
3451 | { |
3452 | char *file; |
3453 | const char *status; |
3454 | size_t length, status_len; |
3455 | MY_STAT stat_buff, *stat; |
3456 | const char error[]= "can't stat" ; |
3457 | char object[SHOW_MSG_LEN]; |
3458 | file= translog_filename_by_fileno(i, path); |
3459 | if (!(stat= mysql_file_stat(key_file_translog, file, &stat_buff, MYF(0)))) |
3460 | { |
3461 | status= error; |
3462 | status_len= sizeof(error) - 1; |
3463 | length= my_snprintf(object, SHOW_MSG_LEN, "Size unknown ; %s" , file); |
3464 | } |
3465 | else |
3466 | { |
3467 | if (first_needed == 0) |
3468 | { |
3469 | status= unknown; |
3470 | status_len= sizeof(unknown) - 1; |
3471 | } |
3472 | else if (i < first_needed) |
3473 | { |
3474 | status= unneeded; |
3475 | status_len= sizeof(unneeded) - 1; |
3476 | } |
3477 | else |
3478 | { |
3479 | status= needed; |
3480 | status_len= sizeof(needed) - 1; |
3481 | } |
3482 | length= my_snprintf(object, SHOW_MSG_LEN, "Size %12llu ; %s" , |
3483 | (ulonglong) stat->st_size, file); |
3484 | } |
3485 | |
3486 | print(thd, engine_name->str, engine_name->length, |
3487 | object, length, status, status_len); |
3488 | } |
3489 | break; |
3490 | } |
3491 | case HA_ENGINE_STATUS: |
3492 | case HA_ENGINE_MUTEX: |
3493 | default: |
3494 | break; |
3495 | } |
3496 | return 0; |
3497 | } |
3498 | |
3499 | |
3500 | /** |
3501 | Callback to delete all logs in directory. This is lower-level than other |
3502 | functions in ma_loghandler.c which delete logs, as it does not rely on |
3503 | translog_init() having been called first. |
3504 | |
3505 | @param directory directory where file is |
3506 | @param filename base name of the file to delete |
3507 | */ |
3508 | |
3509 | static my_bool translog_callback_delete_all(const char *directory, |
3510 | const char *filename) |
3511 | { |
3512 | char complete_name[FN_REFLEN]; |
3513 | fn_format(complete_name, filename, directory, "" , MYF(MY_UNPACK_FILENAME)); |
3514 | return mysql_file_delete(key_file_translog, complete_name, MYF(MY_WME)); |
3515 | } |
3516 | |
3517 | |
3518 | /** |
3519 | Helper function for option aria-force-start-after-recovery-failures. |
3520 | Deletes logs if too many failures. Otherwise, increments the counter of |
3521 | failures in the control file. |
3522 | Notice how this has to be called _before_ translog_init() (if log is |
3523 | corrupted, translog_init() might crash the server, so we need to remove logs |
3524 | before). |
3525 | |
3526 | @param log_dir directory where logs to be deleted are |
3527 | */ |
3528 | |
3529 | static int mark_recovery_start(const char* log_dir) |
3530 | { |
3531 | int res; |
3532 | DBUG_ENTER("mark_recovery_start" ); |
3533 | if (!(maria_recover_options & HA_RECOVER_ANY)) |
3534 | ma_message_no_user(ME_JUST_WARNING, "Please consider using option" |
3535 | " --aria-recover-options[=...] to automatically check and" |
3536 | " repair tables when logs are removed by option" |
3537 | " --aria-force-start-after-recovery-failures=#" ); |
3538 | if (recovery_failures >= force_start_after_recovery_failures) |
3539 | { |
3540 | /* |
3541 | Remove logs which cause the problem; keep control file which has |
3542 | critical info like uuid, max_trid (removing control file may make |
3543 | correct tables look corrupted!). |
3544 | */ |
3545 | char msg[100]; |
3546 | res= translog_walk_filenames(log_dir, &translog_callback_delete_all); |
3547 | my_snprintf(msg, sizeof(msg), |
3548 | "%s logs after %u consecutive failures of" |
3549 | " recovery from logs" , |
3550 | (res ? "failed to remove some" : "removed all" ), |
3551 | recovery_failures); |
3552 | ma_message_no_user((res ? 0 : ME_JUST_WARNING), msg); |
3553 | } |
3554 | else |
3555 | res= ma_control_file_write_and_force(last_checkpoint_lsn, last_logno, |
3556 | max_trid_in_control_file, |
3557 | recovery_failures + 1); |
3558 | DBUG_RETURN(res); |
3559 | } |
3560 | |
3561 | |
3562 | /** |
3563 | Helper function for option aria-force-start-after-recovery-failures. |
3564 | Records in the control file that recovery was a success, so that it's not |
3565 | counted for aria-force-start-after-recovery-failures. |
3566 | */ |
3567 | |
3568 | static int mark_recovery_success(void) |
3569 | { |
3570 | /* success of recovery, reset recovery_failures: */ |
3571 | int res; |
3572 | DBUG_ENTER("mark_recovery_success" ); |
3573 | res= ma_control_file_write_and_force(last_checkpoint_lsn, last_logno, |
3574 | max_trid_in_control_file, 0); |
3575 | DBUG_RETURN(res); |
3576 | } |
3577 | |
3578 | |
3579 | /* |
3580 | Return 1 if table has changed during the current transaction |
3581 | */ |
3582 | |
3583 | bool ha_maria::is_changed() const |
3584 | { |
3585 | return file->state->changed; |
3586 | } |
3587 | |
3588 | |
3589 | static int ha_maria_init(void *p) |
3590 | { |
3591 | int res; |
3592 | const char *log_dir= maria_data_root; |
3593 | |
3594 | #ifdef HAVE_PSI_INTERFACE |
3595 | init_aria_psi_keys(); |
3596 | #endif |
3597 | |
3598 | maria_hton= (handlerton *)p; |
3599 | maria_hton->state= SHOW_OPTION_YES; |
3600 | maria_hton->db_type= DB_TYPE_ARIA; |
3601 | maria_hton->create= maria_create_handler; |
3602 | maria_hton->panic= maria_hton_panic; |
3603 | maria_hton->tablefile_extensions= ha_maria_exts; |
3604 | maria_hton->commit= maria_commit; |
3605 | maria_hton->rollback= maria_rollback; |
3606 | maria_hton->checkpoint_state= maria_checkpoint_state; |
3607 | #ifdef MARIA_CANNOT_ROLLBACK |
3608 | maria_hton->commit= 0; |
3609 | #endif |
3610 | maria_hton->flush_logs= maria_flush_logs; |
3611 | maria_hton->show_status= maria_show_status; |
3612 | /* TODO: decide if we support Maria being used for log tables */ |
3613 | maria_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES; |
3614 | bzero(maria_log_pagecache, sizeof(*maria_log_pagecache)); |
3615 | maria_tmpdir= &mysql_tmpdir_list; /* For REDO */ |
3616 | res= maria_upgrade() || maria_init() || ma_control_file_open(TRUE, TRUE) || |
3617 | ((force_start_after_recovery_failures != 0) && |
3618 | mark_recovery_start(log_dir)) || |
3619 | !init_pagecache(maria_pagecache, |
3620 | (size_t) pagecache_buffer_size, pagecache_division_limit, |
3621 | pagecache_age_threshold, maria_block_size, pagecache_file_hash_size, |
3622 | 0) || |
3623 | !init_pagecache(maria_log_pagecache, |
3624 | TRANSLOG_PAGECACHE_SIZE, 0, 0, |
3625 | TRANSLOG_PAGE_SIZE, 0, 0) || |
3626 | translog_init(maria_data_root, log_file_size, |
3627 | MYSQL_VERSION_ID, server_id, maria_log_pagecache, |
3628 | TRANSLOG_DEFAULT_FLAGS, 0) || |
3629 | maria_recovery_from_log() || |
3630 | ((force_start_after_recovery_failures != 0 || |
3631 | maria_recovery_changed_data) && mark_recovery_success()) || |
3632 | ma_checkpoint_init(checkpoint_interval); |
3633 | maria_multi_threaded= maria_in_ha_maria= TRUE; |
3634 | maria_create_trn_hook= maria_create_trn_for_mysql; |
3635 | maria_pagecache->extra_debug= 1; |
3636 | maria_assert_if_crashed_table= debug_assert_if_crashed_table; |
3637 | |
3638 | if (res) |
3639 | maria_hton= 0; |
3640 | |
3641 | ma_killed= ma_killed_in_mariadb; |
3642 | |
3643 | return res ? HA_ERR_INITIALIZATION : 0; |
3644 | } |
3645 | |
3646 | |
3647 | #ifdef HAVE_QUERY_CACHE |
3648 | /** |
3649 | @brief Register a named table with a call back function to the query cache. |
3650 | |
3651 | @param thd The thread handle |
3652 | @param table_key A pointer to the table name in the table cache |
3653 | @param key_length The length of the table name |
3654 | @param[out] engine_callback The pointer to the storage engine call back |
3655 | function, currently 0 |
3656 | @param[out] engine_data Engine data will be set to 0. |
3657 | |
3658 | @note Despite the name of this function, it is used to check each statement |
3659 | before it is cached and not to register a table or callback function. |
3660 | |
3661 | @see handler::register_query_cache_table |
3662 | |
3663 | @return The error code. The engine_data and engine_callback will be set to 0. |
3664 | @retval TRUE Success |
3665 | @retval FALSE An error occurred |
3666 | */ |
3667 | |
3668 | my_bool ha_maria::register_query_cache_table(THD *thd, const char *table_name, |
3669 | uint table_name_len, |
3670 | qc_engine_callback |
3671 | *engine_callback, |
3672 | ulonglong *engine_data) |
3673 | { |
3674 | ulonglong actual_data_file_length; |
3675 | ulonglong current_data_file_length; |
3676 | DBUG_ENTER("ha_maria::register_query_cache_table" ); |
3677 | |
3678 | /* |
3679 | No call back function is needed to determine if a cached statement |
3680 | is valid or not. |
3681 | */ |
3682 | *engine_callback= 0; |
3683 | |
3684 | /* |
3685 | No engine data is needed. |
3686 | */ |
3687 | *engine_data= 0; |
3688 | |
3689 | if (file->s->now_transactional && file->s->have_versioning) |
3690 | DBUG_RETURN(file->trn->trid >= file->s->state.last_change_trn); |
3691 | |
3692 | /* |
3693 | If a concurrent INSERT has happened just before the currently processed |
3694 | SELECT statement, the total size of the table is unknown. |
3695 | |
3696 | To determine if the table size is known, the current thread's snap shot of |
3697 | the table size with the actual table size are compared. |
3698 | |
3699 | If the table size is unknown the SELECT statement can't be cached. |
3700 | */ |
3701 | |
3702 | /* |
3703 | POSIX visibility rules specify that "2. Whatever memory values a |
3704 | thread can see when it unlocks a mutex <...> can also be seen by any |
3705 | thread that later locks the same mutex". In this particular case, |
3706 | concurrent insert thread had modified the data_file_length in |
3707 | MYISAM_SHARE before it has unlocked (or even locked) |
3708 | structure_guard_mutex. So, here we're guaranteed to see at least that |
3709 | value after we've locked the same mutex. We can see a later value |
3710 | (modified by some other thread) though, but it's ok, as we only want |
3711 | to know if the variable was changed, the actual new value doesn't matter |
3712 | */ |
3713 | actual_data_file_length= file->s->state.state.data_file_length; |
3714 | current_data_file_length= file->state->data_file_length; |
3715 | |
3716 | /* Return whether is ok to try to cache current statement. */ |
3717 | DBUG_RETURN(!(file->s->non_transactional_concurrent_insert && |
3718 | current_data_file_length != actual_data_file_length)); |
3719 | } |
3720 | #endif |
3721 | |
3722 | struct st_mysql_sys_var* system_variables[]= { |
3723 | MYSQL_SYSVAR(block_size), |
3724 | MYSQL_SYSVAR(checkpoint_interval), |
3725 | MYSQL_SYSVAR(checkpoint_log_activity), |
3726 | MYSQL_SYSVAR(force_start_after_recovery_failures), |
3727 | MYSQL_SYSVAR(group_commit), |
3728 | MYSQL_SYSVAR(group_commit_interval), |
3729 | MYSQL_SYSVAR(log_dir_path), |
3730 | MYSQL_SYSVAR(log_file_size), |
3731 | MYSQL_SYSVAR(log_purge_type), |
3732 | MYSQL_SYSVAR(max_sort_file_size), |
3733 | MYSQL_SYSVAR(page_checksum), |
3734 | MYSQL_SYSVAR(pagecache_age_threshold), |
3735 | MYSQL_SYSVAR(pagecache_buffer_size), |
3736 | MYSQL_SYSVAR(pagecache_division_limit), |
3737 | MYSQL_SYSVAR(pagecache_file_hash_size), |
3738 | MYSQL_SYSVAR(recover_options), |
3739 | MYSQL_SYSVAR(repair_threads), |
3740 | MYSQL_SYSVAR(sort_buffer_size), |
3741 | MYSQL_SYSVAR(stats_method), |
3742 | MYSQL_SYSVAR(sync_log_dir), |
3743 | MYSQL_SYSVAR(used_for_temp_tables), |
3744 | MYSQL_SYSVAR(encrypt_tables), |
3745 | NULL |
3746 | }; |
3747 | |
3748 | |
3749 | /** |
3750 | @brief Updates the checkpoint interval and restarts the background thread. |
3751 | */ |
3752 | |
3753 | static void update_checkpoint_interval(MYSQL_THD thd, |
3754 | struct st_mysql_sys_var *var, |
3755 | void *var_ptr, const void *save) |
3756 | { |
3757 | ma_checkpoint_end(); |
3758 | ma_checkpoint_init(*(ulong *)var_ptr= (ulong)(*(long *)save)); |
3759 | } |
3760 | |
3761 | |
3762 | /** |
3763 | @brief Updates group commit mode |
3764 | */ |
3765 | |
3766 | static void update_maria_group_commit(MYSQL_THD thd, |
3767 | struct st_mysql_sys_var *var, |
3768 | void *var_ptr, const void *save) |
3769 | { |
3770 | ulong value= (ulong)*((long *)var_ptr); |
3771 | DBUG_ENTER("update_maria_group_commit" ); |
3772 | DBUG_PRINT("enter" , ("old value: %lu new value %lu rate %lu" , |
3773 | value, (ulong)(*(long *)save), |
3774 | maria_group_commit_interval)); |
3775 | /* old value */ |
3776 | switch (value) { |
3777 | case TRANSLOG_GCOMMIT_NONE: |
3778 | break; |
3779 | case TRANSLOG_GCOMMIT_HARD: |
3780 | translog_hard_group_commit(FALSE); |
3781 | break; |
3782 | case TRANSLOG_GCOMMIT_SOFT: |
3783 | translog_soft_sync(FALSE); |
3784 | if (maria_group_commit_interval) |
3785 | translog_soft_sync_end(); |
3786 | break; |
3787 | default: |
3788 | DBUG_ASSERT(0); /* impossible */ |
3789 | } |
3790 | value= *(ulong *)var_ptr= (ulong)(*(long *)save); |
3791 | translog_sync(); |
3792 | /* new value */ |
3793 | switch (value) { |
3794 | case TRANSLOG_GCOMMIT_NONE: |
3795 | break; |
3796 | case TRANSLOG_GCOMMIT_HARD: |
3797 | translog_hard_group_commit(TRUE); |
3798 | break; |
3799 | case TRANSLOG_GCOMMIT_SOFT: |
3800 | translog_soft_sync(TRUE); |
3801 | /* variable change made under global lock so we can just read it */ |
3802 | if (maria_group_commit_interval) |
3803 | translog_soft_sync_start(); |
3804 | break; |
3805 | default: |
3806 | DBUG_ASSERT(0); /* impossible */ |
3807 | } |
3808 | DBUG_VOID_RETURN; |
3809 | } |
3810 | |
3811 | /** |
3812 | @brief Updates group commit interval |
3813 | */ |
3814 | |
3815 | static void update_maria_group_commit_interval(MYSQL_THD thd, |
3816 | struct st_mysql_sys_var *var, |
3817 | void *var_ptr, const void *save) |
3818 | { |
3819 | ulong new_value= (ulong)*((long *)save); |
3820 | ulong *value_ptr= (ulong*) var_ptr; |
3821 | DBUG_ENTER("update_maria_group_commit_interval" ); |
3822 | DBUG_PRINT("enter" , ("old value: %lu new value %lu group commit %lu" , |
3823 | *value_ptr, new_value, maria_group_commit)); |
3824 | |
3825 | /* variable change made under global lock so we can just read it */ |
3826 | switch (maria_group_commit) { |
3827 | case TRANSLOG_GCOMMIT_NONE: |
3828 | *value_ptr= new_value; |
3829 | translog_set_group_commit_interval(new_value); |
3830 | break; |
3831 | case TRANSLOG_GCOMMIT_HARD: |
3832 | *value_ptr= new_value; |
3833 | translog_set_group_commit_interval(new_value); |
3834 | break; |
3835 | case TRANSLOG_GCOMMIT_SOFT: |
3836 | if (*value_ptr) |
3837 | translog_soft_sync_end(); |
3838 | translog_set_group_commit_interval(new_value); |
3839 | if ((*value_ptr= new_value)) |
3840 | translog_soft_sync_start(); |
3841 | break; |
3842 | default: |
3843 | DBUG_ASSERT(0); /* impossible */ |
3844 | } |
3845 | DBUG_VOID_RETURN; |
3846 | } |
3847 | |
3848 | /** |
3849 | @brief Updates the transaction log file limit. |
3850 | */ |
3851 | |
3852 | static void update_log_file_size(MYSQL_THD thd, |
3853 | struct st_mysql_sys_var *var, |
3854 | void *var_ptr, const void *save) |
3855 | { |
3856 | uint32 size= (uint32)((ulong)(*(long *)save)); |
3857 | translog_set_file_size(size); |
3858 | *(ulong *)var_ptr= size; |
3859 | } |
3860 | |
3861 | |
3862 | SHOW_VAR status_variables[]= { |
3863 | {"pagecache_blocks_not_flushed" , (char*) &maria_pagecache_var.global_blocks_changed, SHOW_LONG}, |
3864 | {"pagecache_blocks_unused" , (char*) &maria_pagecache_var.blocks_unused, SHOW_LONG}, |
3865 | {"pagecache_blocks_used" , (char*) &maria_pagecache_var.blocks_used, SHOW_LONG}, |
3866 | {"pagecache_read_requests" , (char*) &maria_pagecache_var.global_cache_r_requests, SHOW_LONGLONG}, |
3867 | {"pagecache_reads" , (char*) &maria_pagecache_var.global_cache_read, SHOW_LONGLONG}, |
3868 | {"pagecache_write_requests" , (char*) &maria_pagecache_var.global_cache_w_requests, SHOW_LONGLONG}, |
3869 | {"pagecache_writes" , (char*) &maria_pagecache_var.global_cache_write, SHOW_LONGLONG}, |
3870 | {"transaction_log_syncs" , (char*) &translog_syncs, SHOW_LONGLONG}, |
3871 | {NullS, NullS, SHOW_LONG} |
3872 | }; |
3873 | |
3874 | /**************************************************************************** |
3875 | * Maria MRR implementation: use DS-MRR |
3876 | ***************************************************************************/ |
3877 | |
3878 | int ha_maria::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param, |
3879 | uint n_ranges, uint mode, |
3880 | HANDLER_BUFFER *buf) |
3881 | { |
3882 | return ds_mrr.dsmrr_init(this, seq, seq_init_param, n_ranges, mode, buf); |
3883 | } |
3884 | |
3885 | int ha_maria::multi_range_read_next(range_id_t *range_info) |
3886 | { |
3887 | return ds_mrr.dsmrr_next(range_info); |
3888 | } |
3889 | |
3890 | ha_rows ha_maria::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, |
3891 | void *seq_init_param, |
3892 | uint n_ranges, uint *bufsz, |
3893 | uint *flags, Cost_estimate *cost) |
3894 | { |
3895 | /* |
3896 | This call is here because there is no location where this->table would |
3897 | already be known. |
3898 | TODO: consider moving it into some per-query initialization call. |
3899 | */ |
3900 | ds_mrr.init(this, table); |
3901 | return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz, |
3902 | flags, cost); |
3903 | } |
3904 | |
3905 | ha_rows ha_maria::multi_range_read_info(uint keyno, uint n_ranges, uint keys, |
3906 | uint key_parts, uint *bufsz, |
3907 | uint *flags, Cost_estimate *cost) |
3908 | { |
3909 | ds_mrr.init(this, table); |
3910 | return ds_mrr.dsmrr_info(keyno, n_ranges, keys, key_parts, bufsz, flags, cost); |
3911 | } |
3912 | |
3913 | int ha_maria::multi_range_read_explain_info(uint mrr_mode, char *str, |
3914 | size_t size) |
3915 | { |
3916 | return ds_mrr.dsmrr_explain_info(mrr_mode, str, size); |
3917 | } |
3918 | /* MyISAM MRR implementation ends */ |
3919 | |
3920 | |
3921 | /* Index condition pushdown implementation*/ |
3922 | |
3923 | |
3924 | Item *ha_maria::idx_cond_push(uint keyno_arg, Item* idx_cond_arg) |
3925 | { |
3926 | /* |
3927 | Check if the key contains a blob field. If it does then MyISAM |
3928 | should not accept the pushed index condition since MyISAM will not |
3929 | read the blob field from the index entry during evaluation of the |
3930 | pushed index condition and the BLOB field might be part of the |
3931 | range evaluation done by the ICP code. |
3932 | */ |
3933 | const KEY *key= &table_share->key_info[keyno_arg]; |
3934 | |
3935 | for (uint k= 0; k < key->user_defined_key_parts; ++k) |
3936 | { |
3937 | const KEY_PART_INFO *key_part= &key->key_part[k]; |
3938 | if (key_part->key_part_flag & HA_BLOB_PART) |
3939 | { |
3940 | /* Let the server handle the index condition */ |
3941 | return idx_cond_arg; |
3942 | } |
3943 | } |
3944 | |
3945 | pushed_idx_cond_keyno= keyno_arg; |
3946 | pushed_idx_cond= idx_cond_arg; |
3947 | in_range_check_pushed_down= TRUE; |
3948 | if (active_index == pushed_idx_cond_keyno) |
3949 | ma_set_index_cond_func(file, handler_index_cond_check, this); |
3950 | return NULL; |
3951 | } |
3952 | |
3953 | /** |
3954 | Find record by unique constrain (used in temporary tables) |
3955 | |
3956 | @param record (IN|OUT) the record to find |
3957 | @param constrain_no (IN) number of constrain (for this engine) |
3958 | |
3959 | @note It is like hp_search but uses function for raw where hp_search |
3960 | uses functions for index. |
3961 | |
3962 | @retval 0 OK |
3963 | @retval 1 Not found |
3964 | @retval -1 Error |
3965 | */ |
3966 | |
3967 | int ha_maria::find_unique_row(uchar *record, uint constrain_no) |
3968 | { |
3969 | int rc; |
3970 | if (file->s->state.header.uniques) |
3971 | { |
3972 | DBUG_ASSERT(file->s->state.header.uniques > constrain_no); |
3973 | MARIA_UNIQUEDEF *def= file->s->uniqueinfo + constrain_no; |
3974 | ha_checksum unique_hash= _ma_unique_hash(def, record); |
3975 | rc= _ma_check_unique(file, def, record, unique_hash, HA_OFFSET_ERROR); |
3976 | if (rc) |
3977 | { |
3978 | file->cur_row.lastpos= file->dup_key_pos; |
3979 | if ((*file->read_record)(file, record, file->cur_row.lastpos)) |
3980 | return -1; |
3981 | file->update|= HA_STATE_AKTIV; /* Record is read */ |
3982 | } |
3983 | // invert logic |
3984 | rc= !MY_TEST(rc); |
3985 | } |
3986 | else |
3987 | { |
3988 | /* |
3989 | It is case when just unique index used instead unicue constrain |
3990 | (conversion from heap table). |
3991 | */ |
3992 | DBUG_ASSERT(file->s->state.header.keys > constrain_no); |
3993 | MARIA_KEY key; |
3994 | file->once_flags|= USE_PACKED_KEYS; |
3995 | (*file->s->keyinfo[constrain_no].make_key) |
3996 | (file, &key, constrain_no, file->lastkey_buff2, record, 0, 0); |
3997 | rc= maria_rkey(file, record, constrain_no, key.data, key.data_length, |
3998 | HA_READ_KEY_EXACT); |
3999 | rc= MY_TEST(rc); |
4000 | } |
4001 | return rc; |
4002 | } |
4003 | |
4004 | struct st_mysql_storage_engine maria_storage_engine= |
4005 | { MYSQL_HANDLERTON_INTERFACE_VERSION }; |
4006 | |
4007 | maria_declare_plugin(aria) |
4008 | { |
4009 | MYSQL_STORAGE_ENGINE_PLUGIN, |
4010 | &maria_storage_engine, |
4011 | "Aria" , |
4012 | "Monty Program Ab" , |
4013 | "Crash-safe tables with MyISAM heritage" , |
4014 | PLUGIN_LICENSE_GPL, |
4015 | ha_maria_init, /* Plugin Init */ |
4016 | NULL, /* Plugin Deinit */ |
4017 | 0x0105, /* 1.5 */ |
4018 | status_variables, /* status variables */ |
4019 | system_variables, /* system variables */ |
4020 | "1.5" , /* string version */ |
4021 | MariaDB_PLUGIN_MATURITY_STABLE /* maturity */ |
4022 | } |
4023 | maria_declare_plugin_end; |
4024 | |