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