1 | /* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB |
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 as published by |
5 | the Free Software Foundation; version 2 of the License. |
6 | |
7 | This program is distributed in the hope that it will be useful, |
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | GNU General Public License for more details. |
11 | |
12 | You should have received a copy of the GNU General Public License |
13 | along with this program; if not, write to the Free Software |
14 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ |
15 | |
16 | #include "maria_def.h" |
17 | #ifdef HAVE_SYS_MMAN_H |
18 | #include <sys/mman.h> |
19 | #endif |
20 | #include "ma_blockrec.h" |
21 | |
22 | static void maria_extra_keyflag(MARIA_HA *info, |
23 | enum ha_extra_function function); |
24 | |
25 | /** |
26 | @brief Set options and buffers to optimize table handling |
27 | |
28 | @param name table's name |
29 | @param info open table |
30 | @param function operation |
31 | @param extra_arg Pointer to extra argument (normally pointer to |
32 | ulong); used when function is one of: |
33 | HA_EXTRA_WRITE_CACHE |
34 | HA_EXTRA_CACHE |
35 | |
36 | @return Operation status |
37 | @retval 0 ok |
38 | @retval !=0 error |
39 | */ |
40 | |
41 | int (MARIA_HA *info, enum ha_extra_function function, |
42 | void *) |
43 | { |
44 | int error= 0; |
45 | ulong cache_size; |
46 | MARIA_SHARE *share= info->s; |
47 | my_bool block_records= share->data_file_type == BLOCK_RECORD; |
48 | DBUG_ENTER("maria_extra" ); |
49 | DBUG_PRINT("enter" ,("function: %d" ,(int) function)); |
50 | |
51 | switch (function) { |
52 | case HA_EXTRA_RESET_STATE: /* Reset state (don't free buffers) */ |
53 | info->lastinx= ~0; /* Detect index changes */ |
54 | info->last_search_keypage= info->cur_row.lastpos= HA_OFFSET_ERROR; |
55 | info->page_changed= 1; |
56 | /* Next/prev gives first/last */ |
57 | if (info->opt_flag & READ_CACHE_USED) |
58 | { |
59 | reinit_io_cache(&info->rec_cache,READ_CACHE,0, |
60 | (pbool) (info->lock_type != F_UNLCK), |
61 | (pbool) MY_TEST(info->update & HA_STATE_ROW_CHANGED) |
62 | ); |
63 | } |
64 | info->update= ((info->update & HA_STATE_CHANGED) | HA_STATE_NEXT_FOUND | |
65 | HA_STATE_PREV_FOUND); |
66 | break; |
67 | case HA_EXTRA_CACHE: |
68 | if (block_records) |
69 | break; /* Not supported */ |
70 | |
71 | if (info->lock_type == F_UNLCK && |
72 | (share->options & HA_OPTION_PACK_RECORD)) |
73 | { |
74 | error= 1; /* Not possibly if not locked */ |
75 | my_errno= EACCES; |
76 | break; |
77 | } |
78 | if (info->s->file_map) /* Don't use cache if mmap */ |
79 | break; |
80 | #if defined(HAVE_MMAP) && defined(HAVE_MADVISE) |
81 | if ((share->options & HA_OPTION_COMPRESS_RECORD)) |
82 | { |
83 | mysql_mutex_lock(&share->intern_lock); |
84 | if (_ma_memmap_file(info)) |
85 | { |
86 | /* We don't nead MADV_SEQUENTIAL if small file */ |
87 | madvise((char*) share->file_map, share->state.state.data_file_length, |
88 | share->state.state.data_file_length <= RECORD_CACHE_SIZE*16 ? |
89 | MADV_RANDOM : MADV_SEQUENTIAL); |
90 | mysql_mutex_unlock(&share->intern_lock); |
91 | break; |
92 | } |
93 | mysql_mutex_unlock(&share->intern_lock); |
94 | } |
95 | #endif |
96 | if (info->opt_flag & WRITE_CACHE_USED) |
97 | { |
98 | info->opt_flag&= ~WRITE_CACHE_USED; |
99 | if ((error= end_io_cache(&info->rec_cache))) |
100 | break; |
101 | } |
102 | if (!(info->opt_flag & |
103 | (READ_CACHE_USED | WRITE_CACHE_USED | MEMMAP_USED))) |
104 | { |
105 | cache_size= (extra_arg ? *(ulong*) extra_arg : |
106 | my_default_record_cache_size); |
107 | if (!(init_io_cache(&info->rec_cache, info->dfile.file, |
108 | (uint) MY_MIN(share->state.state.data_file_length+1, |
109 | cache_size), |
110 | READ_CACHE,0L,(pbool) (info->lock_type != F_UNLCK), |
111 | MYF(share->write_flag & MY_WAIT_IF_FULL)))) |
112 | { |
113 | info->opt_flag|= READ_CACHE_USED; |
114 | info->update&= ~HA_STATE_ROW_CHANGED; |
115 | } |
116 | if (share->non_transactional_concurrent_insert) |
117 | info->rec_cache.end_of_file= info->state->data_file_length; |
118 | } |
119 | break; |
120 | case HA_EXTRA_REINIT_CACHE: |
121 | if (info->opt_flag & READ_CACHE_USED) |
122 | { |
123 | reinit_io_cache(&info->rec_cache, READ_CACHE, info->cur_row.nextpos, |
124 | (pbool) (info->lock_type != F_UNLCK), |
125 | (pbool) MY_TEST(info->update & HA_STATE_ROW_CHANGED)); |
126 | info->update&= ~HA_STATE_ROW_CHANGED; |
127 | if (share->non_transactional_concurrent_insert) |
128 | info->rec_cache.end_of_file= info->state->data_file_length; |
129 | } |
130 | break; |
131 | case HA_EXTRA_WRITE_CACHE: |
132 | if (info->lock_type == F_UNLCK) |
133 | { |
134 | error= 1; /* Not possibly if not locked */ |
135 | break; |
136 | } |
137 | if (block_records) |
138 | break; /* Not supported */ |
139 | |
140 | cache_size= (extra_arg ? *(ulong*) extra_arg : |
141 | my_default_record_cache_size); |
142 | if (!(info->opt_flag & |
143 | (READ_CACHE_USED | WRITE_CACHE_USED | OPT_NO_ROWS)) && |
144 | !share->state.header.uniques) |
145 | if (!(init_io_cache(&info->rec_cache, info->dfile.file, cache_size, |
146 | WRITE_CACHE, info->state->data_file_length, |
147 | (pbool) (info->lock_type != F_UNLCK), |
148 | MYF(share->write_flag & MY_WAIT_IF_FULL)))) |
149 | { |
150 | info->opt_flag|= WRITE_CACHE_USED; |
151 | info->update&= ~(HA_STATE_ROW_CHANGED | |
152 | HA_STATE_WRITE_AT_END | |
153 | HA_STATE_EXTEND_BLOCK); |
154 | } |
155 | break; |
156 | case HA_EXTRA_PREPARE_FOR_UPDATE: |
157 | if (info->s->data_file_type != DYNAMIC_RECORD) |
158 | break; |
159 | /* Remove read/write cache if dynamic rows */ |
160 | /* fall through */ |
161 | case HA_EXTRA_NO_CACHE: |
162 | if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) |
163 | { |
164 | info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); |
165 | error= end_io_cache(&info->rec_cache); |
166 | /* Sergei will insert full text index caching here */ |
167 | } |
168 | #if defined(HAVE_MMAP) && defined(HAVE_MADVISE) |
169 | if (info->opt_flag & MEMMAP_USED) |
170 | madvise((char*) share->file_map, share->state.state.data_file_length, |
171 | MADV_RANDOM); |
172 | #endif |
173 | break; |
174 | case HA_EXTRA_FLUSH_CACHE: |
175 | if (info->opt_flag & WRITE_CACHE_USED) |
176 | { |
177 | if ((error= flush_io_cache(&info->rec_cache))) |
178 | { |
179 | /* Fatal error found */ |
180 | _ma_set_fatal_error(share, HA_ERR_CRASHED); |
181 | } |
182 | } |
183 | break; |
184 | case HA_EXTRA_NO_READCHECK: |
185 | info->opt_flag&= ~READ_CHECK_USED; /* No readcheck */ |
186 | break; |
187 | case HA_EXTRA_READCHECK: |
188 | info->opt_flag|= READ_CHECK_USED; |
189 | break; |
190 | case HA_EXTRA_KEYREAD: /* Read only keys to record */ |
191 | case HA_EXTRA_REMEMBER_POS: |
192 | info->opt_flag|= REMEMBER_OLD_POS; |
193 | bmove(info->last_key.data + share->base.max_key_length*2, |
194 | info->last_key.data, |
195 | info->last_key.data_length + info->last_key.ref_length); |
196 | info->save_update= info->update; |
197 | info->save_lastinx= info->lastinx; |
198 | info->save_lastpos= info->cur_row.lastpos; |
199 | info->save_lastkey_data_length= info->last_key.data_length; |
200 | info->save_lastkey_ref_length= info->last_key.ref_length; |
201 | if (function == HA_EXTRA_REMEMBER_POS) |
202 | break; |
203 | /* fall through */ |
204 | case HA_EXTRA_KEYREAD_CHANGE_POS: |
205 | info->opt_flag|= KEY_READ_USED; |
206 | info->read_record= _ma_read_key_record; |
207 | break; |
208 | case HA_EXTRA_NO_KEYREAD: |
209 | case HA_EXTRA_RESTORE_POS: |
210 | if (info->opt_flag & REMEMBER_OLD_POS) |
211 | { |
212 | bmove(info->last_key.data, |
213 | info->last_key.data + share->base.max_key_length*2, |
214 | info->save_lastkey_data_length + info->save_lastkey_ref_length); |
215 | info->update= info->save_update | HA_STATE_WRITTEN; |
216 | info->lastinx= info->save_lastinx; |
217 | info->cur_row.lastpos= info->save_lastpos; |
218 | info->last_key.data_length= info->save_lastkey_data_length; |
219 | info->last_key.ref_length= info->save_lastkey_ref_length; |
220 | info->last_key.flag= 0; |
221 | } |
222 | info->read_record= share->read_record; |
223 | info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS); |
224 | break; |
225 | case HA_EXTRA_NO_USER_CHANGE: /* Database is somehow locked agains changes */ |
226 | info->lock_type= F_EXTRA_LCK; /* Simulate as locked */ |
227 | break; |
228 | case HA_EXTRA_WAIT_LOCK: |
229 | info->lock_wait= 0; |
230 | break; |
231 | case HA_EXTRA_NO_WAIT_LOCK: |
232 | info->lock_wait= MY_SHORT_WAIT; |
233 | break; |
234 | case HA_EXTRA_NO_KEYS: |
235 | /* we're going to modify pieces of the state, stall Checkpoint */ |
236 | mysql_mutex_lock(&share->intern_lock); |
237 | if (info->lock_type == F_UNLCK) |
238 | { |
239 | mysql_mutex_unlock(&share->intern_lock); |
240 | error= 1; /* Not possibly if not lock */ |
241 | break; |
242 | } |
243 | if (maria_is_any_key_active(share->state.key_map)) |
244 | { |
245 | MARIA_KEYDEF *key= share->keyinfo; |
246 | uint i; |
247 | for (i =0 ; i < share->base.keys ; i++,key++) |
248 | { |
249 | if (!(key->flag & HA_NOSAME) && info->s->base.auto_key != i+1) |
250 | { |
251 | maria_clear_key_active(share->state.key_map, i); |
252 | info->update|= HA_STATE_CHANGED; |
253 | } |
254 | } |
255 | |
256 | if (!share->changed) |
257 | { |
258 | share->changed= 1; /* Update on close */ |
259 | share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED; |
260 | if (!share->global_changed) |
261 | { |
262 | share->global_changed= 1; |
263 | share->state.open_count++; |
264 | } |
265 | } |
266 | if (!share->now_transactional) |
267 | share->state.state= *info->state; |
268 | /* |
269 | That state write to disk must be done, even for transactional tables; |
270 | indeed the table's share is going to be lost (there was a |
271 | HA_EXTRA_FORCE_REOPEN before, which set share->last_version to |
272 | 0), and so the only way it leaves information (share->state.key_map) |
273 | for the posterity is by writing it to disk. |
274 | */ |
275 | DBUG_ASSERT(!maria_in_recovery); |
276 | error= _ma_state_info_write(share, |
277 | MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET | |
278 | MA_STATE_INFO_WRITE_FULL_INFO); |
279 | } |
280 | mysql_mutex_unlock(&share->intern_lock); |
281 | break; |
282 | case HA_EXTRA_FORCE_REOPEN: |
283 | /* |
284 | MySQL uses this case after it has closed all other instances |
285 | of this table. |
286 | We however do a flush here for additional safety. |
287 | */ |
288 | /** @todo consider porting these flush-es to MyISAM */ |
289 | DBUG_ASSERT(share->reopen == 1); |
290 | error= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX, |
291 | FLUSH_FORCE_WRITE, FLUSH_FORCE_WRITE); |
292 | if (!error && share->changed) |
293 | { |
294 | mysql_mutex_lock(&share->intern_lock); |
295 | error= _ma_state_info_write(share, |
296 | MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET| |
297 | MA_STATE_INFO_WRITE_FULL_INFO); |
298 | mysql_mutex_unlock(&share->intern_lock); |
299 | } |
300 | mysql_mutex_lock(&THR_LOCK_maria); |
301 | mysql_mutex_lock(&share->intern_lock); /* protect against Checkpoint */ |
302 | /* Safety against assert in checkpoint */ |
303 | share->bitmap.changed_not_flushed= 0; |
304 | /* this makes the share not be re-used next time the table is opened */ |
305 | share->last_version= 0L; /* Impossible version */ |
306 | mysql_mutex_unlock(&share->intern_lock); |
307 | mysql_mutex_unlock(&THR_LOCK_maria); |
308 | break; |
309 | case HA_EXTRA_PREPARE_FOR_DROP: |
310 | /* Signals about intent to delete this table */ |
311 | share->deleting= TRUE; |
312 | share->global_changed= FALSE; /* force writing changed flag */ |
313 | /* To force repair if reopened */ |
314 | share->state.open_count= 1; |
315 | share->changed= 1; |
316 | _ma_mark_file_changed_now(share); |
317 | /* fall through */ |
318 | case HA_EXTRA_PREPARE_FOR_RENAME: |
319 | { |
320 | my_bool do_flush= MY_TEST(function != HA_EXTRA_PREPARE_FOR_DROP); |
321 | my_bool save_global_changed; |
322 | enum flush_type type; |
323 | DBUG_ASSERT(!share->temporary); |
324 | /* |
325 | This share, to have last_version=0, needs to save all its data/index |
326 | blocks to disk if this is not for a DROP TABLE. Otherwise they would be |
327 | invisible to future openers; and they could even go to disk late and |
328 | cancel the work of future openers. |
329 | */ |
330 | if (info->lock_type != F_UNLCK && !info->was_locked) |
331 | { |
332 | info->was_locked= info->lock_type; |
333 | if (maria_lock_database(info, F_UNLCK)) |
334 | error= my_errno; |
335 | info->lock_type= F_UNLCK; |
336 | } |
337 | /* |
338 | We don't need to call _mi_decrement_open_count() if we are |
339 | dropping the table, as the files will be removed anyway. If we |
340 | are aborted before the files is removed, it's better to not |
341 | call it as in that case the automatic repair on open will add |
342 | the missing index entries |
343 | */ |
344 | mysql_mutex_lock(&share->intern_lock); |
345 | if (share->kfile.file >= 0 && function != HA_EXTRA_PREPARE_FOR_DROP) |
346 | _ma_decrement_open_count(info, 0); |
347 | if (info->trn) |
348 | { |
349 | _ma_remove_table_from_trnman(share, info->trn); |
350 | /* Ensure we don't point to the deleted data in trn */ |
351 | info->state= info->state_start= &share->state.state; |
352 | } |
353 | /* Remove history for table */ |
354 | _ma_reset_state(info); |
355 | |
356 | type= do_flush ? FLUSH_RELEASE : FLUSH_IGNORE_CHANGED; |
357 | save_global_changed= share->global_changed; |
358 | share->global_changed= 1; /* Don't increment open count */ |
359 | mysql_mutex_unlock(&share->intern_lock); |
360 | if (_ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX, |
361 | type, type)) |
362 | { |
363 | error=my_errno; |
364 | share->changed= 1; |
365 | } |
366 | mysql_mutex_lock(&share->intern_lock); |
367 | share->global_changed= save_global_changed; |
368 | if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) |
369 | { |
370 | info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); |
371 | if (end_io_cache(&info->rec_cache)) |
372 | error= 1; |
373 | } |
374 | if (share->kfile.file >= 0) |
375 | { |
376 | if (do_flush) |
377 | { |
378 | /* Save the state so that others can find it from disk. */ |
379 | if ((share->changed && |
380 | _ma_state_info_write(share, |
381 | MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET | |
382 | MA_STATE_INFO_WRITE_FULL_INFO)) || |
383 | mysql_file_sync(share->kfile.file, MYF(0))) |
384 | error= my_errno; |
385 | } |
386 | else |
387 | { |
388 | /* be sure that state is not tried for write as file may be closed */ |
389 | share->changed= 0; |
390 | share->global_changed= 0; |
391 | share->state.open_count= 0; |
392 | } |
393 | } |
394 | if (share->data_file_type == BLOCK_RECORD && |
395 | share->bitmap.file.file >= 0) |
396 | { |
397 | DBUG_ASSERT(share->bitmap.non_flushable == 0 && |
398 | share->bitmap.changed == 0); |
399 | if (do_flush && my_sync(share->bitmap.file.file, MYF(0))) |
400 | error= my_errno; |
401 | share->bitmap.changed_not_flushed= 0; |
402 | } |
403 | /* last_version must be protected by intern_lock; See collect_tables() */ |
404 | share->last_version= 0L; /* Impossible version */ |
405 | mysql_mutex_unlock(&share->intern_lock); |
406 | break; |
407 | } |
408 | case HA_EXTRA_PREPARE_FOR_FORCED_CLOSE: |
409 | if (info->trn) |
410 | { |
411 | mysql_mutex_lock(&share->intern_lock); |
412 | _ma_remove_table_from_trnman(share, info->trn); |
413 | /* Ensure we don't point to the deleted data in trn */ |
414 | info->state= info->state_start= &share->state.state; |
415 | mysql_mutex_unlock(&share->intern_lock); |
416 | } |
417 | break; |
418 | case HA_EXTRA_FLUSH: |
419 | if (!share->temporary) |
420 | error= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX, |
421 | FLUSH_KEEP, FLUSH_KEEP); |
422 | |
423 | _ma_decrement_open_count(info, 1); |
424 | if (share->not_flushed) |
425 | { |
426 | share->not_flushed= 0; |
427 | if (_ma_sync_table_files(info)) |
428 | error= my_errno; |
429 | if (error) |
430 | { |
431 | /* Fatal error found */ |
432 | share->changed= 1; |
433 | _ma_set_fatal_error(share, HA_ERR_CRASHED); |
434 | } |
435 | } |
436 | break; |
437 | case HA_EXTRA_NORMAL: /* Theese isn't in use */ |
438 | info->quick_mode= 0; |
439 | break; |
440 | case HA_EXTRA_QUICK: |
441 | info->quick_mode= 1; |
442 | break; |
443 | case HA_EXTRA_NO_ROWS: |
444 | if (!share->state.header.uniques) |
445 | info->opt_flag|= OPT_NO_ROWS; |
446 | break; |
447 | case HA_EXTRA_PRELOAD_BUFFER_SIZE: |
448 | info->preload_buff_size= *((ulong *) extra_arg); |
449 | break; |
450 | case HA_EXTRA_CHANGE_KEY_TO_UNIQUE: |
451 | case HA_EXTRA_CHANGE_KEY_TO_DUP: |
452 | maria_extra_keyflag(info, function); |
453 | break; |
454 | case HA_EXTRA_MMAP: |
455 | #ifdef HAVE_MMAP |
456 | if (block_records) |
457 | break; /* Not supported */ |
458 | mysql_mutex_lock(&share->intern_lock); |
459 | /* |
460 | Memory map the data file if it is not already mapped. It is safe |
461 | to memory map a file while other threads are using file I/O on it. |
462 | Assigning a new address to a function pointer is an atomic |
463 | operation. intern_lock prevents that two or more mappings are done |
464 | at the same time. |
465 | */ |
466 | if (!share->file_map) |
467 | { |
468 | if (_ma_dynmap_file(info, share->state.state.data_file_length)) |
469 | { |
470 | DBUG_PRINT("warning" ,("mmap failed: errno: %d" ,errno)); |
471 | error= my_errno= errno; |
472 | } |
473 | else |
474 | { |
475 | share->file_read= _ma_mmap_pread; |
476 | share->file_write= _ma_mmap_pwrite; |
477 | } |
478 | } |
479 | mysql_mutex_unlock(&share->intern_lock); |
480 | #endif |
481 | break; |
482 | case HA_EXTRA_MARK_AS_LOG_TABLE: |
483 | mysql_mutex_lock(&share->intern_lock); |
484 | share->is_log_table= TRUE; |
485 | mysql_mutex_unlock(&share->intern_lock); |
486 | break; |
487 | case HA_EXTRA_KEY_CACHE: |
488 | case HA_EXTRA_NO_KEY_CACHE: |
489 | default: |
490 | break; |
491 | } |
492 | DBUG_RETURN(error); |
493 | } /* maria_extra */ |
494 | |
495 | |
496 | void ma_set_index_cond_func(MARIA_HA *info, index_cond_func_t func, |
497 | void *func_arg) |
498 | { |
499 | info->index_cond_func= func; |
500 | info->index_cond_func_arg= func_arg; |
501 | } |
502 | |
503 | |
504 | /* |
505 | Start/Stop Inserting Duplicates Into a Table, WL#1648. |
506 | */ |
507 | |
508 | static void (MARIA_HA *info, |
509 | enum ha_extra_function function) |
510 | { |
511 | uint idx; |
512 | |
513 | for (idx= 0; idx< info->s->base.keys; idx++) |
514 | { |
515 | switch (function) { |
516 | case HA_EXTRA_CHANGE_KEY_TO_UNIQUE: |
517 | info->s->keyinfo[idx].flag|= HA_NOSAME; |
518 | break; |
519 | case HA_EXTRA_CHANGE_KEY_TO_DUP: |
520 | info->s->keyinfo[idx].flag&= ~(HA_NOSAME); |
521 | break; |
522 | default: |
523 | break; |
524 | } |
525 | } |
526 | } |
527 | |
528 | |
529 | int maria_reset(MARIA_HA *info) |
530 | { |
531 | int error= 0; |
532 | MARIA_SHARE *share= info->s; |
533 | DBUG_ENTER("maria_reset" ); |
534 | /* |
535 | Free buffers and reset the following flags: |
536 | EXTRA_CACHE, EXTRA_WRITE_CACHE, EXTRA_KEYREAD, EXTRA_QUICK |
537 | |
538 | If the row buffer cache is large (for dynamic tables), reduce it |
539 | to save memory. |
540 | */ |
541 | if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) |
542 | { |
543 | info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); |
544 | error= end_io_cache(&info->rec_cache); |
545 | } |
546 | /* Free memory used for keeping blobs */ |
547 | if (share->base.blobs) |
548 | { |
549 | if (info->rec_buff_size > share->base.default_rec_buff_size) |
550 | { |
551 | info->rec_buff_size= 1; /* Force realloc */ |
552 | _ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size, |
553 | share->base.default_rec_buff_size); |
554 | } |
555 | if (info->blob_buff_size > MARIA_SMALL_BLOB_BUFFER) |
556 | { |
557 | info->blob_buff_size= 1; /* Force realloc */ |
558 | _ma_alloc_buffer(&info->blob_buff, &info->blob_buff_size, |
559 | MARIA_SMALL_BLOB_BUFFER); |
560 | } |
561 | } |
562 | #if defined(HAVE_MMAP) && defined(HAVE_MADVISE) |
563 | if (info->opt_flag & MEMMAP_USED) |
564 | madvise((char*) share->file_map, share->state.state.data_file_length, |
565 | MADV_RANDOM); |
566 | #endif |
567 | info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS); |
568 | info->quick_mode= 0; |
569 | info->lastinx= ~0; /* detect index changes */ |
570 | info->last_search_keypage= info->cur_row.lastpos= HA_OFFSET_ERROR; |
571 | info->page_changed= 1; |
572 | info->update= ((info->update & HA_STATE_CHANGED) | HA_STATE_NEXT_FOUND | |
573 | HA_STATE_PREV_FOUND); |
574 | DBUG_RETURN(error); |
575 | } |
576 | |
577 | |
578 | int _ma_sync_table_files(const MARIA_HA *info) |
579 | { |
580 | return (mysql_file_sync(info->dfile.file, MYF(MY_WME)) || |
581 | mysql_file_sync(info->s->kfile.file, MYF(MY_WME))); |
582 | } |
583 | |
584 | uint _ma_file_callback_to_id(void *callback_data) |
585 | { |
586 | MARIA_SHARE *share= (MARIA_SHARE*) callback_data; |
587 | return share ? share->id : 0; |
588 | } |
589 | |
590 | |
591 | /** |
592 | @brief flushes the data and/or index file of a table |
593 | |
594 | This is useful when one wants to read a table using OS syscalls (like |
595 | my_copy()) and first wants to be sure that MySQL-level caches go down to |
596 | the OS so that OS syscalls can see all data. It can flush rec_cache, |
597 | bitmap, pagecache of data file, pagecache of index file. |
598 | |
599 | @param info table |
600 | @param flush_data_or_index one or two of these flags: |
601 | MARIA_FLUSH_DATA, MARIA_FLUSH_INDEX |
602 | @param flush_type_for_data |
603 | @param flush_type_for_index |
604 | |
605 | @note does not sync files (@see _ma_sync_table_files()). |
606 | @note Progressively this function will be used in all places where we flush |
607 | the index but not the data file (probable bugs). |
608 | |
609 | @return Operation status |
610 | @retval 0 OK |
611 | @retval 1 Error |
612 | */ |
613 | |
614 | int _ma_flush_table_files(MARIA_HA *info, uint flush_data_or_index, |
615 | enum flush_type flush_type_for_data, |
616 | enum flush_type flush_type_for_index) |
617 | { |
618 | int error= 0; |
619 | MARIA_SHARE *share= info->s; |
620 | DBUG_ENTER("_ma_flush_table_files" ); |
621 | |
622 | /* flush data file first because it's more critical */ |
623 | if (flush_data_or_index & MARIA_FLUSH_DATA) |
624 | { |
625 | if ((info->opt_flag & WRITE_CACHE_USED) && |
626 | flush_type_for_data != FLUSH_IGNORE_CHANGED && |
627 | flush_io_cache(&info->rec_cache)) |
628 | error= 1; |
629 | if (share->data_file_type == BLOCK_RECORD) |
630 | { |
631 | if (flush_type_for_data != FLUSH_IGNORE_CHANGED) |
632 | { |
633 | if (_ma_bitmap_flush(share)) |
634 | error= 1; |
635 | } |
636 | else |
637 | { |
638 | mysql_mutex_lock(&share->bitmap.bitmap_lock); |
639 | share->bitmap.changed= 0; |
640 | share->bitmap.changed_not_flushed= 0; |
641 | mysql_mutex_unlock(&share->bitmap.bitmap_lock); |
642 | } |
643 | if (flush_pagecache_blocks(share->pagecache, &info->dfile, |
644 | flush_type_for_data)) |
645 | error= 1; |
646 | } |
647 | } |
648 | if ((flush_data_or_index & MARIA_FLUSH_INDEX) && |
649 | flush_pagecache_blocks(share->pagecache, &share->kfile, |
650 | flush_type_for_index)) |
651 | error= 1; |
652 | if (!error) |
653 | DBUG_RETURN(0); |
654 | |
655 | _ma_set_fatal_error(info->s, HA_ERR_CRASHED); |
656 | DBUG_RETURN(1); |
657 | } |
658 | |
659 | |
660 | my_bool ma_killed_standalone(MARIA_HA *info __attribute__((unused))) |
661 | { |
662 | return 0; |
663 | } |
664 | |