2 * Copyright (C) 1994, Index Data I/S
4 * Sebastian Hammer, Adam Dickmeiss
7 * Revision 1.7 1995-12-06 09:59:46 quinn
8 * Fixed memory-consumption bug in memory.c
9 * Added more blocksizes to the default ISAM configuration.
11 * Revision 1.6 1995/09/04 12:33:47 adam
12 * Various cleanup. YAZ util used instead.
14 * Revision 1.5 1994/09/28 16:58:33 quinn
17 * Revision 1.4 1994/09/27 20:03:52 quinn
18 * Seems relatively bug-free.
20 * Revision 1.3 1994/09/26 17:11:30 quinn
23 * Revision 1.2 1994/09/26 17:06:35 quinn
26 * Revision 1.1 1994/09/26 16:07:56 quinn
27 * Most of the functionality in place.
32 * This module accesses and rearranges the records of the tables.
41 int is_mbuf_size[3] = { 0, 1024, 4096 };
43 static is_mblock *mblock_tmplist = 0, *mblock_freelist = 0;
44 static is_mbuf *mbuf_freelist[3] = {0, 0, 0};
46 #define MALLOC_CHUNK 20
48 is_mblock *xmalloc_mblock()
55 mblock_freelist = xmalloc(sizeof(is_mblock) * MALLOC_CHUNK);
56 for (i = 0; i < MALLOC_CHUNK - 1; i++)
57 mblock_freelist[i].next = &mblock_freelist[i+1];
58 mblock_freelist[i].next = 0;
60 tmp = mblock_freelist;
61 mblock_freelist = mblock_freelist->next;
63 tmp->state = IS_MBSTATE_UNREAD;
68 is_mbuf *xmalloc_mbuf(int type)
72 if (mbuf_freelist[type])
74 tmp = mbuf_freelist[type];
75 mbuf_freelist[type] = tmp->next;
79 tmp = xmalloc(sizeof(is_mbuf) + is_mbuf_size[type]);
82 tmp->refcount = type ? 1 : 0;
83 tmp->offset = tmp->num = tmp->cur_record = 0;
84 tmp->data = (char*) tmp + sizeof(is_mbuf);
89 void xfree_mbuf(is_mbuf *p)
91 p->next = mbuf_freelist[p->type];
92 mbuf_freelist[p->type] = p;
95 void xfree_mbufs(is_mbuf *l)
107 void xfree_mblock(is_mblock *p)
109 xfree_mbufs(p->data);
110 p->next = mblock_freelist;
114 void xrelease_mblock(is_mblock *p)
116 p->next = mblock_tmplist;
120 void xfree_mblocks(is_mblock *l)
132 void is_m_establish_tab(ISAM is, is_mtable *tab, ISAM_P pos)
134 tab->data = xmalloc_mblock();
137 tab->pos_type = is_type(pos);
138 tab->num_records = -1;
139 tab->data->num_records = -1;
140 tab->data->diskpos = is_block(pos);
141 tab->data->state = IS_MBSTATE_UNREAD;
143 tab->cur_mblock = tab->data;
144 tab->cur_mblock->cur_mbuf = 0;
149 tab->num_records = 0;
150 tab->data->num_records = 0;
151 tab->data->diskpos = -1;
152 tab->data->state = IS_MBSTATE_CLEAN;
153 tab->data->data = xmalloc_mbuf(IS_MBUF_TYPE_LARGE);
154 tab->cur_mblock = tab->data;
155 tab->cur_mblock->cur_mbuf = tab->data->data;
156 tab->cur_mblock->cur_mbuf->cur_record = 0;
161 void is_m_release_tab(is_mtable *tab)
163 xfree_mblocks(tab->data);
164 xfree_mblocks(mblock_tmplist);
168 void is_m_rewind(is_mtable *tab)
170 tab->cur_mblock = tab->data;
173 tab->data->cur_mbuf = tab->data->data;
175 tab->data->data->cur_record = 0;
179 static int read_current_full(is_mtable *tab, is_mblock *mblock)
181 if (is_p_read_full(tab, mblock) < 0)
183 if (mblock->nextpos && !mblock->next)
185 mblock->next = xmalloc_mblock();
186 mblock->next->diskpos = mblock->nextpos;
187 mblock->next->state = IS_MBSTATE_UNREAD;
188 mblock->next->data = 0;
190 mblock->cur_mbuf = mblock->data;
191 mblock->data->cur_record = 0;
195 int is_m_read_full(is_mtable *tab, is_mblock *mblock)
197 return read_current_full(tab, mblock);
201 * replace the record right behind the pointer.
203 void is_m_replace_record(is_mtable *tab, const void *rec)
205 is_mbuf *mbuf = tab->cur_mblock->cur_mbuf;
207 /* we assume that block is already in memory and that we are in the
208 * right mbuf, and that it has space for us. */
209 memcpy(mbuf->data + mbuf->offset + (mbuf->cur_record - 1) *
210 is_keysize(tab->is), rec, is_keysize(tab->is));
211 tab->cur_mblock->state = IS_MBSTATE_DIRTY;
215 * Delete the record right behind the pointer.
217 void is_m_delete_record(is_mtable *tab)
221 mbuf = tab->cur_mblock->cur_mbuf;
222 if (mbuf->cur_record >= mbuf->num) /* top of mbuf */
227 else /* middle of a block */
229 new = xmalloc_mbuf(IS_MBUF_TYPE_SMALL);
230 new->next = mbuf->next;
232 new->data = mbuf->data;
234 new->offset = mbuf->offset + mbuf->cur_record * is_keysize(tab->is);
235 new->num = mbuf->num - mbuf->cur_record;
236 mbuf->num = mbuf->cur_record -1;
238 mbuf->cur_record = 0;
241 tab->cur_mblock->num_records--;
242 tab->cur_mblock->state = tab->data->state = IS_MBSTATE_DIRTY;
245 int is_m_write_record(is_mtable *tab, const void *rec)
247 is_mbuf *mbuf, *oldnext, *dmbuf;
249 /* make sure block is all in memory */
250 if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
251 if (read_current_full(tab, tab->cur_mblock) < 0)
253 mbuf = tab->cur_mblock->cur_mbuf;
254 if (mbuf->cur_record >= mbuf->num) /* top of mbuf */
256 /* mbuf is reference or full */
257 if (mbuf->refcount != 1 || mbuf->offset + (mbuf->num + 1) *
258 is_keysize(tab->is) > is_mbuf_size[mbuf->type])
260 oldnext = mbuf->next;
261 mbuf->next = xmalloc_mbuf(IS_MBUF_TYPE_LARGE);
262 mbuf->next->next = oldnext;
264 tab->cur_mblock->cur_mbuf = mbuf;
265 mbuf->cur_record = 0;
270 oldnext = mbuf->next;
271 mbuf->next = xmalloc_mbuf(IS_MBUF_TYPE_MEDIUM);
272 mbuf->next->next = dmbuf = xmalloc_mbuf(IS_MBUF_TYPE_SMALL);
273 dmbuf->data = mbuf->data;
274 dmbuf->next = oldnext;
275 dmbuf->offset = mbuf->offset + mbuf->cur_record * is_keysize(tab->is);
276 dmbuf->num = mbuf->num - mbuf->cur_record;
277 mbuf->num -= dmbuf->num;
279 mbuf = tab->cur_mblock->cur_mbuf = mbuf->next;
280 mbuf->cur_record = 0;
282 logf (LOG_DEBUG, "is_m_write_rec(rec == %d)", mbuf->cur_record);
283 memcpy(mbuf->data + mbuf->offset + mbuf->cur_record * is_keysize(tab->is),
284 rec, is_keysize(tab->is));
288 tab->cur_mblock->num_records++;
289 tab->cur_mblock->state = tab->data->state = IS_MBSTATE_DIRTY;
293 void is_m_unread_record(is_mtable *tab)
295 assert(tab->cur_mblock->cur_mbuf->cur_record);
296 tab->cur_mblock->cur_mbuf->cur_record--;
300 * non-destructive read.
302 int is_m_peek_record(is_mtable *tab, void *rec)
307 /* make sure block is all in memory */
308 if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
309 if (read_current_full(tab, tab->cur_mblock) < 0)
311 mblock = tab->cur_mblock;
312 mbuf = mblock->cur_mbuf;
313 if (mbuf->cur_record >= mbuf->num) /* are we at end of mbuf? */
315 if (!mbuf->next) /* end of mblock */
319 mblock = mblock->next;
320 if (mblock->state <= IS_MBSTATE_PARTIAL)
321 if (read_current_full(tab, mblock) < 0)
326 return 0; /* EOTable */
330 mbuf->cur_record = 0;
332 memcpy(rec, mbuf->data + mbuf->offset + mbuf->cur_record *
333 is_keysize(tab->is), is_keysize(tab->is));
337 int is_m_read_record(is_mtable *tab, void *buf)
341 /* make sure block is all in memory */
342 if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
343 if (read_current_full(tab, tab->cur_mblock) < 0)
345 mbuf = tab->cur_mblock->cur_mbuf;
346 if (mbuf->cur_record >= mbuf->num) /* are we at end of mbuf? */
348 if (!mbuf->next) /* end of mblock */
350 if (tab->cur_mblock->state == IS_MBSTATE_CLEAN)
352 xfree_mbufs(tab->cur_mblock->data);
353 tab->cur_mblock->data = 0;
354 tab->cur_mblock->state = IS_MBSTATE_UNREAD;
356 if (tab->cur_mblock->next)
358 tab->cur_mblock = tab->cur_mblock->next;
359 if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
360 if (read_current_full(tab, tab->cur_mblock) < 0)
362 tab->cur_mblock->cur_mbuf = mbuf = tab->cur_mblock->data;
365 return 0; /* EOTable */
368 tab->cur_mblock->cur_mbuf = mbuf = mbuf->next;
369 mbuf->cur_record = 0;
371 memcpy(buf, mbuf->data + mbuf->offset + mbuf->cur_record *
372 is_keysize(tab->is), is_keysize(tab->is));
378 * TODO: optimize this function by introducing a higher-level search.
380 int is_m_seek_record(is_mtable *tab, const void *rec)
382 char peek[IS_MAX_RECORD];
387 if (is_m_read_record(tab, &peek) <= 0)
389 if ((rs = (*tab->is->cmp)(peek, rec)) > 0)
391 is_m_unread_record(tab);
399 int is_m_num_records(is_mtable *tab)
401 if (tab->data->state < IS_MBSTATE_PARTIAL)
402 if (read_current_full(tab, tab->data) < 0)
404 logf (LOG_FATAL, "read full failed");
407 return tab->num_records;