mi_locking.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:14k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /*
  14.   locking of isam-tables.
  15.   reads info from a isam-table. Must be first request before doing any furter
  16.   calls to any isamfunktion.  Is used to allow many process use the same
  17.   isamdatabase.
  18. */
  19. #include "myisamdef.h"
  20. /* lock table by F_UNLCK, F_RDLCK or F_WRLCK */
  21. int mi_lock_database(MI_INFO *info, int lock_type)
  22. {
  23.   int error;
  24.   uint count;
  25.   MYISAM_SHARE *share=info->s;
  26.   uint flag;
  27.   DBUG_ENTER("mi_lock_database");
  28.   DBUG_PRINT("enter",("lock_type: %d  old lock %d  r_locks: %u  w_locks: %u "
  29.                       "global_changed:  %d  open_count: %u  name: '%s'",
  30.                       lock_type, info->lock_type, share->r_locks,
  31.                       share->w_locks,
  32.                       share->global_changed, share->state.open_count,
  33.                       share->index_file_name));
  34.   if (share->options & HA_OPTION_READ_ONLY_DATA ||
  35.       info->lock_type == lock_type)
  36.     DBUG_RETURN(0);
  37.   if (lock_type == F_EXTRA_LCK)                 /* Used by TMP tables */
  38.   {
  39.     ++share->w_locks;
  40.     ++share->tot_locks;
  41.     info->lock_type= lock_type;
  42.     DBUG_RETURN(0);
  43.   }
  44.   flag=error=0;
  45.   pthread_mutex_lock(&share->intern_lock);
  46.   if (share->kfile >= 0) /* May only be false on windows */
  47.   {
  48.     switch (lock_type) {
  49.     case F_UNLCK:
  50.       if (info->lock_type == F_RDLCK)
  51. count= --share->r_locks;
  52.       else
  53. count= --share->w_locks;
  54.       --share->tot_locks;
  55.       if (info->lock_type == F_WRLCK && !share->w_locks &&
  56.   !share->delay_key_write && flush_key_blocks(share->key_cache,
  57.       share->kfile,FLUSH_KEEP))
  58.       {
  59. error=my_errno;
  60. mi_mark_crashed(info); /* Mark that table must be checked */
  61.       }
  62.       if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
  63.       {
  64. if (end_io_cache(&info->rec_cache))
  65. {
  66.   error=my_errno;
  67.   mi_mark_crashed(info);
  68. }
  69.       }
  70.       if (!count)
  71.       {
  72. DBUG_PRINT("info",("changed: %u  w_locks: %u",
  73.    (uint) share->changed, share->w_locks));
  74. if (share->changed && !share->w_locks)
  75. {
  76.   share->state.process= share->last_process=share->this_process;
  77.   share->state.unique=   info->last_unique=  info->this_unique;
  78.   share->state.update_count= info->last_loop= ++info->this_loop;
  79.           if (mi_state_info_write(share->kfile, &share->state, 1))
  80.     error=my_errno;
  81.   share->changed=0;
  82.   if (myisam_flush)
  83.   {
  84.     if (my_sync(share->kfile, MYF(0)))
  85.       error= my_errno;
  86.     if (my_sync(info->dfile, MYF(0)))
  87.       error= my_errno;
  88.   }
  89.   else
  90.     share->not_flushed=1;
  91.   if (error)
  92.     mi_mark_crashed(info);
  93. }
  94. if (info->lock_type != F_EXTRA_LCK)
  95. {
  96.   if (share->r_locks)
  97.   { /* Only read locks left */
  98.     flag=1;
  99.     if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
  100. MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
  101.       error=my_errno;
  102.   }
  103.   else if (!share->w_locks)
  104.   { /* No more locks */
  105.     flag=1;
  106.     if (my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
  107. MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
  108.       error=my_errno;
  109.   }
  110. }
  111.       }
  112.       info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
  113.       info->lock_type= F_UNLCK;
  114.       break;
  115.     case F_RDLCK:
  116.       if (info->lock_type == F_WRLCK)
  117.       {
  118.         /*
  119.           Change RW to READONLY
  120.           mysqld does not turn write locks to read locks,
  121.           so we're never here in mysqld.
  122.         */
  123. if (share->w_locks == 1)
  124. {
  125.   flag=1;
  126.           if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
  127.       MYF(MY_SEEK_NOT_DONE)))
  128.   {
  129.     error=my_errno;
  130.     break;
  131.   }
  132. }
  133. share->w_locks--;
  134. share->r_locks++;
  135. info->lock_type=lock_type;
  136. break;
  137.       }
  138.       if (!share->r_locks && !share->w_locks)
  139.       {
  140. flag=1;
  141. if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
  142.     info->lock_wait | MY_SEEK_NOT_DONE))
  143. {
  144.   error=my_errno;
  145.   break;
  146. }
  147. if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
  148. {
  149.   error=my_errno;
  150.   VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)));
  151.   my_errno=error;
  152.   break;
  153. }
  154.       }
  155.       VOID(_mi_test_if_changed(info));
  156.       share->r_locks++;
  157.       share->tot_locks++;
  158.       info->lock_type=lock_type;
  159.       break;
  160.     case F_WRLCK:
  161.       if (info->lock_type == F_RDLCK)
  162.       { /* Change READONLY to RW */
  163. if (share->r_locks == 1)
  164. {
  165.   flag=1;
  166.   if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
  167.       MYF(info->lock_wait | MY_SEEK_NOT_DONE)))
  168.   {
  169.     error=my_errno;
  170.     break;
  171.   }
  172.   share->r_locks--;
  173.   share->w_locks++;
  174.   info->lock_type=lock_type;
  175.   break;
  176. }
  177.       }
  178.       if (!(share->options & HA_OPTION_READ_ONLY_DATA))
  179.       {
  180. if (!share->w_locks)
  181. {
  182.   flag=1;
  183.   if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
  184.       info->lock_wait | MY_SEEK_NOT_DONE))
  185.   {
  186.     error=my_errno;
  187.     break;
  188.   }
  189.   if (!share->r_locks)
  190.   {
  191.     if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
  192.     {
  193.       error=my_errno;
  194.       VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
  195.    info->lock_wait | MY_SEEK_NOT_DONE));
  196.       my_errno=error;
  197.       break;
  198.     }
  199.   }
  200. }
  201.       }
  202.       VOID(_mi_test_if_changed(info));
  203.       info->lock_type=lock_type;
  204.       info->invalidator=info->s->invalidator;
  205.       share->w_locks++;
  206.       share->tot_locks++;
  207.       break;
  208.     default:
  209.       break; /* Impossible */
  210.     }
  211.   }
  212.   pthread_mutex_unlock(&share->intern_lock);
  213. #if defined(FULL_LOG) || defined(_lint)
  214.   lock_type|=(int) (flag << 8); /* Set bit to set if real lock */
  215.   myisam_log_command(MI_LOG_LOCK,info,(byte*) &lock_type,sizeof(lock_type),
  216.      error);
  217. #endif
  218.   DBUG_RETURN(error);
  219. } /* mi_lock_database */
  220. /****************************************************************************
  221.   The following functions are called by thr_lock() in threaded applications
  222. ****************************************************************************/
  223. void mi_get_status(void* param)
  224. {
  225.   MI_INFO *info=(MI_INFO*) param;
  226.   DBUG_ENTER("mi_get_status");
  227.   DBUG_PRINT("info",("key_file: %ld  data_file: %ld",
  228.      (long) info->s->state.state.key_file_length,
  229.      (long) info->s->state.state.data_file_length));
  230. #ifndef DBUG_OFF
  231.   if (info->state->key_file_length > info->s->state.state.key_file_length ||
  232.       info->state->data_file_length > info->s->state.state.data_file_length)
  233.     DBUG_PRINT("warning",("old info:  key_file: %ld  data_file: %ld",
  234.   (long) info->state->key_file_length,
  235.   (long) info->state->data_file_length));
  236. #endif
  237.   info->save_state=info->s->state.state;
  238.   info->state= &info->save_state;
  239.   DBUG_VOID_RETURN;
  240. }
  241. void mi_update_status(void* param)
  242. {
  243.   MI_INFO *info=(MI_INFO*) param;
  244.   /*
  245.     Because someone may have closed the table we point at, we only
  246.     update the state if its our own state.  This isn't a problem as
  247.     we are always pointing at our own lock or at a read lock.
  248.     (This is enforced by thr_multi_lock.c)
  249.   */
  250.   if (info->state == &info->save_state)
  251.   {
  252. #ifndef DBUG_OFF
  253.     DBUG_PRINT("info",("updating status:  key_file: %ld  data_file: %ld",
  254.        (long) info->state->key_file_length,
  255.        (long) info->state->data_file_length));
  256.     if (info->state->key_file_length < info->s->state.state.key_file_length ||
  257. info->state->data_file_length < info->s->state.state.data_file_length)
  258.       DBUG_PRINT("warning",("old info:  key_file: %ld  data_file: %ld",
  259.     (long) info->s->state.state.key_file_length,
  260.     (long) info->s->state.state.data_file_length));
  261. #endif
  262.     info->s->state.state= *info->state;
  263.     info->state= &info->s->state.state;
  264.   }
  265.   /*
  266.     We have to flush the write cache here as other threads may start
  267.     reading the table before mi_lock_database() is called
  268.   */
  269.   if (info->opt_flag & WRITE_CACHE_USED)
  270.   {
  271.     if (end_io_cache(&info->rec_cache))
  272.     {
  273.       mi_mark_crashed(info);
  274.     }
  275.     info->opt_flag&= ~WRITE_CACHE_USED;
  276.   }
  277. }
  278. void mi_copy_status(void* to,void *from)
  279. {
  280.   ((MI_INFO*) to)->state= &((MI_INFO*) from)->save_state;
  281. }
  282. /*
  283.   Check if should allow concurrent inserts
  284.   IMPLEMENTATION
  285.     Don't allow concurrent inserts if we have a hole in the table.
  286.   NOTES
  287.     Rtree indexes are disabled in mi_open()
  288.   RETURN
  289.     0  ok to use concurrent inserts
  290.     1  not ok
  291. */
  292. my_bool mi_check_status(void* param)
  293. {
  294.   MI_INFO *info=(MI_INFO*) param;
  295.   return (my_bool) (info->s->state.dellink != HA_OFFSET_ERROR);
  296. }
  297. /****************************************************************************
  298.  ** functions to read / write the state
  299. ****************************************************************************/
  300. int _mi_readinfo(register MI_INFO *info, int lock_type, int check_keybuffer)
  301. {
  302.   DBUG_ENTER("_mi_readinfo");
  303.   if (info->lock_type == F_UNLCK)
  304.   {
  305.     MYISAM_SHARE *share=info->s;
  306.     if (!share->tot_locks)
  307.     {
  308.       if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
  309.   info->lock_wait | MY_SEEK_NOT_DONE))
  310. DBUG_RETURN(1);
  311.       if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
  312.       {
  313. int error=my_errno ? my_errno : -1;
  314. VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
  315.      MYF(MY_SEEK_NOT_DONE)));
  316. my_errno=error;
  317. DBUG_RETURN(1);
  318.       }
  319.     }
  320.     if (check_keybuffer)
  321.       VOID(_mi_test_if_changed(info));
  322.     info->invalidator=info->s->invalidator;
  323.   }
  324.   else if (lock_type == F_WRLCK && info->lock_type == F_RDLCK)
  325.   {
  326.     my_errno=EACCES; /* Not allowed to change */
  327.     DBUG_RETURN(-1); /* when have read_lock() */
  328.   }
  329.   DBUG_RETURN(0);
  330. } /* _mi_readinfo */
  331. /*
  332.   Every isam-function that uppdates the isam-database MUST end with this
  333.   request
  334. */
  335. int _mi_writeinfo(register MI_INFO *info, uint operation)
  336. {
  337.   int error,olderror;
  338.   MYISAM_SHARE *share=info->s;
  339.   DBUG_ENTER("_mi_writeinfo");
  340.   DBUG_PRINT("info",("operation: %u  tot_locks: %u", operation,
  341.      share->tot_locks));
  342.   error=0;
  343.   if (share->tot_locks == 0)
  344.   {
  345.     olderror=my_errno; /* Remember last error */
  346.     if (operation)
  347.     { /* Two threads can't be here */
  348.       share->state.process= share->last_process=   share->this_process;
  349.       share->state.unique=  info->last_unique=    info->this_unique;
  350.       share->state.update_count= info->last_loop= ++info->this_loop;
  351.       if ((error=mi_state_info_write(share->kfile, &share->state, 1)))
  352. olderror=my_errno;
  353. #ifdef __WIN__
  354.       if (myisam_flush)
  355.       {
  356. _commit(share->kfile);
  357. _commit(info->dfile);
  358.       }
  359. #endif
  360.     }
  361.     if (!(operation & WRITEINFO_NO_UNLOCK) &&
  362. my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
  363. MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
  364.       DBUG_RETURN(1);
  365.     my_errno=olderror;
  366.   }
  367.   else if (operation)
  368.     share->changed= 1; /* Mark keyfile changed */
  369.   DBUG_RETURN(error);
  370. } /* _mi_writeinfo */
  371. /* Test if someone has changed the database */
  372. /* (Should be called after readinfo) */
  373. int _mi_test_if_changed(register MI_INFO *info)
  374. {
  375.   MYISAM_SHARE *share=info->s;
  376.   if (share->state.process != share->last_process ||
  377.       share->state.unique  != info->last_unique ||
  378.       share->state.update_count != info->last_loop)
  379.   { /* Keyfile has changed */
  380.     DBUG_PRINT("info",("index file changed"));
  381.     if (share->state.process != share->this_process)
  382.       VOID(flush_key_blocks(share->key_cache, share->kfile, FLUSH_RELEASE));
  383.     share->last_process=share->state.process;
  384.     info->last_unique= share->state.unique;
  385.     info->last_loop= share->state.update_count;
  386.     info->update|= HA_STATE_WRITTEN; /* Must use file on next */
  387.     info->data_changed= 1; /* For mi_is_changed */
  388.     return 1;
  389.   }
  390.   return (!(info->update & HA_STATE_AKTIV) ||
  391.   (info->update & (HA_STATE_WRITTEN | HA_STATE_DELETED |
  392.    HA_STATE_KEY_CHANGED)));
  393. } /* _mi_test_if_changed */
  394. /*
  395.   Put a mark in the .MYI file that someone is updating the table
  396.   DOCUMENTATION
  397.   state.open_count in the .MYI file is used the following way:
  398.   - For the first change of the .MYI file in this process open_count is
  399.     incremented by mi_mark_file_change(). (We have a write lock on the file
  400.     when this happens)
  401.   - In mi_close() it's decremented by _mi_decrement_open_count() if it
  402.     was incremented in the same process.
  403.   This mean that if we are the only process using the file, the open_count
  404.   tells us if the MYISAM file wasn't properly closed. (This is true if
  405.   my_disable_locking is set).
  406. */
  407. int _mi_mark_file_changed(MI_INFO *info)
  408. {
  409.   char buff[3];
  410.   register MYISAM_SHARE *share=info->s;
  411.   DBUG_ENTER("_mi_mark_file_changed");
  412.   if (!(share->state.changed & STATE_CHANGED) || ! share->global_changed)
  413.   {
  414.     share->state.changed|=(STATE_CHANGED | STATE_NOT_ANALYZED |
  415.    STATE_NOT_OPTIMIZED_KEYS);
  416.     if (!share->global_changed)
  417.     {
  418.       share->global_changed=1;
  419.       share->state.open_count++;
  420.     }
  421.     if (!share->temporary)
  422.     {
  423.       mi_int2store(buff,share->state.open_count);
  424.       buff[2]=1; /* Mark that it's changed */
  425.       DBUG_RETURN(my_pwrite(share->kfile,buff,sizeof(buff),
  426.                             sizeof(share->state.header),
  427.                             MYF(MY_NABP)));
  428.     }
  429.   }
  430.   DBUG_RETURN(0);
  431. }
  432. /*
  433.   This is only called by close or by extra(HA_FLUSH) if the OS has the pwrite()
  434.   call.  In these context the following code should be safe!
  435.  */
  436. int _mi_decrement_open_count(MI_INFO *info)
  437. {
  438.   char buff[2];
  439.   register MYISAM_SHARE *share=info->s;
  440.   int lock_error=0,write_error=0;
  441.   if (share->global_changed)
  442.   {
  443.     uint old_lock=info->lock_type;
  444.     share->global_changed=0;
  445.     lock_error=mi_lock_database(info,F_WRLCK);
  446.     /* Its not fatal even if we couldn't get the lock ! */
  447.     if (share->state.open_count > 0)
  448.     {
  449.       share->state.open_count--;
  450.       mi_int2store(buff,share->state.open_count);
  451.       write_error=my_pwrite(share->kfile,buff,sizeof(buff),
  452.     sizeof(share->state.header),
  453.     MYF(MY_NABP));
  454.     }
  455.     if (!lock_error)
  456.       lock_error=mi_lock_database(info,old_lock);
  457.   }
  458.   return test(lock_error || write_error);
  459. }