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