~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2005 MySQL 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
#include "myisamdef.h"
17
#ifdef HAVE_SYS_MMAN_H
18
#include <sys/mman.h>
19
#endif
20
21
static void mi_extra_keyflag(MI_INFO *info, enum ha_extra_function function);
22
23
24
/*
25
  Set options and buffers to optimize table handling
26
27
  SYNOPSIS
28
    mi_extra()
29
    info	open table
30
    function	operation
31
    extra_arg	Pointer to extra argument (normally pointer to ulong)
32
    		Used when function is one of:
33
		HA_EXTRA_WRITE_CACHE
34
		HA_EXTRA_CACHE
35
  RETURN VALUES
36
    0  ok
37
    #  error
38
*/
39
40
int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
41
{
42
  int error=0;
43
  ulong cache_size;
44
  MYISAM_SHARE *share=info->s;
45
46
  switch (function) {
47
  case HA_EXTRA_RESET_STATE:		/* Reset state (don't free buffers) */
48
    info->lastinx= 0;			/* Use first index as def */
49
    info->last_search_keypage=info->lastpos= HA_OFFSET_ERROR;
50
    info->page_changed=1;
51
					/* Next/prev gives first/last */
52
    if (info->opt_flag & READ_CACHE_USED)
53
    {
54
      reinit_io_cache(&info->rec_cache,READ_CACHE,0,
154 by Brian Aker
Removed oddball types in my_global.h
55
		      (bool) (info->lock_type != F_UNLCK),
56
		      (bool) test(info->update & HA_STATE_ROW_CHANGED)
1 by brian
clean slate
57
		      );
58
    }
59
    info->update= ((info->update & HA_STATE_CHANGED) | HA_STATE_NEXT_FOUND |
60
		   HA_STATE_PREV_FOUND);
61
    break;
62
  case HA_EXTRA_CACHE:
63
    if (info->lock_type == F_UNLCK &&
64
	(share->options & HA_OPTION_PACK_RECORD))
65
    {
66
      error=1;			/* Not possibly if not locked */
67
      my_errno=EACCES;
68
      break;
69
    }
70
    if (info->s->file_map) /* Don't use cache if mmap */
71
      break;
72
#if defined(HAVE_MMAP) && defined(HAVE_MADVISE)
73
    if ((share->options & HA_OPTION_COMPRESS_RECORD))
74
    {
75
      pthread_mutex_lock(&share->intern_lock);
76
      if (_mi_memmap_file(info))
77
      {
78
	/* We don't nead MADV_SEQUENTIAL if small file */
79
	madvise((char*) share->file_map, share->state.state.data_file_length,
80
		share->state.state.data_file_length <= RECORD_CACHE_SIZE*16 ?
81
		MADV_RANDOM : MADV_SEQUENTIAL);
82
	pthread_mutex_unlock(&share->intern_lock);
83
	break;
84
      }
85
      pthread_mutex_unlock(&share->intern_lock);
86
    }
87
#endif
88
    if (info->opt_flag & WRITE_CACHE_USED)
89
    {
90
      info->opt_flag&= ~WRITE_CACHE_USED;
91
      if ((error=end_io_cache(&info->rec_cache)))
92
	break;
93
    }
94
    if (!(info->opt_flag &
95
	  (READ_CACHE_USED | WRITE_CACHE_USED | MEMMAP_USED)))
96
    {
97
      cache_size= (extra_arg ? *(ulong*) extra_arg :
98
		   my_default_record_cache_size);
99
      if (!(init_io_cache(&info->rec_cache,info->dfile,
100
			 (uint) min(info->state->data_file_length+1,
101
				    cache_size),
154 by Brian Aker
Removed oddball types in my_global.h
102
			  READ_CACHE,0L,(bool) (info->lock_type != F_UNLCK),
1 by brian
clean slate
103
			  MYF(share->write_flag & MY_WAIT_IF_FULL))))
104
      {
105
	info->opt_flag|=READ_CACHE_USED;
106
	info->update&= ~HA_STATE_ROW_CHANGED;
107
      }
108
      if (share->concurrent_insert)
109
	info->rec_cache.end_of_file=info->state->data_file_length;
110
    }
111
    break;
112
  case HA_EXTRA_REINIT_CACHE:
113
    if (info->opt_flag & READ_CACHE_USED)
114
    {
115
      reinit_io_cache(&info->rec_cache,READ_CACHE,info->nextpos,
154 by Brian Aker
Removed oddball types in my_global.h
116
		      (bool) (info->lock_type != F_UNLCK),
117
		      (bool) test(info->update & HA_STATE_ROW_CHANGED));
1 by brian
clean slate
118
      info->update&= ~HA_STATE_ROW_CHANGED;
119
      if (share->concurrent_insert)
120
	info->rec_cache.end_of_file=info->state->data_file_length;
121
    }
122
    break;
123
  case HA_EXTRA_WRITE_CACHE:
124
    if (info->lock_type == F_UNLCK)
125
    {
126
      error=1;			/* Not possibly if not locked */
127
      break;
128
    }
129
130
    cache_size= (extra_arg ? *(ulong*) extra_arg :
131
		 my_default_record_cache_size);
132
    if (!(info->opt_flag &
133
	  (READ_CACHE_USED | WRITE_CACHE_USED | OPT_NO_ROWS)) &&
134
	!share->state.header.uniques)
135
      if (!(init_io_cache(&info->rec_cache,info->dfile, cache_size,
136
			 WRITE_CACHE,info->state->data_file_length,
154 by Brian Aker
Removed oddball types in my_global.h
137
			  (bool) (info->lock_type != F_UNLCK),
1 by brian
clean slate
138
			  MYF(share->write_flag & MY_WAIT_IF_FULL))))
139
      {
140
	info->opt_flag|=WRITE_CACHE_USED;
141
	info->update&= ~(HA_STATE_ROW_CHANGED |
142
			 HA_STATE_WRITE_AT_END |
143
			 HA_STATE_EXTEND_BLOCK);
144
      }
145
    break;
146
  case HA_EXTRA_PREPARE_FOR_UPDATE:
147
    if (info->s->data_file_type != DYNAMIC_RECORD)
148
      break;
149
    /* Remove read/write cache if dynamic rows */
150
  case HA_EXTRA_NO_CACHE:
151
    if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
152
    {
153
      info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
154
      error=end_io_cache(&info->rec_cache);
155
      /* Sergei will insert full text index caching here */
156
    }
157
#if defined(HAVE_MMAP) && defined(HAVE_MADVISE)
158
    if (info->opt_flag & MEMMAP_USED)
159
      madvise((char*) share->file_map, share->state.state.data_file_length,
160
              MADV_RANDOM);
161
#endif
162
    break;
163
  case HA_EXTRA_FLUSH_CACHE:
164
    if (info->opt_flag & WRITE_CACHE_USED)
165
    {
166
      if ((error=flush_io_cache(&info->rec_cache)))
167
      {
168
        mi_print_error(info->s, HA_ERR_CRASHED);
169
	mi_mark_crashed(info);			/* Fatal error found */
170
      }
171
    }
172
    break;
173
  case HA_EXTRA_NO_READCHECK:
174
    info->opt_flag&= ~READ_CHECK_USED;		/* No readcheck */
175
    break;
176
  case HA_EXTRA_READCHECK:
177
    info->opt_flag|= READ_CHECK_USED;
178
    break;
179
  case HA_EXTRA_KEYREAD:			/* Read only keys to record */
180
  case HA_EXTRA_REMEMBER_POS:
181
    info->opt_flag |= REMEMBER_OLD_POS;
182
    bmove((uchar*) info->lastkey+share->base.max_key_length*2,
183
	  (uchar*) info->lastkey,info->lastkey_length);
184
    info->save_update=	info->update;
185
    info->save_lastinx= info->lastinx;
186
    info->save_lastpos= info->lastpos;
187
    info->save_lastkey_length=info->lastkey_length;
188
    if (function == HA_EXTRA_REMEMBER_POS)
189
      break;
190
    /* fall through */
191
  case HA_EXTRA_KEYREAD_CHANGE_POS:
192
    info->opt_flag |= KEY_READ_USED;
193
    info->read_record=_mi_read_key_record;
194
    break;
195
  case HA_EXTRA_NO_KEYREAD:
196
  case HA_EXTRA_RESTORE_POS:
197
    if (info->opt_flag & REMEMBER_OLD_POS)
198
    {
199
      bmove((uchar*) info->lastkey,
200
	    (uchar*) info->lastkey+share->base.max_key_length*2,
201
	    info->save_lastkey_length);
202
      info->update=	info->save_update | HA_STATE_WRITTEN;
203
      info->lastinx=	info->save_lastinx;
204
      info->lastpos=	info->save_lastpos;
205
      info->lastkey_length=info->save_lastkey_length;
206
    }
207
    info->read_record=	share->read_record;
208
    info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
209
    break;
210
  case HA_EXTRA_NO_USER_CHANGE: /* Database is somehow locked agains changes */
211
    info->lock_type= F_EXTRA_LCK; /* Simulate as locked */
212
    break;
213
  case HA_EXTRA_WAIT_LOCK:
214
    info->lock_wait=0;
215
    break;
216
  case HA_EXTRA_NO_WAIT_LOCK:
217
    info->lock_wait=MY_DONT_WAIT;
218
    break;
219
  case HA_EXTRA_NO_KEYS:
220
    if (info->lock_type == F_UNLCK)
221
    {
222
      error=1;					/* Not possibly if not lock */
223
      break;
224
    }
225
    if (mi_is_any_key_active(share->state.key_map))
226
    {
227
      MI_KEYDEF *key=share->keyinfo;
228
      uint i;
229
      for (i=0 ; i < share->base.keys ; i++,key++)
230
      {
231
        if (!(key->flag & HA_NOSAME) && info->s->base.auto_key != i+1)
232
        {
233
          mi_clear_key_active(share->state.key_map, i);
234
          info->update|= HA_STATE_CHANGED;
235
        }
236
      }
237
238
      if (!share->changed)
239
      {
240
	share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED;
241
	share->changed=1;			/* Update on close */
242
	if (!share->global_changed)
243
	{
244
	  share->global_changed=1;
245
	  share->state.open_count++;
246
	}
247
      }
248
      share->state.state= *info->state;
249
      error=mi_state_info_write(share->kfile,&share->state,1 | 2);
250
    }
251
    break;
252
  case HA_EXTRA_FORCE_REOPEN:
253
    pthread_mutex_lock(&THR_LOCK_myisam);
254
    share->last_version= 0L;			/* Impossible version */
255
    pthread_mutex_unlock(&THR_LOCK_myisam);
256
    break;
257
  case HA_EXTRA_PREPARE_FOR_DROP:
258
    pthread_mutex_lock(&THR_LOCK_myisam);
259
    share->last_version= 0L;			/* Impossible version */
260
#ifdef __WIN__REMOVE_OBSOLETE_WORKAROUND
261
    /* Close the isam and data files as Win32 can't drop an open table */
262
    pthread_mutex_lock(&share->intern_lock);
263
    if (flush_key_blocks(share->key_cache, share->kfile,
264
			 (function == HA_EXTRA_FORCE_REOPEN ?
265
			  FLUSH_RELEASE : FLUSH_IGNORE_CHANGED)))
266
    {
267
      error=my_errno;
268
      share->changed=1;
269
      mi_print_error(info->s, HA_ERR_CRASHED);
270
      mi_mark_crashed(info);			/* Fatal error found */
271
    }
272
    if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
273
    {
274
      info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
275
      error=end_io_cache(&info->rec_cache);
276
    }
277
    if (info->lock_type != F_UNLCK && ! info->was_locked)
278
    {
279
      info->was_locked=info->lock_type;
280
      if (mi_lock_database(info,F_UNLCK))
281
	error=my_errno;
282
      info->lock_type = F_UNLCK;
283
    }
284
    if (share->kfile >= 0)
285
      _mi_decrement_open_count(info);
286
    if (share->kfile >= 0 && my_close(share->kfile,MYF(0)))
287
      error=my_errno;
288
    {
289
      LIST *list_element ;
290
      for (list_element=myisam_open_list ;
291
	   list_element ;
292
	   list_element=list_element->next)
293
      {
294
	MI_INFO *tmpinfo=(MI_INFO*) list_element->data;
295
	if (tmpinfo->s == info->s)
296
	{
297
	  if (tmpinfo->dfile >= 0 && my_close(tmpinfo->dfile,MYF(0)))
298
	    error = my_errno;
299
	  tmpinfo->dfile= -1;
300
	}
301
      }
302
    }
303
    share->kfile= -1;				/* Files aren't open anymore */
304
    pthread_mutex_unlock(&share->intern_lock);
305
#endif
306
    pthread_mutex_unlock(&THR_LOCK_myisam);
307
    break;
308
  case HA_EXTRA_FLUSH:
309
    if (!share->temporary)
310
      flush_key_blocks(share->key_cache, share->kfile, FLUSH_KEEP);
311
#ifdef HAVE_PWRITE
312
    _mi_decrement_open_count(info);
313
#endif
314
    if (share->not_flushed)
315
    {
316
      share->not_flushed=0;
317
      if (my_sync(share->kfile, MYF(0)))
318
	error= my_errno;
319
      if (my_sync(info->dfile, MYF(0)))
320
	error= my_errno;
321
      if (error)
322
      {
323
	share->changed=1;
324
        mi_print_error(info->s, HA_ERR_CRASHED);
325
	mi_mark_crashed(info);			/* Fatal error found */
326
      }
327
    }
328
    if (share->base.blobs)
329
      mi_alloc_rec_buff(info, -1, &info->rec_buff);
330
    break;
331
  case HA_EXTRA_NORMAL:				/* Theese isn't in use */
332
    info->quick_mode=0;
333
    break;
334
  case HA_EXTRA_QUICK:
335
    info->quick_mode=1;
336
    break;
337
  case HA_EXTRA_NO_ROWS:
338
    if (!share->state.header.uniques)
339
      info->opt_flag|= OPT_NO_ROWS;
340
    break;
341
  case HA_EXTRA_PRELOAD_BUFFER_SIZE:
342
    info->preload_buff_size= *((ulong *) extra_arg); 
343
    break;
344
  case HA_EXTRA_CHANGE_KEY_TO_UNIQUE:
345
  case HA_EXTRA_CHANGE_KEY_TO_DUP:
346
    mi_extra_keyflag(info, function);
347
    break;
348
  case HA_EXTRA_MMAP:
349
#ifdef HAVE_MMAP
350
    pthread_mutex_lock(&share->intern_lock);
351
    /*
352
      Memory map the data file if it is not already mapped. It is safe
353
      to memory map a file while other threads are using file I/O on it.
354
      Assigning a new address to a function pointer is an atomic
355
      operation. intern_lock prevents that two or more mappings are done
356
      at the same time.
357
    */
358
    if (!share->file_map)
359
    {
360
      if (mi_dynmap_file(info, share->state.state.data_file_length))
361
      {
362
        error= my_errno= errno;
363
      }
364
      else
365
      {
366
        share->file_read= mi_mmap_pread;
367
        share->file_write= mi_mmap_pwrite;
368
      }
369
    }
370
    pthread_mutex_unlock(&share->intern_lock);
371
#endif
372
    break;
373
  case HA_EXTRA_KEY_CACHE:
374
  case HA_EXTRA_NO_KEY_CACHE:
375
  default:
376
    break;
377
  }
378
  {
379
    char tmp[1];
380
    tmp[0]=function;
381
    myisam_log_command(MI_LOG_EXTRA,info,(uchar*) tmp,1,error);
382
  }
51.1.99 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
383
  return(error);
1 by brian
clean slate
384
} /* mi_extra */
385
386
387
void mi_set_index_cond_func(MI_INFO *info, index_cond_func_t func,
388
                            void *func_arg)
389
{
390
  info->index_cond_func= func;
391
  info->index_cond_func_arg= func_arg;
392
}
393
394
/*
395
    Start/Stop Inserting Duplicates Into a Table, WL#1648.
396
 */
397
static void mi_extra_keyflag(MI_INFO *info, enum ha_extra_function function)
398
{
399
  uint  idx;
400
401
  for (idx= 0; idx< info->s->base.keys; idx++)
402
  {
403
    switch (function) {
404
    case HA_EXTRA_CHANGE_KEY_TO_UNIQUE:
405
      info->s->keyinfo[idx].flag|= HA_NOSAME;
406
      break;
407
    case HA_EXTRA_CHANGE_KEY_TO_DUP:
408
      info->s->keyinfo[idx].flag&= ~(HA_NOSAME);
409
      break;
410
    default:
411
      break;
412
    }
413
  }
414
}
415
416
417
int mi_reset(MI_INFO *info)
418
{
419
  int error= 0;
420
  MYISAM_SHARE *share=info->s;
421
  /*
422
    Free buffers and reset the following flags:
423
    EXTRA_CACHE, EXTRA_WRITE_CACHE, EXTRA_KEYREAD, EXTRA_QUICK
424
425
    If the row buffer cache is large (for dynamic tables), reduce it
426
    to save memory.
427
  */
428
  if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
429
  {
430
    info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
431
    error= end_io_cache(&info->rec_cache);
432
  }
433
  if (share->base.blobs)
434
    mi_alloc_rec_buff(info, -1, &info->rec_buff);
435
#if defined(HAVE_MMAP) && defined(HAVE_MADVISE)
436
  if (info->opt_flag & MEMMAP_USED)
437
    madvise((char*) share->file_map, share->state.state.data_file_length,
438
            MADV_RANDOM);
439
#endif
440
  info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
441
  info->quick_mode=0;
442
  info->lastinx= 0;			/* Use first index as def */
443
  info->last_search_keypage= info->lastpos= HA_OFFSET_ERROR;
444
  info->page_changed= 1;
445
  info->update= ((info->update & HA_STATE_CHANGED) | HA_STATE_NEXT_FOUND |
446
                 HA_STATE_PREV_FOUND);
51.1.99 by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE
447
  return(error);
1 by brian
clean slate
448
}