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