Back again...
[idzebra-moved-to-github.git] / isam / memory.c
1 /*
2  * Copyright (C) 1994, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: memory.c,v $
7  * Revision 1.2  1994-09-26 17:06:35  quinn
8  * Back again...
9  *
10  * Revision 1.1  1994/09/26  16:07:56  quinn
11  * Most of the functionality in place.
12  *
13  */
14
15 /*
16  * This module accesses and rearranges the records of the tables.
17  */
18
19 #include <assert.h>
20
21 #include <util.h>
22 #include <ismemory.h>
23 #include "physical.h"
24 #include <isam.h>
25
26 int is_mbuf_size[3] = { 0, 1024, 4096 };
27
28 /*
29  * TODO: make internal memory-management scheme for these units.
30  */
31
32 is_mblock *xmalloc_mblock()
33 {
34     is_mblock *tmp;
35
36     tmp = xmalloc(sizeof(is_mblock));
37     tmp->next = 0;
38     return tmp;
39 }
40
41 is_mbuf *xmalloc_mbuf(int type)
42 {
43     is_mbuf *tmp;
44
45     tmp = xmalloc(sizeof(is_mbuf) + is_mbuf_size[type]);
46     tmp->type = type;
47     tmp->refcount = type ? 1 : 0;
48     tmp->offset = tmp->num = tmp->cur_record = 0;
49     tmp->data = (char*) tmp + sizeof(is_mbuf);
50     tmp->next = 0;
51     return tmp;
52 }
53
54 #if 0
55 void xfree_mblock(is_mblock *p)
56 {
57     xfree(p);
58 }
59 #endif
60
61 #if 0
62 void xfree_mbuf(is_mblock *p)
63 {
64     xfree(p);
65 }
66 #endif
67
68 void is_m_establish_tab(ISAM is, is_mtable *tab, ISAM_P pos)
69 {
70     tab->data = xmalloc_mblock();
71     if (pos > 0)
72     {
73         tab->pos_type = is_type(pos);
74         tab->num_records = -1;
75         tab->data->num_records = -1;
76         tab->data->diskpos = is_block(pos);
77         tab->data->state = IS_MBSTATE_UNREAD;
78         tab->data->data = 0;
79         tab->cur_mblock = tab->data;
80         tab->cur_mblock->cur_mbuf = 0;
81     }
82     else /* new block */
83     {
84         tab->pos_type = 0;
85         tab->num_records = 0;
86         tab->data->num_records = 0;
87         tab->data->diskpos = -1;
88         tab->data->state = IS_MBSTATE_CLEAN;
89         tab->data->data = xmalloc_mbuf(IS_MBUF_TYPE_LARGE);
90         tab->cur_mblock = tab->data;
91         tab->cur_mblock->cur_mbuf = tab->data->data;
92         tab->cur_mblock->cur_mbuf->cur_record = 0;
93     }
94     tab->is = is;
95 }
96
97 void is_m_rewind(is_mtable *tab)
98 {
99     tab->cur_mblock = tab->data;
100     if (tab->data)
101     {
102         tab->data->cur_mbuf = tab->data->data;
103         if (tab->data->data)
104             tab->data->data->cur_record = 0;
105     }
106 }
107
108 static int read_current_full(is_mtable *tab, is_mblock *mblock)
109 {
110     if (is_p_read_full(tab, mblock) < 0)
111         return -1;
112     if (mblock->nextpos && !mblock->next)
113     {
114         mblock->next = xmalloc_mblock();
115         mblock->next->diskpos = mblock->nextpos;
116         mblock->next->state = IS_MBSTATE_UNREAD;
117         mblock->next->data = 0;
118     }
119     mblock->cur_mbuf = mblock->data;
120     mblock->data->cur_record = 0;
121     return 0;
122 }
123
124 int is_m_read_full(is_mtable *tab, is_mblock *mblock)
125 {
126     return read_current_full(tab, mblock);
127 }
128
129 /*
130  * replace the record right behind the pointer.
131  */
132 void is_m_replace_record(is_mtable *tab, const void *rec)
133 {
134     is_mbuf *mbuf = tab->cur_mblock->cur_mbuf;
135     
136     /* we assume that block is already in memory and that we are in the
137      * right mbuf, and that it has space for us. */
138     memcpy(mbuf->data + mbuf->offset + (mbuf->cur_record - 1) *
139         is_keysize(tab->is), rec, is_keysize(tab->is));
140     tab->cur_mblock->state = IS_MBSTATE_DIRTY;
141 }
142
143 /*
144  * Delete the record right behind the pointer.
145  */
146 void is_m_delete_record(is_mtable *tab)
147 {
148     is_mbuf *mbuf, *new;
149
150     mbuf = tab->cur_mblock->cur_mbuf;
151     if (mbuf->cur_record >= mbuf->num)  /* top of mbuf */
152     {
153         mbuf->num--;
154         mbuf->cur_record--;
155     }
156     else /* middle of a block */
157     {
158         new = xmalloc_mbuf(IS_MBUF_TYPE_SMALL);
159         new->next = mbuf->next;
160         mbuf->next = new;
161         new->data = mbuf->data;
162         mbuf->refcount++;
163         new->offset = mbuf->offset + mbuf->cur_record * is_keysize(tab->is);
164         new->num = mbuf->num - mbuf->cur_record;
165         mbuf->num = mbuf->cur_record -1;
166         mbuf = mbuf->next;
167         mbuf->cur_record = 0;
168     }
169     tab->num_records--;
170     tab->cur_mblock->num_records--;
171     tab->cur_mblock->state = tab->data->state = IS_MBSTATE_DIRTY;
172 }
173
174 int is_m_write_record(is_mtable *tab, const void *rec)
175 {
176     is_mbuf *mbuf, *oldnext, *dmbuf;
177
178     /* make sure block is all in memory */
179     if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
180         if (read_current_full(tab, tab->cur_mblock) < 0)
181             return -1;
182     mbuf = tab->cur_mblock->cur_mbuf;
183     if (mbuf->cur_record >= mbuf->num)  /* top of mbuf */
184     {
185         /* mbuf is reference or full */
186         if (mbuf->refcount != 1 || mbuf->offset + (mbuf->num + 1) *
187             is_keysize(tab->is) > is_mbuf_size[mbuf->type])
188         {
189             oldnext = mbuf->next;
190             mbuf->next = xmalloc_mbuf(IS_MBUF_TYPE_LARGE);
191             mbuf->next->next = oldnext;
192             mbuf = mbuf->next;
193             tab->cur_mblock->cur_mbuf = mbuf;
194             mbuf->cur_record = 0;
195         }
196     }
197     else
198     {
199         oldnext = mbuf->next;
200         mbuf->next = xmalloc_mbuf(IS_MBUF_TYPE_MEDIUM);
201         mbuf->next->next = dmbuf = xmalloc_mbuf(IS_MBUF_TYPE_SMALL);
202         dmbuf->data = mbuf->data;
203         dmbuf->next = oldnext;
204         dmbuf->offset = mbuf->offset + mbuf->cur_record * is_keysize(tab->is);
205         dmbuf->num = mbuf->num - mbuf->cur_record;
206         mbuf->num -= dmbuf->num;
207         mbuf->refcount++;
208         mbuf = tab->cur_mblock->cur_mbuf = mbuf->next;
209         mbuf->cur_record = 0;
210     }
211     log(LOG_DEBUG, "is_m_write_rec(rec == %d)", mbuf->cur_record);
212     memcpy(mbuf->data + mbuf->offset + mbuf->cur_record * is_keysize(tab->is),
213         rec, is_keysize(tab->is));
214     mbuf->num++;
215     mbuf->cur_record++;
216     tab->num_records++;
217     tab->cur_mblock->num_records++;
218     tab->cur_mblock->state = tab->data->state = IS_MBSTATE_DIRTY;
219     return 0;
220 }
221
222 void is_m_unread_record(is_mtable *tab)
223 {
224     assert(tab->cur_mblock->cur_mbuf->cur_record);
225     tab->cur_mblock->cur_mbuf->cur_record--;
226 }
227
228 /*
229  * non-destructive read.
230  */
231 int is_m_peek_record(is_mtable *tab, void *rec)
232 {
233     is_mbuf *mbuf;
234
235     /* make sure block is all in memory */
236     if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
237         if (read_current_full(tab, tab->cur_mblock) < 0)
238             return -1;
239     mbuf = tab->cur_mblock->cur_mbuf;
240     if (mbuf->cur_record >= mbuf->num) /* are we at end of mbuf? */
241     {
242         if (!mbuf->next) /* end of mblock */
243         {
244             if (tab->cur_mblock->next)
245             {
246                 tab->cur_mblock = tab->cur_mblock->next;
247                 if (tab->cur_mblock->next->state <= IS_MBSTATE_PARTIAL)
248                     if (read_current_full(tab, tab->cur_mblock->next) < 0)
249                         return -1;
250                 mbuf = tab->cur_mblock->next->data;
251             }
252             else
253                 return 0;   /* EOTable */
254         }
255         else
256             mbuf = mbuf->next;
257         mbuf->cur_record = 0;
258     }
259     memcpy(rec, mbuf->data + mbuf->offset + mbuf->cur_record *
260         is_keysize(tab->is), is_keysize(tab->is));
261     return 1;
262 }
263
264 int is_m_read_record(is_mtable *tab, void *buf)
265 {
266     is_mbuf *mbuf;
267
268     /* make sure block is all in memory */
269     if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
270         if (read_current_full(tab, tab->cur_mblock) < 0)
271             return -1;
272     mbuf = tab->cur_mblock->cur_mbuf;
273     if (mbuf->cur_record >= mbuf->num) /* are we at end of mbuf? */
274     {
275         if (!mbuf->next) /* end of mblock */
276         {
277             if (tab->cur_mblock->next)
278             {
279                 tab->cur_mblock = tab->cur_mblock->next;
280                 if (tab->cur_mblock->state <= IS_MBSTATE_PARTIAL)
281                     if (read_current_full(tab, tab->cur_mblock) < 0)
282                         return -1;
283                 tab->cur_mblock->cur_mbuf = mbuf = tab->cur_mblock->data;
284             }
285             else
286                 return 0;   /* EOTable */
287         }
288         else
289             tab->cur_mblock->cur_mbuf = mbuf = mbuf->next;
290         mbuf->cur_record = 0;
291     }
292     memcpy(buf, mbuf->data + mbuf->offset + mbuf->cur_record *
293         is_keysize(tab->is), is_keysize(tab->is));
294     mbuf->cur_record++;
295     return 1;
296 }
297
298 /*
299  * TODO: optimize this function by introducing a higher-level search.
300  */
301 int is_m_seek_record(is_mtable *tab, const void *rec)
302 {
303     char peek[IS_MAX_RECORD];
304     int rs;
305
306     for (;;)
307     {
308         if (is_m_read_record(tab, &peek) <= 0)
309             return 1;
310         if ((rs = (*tab->is->cmp)(peek, rec)) > 0)
311         {
312             is_m_unread_record(tab);
313             return 1;
314         }
315         else if (rs == 0)
316             return 0;
317     }
318 }