6401c63380bb4f937b05b47efd82c7890336ffe1
[idzebra-moved-to-github.git] / isamc / isamc.c
1 /*
2  * Copyright (c) 1995-1996, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: isamc.c,v $
7  * Revision 1.4  1996-11-01 13:36:46  adam
8  * New element, max_blocks_mem, that control how many blocks of max size
9  * to store in memory during isc_merge.
10  * Function isc_merge now ignoreds delete/update of identical keys and
11  * the proper blocks are then non-dirty and not written in flush_blocks.
12  *
13  * Revision 1.3  1996/11/01  08:59:14  adam
14  * First version of isc_merge that supports update/delete.
15  *
16  * Revision 1.2  1996/10/29 16:44:56  adam
17  * Work on isc_merge.
18  *
19  * Revision 1.1  1996/10/29  13:40:48  adam
20  * First work.
21  *
22  */
23
24 /* 
25  * TODO:
26  *   Reduction to lower categories in isc_merge
27  *   Implementation of isc_numkeys
28  */
29 #include <stdlib.h>
30 #include <assert.h>
31 #include <string.h>
32 #include <stdio.h>
33
34 #include <log.h>
35 #include "isamc-p.h"
36
37 ISAMC_M isc_getmethod (void)
38 {
39     static struct ISAMC_filecat_s def_cat[] = {
40         {   32,    28,     0,    20 },
41         {  512,   490,   100,    20 },
42         { 4096,  3950,  1000,    20 },
43         {32768, 32000, 10000,     0 },
44         {    0,     0,     0,     0 }
45     };
46     ISAMC_M m = xmalloc (sizeof(*m));
47     m->filecat = def_cat;
48
49     m->code_start = NULL;
50     m->code_item = NULL;
51     m->code_stop = NULL;
52
53     m->compare_item = NULL;
54
55     m->debug = 0;
56
57     m->max_blocks_mem = 10;
58
59     return m;
60 }
61
62
63 ISAMC isc_open (const char *name, int writeflag, ISAMC_M method)
64 {
65     ISAMC is;
66     ISAMC_filecat filecat;
67     int i;
68     int max_buf_size = 0;
69
70     is = xmalloc (sizeof(*is));
71
72     is->method = xmalloc (sizeof(*is->method));
73     memcpy (is->method, method, sizeof(*method));
74     filecat = is->method->filecat;
75     assert (filecat);
76
77     /* determine number of block categories */
78     if (is->method->debug)
79         logf (LOG_LOG, "isc: bsize  ifill  mfill mblocks");
80     for (i = 0; filecat[i].bsize; i++)
81     {
82         if (is->method->debug)
83             logf (LOG_LOG, "isc:%6d %6d %6d %6d",
84                   filecat[i].bsize, filecat[i].ifill, 
85                   filecat[i].mfill, filecat[i].mblocks);
86         if (max_buf_size < filecat[i].mblocks * filecat[i].bsize)
87             max_buf_size = filecat[i].mblocks * filecat[i].bsize;
88     }
89     is->no_files = i;
90     is->max_cat = --i;
91     /* max_buf_size is the larget buffer to be used during merge */
92     max_buf_size = (1 + max_buf_size / filecat[i].bsize) * filecat[i].bsize;
93     if (max_buf_size < (1+is->method->max_blocks_mem) * filecat[i].bsize)
94         max_buf_size = (1+is->method->max_blocks_mem) * filecat[i].bsize;
95     if (is->method->debug)
96         logf (LOG_LOG, "isc: max_buf_size %d", max_buf_size);
97     
98     assert (is->no_files > 0);
99     is->files = xmalloc (sizeof(*is->files)*is->no_files);
100     if (writeflag)
101     {
102         is->merge_buf = xmalloc (max_buf_size+128);
103         memset (is->merge_buf, 0, max_buf_size+128);
104     }
105     else
106         is->merge_buf = NULL;
107     for (i = 0; i<is->no_files; i++)
108     {
109         char fname[512];
110
111         sprintf (fname, "%s%c", name, i+'A');
112         is->files[i].bf = bf_open (fname, is->method->filecat[i].bsize,
113                                    writeflag);
114         is->files[i].head_is_dirty = 0;
115         if (!bf_read (is->files[i].bf, 0, 0, sizeof(ISAMC_head),
116                      &is->files[i].head))
117         {
118             is->files[i].head.lastblock = 1;
119             is->files[i].head.freelist = 0;
120         }
121         is->files[i].no_writes = 0;
122         is->files[i].no_reads = 0;
123         is->files[i].no_skip_writes = 0;
124         is->files[i].no_allocated = 0;
125         is->files[i].no_released = 0;
126         is->files[i].no_remap = 0;
127     }
128     return is;
129 }
130
131 int isc_close (ISAMC is)
132 {
133     int i;
134
135     if (is->method->debug)
136         logf (LOG_LOG, "isc:  writes   reads skipped   alloc released  remap");
137     for (i = 0; i<is->no_files; i++)
138     {
139         assert (is->files[i].bf);
140         if (is->files[i].head_is_dirty)
141             bf_write (is->files[i].bf, 0, 0, sizeof(ISAMC_head),
142                  &is->files[i].head);
143         if (is->method->debug)
144             logf (LOG_LOG, "isc:%8d%8d%8d%8d%8d%8d",
145                   is->files[i].no_writes,
146                   is->files[i].no_reads,
147                   is->files[i].no_skip_writes,
148                   is->files[i].no_allocated,
149                   is->files[i].no_released,
150                   is->files[i].no_remap);
151         bf_close (is->files[i].bf);
152     }
153     xfree (is->files);
154     xfree (is->merge_buf);
155     xfree (is);
156     return 0;
157 }
158
159 int isc_read_block (ISAMC is, int cat, int pos, char *dst)
160 {
161     ++(is->files[cat].no_reads);
162     if (is->method->debug > 2)
163         logf (LOG_LOG, "isc: read_block %d %d", cat, pos);
164     return bf_read (is->files[cat].bf, pos, 0, 0, dst);
165 }
166
167 int isc_write_block (ISAMC is, int cat, int pos, char *src)
168 {
169     ++(is->files[cat].no_writes);
170     if (is->method->debug > 2)
171         logf (LOG_LOG, "isc: write_block %d %d", cat, pos);
172     return bf_write (is->files[cat].bf, pos, 0, 0, src);
173 }
174
175 int isc_write_dblock (ISAMC is, int cat, int pos, char *src,
176                       int nextpos, int offset)
177 {
178     int xoffset = offset + 2*sizeof(int);
179     if (is->method->debug > 2)
180         logf (LOG_LOG, "isc: write_dblock. size=%d nextpos=%d",
181               offset, nextpos);
182     memcpy (src - sizeof(int)*2, &nextpos, sizeof(int));
183     memcpy (src - sizeof(int), &xoffset, sizeof(int));
184     return isc_write_block (is, cat, pos, src - sizeof(int)*2);
185 }
186
187 int isc_alloc_block (ISAMC is, int cat)
188 {
189     int block;
190     char buf[sizeof(int)];
191
192     is->files[cat].head_is_dirty = 1;
193     (is->files[cat].no_allocated)++;
194     if ((block = is->files[cat].head.freelist))
195     {
196         bf_read (is->files[cat].bf, block, 0, sizeof(int), buf);
197         memcpy (&is->files[cat].head.freelist, buf, sizeof(int));
198     }
199     else
200         block = (is->files[cat].head.lastblock)++;
201     if (is->method->debug > 2)
202         logf (LOG_LOG, "isc: alloc_block in cat %d: %d", cat, block);
203     return block;
204 }
205
206 void isc_release_block (ISAMC is, int cat, int pos)
207 {
208     char buf[sizeof(int)];
209    
210     (is->files[cat].no_released)++;
211     is->files[cat].head_is_dirty = 1; 
212     memcpy (buf, &is->files[cat].head.freelist, sizeof(int));
213     is->files[cat].head.freelist = pos;
214     bf_write (is->files[cat].bf, pos, 0, sizeof(int), buf);
215     if (is->method->debug > 2)
216         logf (LOG_LOG, "isc: release_block in cat %d: %d", cat, pos);
217 }
218
219 void isc_pp_close (ISAMC_PP pp)
220 {
221     ISAMC is = pp->is;
222
223     (*is->method->code_stop)(ISAMC_DECODE, pp->decodeClientData);
224     xfree (pp->buf);
225     xfree (pp);
226 }
227
228 ISAMC_PP isc_pp_open (ISAMC is, ISAMC_P ipos)
229 {
230     ISAMC_PP pp = xmalloc (sizeof(*pp));
231     char *src;
232    
233     pp->cat = isc_type(ipos);
234     pp->next = isc_block(ipos); 
235
236     src = pp->buf = xmalloc (is->method->filecat[pp->cat].bsize);
237
238     pp->pos = 0;    
239     pp->size = 0;
240     pp->offset = 0;
241     pp->is = is;
242     pp->decodeClientData = (*is->method->code_start)(ISAMC_DECODE);
243     pp->deleteFlag = 0;
244     return pp;
245 }
246
247 /* returns non-zero if item could be read; 0 otherwise */
248 int isc_read_key (ISAMC_PP pp, void *buf)
249 {
250     return isc_read_item (pp, (char **) &buf);
251 }
252
253 /* returns non-zero if item could be read; 0 otherwise */
254 int isc_read_item (ISAMC_PP pp, char **dst)
255 {
256     ISAMC is = pp->is;
257     char *src = pp->buf + pp->offset;
258
259     if (pp->offset >= pp->size)
260     {
261         pp->pos = pp->next;
262         if (!pp->pos)
263             return 0;
264         src = pp->buf;
265         isc_read_block (is, pp->cat, pp->pos, src);
266         memcpy (&pp->next, src, sizeof(pp->next));
267         src += sizeof(pp->next);
268         memcpy (&pp->size, src, sizeof(pp->size));
269         src += sizeof(pp->size);
270         /* assume block is non-empty */
271         assert (pp->next != pp->pos);
272         if (pp->deleteFlag)
273             isc_release_block (is, pp->cat, pp->pos);
274         (*is->method->code_item)(ISAMC_DECODE, pp->decodeClientData, dst, &src);
275         pp->offset = src - pp->buf; 
276         return 2;
277     }
278     (*is->method->code_item)(ISAMC_DECODE, pp->decodeClientData, dst, &src);
279     pp->offset = src - pp->buf; 
280     return 1;
281 }
282
283 int isc_numkeys (ISAMC_PP pp)
284 {
285     return 1;
286 }
287