~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2006 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
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
1 by brian
clean slate
15
16
/*
17
  locking of isam-tables.
18
  reads info from a isam-table. Must be first request before doing any furter
19
  calls to any isamfunktion.  Is used to allow many process use the same
20
  isamdatabase.
21
*/
22
1130.3.28 by Monty Taylor
Moved heapdef.h and myisamdef.h to *_priv.h for easier filtering for include guard check.
23
#include "myisam_priv.h"
2281.5.1 by Muhammad Umair
Merged charset declarations of global_charset_info.h and charset_info.h into charset.h header file.
24
#include <drizzled/charset.h>
492.1.7 by Monty Taylor
Moved test() to its own file.
25
#include <drizzled/util/test.h>
1 by brian
clean slate
26
916.1.35 by Padraig O'Sullivan
Removing the last of LIST from the MyISAM storage engine.
27
using namespace std;
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
28
using namespace drizzled;
916.1.35 by Padraig O'Sullivan
Removing the last of LIST from the MyISAM storage engine.
29
1 by brian
clean slate
30
	/* lock table by F_UNLCK, F_RDLCK or F_WRLCK */
31
32
int mi_lock_database(MI_INFO *info, int lock_type)
33
{
34
  int error;
482 by Brian Aker
Remove uint.
35
  uint32_t count;
1 by brian
clean slate
36
  MYISAM_SHARE *share=info->s;
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
37
#if defined(FULL_LOG) || defined(_lint)
482 by Brian Aker
Remove uint.
38
  uint32_t flag;
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
39
#endif
916.1.37 by Padraig O'Sullivan
Added a lock to protect an instance of the in_use list. Thanks Monty for
40
916.1.35 by Padraig O'Sullivan
Removing the last of LIST from the MyISAM storage engine.
41
  if (!info->s->in_use)
42
    info->s->in_use= new list<Session *>;
51.1.87 by Jay Pipes
Removed/replaced DBUG symbols
43
1 by brian
clean slate
44
  if (lock_type == F_EXTRA_LCK)                 /* Used by TMP tables */
45
  {
46
    ++share->w_locks;
47
    ++share->tot_locks;
48
    info->lock_type= lock_type;
916.1.35 by Padraig O'Sullivan
Removing the last of LIST from the MyISAM storage engine.
49
    info->s->in_use->push_front(info->in_use);
51.1.87 by Jay Pipes
Removed/replaced DBUG symbols
50
    return(0);
1 by brian
clean slate
51
  }
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
52
#if defined(FULL_LOG) || defined(_lint)
53
  flag=0;
54
#endif
1 by brian
clean slate
55
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
56
  error=0;
1 by brian
clean slate
57
  if (share->kfile >= 0)		/* May only be false on windows */
58
  {
59
    switch (lock_type) {
60
    case F_UNLCK:
61
      if (info->lock_type == F_RDLCK)
62
	count= --share->r_locks;
63
      else
64
	count= --share->w_locks;
65
      --share->tot_locks;
66
      if (info->lock_type == F_WRLCK && !share->w_locks &&
1689.2.15 by Brian Aker
Encapsulate the key cache object in myisam.
67
	  !share->delay_key_write && flush_key_blocks(share->getKeyCache(),
1 by brian
clean slate
68
						      share->kfile,FLUSH_KEEP))
69
      {
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
70
	error=errno;
1 by brian
clean slate
71
        mi_print_error(info->s, HA_ERR_CRASHED);
72
	mi_mark_crashed(info);		/* Mark that table must be checked */
73
      }
74
      if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
75
      {
1909.1.1 by Brian Aker
Encapsulation of IO_CACHE.
76
	if (info->rec_cache.end_io_cache())
1 by brian
clean slate
77
	{
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
78
	  error=errno;
1 by brian
clean slate
79
          mi_print_error(info->s, HA_ERR_CRASHED);
80
	  mi_mark_crashed(info);
81
	}
82
      }
83
      if (!count)
84
      {
85
	if (share->changed && !share->w_locks)
86
	{
87
    if ((info->s->mmaped_length != info->s->state.state.data_file_length) &&
88
        (info->s->nonmmaped_inserts > MAX_NONMAPPED_INSERTS))
89
    {
90
      mi_remap_file(info, info->s->state.state.data_file_length);
91
      info->s->nonmmaped_inserts= 0;
92
    }
93
	  share->state.process= share->last_process=share->this_process;
94
	  share->state.unique=   info->last_unique=  info->this_unique;
95
	  share->state.update_count= info->last_loop= ++info->this_loop;
96
          if (mi_state_info_write(share->kfile, &share->state, 1))
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
97
	    error=errno;
1 by brian
clean slate
98
	  share->changed=0;
1115.1.2 by Brian Aker
Taylor the defaults for MyISAM for its "tmp" behavior.
99
          share->not_flushed=1;
1 by brian
clean slate
100
	  if (error)
101
          {
102
            mi_print_error(info->s, HA_ERR_CRASHED);
103
	    mi_mark_crashed(info);
104
          }
105
	}
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
106
#if defined(FULL_LOG) || defined(_lint)
1 by brian
clean slate
107
	if (info->lock_type != F_EXTRA_LCK)
108
	{
109
	  if (share->r_locks)
110
	  {					/* Only read locks left */
111
	    flag=1;
112
	  }
113
	  else if (!share->w_locks)
114
	  {					/* No more locks */
115
	    flag=1;
116
	  }
117
	}
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
118
#endif
1 by brian
clean slate
119
      }
120
      info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
121
      info->lock_type= F_UNLCK;
916.1.35 by Padraig O'Sullivan
Removing the last of LIST from the MyISAM storage engine.
122
      info->s->in_use->remove(info->in_use);
1 by brian
clean slate
123
      break;
124
    case F_RDLCK:
125
      if (info->lock_type == F_WRLCK)
126
      {
127
        /*
128
          Change RW to READONLY
129
130
          mysqld does not turn write locks to read locks,
131
          so we're never here in mysqld.
132
        */
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
133
#if defined(FULL_LOG) || defined(_lint)
1 by brian
clean slate
134
	if (share->w_locks == 1)
135
	{
136
	  flag=1;
137
	}
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
138
#endif
1 by brian
clean slate
139
	share->w_locks--;
140
	share->r_locks++;
141
	info->lock_type=lock_type;
142
	break;
143
      }
144
      if (!share->r_locks && !share->w_locks)
145
      {
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
146
#if defined(FULL_LOG) || defined(_lint)
1 by brian
clean slate
147
	flag=1;
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
148
#endif
1 by brian
clean slate
149
	if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
150
	{
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
151
	  error=errno;
1 by brian
clean slate
152
	  break;
153
	}
154
	if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
155
	{
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
156
	  error=errno;
157
	  errno=error;
1 by brian
clean slate
158
	  break;
159
	}
160
      }
398.1.10 by Monty Taylor
Actually removed VOID() this time.
161
      _mi_test_if_changed(info);
1 by brian
clean slate
162
      share->r_locks++;
163
      share->tot_locks++;
164
      info->lock_type=lock_type;
916.1.35 by Padraig O'Sullivan
Removing the last of LIST from the MyISAM storage engine.
165
      info->s->in_use->push_front(info->in_use);
1 by brian
clean slate
166
      break;
167
    case F_WRLCK:
168
      if (info->lock_type == F_RDLCK)
169
      {						/* Change READONLY to RW */
170
	if (share->r_locks == 1)
171
	{
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
172
#if defined(FULL_LOG) || defined(_lint)
1 by brian
clean slate
173
	  flag=1;
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
174
#endif
1 by brian
clean slate
175
	  share->r_locks--;
176
	  share->w_locks++;
177
	  info->lock_type=lock_type;
178
	  break;
179
	}
180
      }
181
      if (!(share->options & HA_OPTION_READ_ONLY_DATA))
182
      {
183
	if (!share->w_locks)
184
	{
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
185
#if defined(FULL_LOG) || defined(_lint)
1 by brian
clean slate
186
	  flag=1;
2253.1.1 by Andrew Hutchings
Fix Drizzle to compile in GCC 4.6 (which fires warnings and therefore errors if a variable is set and not read)
187
#endif
1 by brian
clean slate
188
	  if (!share->r_locks)
189
	  {
190
	    if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
191
	    {
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
192
	      error=errno;
193
	      errno=error;
1 by brian
clean slate
194
	      break;
195
	    }
196
	  }
197
	}
198
      }
398.1.10 by Monty Taylor
Actually removed VOID() this time.
199
      _mi_test_if_changed(info);
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
200
1 by brian
clean slate
201
      info->lock_type=lock_type;
202
      share->w_locks++;
203
      share->tot_locks++;
916.1.35 by Padraig O'Sullivan
Removing the last of LIST from the MyISAM storage engine.
204
      info->s->in_use->push_front(info->in_use);
1 by brian
clean slate
205
      break;
206
    default:
207
      break;				/* Impossible */
208
    }
209
  }
210
#ifdef __WIN__
211
  else
212
  {
213
    /*
214
       Check for bad file descriptors if this table is part
215
       of a merge union. Failing to capture this may cause
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
216
       a crash on windows if the table is renamed and
1 by brian
clean slate
217
       later on referenced by the merge table.
218
     */
219
    if( info->owned_by_merge && (info->s)->kfile < 0 )
220
    {
221
      error = HA_ERR_NO_SUCH_TABLE;
222
    }
223
  }
224
#endif
225
#if defined(FULL_LOG) || defined(_lint)
226
  lock_type|=(int) (flag << 8);		/* Set bit to set if real lock */
481 by Brian Aker
Remove all of uchar.
227
  myisam_log_command(MI_LOG_LOCK,info,(unsigned char*) &lock_type,sizeof(lock_type),
1 by brian
clean slate
228
		     error);
229
#endif
51.1.87 by Jay Pipes
Removed/replaced DBUG symbols
230
  return(error);
1 by brian
clean slate
231
} /* mi_lock_database */
232
233
234
/****************************************************************************
235
 ** functions to read / write the state
236
****************************************************************************/
237
238
int _mi_readinfo(register MI_INFO *info, int lock_type, int check_keybuffer)
239
{
240
  if (info->lock_type == F_UNLCK)
241
  {
242
    MYISAM_SHARE *share=info->s;
243
    if (!share->tot_locks)
244
    {
245
      if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
246
      {
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
247
	int error=errno ? errno : -1;
248
	errno=error;
51.1.87 by Jay Pipes
Removed/replaced DBUG symbols
249
	return(1);
1 by brian
clean slate
250
      }
251
    }
252
    if (check_keybuffer)
398.1.10 by Monty Taylor
Actually removed VOID() this time.
253
      _mi_test_if_changed(info);
1 by brian
clean slate
254
  }
255
  else if (lock_type == F_WRLCK && info->lock_type == F_RDLCK)
256
  {
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
257
    errno=EACCES;				/* Not allowed to change */
51.1.87 by Jay Pipes
Removed/replaced DBUG symbols
258
    return(-1);				/* when have read_lock() */
1 by brian
clean slate
259
  }
51.1.87 by Jay Pipes
Removed/replaced DBUG symbols
260
  return(0);
1 by brian
clean slate
261
} /* _mi_readinfo */
262
263
264
/*
265
  Every isam-function that uppdates the isam-database MUST end with this
266
  request
267
*/
268
482 by Brian Aker
Remove uint.
269
int _mi_writeinfo(register MI_INFO *info, uint32_t operation)
1 by brian
clean slate
270
{
271
  int error,olderror;
272
  MYISAM_SHARE *share=info->s;
273
274
  error=0;
275
  if (share->tot_locks == 0)
276
  {
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
277
    olderror=errno;			/* Remember last error */
1 by brian
clean slate
278
    if (operation)
279
    {					/* Two threads can't be here */
280
      share->state.process= share->last_process=   share->this_process;
281
      share->state.unique=  info->last_unique=	   info->this_unique;
282
      share->state.update_count= info->last_loop= ++info->this_loop;
283
      if ((error=mi_state_info_write(share->kfile, &share->state, 1)))
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
284
	olderror=errno;
1 by brian
clean slate
285
    }
1241.9.57 by Monty Taylor
Oy. Bigger change than I normally like - but this stuff is all intertwined.
286
    errno=olderror;
1 by brian
clean slate
287
  }
288
  else if (operation)
289
    share->changed= 1;			/* Mark keyfile changed */
51.1.87 by Jay Pipes
Removed/replaced DBUG symbols
290
  return(error);
1 by brian
clean slate
291
} /* _mi_writeinfo */
292
293
294
	/* Test if someone has changed the database */
295
	/* (Should be called after readinfo) */
296
297
int _mi_test_if_changed(register MI_INFO *info)
298
{
299
  MYISAM_SHARE *share=info->s;
300
  if (share->state.process != share->last_process ||
301
      share->state.unique  != info->last_unique ||
302
      share->state.update_count != info->last_loop)
303
  {						/* Keyfile has changed */
304
    if (share->state.process != share->this_process)
1689.2.15 by Brian Aker
Encapsulate the key cache object in myisam.
305
      flush_key_blocks(share->getKeyCache(), share->kfile, FLUSH_RELEASE);
1 by brian
clean slate
306
    share->last_process=share->state.process;
307
    info->last_unique=	share->state.unique;
308
    info->last_loop=	share->state.update_count;
309
    info->update|=	HA_STATE_WRITTEN;	/* Must use file on next */
310
    info->data_changed= 1;			/* For mi_is_changed */
311
    return 1;
312
  }
313
  return (!(info->update & HA_STATE_AKTIV) ||
314
	  (info->update & (HA_STATE_WRITTEN | HA_STATE_DELETED |
315
			   HA_STATE_KEY_CHANGED)));
316
} /* _mi_test_if_changed */
317
318
319
/*
320
  Put a mark in the .MYI file that someone is updating the table
321
322
323
  DOCUMENTATION
324
325
  state.open_count in the .MYI file is used the following way:
326
  - For the first change of the .MYI file in this process open_count is
327
    incremented by mi_mark_file_change(). (We have a write lock on the file
328
    when this happens)
329
  - In mi_close() it's decremented by _mi_decrement_open_count() if it
330
    was incremented in the same process.
331
332
  This mean that if we are the only process using the file, the open_count
77.1.96 by Monty Taylor
Removed skip-external-locking.
333
  tells us if the MYISAM file wasn't properly closed.*/
1 by brian
clean slate
334
335
336
int _mi_mark_file_changed(MI_INFO *info)
337
{
481 by Brian Aker
Remove all of uchar.
338
  unsigned char buff[3];
1 by brian
clean slate
339
  register MYISAM_SHARE *share=info->s;
340
341
  if (!(share->state.changed & STATE_CHANGED) || ! share->global_changed)
342
  {
343
    share->state.changed|=(STATE_CHANGED | STATE_NOT_ANALYZED |
344
			   STATE_NOT_OPTIMIZED_KEYS);
345
    if (!share->global_changed)
346
    {
347
      share->global_changed=1;
348
      share->state.open_count++;
349
    }
350
    if (!share->temporary)
351
    {
352
      mi_int2store(buff,share->state.open_count);
353
      buff[2]=1;				/* Mark that it's changed */
51.1.87 by Jay Pipes
Removed/replaced DBUG symbols
354
      return(my_pwrite(share->kfile,buff,sizeof(buff),
1 by brian
clean slate
355
                            sizeof(share->state.header),
356
                            MYF(MY_NABP)));
357
    }
358
  }
51.1.87 by Jay Pipes
Removed/replaced DBUG symbols
359
  return(0);
1 by brian
clean slate
360
}
361
362
363
/*
364
  This is only called by close or by extra(HA_FLUSH) if the OS has the pwrite()
365
  call.  In these context the following code should be safe!
366
 */
367
368
int _mi_decrement_open_count(MI_INFO *info)
369
{
481 by Brian Aker
Remove all of uchar.
370
  unsigned char buff[2];
1 by brian
clean slate
371
  register MYISAM_SHARE *share=info->s;
372
  int lock_error=0,write_error=0;
373
  if (share->global_changed)
374
  {
482 by Brian Aker
Remove uint.
375
    uint32_t old_lock=info->lock_type;
1 by brian
clean slate
376
    share->global_changed=0;
377
    lock_error=mi_lock_database(info,F_WRLCK);
378
    /* Its not fatal even if we couldn't get the lock ! */
379
    if (share->state.open_count > 0)
380
    {
381
      share->state.open_count--;
382
      mi_int2store(buff,share->state.open_count);
383
      write_error=my_pwrite(share->kfile,buff,sizeof(buff),
384
			    sizeof(share->state.header),
385
			    MYF(MY_NABP));
386
    }
387
    if (!lock_error)
388
      lock_error=mi_lock_database(info,old_lock);
389
  }
390
  return test(lock_error || write_error);
391
}