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