home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / isam / open.c < prev    next >
C/C++ Source or Header  |  2000-08-31  |  14KB  |  456 lines

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16.  
  17. /* open a isam-database */
  18.  
  19. #include "isamdef.h"
  20. #if defined(MSDOS) || defined(__WIN__)
  21. #ifdef __WIN__
  22. #include <fcntl.h>
  23. #else
  24. #include <process.h>            /* Prototype for getpid */
  25. #endif
  26. #endif
  27. #ifdef VMS
  28. #include "static.c"
  29. #endif
  30.  
  31. static void setup_functions(ISAM_SHARE *info);
  32. static void setup_key_functions(N_KEYDEF *keyinfo);
  33.  
  34. #define get_next_element(to,pos,size) { memcpy((char*) to,pos,(size_t) size); \
  35.                     pos+=size;}
  36.  
  37. /******************************************************************************
  38. ** Return the shared struct if the table is already open.
  39. ** In MySQL the server will handle version issues.
  40. ******************************************************************************/
  41.  
  42. static N_INFO *test_if_reopen(char *filename)
  43. {
  44.   LIST *pos;
  45.  
  46.   for (pos=nisam_open_list ; pos ; pos=pos->next)
  47.   {
  48.     N_INFO *info=(N_INFO*) pos->data;
  49.     ISAM_SHARE *share=info->s;
  50.     if (!strcmp(share->filename,filename) && share->last_version)
  51.       return info;
  52.   }
  53.   return 0;
  54. }
  55.  
  56.  
  57. /******************************************************************************
  58.   open a isam database.
  59.   By default exit with error if database is locked
  60.   if handle_locking & HA_OPEN_WAIT_IF_LOCKED then wait if database is locked
  61.   if handle_locking & HA_OPEN_IGNORE_IF_LOCKED then continue, but count-vars
  62.     in st_i_info may be wrong. count-vars are automaticly fixed after next
  63.     isam request.
  64. ******************************************************************************/
  65.  
  66.  
  67. N_INFO *nisam_open(const char *name, int mode, uint handle_locking)
  68. {
  69.   int lock_error,kfile,open_mode,save_errno;
  70.   uint i,j,len,errpos,head_length,base_pos,offset,info_length,extra;
  71.   char name_buff[FN_REFLEN],*disk_cache,*disk_pos;
  72.   N_INFO info,*m_info,*old_info;
  73.   ISAM_SHARE share_buff,*share;
  74.   DBUG_ENTER("nisam_open");
  75.  
  76.   LINT_INIT(m_info);
  77.   kfile= -1;
  78.   lock_error=1;
  79.   errpos=0;
  80.   head_length=sizeof(share_buff.state.header);
  81.   bzero((byte*) &info,sizeof(info));
  82.  
  83.   VOID(fn_format(name_buff,name,"",N_NAME_IEXT,4+16+32));
  84.   pthread_mutex_lock(&THR_LOCK_isam);
  85.   if (!(old_info=test_if_reopen(name_buff)))
  86.   {
  87.     share= &share_buff;
  88.     bzero((gptr) &share_buff,sizeof(share_buff));
  89.  
  90.     if ((kfile=my_open(name_buff,(open_mode=O_RDWR) | O_SHARE,MYF(0))) < 0)
  91.     {
  92.       if ((errno != EROFS && errno != EACCES) ||
  93.       mode != O_RDONLY ||
  94.       (kfile=my_open(name_buff,(open_mode=O_RDONLY) | O_SHARE,MYF(0))) < 0)
  95.     goto err;
  96.     }
  97.     errpos=1;
  98.     if (my_read(kfile,(char*) share->state.header.file_version,head_length,
  99.         MYF(MY_NABP)))
  100.       goto err;
  101.  
  102.     if (memcmp((byte*) share->state.header.file_version,
  103.            (byte*) nisam_file_magic, 3) ||
  104.     share->state.header.file_version[3] == 0 ||
  105.     (uchar) share->state.header.file_version[3] > 3)
  106.     {
  107.       DBUG_PRINT("error",("Wrong header in %s",name_buff));
  108.       DBUG_DUMP("error_dump",(char*) share->state.header.file_version,
  109.         head_length);
  110.       my_errno=HA_ERR_CRASHED;
  111.       goto err;
  112.     }
  113.     if (uint2korr(share->state.header.options) &
  114.     ~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS |
  115.       HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
  116.       HA_OPTION_TEMP_COMPRESS_RECORD))
  117.     {
  118.       DBUG_PRINT("error",("wrong options: 0x%lx",
  119.               uint2korr(share->state.header.options)));
  120.       my_errno=HA_ERR_OLD_FILE;
  121.       goto err;
  122.     }
  123.     info_length=uint2korr(share->state.header.header_length);
  124.     base_pos=uint2korr(share->state.header.base_pos);
  125.     if (!(disk_cache=(char*) my_alloca(info_length)))
  126.     {
  127.       my_errno=ENOMEM;
  128.       goto err;
  129.     }
  130.     errpos=2;
  131.  
  132.     VOID(my_seek(kfile,0L,MY_SEEK_SET,MYF(0)));
  133. #ifndef NO_LOCKING
  134.     if (!(handle_locking & HA_OPEN_TMP_TABLE))
  135.     {
  136.       if ((lock_error=my_lock(kfile,F_RDLCK,0L,F_TO_EOF,
  137.                   MYF(handle_locking & HA_OPEN_WAIT_IF_LOCKED ?
  138.                   0 : MY_DONT_WAIT))) &&
  139.       !(handle_locking & HA_OPEN_IGNORE_IF_LOCKED))
  140.     goto err;
  141.     }
  142. #endif
  143.     errpos=3;
  144.     if (my_read(kfile,disk_cache,info_length,MYF(MY_NABP)))
  145.       goto err;
  146.     len=uint2korr(share->state.header.state_info_length);
  147.     if (len != sizeof(N_STATE_INFO))
  148.     {
  149.       DBUG_PRINT("warning",
  150.          ("saved_state_info_length: %d  base_info_length: %d",
  151.           len,sizeof(N_STATE_INFO)));
  152.     }
  153.     if (len > sizeof(N_STATE_INFO))
  154.       len=sizeof(N_STATE_INFO);
  155.     share->state_length=len;
  156.     memcpy(&share->state.header.file_version[0],disk_cache,(size_t) len);
  157.     len=uint2korr(share->state.header.base_info_length);
  158.     if (len != sizeof(N_BASE_INFO))
  159.     {
  160.       DBUG_PRINT("warning",("saved_base_info_length: %d  base_info_length: %d",
  161.                 len,sizeof(N_BASE_INFO)));
  162.       if (len <= offsetof(N_BASE_INFO,sortkey))
  163.     share->base.sortkey=(ushort) ~0;
  164.     }
  165.     memcpy((char*) (byte*) &share->base,disk_cache+base_pos,
  166.        (size_t) min(len,sizeof(N_BASE_INFO)));
  167.     disk_pos=disk_cache+base_pos+len;
  168.     share->base.options=uint2korr(share->state.header.options);
  169.     if (share->base.max_key_length > N_MAX_KEY_BUFF)
  170.     {
  171.       my_errno=HA_ERR_UNSUPPORTED;
  172.       goto err;
  173.     }
  174.     if (share->base.options & HA_OPTION_COMPRESS_RECORD)
  175.       share->base.max_key_length+=2;    /* For safety */
  176.  
  177.     if (!my_multi_malloc(MY_WME,
  178.              &share,sizeof(*share),
  179.              &share->keyinfo,share->base.keys*sizeof(N_KEYDEF),
  180.              &share->rec,(share->base.fields+1)*sizeof(N_RECINFO),
  181.              &share->blobs,sizeof(N_BLOB)*share->base.blobs,
  182.              &share->filename,strlen(name_buff)+1,
  183.              NullS))
  184.       goto err;
  185.     errpos=4;
  186.     *share=share_buff;
  187.     strmov(share->filename,name_buff);
  188.  
  189.     /* Fix key in used if old nisam-database */
  190.     if (share->state_length <= offsetof(N_STATE_INFO,keys))
  191.       share->state.keys=share->base.keys;
  192.  
  193.     share->blocksize=min(IO_SIZE,nisam_block_size);
  194.     for (i=0 ; i < share->base.keys ; i++)
  195.     {
  196.       get_next_element(&share->keyinfo[i].base,disk_pos,sizeof(N_SAVE_KEYDEF));
  197.       setup_key_functions(share->keyinfo+i);
  198.       set_if_smaller(share->blocksize,share->keyinfo[i].base.block_length);
  199.       for (j=0 ; j <= share->keyinfo[i].base.keysegs ; j++)
  200.       {
  201.     get_next_element(&share->keyinfo[i].seg[j],disk_pos,
  202.              sizeof(N_SAVE_KEYSEG));
  203.       }
  204.     }
  205.     if (!share->blocksize)
  206.     {
  207.       my_errno=HA_ERR_CRASHED;
  208.       goto err;
  209.     }
  210.  
  211.     for (i=j=offset=0 ; i < share->base.fields ; i++)
  212.     {
  213.       get_next_element(&share->rec[i].base,disk_pos,sizeof(N_SAVE_RECINFO));
  214. #ifndef NOT_PACKED_DATABASES
  215.       share->rec[i].pack_type=0;
  216.       share->rec[i].huff_tree=0;
  217. #endif
  218.       if (share->rec[i].base.type == (int) FIELD_BLOB)
  219.       {
  220.     share->blobs[j].pack_length=share->rec[i].base.length;
  221.     share->blobs[j].offset=offset;
  222.     j++;
  223.     offset+=sizeof(char*);
  224.       }
  225.       offset+=share->rec[i].base.length;
  226.     }
  227.     share->rec[i].base.type=(int) FIELD_LAST;
  228.  
  229. #ifndef NO_LOCKING
  230.     if (! lock_error)
  231.     {
  232.       VOID(my_lock(kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)));
  233.       lock_error=1;            /* Database unlocked */
  234.     }
  235. #endif
  236.  
  237.     if ((info.dfile=my_open(fn_format(name_buff,name,"",N_NAME_DEXT,2+4),
  238.                 mode | O_SHARE,
  239.                 MYF(MY_WME))) < 0)
  240.       goto err;
  241.     errpos=5;
  242.  
  243.     share->kfile=kfile;
  244.     share->mode=open_mode;
  245.     share->this_process=(ulong) getpid();
  246.     share->rnd= (int)     share->this_process;    /* rnd-counter for splitts */
  247. #ifndef DBUG_OFF
  248.     share->rnd=0;                /* To make things repeatable */
  249. #endif
  250.     share->last_process= share->state.process;
  251.     if (!(share->last_version=share->state.version))
  252.       share->last_version=1;            /* Safety */
  253.     share->rec_reflength=share->base.rec_reflength; /* May be changed */
  254.  
  255.     share->data_file_type=STATIC_RECORD;
  256.     if (share->base.options & HA_OPTION_COMPRESS_RECORD)
  257.     {
  258.       share->data_file_type = COMPRESSED_RECORD;
  259.       share->base.options|= HA_OPTION_READ_ONLY_DATA;
  260.       info.s=share;
  261.       if (_nisam_read_pack_info(&info,
  262.                 (pbool) test(!(share->base.options &
  263.                            (HA_OPTION_PACK_RECORD |
  264.                         HA_OPTION_TEMP_COMPRESS_RECORD)))))
  265.     goto err;
  266.     }
  267.     else if (share->base.options & HA_OPTION_PACK_RECORD)
  268.       share->data_file_type = DYNAMIC_RECORD;
  269.     my_afree((gptr) disk_cache);
  270.     setup_functions(share);
  271. #ifdef THREAD
  272.     thr_lock_init(&share->lock);
  273.     VOID(pthread_mutex_init(&share->intern_lock,NULL));
  274. #endif
  275.   }
  276.   else
  277.   {
  278.     share= old_info->s;
  279.     if (mode == O_RDWR && share->mode == O_RDONLY)
  280.     {
  281.       my_errno=EACCES;                /* Can't open in write mode*/
  282.       goto err;
  283.     }
  284.     if ((info.dfile=my_open(fn_format(name_buff,old_info->filename,"",
  285.                       N_NAME_DEXT,2+4),
  286.                 mode | O_SHARE,MYF(MY_WME))) < 0)
  287.     {
  288.       my_errno=errno;
  289.       goto err;
  290.     }
  291.     errpos=5;
  292.   }
  293.  
  294.   /* alloc and set up private structure parts */
  295.   if (!my_multi_malloc(MY_WME,
  296.                &m_info,sizeof(N_INFO),
  297.                &info.blobs,sizeof(N_BLOB)*share->base.blobs,
  298.                &info.buff,(share->base.max_block*2+
  299.                    share->base.max_key_length),
  300.                &info.lastkey,share->base.max_key_length*3+1,
  301.                &info.filename,strlen(name)+1,
  302.                NullS))
  303.     goto err;
  304.   errpos=6;
  305.   strmov(info.filename,name);
  306.   memcpy(info.blobs,share->blobs,sizeof(N_BLOB)*share->base.blobs);
  307.  
  308.   info.s=share;
  309.   info.lastpos= NI_POS_ERROR;
  310.   info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
  311.   info.opt_flag=READ_CHECK_USED;
  312.   info.alloced_rec_buff_length=share->base.pack_reclength;
  313.   info.this_uniq= (ulong) info.dfile;    /* Uniq number in process */
  314.   info.this_loop=0;            /* Update counter */
  315.   info.last_uniq= share->state.uniq;
  316.   info.last_loop= share->state.loop;
  317.   info.options=share->base.options |
  318.     (mode == O_RDONLY ? HA_OPTION_READ_ONLY_DATA : 0);
  319.   info.lock_type=F_UNLCK;
  320.   info.errkey= -1;
  321.   pthread_mutex_lock(&share->intern_lock);
  322.   info.read_record=share->read_record;
  323.   share->reopen++;
  324.   if (share->base.options & HA_OPTION_READ_ONLY_DATA)
  325.   {
  326.     info.lock_type=F_RDLCK;
  327.     share->r_locks++;
  328.     info.this_uniq=share->state.uniq;    /* Row checksum */
  329.   }
  330. #ifndef NO_LOCKING
  331.   if (handle_locking & HA_OPEN_TMP_TABLE)
  332. #endif
  333.   {
  334.     share->w_locks++;            /* We don't have to update status */
  335.     info.lock_type=F_WRLCK;
  336.   }
  337.   pthread_mutex_unlock(&share->intern_lock);
  338.  
  339.   /* Allocate buffer for one record */
  340.  
  341.   extra=0;
  342.   if (share->base.options & HA_OPTION_PACK_RECORD)
  343.     extra=ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
  344.       DYN_DELETE_BLOCK_HEADER;
  345.   if (!(info.rec_alloc=(byte*) my_malloc(share->base.pack_reclength+extra+
  346.                      6,
  347.                      MYF(MY_WME | MY_ZEROFILL))))
  348.     goto err;
  349.   if (extra)
  350.     info.rec_buff=info.rec_alloc+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER);
  351.   else
  352.     info.rec_buff=info.rec_alloc;
  353.  
  354.   *m_info=info;
  355. #ifdef THREAD
  356.   thr_lock_data_init(&share->lock,&m_info->lock,NULL);
  357. #endif
  358.  
  359.   m_info->open_list.data=(void*) m_info;
  360.   nisam_open_list=list_add(nisam_open_list,&m_info->open_list);
  361.  
  362.   pthread_mutex_unlock(&THR_LOCK_isam);
  363.   nisam_log_simple(LOG_OPEN,m_info,share->filename,
  364.            (uint) strlen(share->filename));
  365.   DBUG_RETURN(m_info);
  366.  
  367. err:
  368.   save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
  369.   switch (errpos) {
  370.   case 6:
  371.     my_free((gptr) m_info,MYF(0));
  372.     /* fall through */
  373.   case 5:
  374.     VOID(my_close(info.dfile,MYF(0)));
  375.     if (old_info)
  376.       break;                    /* Don't remove open table */
  377.     /* fall through */
  378.   case 4:
  379.     my_free((gptr) share,MYF(0));
  380.     /* fall through */
  381.   case 3:
  382. #ifndef NO_LOCKING
  383.     if (! lock_error)
  384.       VOID(my_lock(kfile, F_UNLCK, 0L, F_TO_EOF, MYF(MY_SEEK_NOT_DONE)));
  385. #endif
  386.     /* fall through */
  387.   case 2:
  388.     my_afree((gptr) disk_cache);
  389.     /* fall through */
  390.   case 1:
  391.     VOID(my_close(kfile,MYF(0)));
  392.     /* fall through */
  393.   case 0:
  394.   default:
  395.     break;
  396.   }
  397.   pthread_mutex_unlock(&THR_LOCK_isam);
  398.   my_errno=save_errno;
  399.   DBUG_RETURN (NULL);
  400. } /* nisam_open */
  401.  
  402.  
  403.     /* Set up functions in structs */
  404.  
  405. static void setup_functions(register ISAM_SHARE *share)
  406. {
  407.   if (share->base.options & HA_OPTION_COMPRESS_RECORD)
  408.   {
  409.     share->read_record=_nisam_read_pack_record;
  410.     share->read_rnd=_nisam_read_rnd_pack_record;
  411.   }
  412.   else if (share->base.options & HA_OPTION_PACK_RECORD)
  413.   {
  414.     share->read_record=_nisam_read_dynamic_record;
  415.     share->read_rnd=_nisam_read_rnd_dynamic_record;
  416.     share->delete_record=_nisam_delete_dynamic_record;
  417.     share->compare_record=_nisam_cmp_dynamic_record;
  418.     if (share->base.blobs)
  419.     {
  420.       share->update_record=_nisam_update_blob_record;
  421.       share->write_record=_nisam_write_blob_record;
  422.     }
  423.     else
  424.     {
  425.       share->write_record=_nisam_write_dynamic_record;
  426.       share->update_record=_nisam_update_dynamic_record;
  427.     }
  428.   }
  429.   else
  430.   {
  431.     share->read_record=_nisam_read_static_record;
  432.     share->read_rnd=_nisam_read_rnd_static_record;
  433.     share->delete_record=_nisam_delete_static_record;
  434.     share->compare_record=_nisam_cmp_static_record;
  435.     share->update_record=_nisam_update_static_record;
  436.     share->write_record=_nisam_write_static_record;
  437.   }
  438.   return;
  439. }
  440.  
  441.  
  442. static void setup_key_functions(register N_KEYDEF *keyinfo)
  443. {
  444.   if (keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED))
  445.   {
  446.     keyinfo->bin_search=_nisam_seq_search;
  447.     keyinfo->get_key=_nisam_get_key;
  448.   }
  449.   else
  450.   {
  451.     keyinfo->bin_search=_nisam_bin_search;
  452.     keyinfo->get_key=_nisam_get_static_key;
  453.   }
  454.   return;
  455. }
  456.