1 /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include "my_config.h"
24
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <sys/types.h>
28
29 #include "my_dbug.h"
30 #include "my_inttypes.h"
31 #include "my_macros.h"
32 #include "storage/myisam/myisamdef.h"
33 #ifdef HAVE_SYS_MMAN_H
34 #include <sys/mman.h>
35 #endif
36
37 static void mi_extra_keyflag(MI_INFO *info, enum ha_extra_function function);
38
39 /*
40 Set options and buffers to optimize table handling
41
42 SYNOPSIS
43 mi_extra()
44 info open table
45 function operation
46 extra_arg Pointer to extra argument (normally pointer to ulong)
47 Not used.
48 RETURN VALUES
49 0 ok
50 # error
51 */
52
mi_extra(MI_INFO * info,enum ha_extra_function function,void * extra_arg)53 int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) {
54 int error = 0;
55 MYISAM_SHARE *share = info->s;
56 DBUG_TRACE;
57 DBUG_PRINT("enter", ("function: %d", (int)function));
58
59 switch (function) {
60 case HA_EXTRA_RESET_STATE: /* Reset state (don't free buffers) */
61 info->lastinx = 0; /* Use first index as def */
62 info->last_search_keypage = info->lastpos = HA_OFFSET_ERROR;
63 info->page_changed = true;
64 /* Next/prev gives first/last */
65 if (info->opt_flag & READ_CACHE_USED) {
66 reinit_io_cache(&info->rec_cache, READ_CACHE, 0,
67 (bool)(info->lock_type != F_UNLCK),
68 (bool)(info->update & HA_STATE_ROW_CHANGED));
69 }
70 info->update = ((info->update & HA_STATE_CHANGED) | HA_STATE_NEXT_FOUND |
71 HA_STATE_PREV_FOUND);
72 break;
73 case HA_EXTRA_PREPARE_FOR_UPDATE:
74 if (info->s->data_file_type != DYNAMIC_RECORD) break;
75 /* Remove read/write cache if dynamic rows */
76 // Fall through.
77 case HA_EXTRA_NO_READCHECK:
78 info->opt_flag &= ~READ_CHECK_USED; /* No readcheck */
79 break;
80 case HA_EXTRA_READCHECK:
81 info->opt_flag |= READ_CHECK_USED;
82 break;
83 case HA_EXTRA_KEYREAD: /* Read only keys to record */
84 case HA_EXTRA_REMEMBER_POS:
85 info->opt_flag |= REMEMBER_OLD_POS;
86 memmove((uchar *)info->lastkey + share->base.max_key_length * 2,
87 (uchar *)info->lastkey, info->lastkey_length);
88 info->save_update = info->update;
89 info->save_lastinx = info->lastinx;
90 info->save_lastpos = info->lastpos;
91 info->save_lastkey_length = info->lastkey_length;
92 if (function == HA_EXTRA_REMEMBER_POS) break;
93 /* fall through */
94 case HA_EXTRA_KEYREAD_CHANGE_POS:
95 info->opt_flag |= KEY_READ_USED;
96 info->read_record = _mi_read_key_record;
97 break;
98 case HA_EXTRA_NO_KEYREAD:
99 case HA_EXTRA_RESTORE_POS:
100 if (info->opt_flag & REMEMBER_OLD_POS) {
101 memmove((uchar *)info->lastkey,
102 (uchar *)info->lastkey + share->base.max_key_length * 2,
103 info->save_lastkey_length);
104 info->update = info->save_update | HA_STATE_WRITTEN;
105 info->lastinx = info->save_lastinx;
106 info->lastpos = info->save_lastpos;
107 info->lastkey_length = info->save_lastkey_length;
108 }
109 info->read_record = share->read_record;
110 info->opt_flag &= ~(KEY_READ_USED | REMEMBER_OLD_POS);
111 break;
112 case HA_EXTRA_NO_USER_CHANGE: /* Database is somehow locked agains changes
113 */
114 info->lock_type = F_EXTRA_LCK; /* Simulate as locked */
115 break;
116 case HA_EXTRA_WAIT_LOCK:
117 info->lock_wait = 0;
118 break;
119 case HA_EXTRA_NO_WAIT_LOCK:
120 info->lock_wait = MY_DONT_WAIT;
121 break;
122 case HA_EXTRA_NO_KEYS:
123 if (info->lock_type == F_UNLCK) {
124 error = 1; /* Not possibly if not lock */
125 break;
126 }
127 if (mi_is_any_key_active(share->state.key_map)) {
128 MI_KEYDEF *key = share->keyinfo;
129 uint i;
130 for (i = 0; i < share->base.keys; i++, key++) {
131 if (!(key->flag & HA_NOSAME) && info->s->base.auto_key != i + 1) {
132 mi_clear_key_active(share->state.key_map, i);
133 info->update |= HA_STATE_CHANGED;
134 }
135 }
136
137 if (!share->changed) {
138 share->state.changed |= STATE_CHANGED | STATE_NOT_ANALYZED;
139 share->changed = true; /* Update on close */
140 if (!share->global_changed) {
141 share->global_changed = true;
142 share->state.open_count++;
143 }
144 }
145 share->state.state = *info->state;
146 error = mi_state_info_write(share->kfile, &share->state, 1 | 2);
147 }
148 break;
149 case HA_EXTRA_FORCE_REOPEN:
150 mysql_mutex_lock(&THR_LOCK_myisam);
151 share->last_version = 0L; /* Impossible version */
152 mysql_mutex_unlock(&THR_LOCK_myisam);
153 break;
154 case HA_EXTRA_PREPARE_FOR_DROP:
155 mysql_mutex_lock(&THR_LOCK_myisam);
156 share->last_version = 0L; /* Impossible version */
157 mysql_mutex_unlock(&THR_LOCK_myisam);
158 break;
159 case HA_EXTRA_FLUSH:
160 if (!share->temporary)
161 flush_key_blocks(share->key_cache, keycache_thread_var(), share->kfile,
162 FLUSH_KEEP);
163 #ifndef _WIN32
164 _mi_decrement_open_count(info);
165 #endif
166 if (share->not_flushed) {
167 share->not_flushed = false;
168 if (mysql_file_sync(share->kfile, MYF(0))) error = my_errno();
169 if (mysql_file_sync(info->dfile, MYF(0))) error = my_errno();
170 if (error) {
171 share->changed = true;
172 mi_print_error(info->s, HA_ERR_CRASHED);
173 mi_mark_crashed(info); /* Fatal error found */
174 }
175 }
176 if (share->base.blobs) mi_alloc_rec_buff(info, -1, &info->rec_buff);
177 break;
178 case HA_EXTRA_NORMAL: /* Theese isn't in use */
179 info->quick_mode = false;
180 break;
181 case HA_EXTRA_QUICK:
182 info->quick_mode = true;
183 break;
184 case HA_EXTRA_NO_ROWS:
185 if (!share->state.header.uniques) info->opt_flag |= OPT_NO_ROWS;
186 break;
187 case HA_EXTRA_PRELOAD_BUFFER_SIZE:
188 info->preload_buff_size = *((ulong *)extra_arg);
189 break;
190 case HA_EXTRA_CHANGE_KEY_TO_UNIQUE:
191 case HA_EXTRA_CHANGE_KEY_TO_DUP:
192 mi_extra_keyflag(info, function);
193 break;
194 case HA_EXTRA_MARK_AS_LOG_TABLE:
195 mysql_mutex_lock(&share->intern_lock);
196 share->is_log_table = true;
197 mysql_mutex_unlock(&share->intern_lock);
198 break;
199 default:
200 break;
201 }
202 {
203 char tmp[1];
204 tmp[0] = function;
205 myisam_log_command(MI_LOG_EXTRA, info, (uchar *)tmp, 1, error);
206 }
207 return error;
208 } /* mi_extra */
209
mi_set_index_cond_func(MI_INFO * info,index_cond_func_t func,void * func_arg)210 void mi_set_index_cond_func(MI_INFO *info, index_cond_func_t func,
211 void *func_arg) {
212 info->index_cond_func = func;
213 info->index_cond_func_arg = func_arg;
214 }
215
216 /*
217 Start/Stop Inserting Duplicates Into a Table, WL#1648.
218 */
mi_extra_keyflag(MI_INFO * info,enum ha_extra_function function)219 static void mi_extra_keyflag(MI_INFO *info, enum ha_extra_function function) {
220 uint idx;
221
222 for (idx = 0; idx < info->s->base.keys; idx++) {
223 switch (function) {
224 case HA_EXTRA_CHANGE_KEY_TO_UNIQUE:
225 info->s->keyinfo[idx].flag |= HA_NOSAME;
226 break;
227 case HA_EXTRA_CHANGE_KEY_TO_DUP:
228 info->s->keyinfo[idx].flag &= ~(HA_NOSAME);
229 break;
230 default:
231 break;
232 }
233 }
234 }
235
mi_reset(MI_INFO * info)236 int mi_reset(MI_INFO *info) {
237 int error = 0;
238 MYISAM_SHARE *share = info->s;
239 DBUG_TRACE;
240 /*
241 Free buffers and reset the following flags:
242 EXTRA_CACHE, EXTRA_WRITE_CACHE, EXTRA_KEYREAD, EXTRA_QUICK
243
244 If the row buffer cache is large (for dynamic tables), reduce it
245 to save memory.
246 */
247 if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) {
248 info->opt_flag &= ~(READ_CACHE_USED | WRITE_CACHE_USED);
249 error = end_io_cache(&info->rec_cache);
250 }
251 if (share->base.blobs) mi_alloc_rec_buff(info, -1, &info->rec_buff);
252 #if defined(HAVE_MADVISE)
253 if (info->opt_flag & MEMMAP_USED)
254 madvise((char *)share->file_map, share->state.state.data_file_length,
255 MADV_RANDOM);
256 #endif
257 info->opt_flag &= ~(KEY_READ_USED | REMEMBER_OLD_POS);
258 info->quick_mode = false;
259 info->lastinx = 0; /* Use first index as def */
260 info->last_search_keypage = info->lastpos = HA_OFFSET_ERROR;
261 info->page_changed = true;
262 info->update = ((info->update & HA_STATE_CHANGED) | HA_STATE_NEXT_FOUND |
263 HA_STATE_PREV_FOUND);
264 return error;
265 }
266