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