1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
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, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 /* Functions to handle fixed-length-records */
24
25 #include "myisamdef.h"
26
27
_mi_write_static_record(MI_INFO * info,const uchar * record)28 int _mi_write_static_record(MI_INFO *info, const uchar *record)
29 {
30 uchar temp[8]; /* max pointer length */
31 if (info->s->state.dellink != HA_OFFSET_ERROR &&
32 !info->append_insert_at_end)
33 {
34 my_off_t filepos=info->s->state.dellink;
35 info->rec_cache.seek_not_done=1; /* We have done a seek */
36 if (info->s->file_read(info, &temp[0],info->s->base.rec_reflength,
37 info->s->state.dellink+1,
38 MYF(MY_NABP)))
39 goto err;
40 info->s->state.dellink= _mi_rec_pos(info->s,temp);
41 info->state->del--;
42 info->state->empty-=info->s->base.pack_reclength;
43 if (info->s->file_write(info, record, info->s->base.reclength,
44 filepos,
45 MYF(MY_NABP)))
46 goto err;
47 }
48 else
49 {
50 if (info->state->data_file_length > info->s->base.max_data_file_length-
51 info->s->base.pack_reclength)
52 {
53 my_errno=HA_ERR_RECORD_FILE_FULL;
54 return(2);
55 }
56 if (info->opt_flag & WRITE_CACHE_USED)
57 { /* Cash in use */
58 if (my_b_write(&info->rec_cache, record,
59 info->s->base.reclength))
60 goto err;
61 if (info->s->base.pack_reclength != info->s->base.reclength)
62 {
63 uint length=info->s->base.pack_reclength - info->s->base.reclength;
64 memset(temp, 0, length);
65 if (my_b_write(&info->rec_cache, temp,length))
66 goto err;
67 }
68 }
69 else
70 {
71 info->rec_cache.seek_not_done=1; /* We have done a seek */
72 if (info->s->file_write(info, record, info->s->base.reclength,
73 info->state->data_file_length,
74 info->s->write_flag))
75 goto err;
76 if (info->s->base.pack_reclength != info->s->base.reclength)
77 {
78 uint length=info->s->base.pack_reclength - info->s->base.reclength;
79 memset(temp, 0, length);
80 if (info->s->file_write(info, temp,length,
81 info->state->data_file_length+
82 info->s->base.reclength,
83 info->s->write_flag))
84 goto err;
85 }
86 }
87 info->state->data_file_length+=info->s->base.pack_reclength;
88 info->s->state.split++;
89 }
90 return 0;
91 err:
92 return 1;
93 }
94
_mi_update_static_record(MI_INFO * info,my_off_t pos,const uchar * record)95 int _mi_update_static_record(MI_INFO *info, my_off_t pos, const uchar *record)
96 {
97 info->rec_cache.seek_not_done=1; /* We have done a seek */
98 return (info->s->file_write(info,
99 record, info->s->base.reclength,
100 pos,
101 MYF(MY_NABP)) != 0);
102 }
103
104
_mi_delete_static_record(MI_INFO * info)105 int _mi_delete_static_record(MI_INFO *info)
106 {
107 uchar temp[9]; /* 1+sizeof(uint32) */
108
109 info->state->del++;
110 info->state->empty+=info->s->base.pack_reclength;
111 temp[0]= '\0'; /* Mark that record is deleted */
112 _mi_dpointer(info,temp+1,info->s->state.dellink);
113 info->s->state.dellink = info->lastpos;
114 info->rec_cache.seek_not_done=1;
115 return (info->s->file_write(info,(uchar*) temp, 1+info->s->rec_reflength,
116 info->lastpos, MYF(MY_NABP)) != 0);
117 }
118
119
_mi_cmp_static_record(MI_INFO * info,const uchar * old)120 int _mi_cmp_static_record(MI_INFO *info, const uchar *old)
121 {
122 DBUG_ENTER("_mi_cmp_static_record");
123
124 if (info->opt_flag & WRITE_CACHE_USED)
125 {
126 if (flush_io_cache(&info->rec_cache))
127 {
128 DBUG_RETURN(-1);
129 }
130 info->rec_cache.seek_not_done=1; /* We have done a seek */
131 }
132
133 if ((info->opt_flag & READ_CHECK_USED))
134 { /* If check isn't disabled */
135 info->rec_cache.seek_not_done=1; /* We have done a seek */
136 if (info->s->file_read(info, info->rec_buff, info->s->base.reclength,
137 info->lastpos,
138 MYF(MY_NABP)))
139 DBUG_RETURN(-1);
140 if (memcmp(info->rec_buff, old,
141 (uint) info->s->base.reclength))
142 {
143 DBUG_DUMP("read",old,info->s->base.reclength);
144 DBUG_DUMP("disk",info->rec_buff,info->s->base.reclength);
145 my_errno=HA_ERR_RECORD_CHANGED; /* Record have changed */
146 DBUG_RETURN(1);
147 }
148 }
149 DBUG_RETURN(0);
150 }
151
152
_mi_cmp_static_unique(MI_INFO * info,MI_UNIQUEDEF * def,const uchar * record,my_off_t pos)153 int _mi_cmp_static_unique(MI_INFO *info, MI_UNIQUEDEF *def,
154 const uchar *record, my_off_t pos)
155 {
156 DBUG_ENTER("_mi_cmp_static_unique");
157
158 info->rec_cache.seek_not_done=1; /* We have done a seek */
159 if (info->s->file_read(info, info->rec_buff, info->s->base.reclength,
160 pos, MYF(MY_NABP)))
161 DBUG_RETURN(-1);
162 DBUG_RETURN(mi_unique_comp(def, record, info->rec_buff,
163 def->null_are_equal));
164 }
165
166
167 /* Read a fixed-length-record */
168 /* Returns 0 if Ok. */
169 /* 1 if record is deleted */
170 /* MY_FILE_ERROR on read-error or locking-error */
171
_mi_read_static_record(MI_INFO * info,my_off_t pos,uchar * record)172 int _mi_read_static_record(MI_INFO *info, my_off_t pos,
173 uchar *record)
174 {
175 int error;
176
177 if (pos != HA_OFFSET_ERROR)
178 {
179 if (info->opt_flag & WRITE_CACHE_USED &&
180 info->rec_cache.pos_in_file <= pos &&
181 flush_io_cache(&info->rec_cache))
182 return(-1);
183 info->rec_cache.seek_not_done=1; /* We have done a seek */
184
185 error=info->s->file_read(info, record, info->s->base.reclength,
186 pos,MYF(MY_NABP)) != 0;
187 fast_mi_writeinfo(info);
188 if (! error)
189 {
190 if (!*record)
191 {
192 my_errno=HA_ERR_RECORD_DELETED;
193 return(1); /* Record is deleted */
194 }
195 info->update|= HA_STATE_AKTIV; /* Record is read */
196 return(0);
197 }
198 return(-1); /* Error on read */
199 }
200 fast_mi_writeinfo(info); /* No such record */
201 return(-1);
202 }
203
204
205
_mi_read_rnd_static_record(MI_INFO * info,uchar * buf,my_off_t filepos,my_bool skip_deleted_blocks)206 int _mi_read_rnd_static_record(MI_INFO *info, uchar *buf,
207 my_off_t filepos,
208 my_bool skip_deleted_blocks)
209 {
210 int locked,error,cache_read;
211 uint cache_length;
212 MYISAM_SHARE *share=info->s;
213 DBUG_ENTER("_mi_read_rnd_static_record");
214
215 cache_read=0;
216 cache_length=0;
217 if (info->opt_flag & WRITE_CACHE_USED &&
218 (info->rec_cache.pos_in_file <= filepos || skip_deleted_blocks) &&
219 flush_io_cache(&info->rec_cache))
220 DBUG_RETURN(my_errno);
221 if (info->opt_flag & READ_CACHE_USED)
222 { /* Cache in use */
223 if (filepos == my_b_tell(&info->rec_cache) &&
224 (skip_deleted_blocks || !filepos))
225 {
226 cache_read=1; /* Read record using cache */
227 cache_length=(uint) (info->rec_cache.read_end - info->rec_cache.read_pos);
228 }
229 else
230 info->rec_cache.seek_not_done=1; /* Filepos is changed */
231 }
232 locked=0;
233 if (info->lock_type == F_UNLCK)
234 {
235 if (filepos >= info->state->data_file_length)
236 { /* Test if new records */
237 if (_mi_readinfo(info,F_RDLCK,0))
238 DBUG_RETURN(my_errno);
239 locked=1;
240 }
241 else
242 { /* We don't nead new info */
243 #ifndef UNSAFE_LOCKING
244 if ((! cache_read || share->base.reclength > cache_length) &&
245 share->tot_locks == 0)
246 { /* record not in cache */
247 if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
248 MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
249 DBUG_RETURN(my_errno);
250 locked=1;
251 }
252 #else
253 info->tmp_lock_type=F_RDLCK;
254 #endif
255 }
256 }
257 if (filepos >= info->state->data_file_length)
258 {
259 DBUG_PRINT("test",("filepos: %ld (%ld) records: %ld del: %ld",
260 (long) filepos/share->base.reclength, (long) filepos,
261 (long) info->state->records, (long) info->state->del));
262 fast_mi_writeinfo(info);
263 DBUG_RETURN(my_errno=HA_ERR_END_OF_FILE);
264 }
265 info->lastpos= filepos;
266 info->nextpos= filepos+share->base.pack_reclength;
267
268 if (! cache_read) /* No cacheing */
269 {
270 if ((error=_mi_read_static_record(info,filepos,buf)))
271 {
272 if (error > 0)
273 error=my_errno=HA_ERR_RECORD_DELETED;
274 else
275 error=my_errno;
276 }
277 DBUG_RETURN(error);
278 }
279
280 /*
281 Read record with caching. If my_b_read() returns TRUE, less than the
282 requested bytes have been read. In this case rec_cache.error is
283 either -1 for a read error, or contains the number of bytes copied
284 into the buffer.
285 */
286 error=my_b_read(&info->rec_cache,(uchar*) buf,share->base.reclength);
287 if (info->s->base.pack_reclength != info->s->base.reclength && !error)
288 {
289 char tmp[8]; /* Skill fill bytes */
290 error=my_b_read(&info->rec_cache,(uchar*) tmp,
291 info->s->base.pack_reclength - info->s->base.reclength);
292 }
293 if (locked)
294 (void) _mi_writeinfo(info,0); /* Unlock keyfile */
295 if (!error)
296 {
297 if (!buf[0])
298 { /* Record is removed */
299 DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED);
300 }
301 /* Found and may be updated */
302 info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
303 DBUG_RETURN(0);
304 }
305 /* error is TRUE. my_errno should be set if rec_cache.error == -1 */
306 if (info->rec_cache.error != -1 || my_errno == 0)
307 {
308 /*
309 If we could not get a full record, we either have a broken record,
310 or are at end of file.
311 */
312 if (info->rec_cache.error == 0)
313 my_errno= HA_ERR_END_OF_FILE;
314 else
315 my_errno= HA_ERR_WRONG_IN_RECORD;
316 }
317 DBUG_RETURN(my_errno); /* Something wrong (EOF?) */
318 }
319