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