~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/myisam/mi_locking.cc

  • Committer: Monty Taylor
  • Date: 2009-04-25 19:24:49 UTC
  • mto: (997.2.5 mordred)
  • mto: This revision was merged to the branch mainline in revision 1003.
  • Revision ID: mordred@inaugust.com-20090425192449-0htujbt2r9jzupn5
Moved heap.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  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
 
 
23
 
#include "myisam_priv.h"
24
 
#include "drizzled/charset_info.h"
25
 
#include <drizzled/util/test.h>
26
 
 
27
 
using namespace std;
28
 
using namespace drizzled;
29
 
 
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;
35
 
  uint32_t count;
36
 
  MYISAM_SHARE *share=info->s;
37
 
  uint32_t flag;
38
 
 
39
 
  if (!info->s->in_use)
40
 
    info->s->in_use= new list<Session *>;
41
 
 
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;
47
 
    info->s->in_use->push_front(info->in_use);
48
 
    return(0);
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 &&
62
 
          !share->delay_key_write && flush_key_blocks(share->getKeyCache(),
63
 
                                                      share->kfile,FLUSH_KEEP))
64
 
      {
65
 
        error=errno;
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 (info->rec_cache.end_io_cache())
72
 
        {
73
 
          error=errno;
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))
92
 
            error=errno;
93
 
          share->changed=0;
94
 
          share->not_flushed=1;
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;
115
 
      info->s->in_use->remove(info->in_use);
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
 
        {
140
 
          error=errno;
141
 
          break;
142
 
        }
143
 
        if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
144
 
        {
145
 
          error=errno;
146
 
          errno=error;
147
 
          break;
148
 
        }
149
 
      }
150
 
      _mi_test_if_changed(info);
151
 
      share->r_locks++;
152
 
      share->tot_locks++;
153
 
      info->lock_type=lock_type;
154
 
      info->s->in_use->push_front(info->in_use);
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
 
            {
177
 
              error=errno;
178
 
              errno=error;
179
 
              break;
180
 
            }
181
 
          }
182
 
        }
183
 
      }
184
 
      _mi_test_if_changed(info);
185
 
 
186
 
      info->lock_type=lock_type;
187
 
      share->w_locks++;
188
 
      share->tot_locks++;
189
 
      info->s->in_use->push_front(info->in_use);
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
201
 
       a crash on windows if the table is renamed and
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 */
212
 
  myisam_log_command(MI_LOG_LOCK,info,(unsigned char*) &lock_type,sizeof(lock_type),
213
 
                     error);
214
 
#endif
215
 
  return(error);
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
 
      {
232
 
        int error=errno ? errno : -1;
233
 
        errno=error;
234
 
        return(1);
235
 
      }
236
 
    }
237
 
    if (check_keybuffer)
238
 
      _mi_test_if_changed(info);
239
 
  }
240
 
  else if (lock_type == F_WRLCK && info->lock_type == F_RDLCK)
241
 
  {
242
 
    errno=EACCES;                               /* Not allowed to change */
243
 
    return(-1);                         /* when have read_lock() */
244
 
  }
245
 
  return(0);
246
 
} /* _mi_readinfo */
247
 
 
248
 
 
249
 
/*
250
 
  Every isam-function that uppdates the isam-database MUST end with this
251
 
  request
252
 
*/
253
 
 
254
 
int _mi_writeinfo(register MI_INFO *info, uint32_t operation)
255
 
{
256
 
  int error,olderror;
257
 
  MYISAM_SHARE *share=info->s;
258
 
 
259
 
  error=0;
260
 
  if (share->tot_locks == 0)
261
 
  {
262
 
    olderror=errno;                     /* Remember last error */
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)))
269
 
        olderror=errno;
270
 
    }
271
 
    errno=olderror;
272
 
  }
273
 
  else if (operation)
274
 
    share->changed= 1;                  /* Mark keyfile changed */
275
 
  return(error);
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)
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 */
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
318
 
  tells us if the MYISAM file wasn't properly closed.*/
319
 
 
320
 
 
321
 
int _mi_mark_file_changed(MI_INFO *info)
322
 
{
323
 
  unsigned char buff[3];
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 */
339
 
      return(my_pwrite(share->kfile,buff,sizeof(buff),
340
 
                            sizeof(share->state.header),
341
 
                            MYF(MY_NABP)));
342
 
    }
343
 
  }
344
 
  return(0);
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
 
{
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)
359
 
  {
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)
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
 
}