Most of the functionality in place.
[idzebra-moved-to-github.git] / isam / physical.c
1 /*
2  * Copyright (C) 1994, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: physical.c,v $
7  * Revision 1.1  1994-09-26 16:07:57  quinn
8  * Most of the functionality in place.
9  *
10  */
11
12 /*
13  * This module handles the representation of tables in the bfiles.
14  */
15
16 #include <assert.h>
17
18 #include <isam.h>
19 #include "memory.h"
20
21 static int is_freestore_alloc(ISAM is, int type)
22 {
23     int tmp;
24
25     if (is->types[type].freelist >= 0)
26     {
27         tmp = is->types[type].freelist;
28         if (bf_read(is->types[type].bf, tmp, 0, sizeof(tmp),
29             &is->types[type].freelist) <=0)
30         {
31             log(LOG_FATAL, "Failed to allocate block");
32             exit(1);
33         }
34     }
35     else
36         tmp = is->types[type].top++;
37
38     return tmp;
39 }
40
41 static void is_freestore_free(ISAM is, int type, int block)
42 {
43     int tmp;
44
45     tmp = is->types[type].freelist;
46     is->types[type].freelist = block;
47     if (bf_write(is->types[type].bf, block, 0, sizeof(tmp), &tmp) < 0)
48     {
49         log(LOG_FATAL, "Failed to deallocate block.");
50         exit(1);
51     }
52 }
53
54 /* this code must be modified to handle an index */
55 int is_p_read_partial(is_mtable *tab, is_mblock *block)
56 {
57     int toread;
58     is_mbuf *buf;
59
60     assert(block->state == IS_MBSTATE_UNREAD);
61     block->data = buf =  xmalloc_mbuf(IS_MBUF_TYPE_LARGE);
62     toread = tab->is->types[tab->pos_type].blocksize;
63     if (toread > is_mbuf_size[buf->type])
64     {
65         toread = is_mbuf_size[buf->type];
66         block->state = IS_MBSTATE_PARTIAL;
67     }
68     else
69         block->state = IS_MBSTATE_CLEAN;
70     if (bf_read(tab->is->types[tab->pos_type].bf, block->diskpos, 0, toread,
71         buf->data) < 0)
72     {
73         log(LOG_FATAL, "bfread failed.");
74         return -1;
75     }
76     /* extract header info */
77     buf->offset = 0;
78     memcpy(&block->num_records, buf->data, sizeof(block->num_records));
79     buf->offset += sizeof(block->num_records);
80     memcpy(&block->nextpos, buf->data + buf->offset,
81         sizeof(block->nextpos));
82     buf->offset += sizeof(block->nextpos);
83     if (block == tab->data) /* first block */
84     {
85         memcpy(&tab->num_records, buf->data + buf->offset,
86             sizeof(tab->num_records));
87         buf->offset +=sizeof(tab->num_records);
88     }
89     buf->num = (toread - buf->offset) / is_keysize(tab->is);
90     if (buf->num >= block->num_records)
91     {
92         buf->num = block->num_records;
93         block->state = IS_MBSTATE_CLEAN;
94     }
95     else
96         block->bread = buf->num * is_keysize(tab->is);
97     return 0;
98 }
99
100 int is_p_read_full(is_mtable *tab, is_mblock *block)
101 {
102     is_mbuf *buf;
103     int dread, toread;
104
105     if (block->state == IS_MBSTATE_UNREAD && is_p_read_partial(tab, block) < 0)
106     {
107         log(LOG_FATAL, "partial read failed.");
108         return -1;
109     }
110     if (block->state == IS_MBSTATE_PARTIAL)
111     {
112         buf = block->data;
113         dread = block->data->num;
114         while (dread < block->num_records)
115         {
116             buf->next = xmalloc_mbuf(IS_MBUF_TYPE_LARGE);
117             buf = buf->next;
118
119             toread = is_mbuf_size[buf->type] / is_keysize(tab->is);
120             if (toread > block->num_records - dread)
121                 toread = block->num_records - dread;
122
123             if (bf_read(tab->is->types[tab->pos_type].bf, block->diskpos, block->bread, toread *
124                 is_keysize(tab->is), buf->data) < 0)
125             {
126                 log(LOG_FATAL, "bfread failed.");
127                 return -1;
128             }
129             buf->offset = 0;
130             buf->num = toread;
131             dread += toread;
132             block->bread += toread * is_keysize(tab->is);
133         }
134     }
135     return 0;
136 }
137
138 /*
139  * write dirty blocks to bfile.
140  * Allocate blocks as necessary.
141  */
142 void is_p_sync(is_mtable *tab)
143 {
144     is_mblock *p;
145     is_mbuf *b;
146     int sum, v;
147     isam_blocktype *type;
148
149     type = &tab->is->types[tab->pos_type];
150     for (p = tab->data; p; p = p->next)
151     {
152         /* make sure that blocks are allocated. */
153         if (p->diskpos < 0)
154             p->diskpos = is_freestore_alloc(tab->is, tab->pos_type);
155         if (p->next)
156         {
157             if (p->next->diskpos < 0)
158                 p->nextpos = p->next->diskpos = is_freestore_alloc(tab->is,
159                     tab->pos_type);
160             else
161                 p->nextpos = p->next->diskpos;
162         }
163         sum = 0;
164         memcpy(type->dbuf, &p->num_records, sizeof(p->num_records));
165         sum += sizeof(p->num_records);
166         memcpy(type->dbuf + sum, &p->nextpos, sizeof(p->nextpos));
167         sum += sizeof(p->nextpos);
168         if (p == tab->data)  /* first block */
169         {
170             memcpy(type->dbuf + sum, &tab->num_records,
171                 sizeof(tab->num_records));
172             sum += sizeof(tab->num_records);
173         }
174         for (b = p->data; b; b = b->next)
175         {
176             memcpy(type->dbuf + sum, b->data + b->offset, v = b->num *
177                 is_keysize(tab->is));
178             sum += v;
179             assert(sum <= type->blocksize);
180         }
181         if (bf_write(type->bf, p->diskpos, 0, sum, type->dbuf) < 0)
182         {
183             log(LOG_FATAL, "Failed to write block.");
184             exit(1);
185         }
186     }
187 }
188
189 /*
190  * Free all disk blocks associated with table.
191  */
192 void is_p_unmap(is_mtable *tab)
193 {
194     is_mblock *p;
195
196     for (p = tab->data; p; p = p->next)
197         if (p->diskpos >= 0)
198         {
199             is_freestore_free(tab->is, tab->pos_type, p->diskpos);
200             p->diskpos = -1;
201         }
202 }
203
204 static is_mbuf *mbuf_takehead(is_mbuf **mb, int *num, int keysize)
205 {
206     is_mbuf *p = 0, **pp = &p, *new;
207     int toget = *num;
208
209     while (*mb && toget >= (*mb)->num)
210     {
211         toget -= (*mb)->num;
212         *pp = *mb;
213         *mb = (*mb)->next;
214         (*pp)->next = 0;
215         pp = &(*pp)->next;
216     }
217     if (toget > 0 && *mb)
218     {
219         new = xmalloc_mbuf(IS_MBUF_TYPE_SMALL);
220         new->next = (*mb)->next;
221         (*mb)->next = new;
222         new->data = (*mb)->data;
223         (*mb)->refcount++;
224         new->offset = (*mb)->offset + toget * keysize;
225         new->num = (*mb)->num - toget;
226         (*mb)->num = toget;
227         *pp = *mb;
228         *mb = (*mb)->next;
229         (*pp)->next = 0;
230         toget = 0;
231     }
232     *num -= toget;
233     return p;
234 }
235
236 /*
237  * Split up individual blocks which have grown too large.
238  * is_p_align and is_p_remap are alternative functions which trade off
239  * speed in updating versus optimum usage of disk blocks.
240  */
241 void is_p_align(is_mtable *tab)
242 {
243     is_mblock *mblock, *new;
244     is_mbuf *mbufs, *mbp;
245     int blocks, recsblock;
246
247     log(LOG_DEBUG, "Realigning table.");
248     for (mblock = tab->data; mblock; mblock = mblock->next)
249     {
250         if (mblock->state == IS_MBSTATE_DIRTY && mblock->num_records >
251             (mblock == tab->data ?
252             tab->is->types[tab->pos_type].max_keys_block0 :
253             tab->is->types[tab->pos_type].max_keys_block))
254         {
255             blocks = tab->num_records /
256             tab->is->types[tab->pos_type].nice_keys_block;
257             if (tab->num_records %
258                 tab->is->types[tab->pos_type].nice_keys_block)
259                 blocks++;
260             recsblock = tab->num_records / blocks;
261             if (recsblock < 1)
262                 recsblock = 1;
263             mbufs = mblock->data;
264             while ((mbp = mbuf_takehead(&mbufs, &recsblock,
265                 is_keysize(tab->is))))
266             {
267                 new = xmalloc_mblock();
268                 new->diskpos = -1;
269                 new->state = IS_MBSTATE_DIRTY;
270                 new->next = mblock->next;
271                 mblock->next = new;
272                 mblock->data = mbp;
273                 mblock->num_records = recsblock;
274                 mblock = mblock->next;
275             }
276         }
277     }
278 }
279
280 /*
281  * Reorganize data in blocks for minimum block usage and quick access.
282  * Free surplus blocks.
283  * is_p_align and is_p_remap are alternative functions which trade off
284  * speed in updating versus optimum usage of disk blocks.
285  */
286 void is_p_remap(is_mtable *tab)
287 {
288     is_mbuf *mbufs, **bufpp, *mbp;
289     is_mblock *blockp, **blockpp;
290     int recsblock, blocks;
291
292     log(LOG_DEBUG, "Remapping table.");
293     /* collect all data */
294     bufpp = &mbufs;
295     for (blockp = tab->data; blockp; blockp = blockp->next)
296     {
297         *bufpp = blockp->data;
298         while (*bufpp)
299             bufpp = &(*bufpp)->next;
300         blockp->data = 0;
301     }
302     blocks = tab->num_records / tab->is->types[tab->pos_type].nice_keys_block;
303     if (tab->num_records % tab->is->types[tab->pos_type].nice_keys_block)
304         blocks++;
305     recsblock = tab->num_records / blocks;
306     if (recsblock < 1)
307         recsblock = 1;
308     blockpp = &tab->data;
309     while ((mbp = mbuf_takehead(&mbufs, &recsblock, is_keysize(tab->is))))
310     {
311         if (!*blockpp)
312         {
313             *blockpp = xmalloc_mblock();
314             (*blockpp)->diskpos = -1;
315         }
316         (*blockpp)->data = mbp;
317         (*blockpp)->num_records = recsblock;
318         (*blockpp)->state = IS_MBSTATE_DIRTY;
319         blockpp = &(*blockpp)->next;
320     }
321 }