Drizzled Public API Documentation

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