Updated footer comment
[idzebra-moved-to-github.git] / isams / isams.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 1994-2009 Index Data
3
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20
21 #include <stdlib.h>
22 #include <assert.h>
23 #include <string.h>
24 #include <stdio.h>
25
26 #include <yaz/log.h>
27 #include <yaz/xmalloc.h>
28 #include <idzebra/isams.h>
29
30 typedef struct {
31     int last_offset;
32     int last_block;
33 } ISAMS_head;
34
35 typedef unsigned ISAMS_BLOCK_SIZE;
36
37 struct ISAMS_s {
38     ISAMS_M *method;
39     ISAMS_head head;
40     ISAMS_head head_old;
41     char *merge_buf;
42
43     int block_size;
44     int debug;
45     BFile bf;
46 }; 
47
48 struct ISAMS_PP_s {
49     ISAMS is;
50     char *buf;
51     int block_offset;
52     int block_no;
53     void *decodeClientData;
54     int numKeys;
55     int numRead;
56 };
57
58 void isams_getmethod (ISAMS_M *m)
59 {
60     m->codec.start = NULL;
61     m->codec.decode = NULL;
62     m->codec.encode = NULL;
63     m->codec.stop = NULL;
64     m->codec.reset = NULL;
65
66     m->compare_item = NULL;
67     m->log_item = NULL;
68
69     m->debug = 1;
70     m->block_size = 128;
71 }
72
73 ISAMS isams_open (BFiles bfs, const char *name, int writeflag,
74                   ISAMS_M *method)
75 {
76     ISAMS is = (ISAMS) xmalloc (sizeof(*is));
77
78     is->method = (ISAMS_M *) xmalloc (sizeof(*is->method));
79     memcpy (is->method, method, sizeof(*method));
80     is->block_size = is->method->block_size;
81     is->debug = is->method->debug;
82
83     is->bf = bf_open (bfs, name, is->block_size, writeflag);
84
85     if (!bf_read (is->bf, 0, 0, sizeof(ISAMS_head), &is->head))
86     {
87         is->head.last_block = 1;
88         is->head.last_offset = 0;
89     }
90     memcpy (&is->head_old, &is->head, sizeof(is->head));
91     is->merge_buf = (char *) xmalloc(2*is->block_size);
92     memset(is->merge_buf, 0, 2*is->block_size);
93     return is;
94 }
95
96 int isams_close (ISAMS is)
97 {
98     if (memcmp(&is->head, &is->head_old, sizeof(is->head)))
99     {
100         if (is->head.last_offset)
101             bf_write(is->bf, is->head.last_block, 0, is->head.last_offset,
102                      is->merge_buf);
103         bf_write (is->bf, 0, 0, sizeof(is->head), &is->head);
104     }
105     bf_close (is->bf);
106     xfree (is->merge_buf);
107     xfree (is->method);
108     xfree (is);
109     return 0;
110 }
111
112 ISAM_P isams_merge (ISAMS is, ISAMS_I data)
113 {
114     char i_item[128];
115     int i_more, i_mode;
116     void *r_clientData;
117     int first_block = is->head.last_block;
118     int first_offset = is->head.last_offset;
119     int count = 0;
120
121     r_clientData = (*is->method->codec.start)();
122
123     is->head.last_offset += sizeof(int);
124     if (is->head.last_offset > is->block_size)
125     {
126         if (is->debug > 2)
127             yaz_log (YLOG_LOG, "first_block=%d", first_block);
128         bf_write(is->bf, is->head.last_block, 0, 0, is->merge_buf);
129         (is->head.last_block)++;
130         is->head.last_offset -= is->block_size;
131         memcpy (is->merge_buf, is->merge_buf + is->block_size,
132                 is->head.last_offset);
133     }
134     while (1)
135     {
136         char *tmp_ptr = i_item;
137         i_more = (*data->read_item)(data->clientData, &tmp_ptr, &i_mode);
138         assert (i_mode);
139         
140         if (!i_more)
141             break;
142         else
143         {
144             char *r_out_ptr = is->merge_buf + is->head.last_offset;
145             
146             const char *i_item_ptr = i_item;
147             (*is->method->codec.encode)(r_clientData, &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->codec.stop)(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, ISAM_P pos)
185 {
186     ISAMS_PP pp = (ISAMS_PP) xmalloc (sizeof(*pp));
187
188     if (is->debug > 1)
189         yaz_log (YLOG_LOG, "isams: isams_pp_open pos=%ld", (long) pos);
190     pp->is = is;
191     pp->decodeClientData = (*is->method->codec.start)();
192     pp->numKeys = 0;
193     pp->numRead = 0;
194     pp->buf = (char *) xmalloc(is->block_size*2);
195     pp->block_no = (int) (pos/is->block_size);
196     pp->block_offset = (int) (pos - pp->block_no * is->block_size);
197     if (is->debug)
198         yaz_log (YLOG_LOG, "isams: isams_pp_open off=%d no=%d",
199               pp->block_offset, pp->block_no);
200     if (pos)
201     {
202         bf_read (is->bf, pp->block_no, 0, 0, pp->buf);
203         bf_read (is->bf, pp->block_no+1, 0, 0, pp->buf + is->block_size);
204         memcpy(&pp->numKeys, pp->buf + pp->block_offset, sizeof(int));
205         if (is->debug)
206             yaz_log (YLOG_LOG, "isams: isams_pp_open numKeys=%d", pp->numKeys);
207         pp->block_offset += sizeof(int);
208     }
209     return pp;
210 }
211
212 void isams_pp_close (ISAMS_PP pp)
213 {
214     (*pp->is->method->codec.stop)(pp->decodeClientData);
215     xfree(pp->buf);
216     xfree(pp);
217 }
218
219 int isams_pp_num (ISAMS_PP pp)
220 {
221     return pp->numKeys;
222 }
223
224 int isams_pp_read (ISAMS_PP pp, void *buf)
225 {
226     char *cp = buf;
227     return isams_read_item (pp, &cp);
228 }
229
230 int isams_read_item (ISAMS_PP pp, char **dst)
231 {
232     const 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->codec.decode)(pp->decodeClientData, dst, &src);
246     pp->block_offset = src - pp->buf; 
247     return 1;
248 }
249
250
251 /*
252  * Local variables:
253  * c-basic-offset: 4
254  * c-file-style: "Stroustrup"
255  * indent-tabs-mode: nil
256  * End:
257  * vim: shiftwidth=4 tabstop=8 expandtab
258  */
259