1
/* Copyright (C) 2000-2006 MySQL AB
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.
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.
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 St, Fifth Floor, Boston, MA 02110-1301 USA */
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
23
#include "myisam_priv.h"
24
#include "drizzled/charset_info.h"
25
#include <drizzled/util/test.h>
28
using namespace drizzled;
30
/* lock table by F_UNLCK, F_RDLCK or F_WRLCK */
32
int mi_lock_database(MI_INFO *info, int lock_type)
36
MYISAM_SHARE *share=info->s;
40
info->s->in_use= new list<Session *>;
42
if (lock_type == F_EXTRA_LCK) /* Used by TMP tables */
46
info->lock_type= lock_type;
47
info->s->in_use->push_front(info->in_use);
52
if (share->kfile >= 0) /* May only be false on windows */
56
if (info->lock_type == F_RDLCK)
57
count= --share->r_locks;
59
count= --share->w_locks;
61
if (info->lock_type == F_WRLCK && !share->w_locks &&
62
!share->delay_key_write && flush_key_blocks(share->getKeyCache(),
63
share->kfile,FLUSH_KEEP))
66
mi_print_error(info->s, HA_ERR_CRASHED);
67
mi_mark_crashed(info); /* Mark that table must be checked */
69
if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
71
if (info->rec_cache.end_io_cache())
74
mi_print_error(info->s, HA_ERR_CRASHED);
75
mi_mark_crashed(info);
80
if (share->changed && !share->w_locks)
82
if ((info->s->mmaped_length != info->s->state.state.data_file_length) &&
83
(info->s->nonmmaped_inserts > MAX_NONMAPPED_INSERTS))
85
mi_remap_file(info, info->s->state.state.data_file_length);
86
info->s->nonmmaped_inserts= 0;
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))
97
mi_print_error(info->s, HA_ERR_CRASHED);
98
mi_mark_crashed(info);
101
if (info->lock_type != F_EXTRA_LCK)
104
{ /* Only read locks left */
107
else if (!share->w_locks)
108
{ /* No more locks */
113
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
114
info->lock_type= F_UNLCK;
115
info->s->in_use->remove(info->in_use);
118
if (info->lock_type == F_WRLCK)
121
Change RW to READONLY
123
mysqld does not turn write locks to read locks,
124
so we're never here in mysqld.
126
if (share->w_locks == 1)
132
info->lock_type=lock_type;
135
if (!share->r_locks && !share->w_locks)
138
if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
143
if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
150
_mi_test_if_changed(info);
153
info->lock_type=lock_type;
154
info->s->in_use->push_front(info->in_use);
157
if (info->lock_type == F_RDLCK)
158
{ /* Change READONLY to RW */
159
if (share->r_locks == 1)
164
info->lock_type=lock_type;
168
if (!(share->options & HA_OPTION_READ_ONLY_DATA))
175
if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
184
_mi_test_if_changed(info);
186
info->lock_type=lock_type;
189
info->s->in_use->push_front(info->in_use);
192
break; /* Impossible */
199
Check for bad file descriptors if this table is part
200
of a merge union. Failing to capture this may cause
201
a crash on windows if the table is renamed and
202
later on referenced by the merge table.
204
if( info->owned_by_merge && (info->s)->kfile < 0 )
206
error = HA_ERR_NO_SUCH_TABLE;
210
#if defined(FULL_LOG) || defined(_lint)
211
lock_type|=(int) (flag << 8); /* Set bit to set if real lock */
212
myisam_log_command(MI_LOG_LOCK,info,(unsigned char*) &lock_type,sizeof(lock_type),
216
} /* mi_lock_database */
219
/****************************************************************************
220
** functions to read / write the state
221
****************************************************************************/
223
int _mi_readinfo(register MI_INFO *info, int lock_type, int check_keybuffer)
225
if (info->lock_type == F_UNLCK)
227
MYISAM_SHARE *share=info->s;
228
if (!share->tot_locks)
230
if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
232
int error=errno ? errno : -1;
238
_mi_test_if_changed(info);
240
else if (lock_type == F_WRLCK && info->lock_type == F_RDLCK)
242
errno=EACCES; /* Not allowed to change */
243
return(-1); /* when have read_lock() */
250
Every isam-function that uppdates the isam-database MUST end with this
254
int _mi_writeinfo(register MI_INFO *info, uint32_t operation)
257
MYISAM_SHARE *share=info->s;
260
if (share->tot_locks == 0)
262
olderror=errno; /* Remember last error */
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)))
274
share->changed= 1; /* Mark keyfile changed */
276
} /* _mi_writeinfo */
279
/* Test if someone has changed the database */
280
/* (Should be called after readinfo) */
282
int _mi_test_if_changed(register MI_INFO *info)
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)
290
flush_key_blocks(share->getKeyCache(), share->kfile, FLUSH_RELEASE);
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 */
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 */
305
Put a mark in the .MYI file that someone is updating the table
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
314
- In mi_close() it's decremented by _mi_decrement_open_count() if it
315
was incremented in the same process.
317
This mean that if we are the only process using the file, the open_count
318
tells us if the MYISAM file wasn't properly closed.*/
321
int _mi_mark_file_changed(MI_INFO *info)
323
unsigned char buff[3];
324
register MYISAM_SHARE *share=info->s;
326
if (!(share->state.changed & STATE_CHANGED) || ! share->global_changed)
328
share->state.changed|=(STATE_CHANGED | STATE_NOT_ANALYZED |
329
STATE_NOT_OPTIMIZED_KEYS);
330
if (!share->global_changed)
332
share->global_changed=1;
333
share->state.open_count++;
335
if (!share->temporary)
337
mi_int2store(buff,share->state.open_count);
338
buff[2]=1; /* Mark that it's changed */
339
return(my_pwrite(share->kfile,buff,sizeof(buff),
340
sizeof(share->state.header),
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!
353
int _mi_decrement_open_count(MI_INFO *info)
355
unsigned char buff[2];
356
register MYISAM_SHARE *share=info->s;
357
int lock_error=0,write_error=0;
358
if (share->global_changed)
360
uint32_t old_lock=info->lock_type;
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)
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),
373
lock_error=mi_lock_database(info,old_lock);
375
return test(lock_error || write_error);