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