2 * Copyright (C) 1994, Index Data I/S
4 * Sebastian Hammer, Adam Dickmeiss
7 * Revision 1.6 1995-09-04 12:33:47 adam
8 * Various cleanup. YAZ util used instead.
10 * Revision 1.5 1994/09/28 16:58:33 quinn
13 * Revision 1.4 1994/09/27 20:03:52 quinn
14 * Seems relatively bug-free.
16 * Revision 1.3 1994/09/26 17:11:30 quinn
19 * Revision 1.2 1994/09/26 17:06:35 quinn
22 * Revision 1.1 1994/09/26 16:07:56 quinn
23 * Most of the functionality in place.
28 * This module accesses and rearranges the records of the tables.
37 int is_mbuf_size[3] = { 0, 1024, 4096 };
39 static is_mblock *mblock_tmplist = 0, *mblock_freelist = 0;
40 static is_mbuf *mbuf_freelist[3] = {0, 0, 0};
42 #define MALLOC_CHUNK 20
44 is_mblock *xmalloc_mblock()
51 mblock_freelist = xmalloc(sizeof(is_mblock) * MALLOC_CHUNK);
52 for (i = 0; i < MALLOC_CHUNK - 1; i++)
53 mblock_freelist[i].next = &mblock_freelist[i+1];
54 mblock_freelist[i].next = 0;
56 tmp = mblock_freelist;
57 mblock_freelist = mblock_freelist->next;
59 tmp->state = IS_MBSTATE_UNREAD;
64 is_mbuf *xmalloc_mbuf(int type)
68 if (mbuf_freelist[type])
70 tmp = mbuf_freelist[type];
71 mbuf_freelist[type] = tmp->next;
75 tmp = xmalloc(sizeof(is_mbuf) + is_mbuf_size[type]);
78 tmp->refcount = type ? 1 : 0;
79 tmp->offset = tmp->num = tmp->cur_record = 0;
80 tmp->data = (char*) tmp + sizeof(is_mbuf);
85 void xfree_mbuf(is_mbuf *p)
87 p->next = mbuf_freelist[p->type];
88 mbuf_freelist[p->type] = p;
91 void xfree_mbufs(is_mbuf *l)
103 void xfree_mblock(is_mblock *p)
105 xfree_mbufs(p->data);
106 p->next = mblock_freelist;
110 void xrelease_mblock(is_mblock *p)
112 p->next = mblock_tmplist;
116 void xfree_mblocks(is_mblock *l)
128 void is_m_establish_tab(ISAM is, is_mtable *tab, ISAM_P pos)
130 tab->data = xmalloc_mblock();
133 tab->pos_type = is_type(pos);
134 tab->num_records = -1;
135 tab->data->num_records = -1;
136 tab->data->diskpos = is_block(pos);
137 tab->data->state = IS_MBSTATE_UNREAD;
139 tab->cur_mblock = tab->data;
140 tab->cur_mblock->cur_mbuf = 0;
145 tab->num_records = 0;
146 tab->data->num_records = 0;
147 tab->data->diskpos = -1;
148 tab->data->state = IS_MBSTATE_CLEAN;
149 tab->data->data = xmalloc_mbuf(IS_MBUF_TYPE_LARGE);
150 tab->cur_mblock = tab->data;
151 tab->cur_mblock->cur_mbuf = tab->data->data;
152 tab->cur_mblock->cur_mbuf->cur_record = 0;
157 void is_m_release_tab(is_mtable *tab)
159 xfree_mblocks(tab->data);
160 xfree_mblocks(mblock_tmplist);
164 void is_m_rewind(is_mtable *tab)
166 tab->cur_mblock = tab->data;
169 tab->data->cur_mbuf = tab->data->data;
171 tab->data->data->cur_record = 0;
175 static int read_current_full(is_mtable *tab, is_mblock *mblock)
177 if (is_p_read_full(tab, mblock) < 0)
179 if (mblock->nextpos && !mblock->next)
181 mblock->next = xmalloc_mblock();
182 mblock->next->diskpos = mblock->nextpos;
183 mblock->next->state = IS_MBSTATE_UNREAD;
184 mblock->next->data = 0;
186 mblock->cur_mbuf = mblock->data;
187 mblock->data->cur_record = 0;
191 int is_m_read_full(is_mtable *tab, is_mblock *mblock)
193 return read_current_full(tab, mblock);
197 * replace the record right behind the pointer.
199 void is_m_replace_record(is_mtable *tab, const void *rec)
201 is_mbuf *mbuf = tab->cur_mblock->cur_mbuf;
203 /* we assume that block is already in memory and that we are in the
204 * right mbuf, and that it has space for us. */
205 memcpy(mbuf->data + mbuf->offset + (mbuf->cur_record - 1) *
206 is_keysize(tab->is), rec, is_keysize(tab->is));
207 tab->cur_mblock->state = IS_MBSTATE_DIRTY;
211 * Delete the record right behind the pointer.
213 void is_m_delete_record(is_mtable *tab)
217 mbuf = tab->cur_mblock->cur_mbuf;
218 if (mbuf->cur_record >= mbuf->num) /* top of mbuf */
223 else /* middle of a block */
225 new = xmalloc_mbuf(IS_MBUF_TYPE_SMALL);
226 new->next = mbuf->next;
228 new->data = mbuf->data;
230 new->offset = mbuf->offset + mbuf->cur_record * is_keysize(tab->is);
231 new->num = mbuf->num - mbuf->cur_record;
232 mbuf->num = mbuf->cur_record -1;
234 mbuf->cur_record = 0;
237 tab->cur_mblock->num_records--;
238 tab->cur_mblock->state = tab->data->state = IS_MBSTATE_DIRTY;
241 int is_m_write_record(is_mtable *tab, const void *rec)
243 is_mbuf *mbuf, *oldnext, *dmbuf;
245 /* make sure block is all in memory */
246 if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
247 if (read_current_full(tab, tab->cur_mblock) < 0)
249 mbuf = tab->cur_mblock->cur_mbuf;
250 if (mbuf->cur_record >= mbuf->num) /* top of mbuf */
252 /* mbuf is reference or full */
253 if (mbuf->refcount != 1 || mbuf->offset + (mbuf->num + 1) *
254 is_keysize(tab->is) > is_mbuf_size[mbuf->type])
256 oldnext = mbuf->next;
257 mbuf->next = xmalloc_mbuf(IS_MBUF_TYPE_LARGE);
258 mbuf->next->next = oldnext;
260 tab->cur_mblock->cur_mbuf = mbuf;
261 mbuf->cur_record = 0;
266 oldnext = mbuf->next;
267 mbuf->next = xmalloc_mbuf(IS_MBUF_TYPE_MEDIUM);
268 mbuf->next->next = dmbuf = xmalloc_mbuf(IS_MBUF_TYPE_SMALL);
269 dmbuf->data = mbuf->data;
270 dmbuf->next = oldnext;
271 dmbuf->offset = mbuf->offset + mbuf->cur_record * is_keysize(tab->is);
272 dmbuf->num = mbuf->num - mbuf->cur_record;
273 mbuf->num -= dmbuf->num;
275 mbuf = tab->cur_mblock->cur_mbuf = mbuf->next;
276 mbuf->cur_record = 0;
278 logf (LOG_DEBUG, "is_m_write_rec(rec == %d)", mbuf->cur_record);
279 memcpy(mbuf->data + mbuf->offset + mbuf->cur_record * is_keysize(tab->is),
280 rec, is_keysize(tab->is));
284 tab->cur_mblock->num_records++;
285 tab->cur_mblock->state = tab->data->state = IS_MBSTATE_DIRTY;
289 void is_m_unread_record(is_mtable *tab)
291 assert(tab->cur_mblock->cur_mbuf->cur_record);
292 tab->cur_mblock->cur_mbuf->cur_record--;
296 * non-destructive read.
298 int is_m_peek_record(is_mtable *tab, void *rec)
303 /* make sure block is all in memory */
304 if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
305 if (read_current_full(tab, tab->cur_mblock) < 0)
307 mblock = tab->cur_mblock;
308 mbuf = mblock->cur_mbuf;
309 if (mbuf->cur_record >= mbuf->num) /* are we at end of mbuf? */
311 if (!mbuf->next) /* end of mblock */
315 mblock = mblock->next;
316 if (mblock->state <= IS_MBSTATE_PARTIAL)
317 if (read_current_full(tab, mblock) < 0)
322 return 0; /* EOTable */
326 mbuf->cur_record = 0;
328 memcpy(rec, mbuf->data + mbuf->offset + mbuf->cur_record *
329 is_keysize(tab->is), is_keysize(tab->is));
333 int is_m_read_record(is_mtable *tab, void *buf)
337 /* make sure block is all in memory */
338 if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
339 if (read_current_full(tab, tab->cur_mblock) < 0)
341 mbuf = tab->cur_mblock->cur_mbuf;
342 if (mbuf->cur_record >= mbuf->num) /* are we at end of mbuf? */
344 if (!mbuf->next) /* end of mblock */
346 if (tab->cur_mblock->next)
348 tab->cur_mblock = tab->cur_mblock->next;
349 if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
350 if (read_current_full(tab, tab->cur_mblock) < 0)
352 tab->cur_mblock->cur_mbuf = mbuf = tab->cur_mblock->data;
355 return 0; /* EOTable */
358 tab->cur_mblock->cur_mbuf = mbuf = mbuf->next;
359 mbuf->cur_record = 0;
361 memcpy(buf, mbuf->data + mbuf->offset + mbuf->cur_record *
362 is_keysize(tab->is), is_keysize(tab->is));
368 * TODO: optimize this function by introducing a higher-level search.
370 int is_m_seek_record(is_mtable *tab, const void *rec)
372 char peek[IS_MAX_RECORD];
377 if (is_m_read_record(tab, &peek) <= 0)
379 if ((rs = (*tab->is->cmp)(peek, rec)) > 0)
381 is_m_unread_record(tab);
389 int is_m_num_records(is_mtable *tab)
391 if (tab->data->state < IS_MBSTATE_PARTIAL)
392 if (read_current_full(tab, tab->data) < 0)
394 logf (LOG_FATAL, "read full failed");
397 return tab->num_records;