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 | |
21 | int _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 | |
88 | int _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 | |
98 | int _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 | |
113 | int _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 | |
146 | int _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 | |
165 | int _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 | |
199 | int _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 | |