Changed functions isc_getmethod, isams_getmethod.
[idzebra-moved-to-github.git] / isamc / isams.c
1 /*
2  * Copyright (c) 1995-1999, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: isams.c,v $
7  * Revision 1.5  1999-07-14 10:59:27  adam
8  * Changed functions isc_getmethod, isams_getmethod.
9  * Improved fatal error handling (such as missing EXPLAIN schema).
10  *
11  * Revision 1.4  1999/05/26 07:49:14  adam
12  * C++ compilation.
13  *
14  * Revision 1.3  1999/05/20 12:57:18  adam
15  * Implemented TCL filter. Updated recctrl system.
16  *
17  * Revision 1.2  1999/05/15 14:35:48  adam
18  * Minor changes.
19  *
20  * Revision 1.1  1999/05/12 13:08:06  adam
21  * First version of ISAMS.
22  *
23  */
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <string.h>
27 #include <stdio.h>
28
29 #include <log.h>
30 #include <isams.h>
31
32 typedef struct {
33     int last_offset;
34     int last_block;
35 } ISAMS_head;
36
37 typedef unsigned ISAMS_BLOCK_SIZE;
38
39 struct ISAMS_s {
40     ISAMS_M method;
41     ISAMS_head head;
42     ISAMS_head head_old;
43     char *merge_buf;
44
45     int block_size;
46     int debug;
47     BFile bf;
48 }; 
49
50 struct ISAMS_PP_s {
51     ISAMS is;
52     char *buf;
53     int block_offset;
54     int block_no;
55     void *decodeClientData;
56     int numKeys;
57     int numRead;
58 };
59
60 void isams_getmethod (ISAMS_M m)
61 {
62     m->code_start = NULL;
63     m->code_item = NULL;
64     m->code_stop = NULL;
65
66     m->compare_item = NULL;
67
68     m->debug = 1;
69     m->block_size = 128;
70 }
71
72 ISAMS isams_open (BFiles bfs, const char *name, int writeflag,
73                   ISAMS_M method)
74 {
75     ISAMS is = (ISAMS) xmalloc (sizeof(*is));
76
77     is->method = (ISAMS_M) xmalloc (sizeof(*is->method));
78     memcpy (is->method, method, sizeof(*method));
79     is->block_size = is->method->block_size;
80     is->debug = is->method->debug;
81
82     is->bf = bf_open (bfs, name, is->block_size, writeflag);
83
84     if (!bf_read (is->bf, 0, 0, sizeof(ISAMS_head), &is->head))
85     {
86         is->head.last_block = 1;
87         is->head.last_offset = 0;
88     }
89     memcpy (&is->head_old, &is->head, sizeof(is->head));
90     is->merge_buf = (char *) xmalloc(2*is->block_size);
91     memset(is->merge_buf, 0, 2*is->block_size);
92     return is;
93 }
94
95 int isams_close (ISAMS is)
96 {
97     if (memcmp(&is->head, &is->head_old, sizeof(is->head)))
98     {
99         if (is->head.last_offset)
100             bf_write(is->bf, is->head.last_block, 0, is->head.last_offset,
101                      is->merge_buf);
102         bf_write (is->bf, 0, 0, sizeof(is->head), &is->head);
103     }
104     bf_close (is->bf);
105     xfree (is->merge_buf);
106     xfree (is->method);
107     xfree (is);
108     return 0;
109 }
110
111 ISAMS_P isams_merge (ISAMS is, ISAMS_I data)
112 {
113     char i_item[128], *i_item_ptr;
114     int i_more, i_mode;
115     void *r_clientData;
116     int first_block = is->head.last_block;
117     int first_offset = is->head.last_offset;
118     int count = 0;
119
120     r_clientData = (*is->method->code_start)(ISAMC_ENCODE);
121
122     is->head.last_offset += sizeof(int);
123     if (is->head.last_offset > is->block_size)
124     {
125         if (is->debug > 2)
126             logf (LOG_LOG, "first_block=%d", first_block);
127         bf_write(is->bf, is->head.last_block, 0, 0, is->merge_buf);
128         (is->head.last_block)++;
129         is->head.last_offset -= is->block_size;
130         memcpy (is->merge_buf, is->merge_buf + is->block_size,
131                 is->head.last_offset);
132     }
133     while (1)
134     {
135         i_item_ptr = i_item;
136         i_more = (*data->read_item)(data->clientData, &i_item_ptr, &i_mode);
137         assert (i_mode);
138         
139         if (!i_more)
140             break;
141         else
142         {
143             char *r_out_ptr = is->merge_buf + is->head.last_offset;
144             
145             i_item_ptr = i_item;
146             (*is->method->code_item)(ISAMC_ENCODE, r_clientData,
147                                      &r_out_ptr, &i_item_ptr);
148             is->head.last_offset = r_out_ptr - is->merge_buf;
149             if (is->head.last_offset > is->block_size)
150             {
151                 bf_write(is->bf, is->head.last_block, 0, 0, is->merge_buf);
152                 (is->head.last_block)++;
153                 is->head.last_offset -= is->block_size;
154                 memcpy (is->merge_buf, is->merge_buf + is->block_size,
155                         is->head.last_offset);
156             }
157             count++;
158         }
159     }
160     (*is->method->code_stop)(ISAMC_ENCODE, r_clientData);
161     if (first_block == is->head.last_block)
162         memcpy(is->merge_buf + first_offset, &count, sizeof(int));
163     else if (first_block == is->head.last_block-1)
164     {
165         int gap = first_offset + sizeof(int) - is->block_size;
166         assert (gap <= (int) sizeof(int));
167         if (gap > 0)
168         {
169             if (gap < (int) sizeof(int))
170                 bf_write(is->bf, first_block, first_offset, sizeof(int)-gap,
171                          &count);
172             memcpy (is->merge_buf, ((char*)&count)+(sizeof(int)-gap), gap);
173         }
174         else
175             bf_write(is->bf, first_block, first_offset, sizeof(int), &count);
176     }
177     else
178     {
179         bf_write(is->bf, first_block, first_offset, sizeof(int), &count);
180     }
181     return first_block * is->block_size + first_offset;
182 }
183
184 ISAMS_PP isams_pp_open (ISAMS is, ISAMS_P pos)
185 {
186     ISAMS_PP pp = (ISAMS_PP) xmalloc (sizeof(*pp));
187
188     if (is->debug > 1)
189         logf (LOG_LOG, "isams: isams_pp_open pos=%ld", (long) pos);
190     pp->is = is;
191     pp->decodeClientData = (*is->method->code_start)(ISAMC_DECODE);
192     pp->numKeys = 0;
193     pp->numRead = 0;
194     pp->buf = (char *) xmalloc(is->block_size*2);
195     pp->block_no = pos/is->block_size;
196     pp->block_offset = pos - pp->block_no * is->block_size;
197     logf (LOG_LOG, "isams: isams_pp_open off=%d no=%d",
198           pp->block_offset, pp->block_no);
199     if (pos)
200     {
201         bf_read (is->bf, pp->block_no, 0, 0, pp->buf);
202         bf_read (is->bf, pp->block_no+1, 0, 0, pp->buf + is->block_size);
203         memcpy(&pp->numKeys, pp->buf + pp->block_offset, sizeof(int));
204         logf (LOG_LOG, "isams: isams_pp_open numKeys=%d", pp->numKeys);
205         pp->block_offset += sizeof(int);
206     }
207     return pp;
208 }
209
210 void isams_pp_close (ISAMS_PP pp)
211 {
212     (*pp->is->method->code_stop)(ISAMC_DECODE, pp->decodeClientData);
213     xfree(pp->buf);
214     xfree(pp);
215 }
216
217 int isams_pp_num (ISAMS_PP pp)
218 {
219     return pp->numKeys;
220 }
221
222 int isams_pp_read (ISAMS_PP pp, void *buf)
223 {
224     return isams_read_item (pp, (char **) &buf);
225 }
226
227 int isams_read_item (ISAMS_PP pp, char **dst)
228 {
229     char *src;
230     if (pp->numRead >= pp->numKeys)
231         return 0;
232     (pp->numRead)++;
233     if (pp->block_offset > pp->is->block_size)
234     {
235         pp->block_offset -= pp->is->block_size;
236         (pp->block_no)++;
237         memcpy (pp->buf, pp->buf + pp->is->block_size, pp->is->block_size);
238         bf_read (pp->is->bf, pp->block_no+1, 0, 0,
239                  pp->buf + pp->is->block_size);
240     }
241     src = pp->buf + pp->block_offset;
242     (*pp->is->method->code_item)(ISAMC_DECODE, pp->decodeClientData,
243                                  dst, &src);
244     pp->block_offset = src - pp->buf; 
245     return 1;
246 }
247
248