2 * Copyright (C) 1994, Index Data I/S
4 * Sebastian Hammer, Adam Dickmeiss
7 * Revision 1.4 1994-09-27 20:03:52 quinn
8 * Seems relatively bug-free.
10 * Revision 1.3 1994/09/26 17:11:30 quinn
13 * Revision 1.2 1994/09/26 17:06:35 quinn
16 * Revision 1.1 1994/09/26 16:07:56 quinn
17 * Most of the functionality in place.
22 * This module accesses and rearranges the records of the tables.
30 int is_mbuf_size[3] = { 0, 1024, 4096 };
32 static is_mblock *mblock_tmplist = 0, *mblock_freelist = 0;
33 static is_mbuf *mbuf_freelist[3] = {0, 0, 0};
35 #define MALLOC_CHUNK 20
37 is_mblock *xmalloc_mblock()
44 mblock_freelist = xmalloc(sizeof(is_mblock) * MALLOC_CHUNK);
45 for (i = 0; i < MALLOC_CHUNK - 1; i++)
46 mblock_freelist[i].next = &mblock_freelist[i+1];
47 mblock_freelist[i].next = 0;
49 tmp = mblock_freelist;
50 mblock_freelist = mblock_freelist->next;
52 tmp->state = IS_MBSTATE_UNREAD;
57 is_mbuf *xmalloc_mbuf(int type)
61 if (mbuf_freelist[type])
63 tmp = mbuf_freelist[type];
64 mbuf_freelist[type] = tmp->next;
68 tmp = xmalloc(sizeof(is_mbuf) + is_mbuf_size[type]);
71 tmp->refcount = type ? 1 : 0;
72 tmp->offset = tmp->num = tmp->cur_record = 0;
73 tmp->data = (char*) tmp + sizeof(is_mbuf);
78 void xfree_mbuf(is_mbuf *p)
80 p->next = mbuf_freelist[p->type];
81 mbuf_freelist[p->type] = p;
84 void xfree_mbufs(is_mbuf *l)
96 void xfree_mblock(is_mblock *p)
99 p->next = mblock_freelist;
103 void xrelease_mblock(is_mblock *p)
105 p->next = mblock_tmplist;
109 void xfree_mblocks(is_mblock *l)
121 void is_m_establish_tab(ISAM is, is_mtable *tab, ISAM_P pos)
123 tab->data = xmalloc_mblock();
126 tab->pos_type = is_type(pos);
127 tab->num_records = -1;
128 tab->data->num_records = -1;
129 tab->data->diskpos = is_block(pos);
130 tab->data->state = IS_MBSTATE_UNREAD;
132 tab->cur_mblock = tab->data;
133 tab->cur_mblock->cur_mbuf = 0;
138 tab->num_records = 0;
139 tab->data->num_records = 0;
140 tab->data->diskpos = -1;
141 tab->data->state = IS_MBSTATE_CLEAN;
142 tab->data->data = xmalloc_mbuf(IS_MBUF_TYPE_LARGE);
143 tab->cur_mblock = tab->data;
144 tab->cur_mblock->cur_mbuf = tab->data->data;
145 tab->cur_mblock->cur_mbuf->cur_record = 0;
150 void is_m_release_tab(is_mtable *tab)
152 xfree_mblocks(tab->data);
153 xfree_mblocks(mblock_tmplist);
157 void is_m_rewind(is_mtable *tab)
159 tab->cur_mblock = tab->data;
162 tab->data->cur_mbuf = tab->data->data;
164 tab->data->data->cur_record = 0;
168 static int read_current_full(is_mtable *tab, is_mblock *mblock)
170 if (is_p_read_full(tab, mblock) < 0)
172 if (mblock->nextpos && !mblock->next)
174 mblock->next = xmalloc_mblock();
175 mblock->next->diskpos = mblock->nextpos;
176 mblock->next->state = IS_MBSTATE_UNREAD;
177 mblock->next->data = 0;
179 mblock->cur_mbuf = mblock->data;
180 mblock->data->cur_record = 0;
184 int is_m_read_full(is_mtable *tab, is_mblock *mblock)
186 return read_current_full(tab, mblock);
190 * replace the record right behind the pointer.
192 void is_m_replace_record(is_mtable *tab, const void *rec)
194 is_mbuf *mbuf = tab->cur_mblock->cur_mbuf;
196 /* we assume that block is already in memory and that we are in the
197 * right mbuf, and that it has space for us. */
198 memcpy(mbuf->data + mbuf->offset + (mbuf->cur_record - 1) *
199 is_keysize(tab->is), rec, is_keysize(tab->is));
200 tab->cur_mblock->state = IS_MBSTATE_DIRTY;
204 * Delete the record right behind the pointer.
206 void is_m_delete_record(is_mtable *tab)
210 mbuf = tab->cur_mblock->cur_mbuf;
211 if (mbuf->cur_record >= mbuf->num) /* top of mbuf */
216 else /* middle of a block */
218 new = xmalloc_mbuf(IS_MBUF_TYPE_SMALL);
219 new->next = mbuf->next;
221 new->data = mbuf->data;
223 new->offset = mbuf->offset + mbuf->cur_record * is_keysize(tab->is);
224 new->num = mbuf->num - mbuf->cur_record;
225 mbuf->num = mbuf->cur_record -1;
227 mbuf->cur_record = 0;
230 tab->cur_mblock->num_records--;
231 tab->cur_mblock->state = tab->data->state = IS_MBSTATE_DIRTY;
234 int is_m_write_record(is_mtable *tab, const void *rec)
236 is_mbuf *mbuf, *oldnext, *dmbuf;
238 /* make sure block is all in memory */
239 if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
240 if (read_current_full(tab, tab->cur_mblock) < 0)
242 mbuf = tab->cur_mblock->cur_mbuf;
243 if (mbuf->cur_record >= mbuf->num) /* top of mbuf */
245 /* mbuf is reference or full */
246 if (mbuf->refcount != 1 || mbuf->offset + (mbuf->num + 1) *
247 is_keysize(tab->is) > is_mbuf_size[mbuf->type])
249 oldnext = mbuf->next;
250 mbuf->next = xmalloc_mbuf(IS_MBUF_TYPE_LARGE);
251 mbuf->next->next = oldnext;
253 tab->cur_mblock->cur_mbuf = mbuf;
254 mbuf->cur_record = 0;
259 oldnext = mbuf->next;
260 mbuf->next = xmalloc_mbuf(IS_MBUF_TYPE_MEDIUM);
261 mbuf->next->next = dmbuf = xmalloc_mbuf(IS_MBUF_TYPE_SMALL);
262 dmbuf->data = mbuf->data;
263 dmbuf->next = oldnext;
264 dmbuf->offset = mbuf->offset + mbuf->cur_record * is_keysize(tab->is);
265 dmbuf->num = mbuf->num - mbuf->cur_record;
266 mbuf->num -= dmbuf->num;
268 mbuf = tab->cur_mblock->cur_mbuf = mbuf->next;
269 mbuf->cur_record = 0;
271 log(LOG_DEBUG, "is_m_write_rec(rec == %d)", mbuf->cur_record);
272 memcpy(mbuf->data + mbuf->offset + mbuf->cur_record * is_keysize(tab->is),
273 rec, is_keysize(tab->is));
277 tab->cur_mblock->num_records++;
278 tab->cur_mblock->state = tab->data->state = IS_MBSTATE_DIRTY;
282 void is_m_unread_record(is_mtable *tab)
284 assert(tab->cur_mblock->cur_mbuf->cur_record);
285 tab->cur_mblock->cur_mbuf->cur_record--;
289 * non-destructive read.
291 int is_m_peek_record(is_mtable *tab, void *rec)
296 /* make sure block is all in memory */
297 if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
298 if (read_current_full(tab, tab->cur_mblock) < 0)
300 mblock = tab->cur_mblock;
301 mbuf = mblock->cur_mbuf;
302 if (mbuf->cur_record >= mbuf->num) /* are we at end of mbuf? */
304 if (!mbuf->next) /* end of mblock */
308 mblock = mblock->next;
309 if (mblock->state <= IS_MBSTATE_PARTIAL)
310 if (read_current_full(tab, mblock) < 0)
315 return 0; /* EOTable */
319 mbuf->cur_record = 0;
321 memcpy(rec, mbuf->data + mbuf->offset + mbuf->cur_record *
322 is_keysize(tab->is), is_keysize(tab->is));
326 int is_m_read_record(is_mtable *tab, void *buf)
330 /* make sure block is all in memory */
331 if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
332 if (read_current_full(tab, tab->cur_mblock) < 0)
334 mbuf = tab->cur_mblock->cur_mbuf;
335 if (mbuf->cur_record >= mbuf->num) /* are we at end of mbuf? */
337 if (!mbuf->next) /* end of mblock */
339 if (tab->cur_mblock->next)
341 tab->cur_mblock = tab->cur_mblock->next;
342 if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
343 if (read_current_full(tab, tab->cur_mblock) < 0)
345 tab->cur_mblock->cur_mbuf = mbuf = tab->cur_mblock->data;
348 return 0; /* EOTable */
351 tab->cur_mblock->cur_mbuf = mbuf = mbuf->next;
352 mbuf->cur_record = 0;
354 memcpy(buf, mbuf->data + mbuf->offset + mbuf->cur_record *
355 is_keysize(tab->is), is_keysize(tab->is));
361 * TODO: optimize this function by introducing a higher-level search.
363 int is_m_seek_record(is_mtable *tab, const void *rec)
365 char peek[IS_MAX_RECORD];
370 if (is_m_read_record(tab, &peek) <= 0)
372 if ((rs = (*tab->is->cmp)(peek, rec)) > 0)
374 is_m_unread_record(tab);