12
12
You should have received a copy of the GNU General Public License
13
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
16
/* open a isam-database */
18
#include "myisamdef.h"
19
#include <mystrings/m_ctype.h>
20
#include <mystrings/m_string.h>
18
#include "myisam_priv.h"
23
#include <boost/scoped_ptr.hpp>
24
#include <boost/scoped_array.hpp>
26
#include <drizzled/internal/m_string.h>
21
27
#include <drizzled/util/test.h>
28
#include <drizzled/charset.h>
29
#include <drizzled/memory/multi_malloc.h>
30
#include <drizzled/identifier.h>
34
using namespace drizzled;
25
36
static void setup_key_functions(MI_KEYDEF *keyinfo);
37
static unsigned char *mi_keydef_read(unsigned char *ptr, MI_KEYDEF *keydef);
38
static unsigned char *mi_keyseg_read(unsigned char *ptr, HA_KEYSEG *keyseg);
39
static unsigned char *mi_recinfo_read(unsigned char *ptr, MI_COLUMNDEF *recinfo);
40
static uint64_t mi_safe_mul(uint64_t a, uint64_t b);
41
static unsigned char *mi_state_info_read(unsigned char *ptr, MI_STATE_INFO *state);
42
static unsigned char *mi_uniquedef_read(unsigned char *ptr, MI_UNIQUEDEF *def);
43
static unsigned char *my_n_base_info_read(unsigned char *ptr, MI_BASE_INFO *base);
27
45
#define disk_pos_assert(pos, end_pos) \
28
46
if (pos > end_pos) \
30
my_errno=HA_ERR_CRASHED; \
48
errno=HA_ERR_CRASHED; \
60
78
have an open count of 0.
61
79
******************************************************************************/
63
MI_INFO *mi_open(const char *name, int mode, uint32_t open_flags)
81
MI_INFO *mi_open(const drizzled::identifier::Table &identifier, int mode, uint32_t open_flags)
65
83
int lock_error,kfile,open_mode,save_errno,have_rtree=0;
66
84
uint32_t i,j,len,errpos,head_length,base_pos,offset,info_length,keys,
67
key_parts,unique_key_parts,fulltext_keys,uniques;
85
key_parts,unique_key_parts,uniques;
68
86
char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
87
data_name[FN_REFLEN], rp_buff[PATH_MAX];
70
88
unsigned char *disk_cache= NULL;
71
89
unsigned char *disk_pos, *end_pos;
72
90
MI_INFO info,*m_info,*old_info;
73
MYISAM_SHARE share_buff,*share;
74
ulong rec_per_key_part[HA_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG];
75
my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
91
boost::scoped_ptr<MYISAM_SHARE> share_buff_ap(new MYISAM_SHARE);
92
MYISAM_SHARE &share_buff= *share_buff_ap.get();
94
boost::scoped_array<ulong> rec_per_key_part_ap(new ulong[HA_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG]);
95
ulong *rec_per_key_part= rec_per_key_part_ap.get();
96
internal::my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
76
97
uint64_t max_key_file_length, max_data_file_length;
81
102
head_length=sizeof(share_buff.state.header);
82
103
memset(&info, 0, sizeof(info));
84
my_realpath(name_buff, fn_format(org_name,name,"",MI_NAME_IEXT,
85
MY_UNPACK_FILENAME),MYF(0));
86
pthread_mutex_lock(&THR_LOCK_myisam);
105
(void)internal::fn_format(org_name,
106
identifier.getPath().c_str(),
110
if (!realpath(org_name,rp_buff))
111
internal::my_load_path(rp_buff,org_name, NULL);
112
rp_buff[FN_REFLEN-1]= '\0';
113
strcpy(name_buff,rp_buff);
114
THR_LOCK_myisam.lock();
87
115
if (!(old_info=test_if_reopen(name_buff)))
89
117
share= &share_buff;
91
119
share_buff.state.rec_per_key_part=rec_per_key_part;
92
120
share_buff.state.key_root=key_root;
93
121
share_buff.state.key_del=key_del;
94
share_buff.key_cache= multi_key_cache_search((unsigned char*) name_buff,
97
if ((kfile=my_open(name_buff,(open_mode=O_RDWR),MYF(0))) < 0)
123
if ((kfile=internal::my_open(name_buff,(open_mode=O_RDWR),MYF(0))) < 0)
99
125
if ((errno != EROFS && errno != EACCES) ||
100
126
mode != O_RDONLY ||
101
(kfile=my_open(name_buff,(open_mode=O_RDONLY),MYF(0))) < 0)
127
(kfile=internal::my_open(name_buff,(open_mode=O_RDONLY),MYF(0))) < 0)
104
130
share->mode=open_mode;
106
if (my_read(kfile, share->state.header.file_version, head_length,
132
if (internal::my_read(kfile, share->state.header.file_version, head_length,
109
my_errno= HA_ERR_NOT_A_TABLE;
135
errno= HA_ERR_NOT_A_TABLE;
112
138
if (memcmp(share->state.header.file_version, myisam_file_magic, 4))
114
my_errno=HA_ERR_NOT_A_TABLE;
140
errno=HA_ERR_NOT_A_TABLE;
117
143
share->options= mi_uint2korr(share->state.header.options);
119
~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS |
120
HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
121
HA_OPTION_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM |
122
HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE |
123
HA_OPTION_RELIES_ON_SQL_LAYER))
125
my_errno=HA_ERR_OLD_FILE;
128
if ((share->options & HA_OPTION_RELIES_ON_SQL_LAYER) &&
129
! (open_flags & HA_OPEN_FROM_SQL_LAYER))
131
my_errno= HA_ERR_UNSUPPORTED;
144
static const uint64_t OLD_FILE_OPTIONS= HA_OPTION_PACK_RECORD |
145
HA_OPTION_PACK_KEYS |
146
HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
147
HA_OPTION_TEMP_COMPRESS_RECORD |
149
if (share->options & ~OLD_FILE_OPTIONS)
151
errno=HA_ERR_OLD_FILE;
134
155
/* Don't call realpath() if the name can't be a link */
135
if (!strcmp(name_buff, org_name) ||
136
my_readlink(index_name, org_name, MYF(0)) == -1)
137
(void) my_stpcpy(index_name, org_name);
156
ssize_t sym_link_size= readlink(org_name,index_name,FN_REFLEN-1);
157
if (sym_link_size >= 0 )
158
index_name[sym_link_size]= '\0';
159
if (!strcmp(name_buff, org_name) || sym_link_size == -1)
160
(void) strcpy(index_name, org_name);
138
161
*strrchr(org_name, '.')= '\0';
139
(void) fn_format(data_name,org_name,"",MI_NAME_DEXT,
162
(void) internal::fn_format(data_name,org_name,"",MI_NAME_DEXT,
140
163
MY_APPEND_EXT|MY_UNPACK_FILENAME|MY_RESOLVE_SYMLINKS);
142
165
info_length=mi_uint2korr(share->state.header.header_length);
143
166
base_pos=mi_uint2korr(share->state.header.base_pos);
144
167
if (!(disk_cache= (unsigned char*) malloc(info_length+128)))
149
172
end_pos=disk_cache+info_length;
152
my_seek(kfile,0L,MY_SEEK_SET,MYF(0));
175
lseek(kfile,0,SEEK_SET);
154
if (my_read(kfile,disk_cache,info_length,MYF(MY_NABP)))
177
if (internal::my_read(kfile,disk_cache,info_length,MYF(MY_NABP)))
156
my_errno=HA_ERR_CRASHED;
179
errno=HA_ERR_CRASHED;
159
182
len=mi_uint2korr(share->state.header.state_info_length);
160
183
keys= (uint) share->state.header.keys;
161
184
uniques= (uint) share->state.header.uniques;
162
fulltext_keys= (uint) share->state.header.fulltext_keys;
163
185
key_parts= mi_uint2korr(share->state.header.key_parts);
164
186
unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts);
165
187
share->state_diff_length=len-MI_STATE_INFO_SIZE;
220
239
/* Add space for node pointer */
221
240
share->base.max_key_length+= share->base.key_reflength;
223
if (!my_multi_malloc(MY_WME,
224
&share,sizeof(*share),
225
&share->state.rec_per_key_part,sizeof(long)*key_parts,
226
&share->keyinfo,keys*sizeof(MI_KEYDEF),
227
&share->uniqueinfo,uniques*sizeof(MI_UNIQUEDEF),
229
(key_parts+unique_key_parts+keys+uniques) *
232
(share->base.fields+1)*sizeof(MI_COLUMNDEF),
233
&share->blobs,sizeof(MI_BLOB)*share->base.blobs,
234
&share->unique_file_name,strlen(name_buff)+1,
235
&share->index_file_name,strlen(index_name)+1,
236
&share->data_file_name,strlen(data_name)+1,
237
&share->state.key_root,keys*sizeof(my_off_t),
238
&share->state.key_del,
239
(share->state.header.max_block_size_index*sizeof(my_off_t)),
240
&share->key_root_lock,sizeof(rw_lock_t)*keys,
241
&share->mmap_lock,sizeof(rw_lock_t),
242
if (!drizzled::memory::multi_malloc(false,
243
&share,sizeof(*share),
244
&share->state.rec_per_key_part,sizeof(long)*key_parts,
245
&share->keyinfo,keys*sizeof(MI_KEYDEF),
246
&share->uniqueinfo,uniques*sizeof(MI_UNIQUEDEF),
248
(key_parts+unique_key_parts+keys+uniques) * sizeof(HA_KEYSEG),
249
&share->rec, (share->base.fields+1)*sizeof(MI_COLUMNDEF),
250
&share->blobs,sizeof(MI_BLOB)*share->base.blobs,
251
&share->unique_file_name,strlen(name_buff)+1,
252
&share->index_file_name,strlen(index_name)+1,
253
&share->data_file_name,strlen(data_name)+1,
254
&share->state.key_root,keys*sizeof(uint64_t),
255
&share->state.key_del,
256
(share->state.header.max_block_size_index*sizeof(uint64_t)),
245
260
*share=share_buff;
246
261
memcpy(share->state.rec_per_key_part, rec_per_key_part,
247
262
sizeof(long)*key_parts);
248
263
memcpy(share->state.key_root, key_root,
249
sizeof(my_off_t)*keys);
264
sizeof(internal::my_off_t)*keys);
250
265
memcpy(share->state.key_del, key_del,
251
sizeof(my_off_t) * share->state.header.max_block_size_index);
252
my_stpcpy(share->unique_file_name, name_buff);
266
sizeof(internal::my_off_t) * share->state.header.max_block_size_index);
267
strcpy(share->unique_file_name, name_buff);
253
268
share->unique_name_length= strlen(name_buff);
254
my_stpcpy(share->index_file_name, index_name);
255
my_stpcpy(share->data_file_name, data_name);
269
strcpy(share->index_file_name, index_name);
270
strcpy(share->data_file_name, data_name);
257
share->blocksize=cmin(IO_SIZE,myisam_block_size);
272
share->blocksize=min((uint32_t)IO_SIZE,myisam_block_size);
259
274
HA_KEYSEG *pos=share->keyparts;
260
275
for (i=0 ; i < keys ; i++)
381
394
disk_cache= NULL;
382
395
mi_setup_functions(share);
383
396
share->is_log_table= false;
384
thr_lock_init(&share->lock);
385
pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST);
386
for (i=0; i<keys; i++)
387
my_rwlock_init(&share->key_root_lock[i], NULL);
388
my_rwlock_init(&share->mmap_lock, NULL);
389
if (!thr_lock_inited)
391
/* Probably a single threaded program; Don't use concurrent inserts */
392
myisam_concurrent_insert=0;
394
else if (myisam_concurrent_insert)
397
if (myisam_concurrent_insert)
396
399
share->concurrent_insert=
397
400
((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
400
403
(open_flags & HA_OPEN_TMP_TABLE) || have_rtree) ? 0 : 1;
401
404
if (share->concurrent_insert)
403
share->lock.get_status= mi_get_status;
404
share->lock.copy_status= mi_copy_status;
405
share->lock.update_status= mi_update_status;
406
share->lock.restore_status= mi_restore_status;
407
share->lock.check_status= mi_check_status;
411
Memory mapping can only be requested after initializing intern_lock.
413
if (open_flags & HA_OPEN_MMAP)
416
mi_extra(&info, HA_EXTRA_MMAP, 0);
421
412
share= old_info->s;
422
413
if (mode == O_RDWR && share->mode == O_RDONLY)
424
my_errno=EACCES; /* Can't open in write mode */
415
errno=EACCES; /* Can't open in write mode */
427
418
if (mi_open_datafile(&info, share, old_info->dfile))
433
424
/* alloc and set up private structure parts */
434
if (!my_multi_malloc(MY_WME,
435
&m_info,sizeof(MI_INFO),
436
&info.blobs,sizeof(MI_BLOB)*share->base.blobs,
437
&info.buff,(share->base.max_key_block_length*2+
438
share->base.max_key_length),
439
&info.lastkey,share->base.max_key_length*3+1,
440
&info.first_mbr_key, share->base.max_key_length,
441
&info.filename,strlen(name)+1,
442
&info.rtree_recursion_state,have_rtree ? 1024 : 0,
425
if (!drizzled::memory::multi_malloc(MY_WME,
426
&m_info,sizeof(MI_INFO),
427
&info.blobs,sizeof(MI_BLOB)*share->base.blobs,
428
&info.buff,(share->base.max_key_block_length*2+
429
share->base.max_key_length),
430
&info.lastkey,share->base.max_key_length*3+1,
431
&info.first_mbr_key, share->base.max_key_length,
432
&info.filename, identifier.getPath().length()+1,
433
&info.rtree_recursion_state,have_rtree ? 1024 : 0,
448
439
info.rtree_recursion_state= NULL;
450
my_stpcpy(info.filename,name);
441
strcpy(info.filename, identifier.getPath().c_str());
451
442
memcpy(info.blobs,share->blobs,sizeof(MI_BLOB)*share->base.blobs);
452
443
info.lastkey2=info.lastkey+share->base.max_key_length;
484
474
share->temporary=share->delay_key_write=1;
485
475
share->write_flag=MYF(MY_NABP);
486
share->w_locks++; /* We don't have to update status */
477
* The following two statements are commented out as a fix of
478
* bug https://bugs.launchpad.net/drizzle/+bug/387627
480
* UPDATE can be TRUNCATE on TEMPORARY TABLE (MyISAM).
481
* The root cause of why this makes a difference hasn't
482
* been found, but this fixes things for now.
484
// share->w_locks++; // We don't have to update status
485
// share->tot_locks++;
488
486
info.lock_type=F_WRLCK;
490
if (((open_flags & HA_OPEN_DELAY_KEY_WRITE) ||
491
(share->options & HA_OPTION_DELAY_KEY_WRITE)) &&
492
myisam_delay_key_write)
493
share->delay_key_write=1;
489
share->delay_key_write= 1;
494
490
info.state= &share->state.state; /* Change global values by default */
495
pthread_mutex_unlock(&share->intern_lock);
497
492
/* Allocate buffer for one record */
499
494
/* prerequisites: memset(info, 0) && info->s=share; are met. */
500
if (!mi_alloc_rec_buff(&info, -1, &info.rec_buff))
495
if (!mi_alloc_rec_buff(&info, SIZE_MAX, &info.rec_buff))
502
497
memset(info.rec_buff, 0, mi_get_rec_buff_len(&info, info.rec_buff));
505
thr_lock_data_init(&share->lock,&m_info->lock,(void*) m_info);
506
m_info->open_list.data=(void*) m_info;
507
myisam_open_list=list_add(myisam_open_list,&m_info->open_list);
500
myisam_open_list.push_front(m_info);
509
pthread_mutex_unlock(&THR_LOCK_myisam);
502
THR_LOCK_myisam.unlock();
513
if (disk_cache != NULL)
515
save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
507
save_errno=errno ? errno : HA_ERR_END_OF_FILE;
516
508
if ((save_errno == HA_ERR_CRASHED) ||
517
509
(save_errno == HA_ERR_CRASHED_ON_USAGE) ||
518
510
(save_errno == HA_ERR_CRASHED_ON_REPAIR))
519
mi_report_error(save_errno, name);
511
mi_report_error(save_errno, identifier.getPath().c_str());
520
512
switch (errpos) {
522
514
free((unsigned char*) m_info);
523
515
/* fall through */
525
my_close(info.dfile,MYF(0));
517
internal::my_close(info.dfile,MYF(0));
527
519
break; /* Don't remove open table */
528
520
/* fall through */
554
546
unsigned char *newptr = *buf;
556
548
/* to simplify initial init of info->rec_buf in mi_open and mi_extra */
557
if (length == (ulong) -1)
549
if (length == SIZE_MAX)
559
551
if (info->s->options & HA_OPTION_COMPRESS_RECORD)
560
length= cmax(info->s->base.pack_reclength, info->s->max_pack_length);
552
length= max(info->s->base.pack_reclength, info->s->max_pack_length);
562
554
length= info->s->base.pack_reclength;
563
length= cmax(length, info->s->base.max_key_length);
555
length= max((uint32_t)length, info->s->base.max_key_length);
564
556
/* Avoid unnecessary realloc */
565
557
if (newptr && length == old_length)
751
742
return(my_pwrite(file, buff, (size_t) (ptr-buff), 0L,
752
743
MYF(MY_NABP | MY_THREADSAFE)) != 0);
753
return(my_write(file, buff, (size_t) (ptr-buff),
744
return(internal::my_write(file, buff, (size_t) (ptr-buff),
754
745
MYF(MY_NABP)) != 0);
758
unsigned char *mi_state_info_read(unsigned char *ptr, MI_STATE_INFO *state)
749
static unsigned char *mi_state_info_read(unsigned char *ptr, MI_STATE_INFO *state)
760
751
uint32_t i,keys,key_parts,key_blocks;
761
752
memcpy(&state->header,ptr, sizeof(state->header));
811
uint32_t mi_state_info_read_dsk(File file, MI_STATE_INFO *state, bool pRead)
802
uint32_t mi_state_info_read_dsk(int file, MI_STATE_INFO *state, bool pRead)
813
804
unsigned char buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
815
if (!myisam_single_user)
819
if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP)))
822
else if (my_read(file, buff, state->state_length,MYF(MY_NABP)))
808
if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP)))
824
mi_state_info_read(buff, state);
811
else if (internal::my_read(file, buff, state->state_length,MYF(MY_NABP)))
813
mi_state_info_read(buff, state);
864
853
mi_int4store(ptr,UINT32_C(0)); ptr +=4;
866
855
memset(ptr, 0, 6); ptr +=6; /* extra */
867
return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
856
return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
871
unsigned char *my_n_base_info_read(unsigned char *ptr, MI_BASE_INFO *base)
860
static unsigned char *my_n_base_info_read(unsigned char *ptr, MI_BASE_INFO *base)
873
862
base->keystart = mi_sizekorr(ptr); ptr +=8;
874
863
base->max_data_file_length = mi_sizekorr(ptr); ptr +=8;
918
907
mi_int2store(ptr,keydef->keylength); ptr +=2;
919
908
mi_int2store(ptr,keydef->minlength); ptr +=2;
920
909
mi_int2store(ptr,keydef->maxlength); ptr +=2;
921
return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
910
return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
924
unsigned char *mi_keydef_read(unsigned char *ptr, MI_KEYDEF *keydef)
913
static unsigned char *mi_keydef_read(unsigned char *ptr, MI_KEYDEF *keydef)
926
915
keydef->keysegs = (uint) *ptr++;
927
916
keydef->key_alg = *ptr++; /* Rtree or Btree */
1024
1013
mi_int2store(ptr,recinfo->length); ptr +=2;
1025
1014
*ptr++ = recinfo->null_bit;
1026
1015
mi_int2store(ptr,recinfo->null_pos); ptr+= 2;
1027
return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1016
return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
1030
unsigned char *mi_recinfo_read(unsigned char *ptr, MI_COLUMNDEF *recinfo)
1019
static unsigned char *mi_recinfo_read(unsigned char *ptr, MI_COLUMNDEF *recinfo)
1032
1021
recinfo->type= mi_sint2korr(ptr); ptr +=2;
1033
1022
recinfo->length=mi_uint2korr(ptr); ptr +=2;
1045
1034
exist a dup()-like call that would give us two different file descriptors.
1046
1035
*************************************************************************/
1048
int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share,
1049
File file_to_dup __attribute__((unused)))
1037
int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, int file_to_dup)
1051
info->dfile=my_open(share->data_file_name, share->mode,
1040
info->dfile=internal::my_open(share->data_file_name, share->mode,
1053
1042
return info->dfile >= 0 ? 0 : 1;
1057
1046
int mi_open_keyfile(MYISAM_SHARE *share)
1059
if ((share->kfile=my_open(share->unique_file_name, share->mode,
1048
if ((share->kfile=internal::my_open(share->unique_file_name, share->mode,
1060
1049
MYF(MY_WME))) < 0)