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