Extend recindex system may use ISAMB for records map.
[idzebra-moved-to-github.git] / index / recindex.c
1 /* $Id: recindex.c,v 1.59 2007-11-28 11:16:32 adam Exp $
2    Copyright (C) 1995-2007
3    Index Data ApS
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <string.h>
27
28 #include <idzebra/isamb.h>
29 #include <yaz/yaz-util.h>
30 #include "recindex.h"
31
32 #define RIDX_CHUNK 128
33
34
35 struct recindex {
36     char *index_fname;
37     BFile index_BFile;
38     ISAMB isamb;
39     ISAM_P isam_p;
40 };
41
42 struct record_index_entry {
43     zint next;         /* first block of record info / next free entry */
44     int size;          /* size of record or 0 if free entry */
45 } ent;
46
47
48 static void rect_log_item(int level, const void *b, const char *txt)
49 {
50     zint sys;
51     int len;
52
53
54     memcpy(&sys, b, sizeof(sys));
55     len = ((const char *) b)[sizeof(sys)];
56
57     if (len == sizeof(struct record_index_entry))
58     {
59         memcpy(&ent, (const char *)b + sizeof(sys) + 1, len);
60         yaz_log(YLOG_LOG, "%s " ZINT_FORMAT " next=" ZINT_FORMAT " sz=%d", txt, sys,
61                 ent.next, ent.size);
62             
63     }
64     else
65         yaz_log(YLOG_LOG, "%s " ZINT_FORMAT, txt, sys);
66 }
67
68 int rect_compare(const void *a, const void *b)
69 {
70     zint s_a, s_b;
71
72     memcpy(&s_a, a, sizeof(s_a));
73     memcpy(&s_b, b, sizeof(s_b));
74
75     if (s_a > s_b)
76         return 1;
77     else if (s_a < s_b)
78         return -1;
79     return 0;
80 }
81
82 void *rect_code_start(void)
83 {
84     return 0;
85 }
86
87 void rect_encode(void *p, char **dst, const char **src)
88 {
89     zint sys;
90     int len;
91
92     memcpy(&sys, *src, sizeof(sys));
93     zebra_zint_encode(dst, sys);
94     (*src) += sizeof(sys);
95
96     len = **src;
97     **dst = len;
98     (*src)++;
99     (*dst)++;
100
101     memcpy(*dst, *src, len);
102     *dst += len;
103     *src += len;
104 }
105
106 void rect_decode(void *p, char **dst, const char **src)
107 {
108     zint sys;
109     int len;
110
111     zebra_zint_decode(src, &sys);
112     memcpy(*dst, &sys, sizeof(sys));
113     *dst += sizeof(sys);
114
115     len = **src;
116     **dst = len;
117     (*src)++;
118     (*dst)++;
119
120     memcpy(*dst, *src, len);
121     *dst += len;
122     *src += len;
123 }
124
125 void rect_code_reset(void *p)
126 {
127 }
128
129 void rect_code_stop(void *p)
130 {
131 }
132
133
134 recindex_t recindex_open(BFiles bfs, int rw, int use_isamb)
135 {
136     recindex_t p = xmalloc(sizeof(*p));
137     p->index_BFile = 0;
138     p->isamb = 0;
139     
140     p->index_fname = "reci";
141     p->index_BFile = bf_open(bfs, p->index_fname, RIDX_CHUNK, rw);
142     if (p->index_BFile == NULL)
143     {
144         yaz_log(YLOG_FATAL|YLOG_ERRNO, "open %s", p->index_fname);
145         xfree(p);
146         return 0;
147     }
148     
149     if (use_isamb)
150     {
151         int isam_block_size = 4096;
152         ISAMC_M method;
153
154         method.compare_item = rect_compare;
155         method.log_item = rect_log_item;
156         method.codec.start = rect_code_start;
157         method.codec.encode = rect_encode;
158         method.codec.decode = rect_decode;
159         method.codec.reset = rect_code_reset;
160         method.codec.stop = rect_code_stop;
161
162         p->index_fname = "rect";
163         p->isamb = isamb_open2(bfs, p->index_fname, rw, &method,
164                                /* cache */ 0,
165                                /* no_cat */ 1, &isam_block_size,
166                                /* use_root_ptr */ 1);
167
168         p->isam_p = 0;
169         if (p->isamb)
170             p->isam_p = isamb_get_root_ptr(p->isamb);
171
172     }
173     return p;
174 }
175
176 static void log_pr(const char *txt)
177 {
178     yaz_log(YLOG_LOG, "%s", txt);
179 }
180
181
182 void recindex_close(recindex_t p)
183 {
184     if (p)
185     {
186         if (p->index_BFile)
187             bf_close(p->index_BFile);
188         if (p->isamb)
189         {
190             isamb_set_root_ptr(p->isamb, p->isam_p);
191             isamb_dump(p->isamb, p->isam_p, log_pr);
192             isamb_close(p->isamb);
193         }
194         xfree(p);
195     }
196 }
197
198 int recindex_read_head(recindex_t p, void *buf)
199 {
200     return bf_read(p->index_BFile, 0, 0, 0, buf);
201 }
202
203 const char *recindex_get_fname(recindex_t p)
204 {
205     return p->index_fname;
206 }
207
208 ZEBRA_RES recindex_write_head(recindex_t p, const void *buf, size_t len)
209 {
210     int r;
211
212     assert(p);
213
214     assert(p->index_BFile);
215     
216     r = bf_write(p->index_BFile, 0, 0, len, buf);
217     if (r)
218     {
219         yaz_log(YLOG_FATAL|YLOG_ERRNO, "write head of %s", p->index_fname);
220         return ZEBRA_FAIL;
221     }
222     return ZEBRA_OK;
223 }
224
225 int recindex_read_indx(recindex_t p, zint sysno, void *buf, int itemsize, 
226                        int ignoreError)
227 {
228     int r = 0;
229     struct record_index_entry *ep = buf;
230     if (p->isamb)
231     {
232         if (p->isam_p)
233         {
234             char item[256];
235             char *st = item;
236             char untilbuf[sizeof(zint) + 1];
237             
238             ISAMB_PP isam_pp = isamb_pp_open(p->isamb, p->isam_p, 1);
239             
240             memcpy(untilbuf, &sysno, sizeof(sysno));
241             untilbuf[sizeof(sysno)] = 0;
242             r = isamb_pp_forward(isam_pp, st, untilbuf);
243             
244             isamb_pp_close(isam_pp);
245             if (!r)
246                 return 0;
247             
248             if (item[sizeof(sysno)] != itemsize)
249             {
250                 yaz_log(YLOG_WARN, "unexpected entry size %d != %d",
251                         item[sizeof(sysno)], itemsize);
252                 return 0;
253             }
254             memcpy(buf, item + sizeof(sysno) + 1, itemsize);
255         }
256     }
257     else
258     {
259         zint pos = (sysno-1)*itemsize;
260         int off = CAST_ZINT_TO_INT(pos%RIDX_CHUNK);
261         int sz1 = RIDX_CHUNK - off;    /* sz1 is size of buffer to read.. */
262         
263         if (sz1 > itemsize)
264             sz1 = itemsize;  /* no more than itemsize bytes */
265         
266         r = bf_read(p->index_BFile, 1+pos/RIDX_CHUNK, off, sz1, buf);
267         if (r == 1 && sz1 < itemsize) /* boundary? - must read second part */
268             r = bf_read(p->index_BFile, 2+pos/RIDX_CHUNK, 0, itemsize - sz1,
269                         (char*) buf + sz1);
270         if (r != 1 && !ignoreError)
271         {
272             yaz_log(YLOG_FATAL|YLOG_ERRNO, "read in %s at pos %ld",
273                     p->index_fname, (long) pos);
274         }
275     }
276 #if 0
277     yaz_log(YLOG_LOG, "read r=%d sysno=" ZINT_FORMAT " next=" ZINT_FORMAT 
278             " sz=%d", r, sysno, ep->next, ep->size);
279 #endif
280     return r;
281 }
282
283 struct code_read_data {
284     int no;
285     zint sysno;
286     void *buf;
287     int itemsize;
288     int insert_flag;
289 };
290
291 int bt_code_read(void *vp, char **dst, int *insertMode)
292 {
293     struct code_read_data *s = (struct code_read_data *) vp;
294     
295     if (s->no == 0)
296         return 0;
297
298     (s->no)--;
299     
300     memcpy(*dst, &s->sysno, sizeof(zint));
301     *dst += sizeof(zint);
302     **dst = s->itemsize;
303     (*dst)++;
304     memcpy(*dst, s->buf, s->itemsize);
305     *dst += s->itemsize;
306     *insertMode = s->insert_flag;
307     return 1;
308 }
309
310 void recindex_write_indx(recindex_t p, zint sysno, void *buf, int itemsize)
311 {
312 #if 0
313     yaz_log(YLOG_LOG, "write_indx sysno=" ZINT_FORMAT, sysno);
314 #endif
315     if (p->isamb)
316     {
317         struct code_read_data input;
318         ISAMC_I isamc_i;
319
320         input.sysno = sysno;
321         input.buf = buf;
322         input.itemsize = itemsize;
323
324         isamc_i.clientData = &input;
325         isamc_i.read_item = bt_code_read;
326
327         input.no = 1;
328         input.insert_flag = 2;
329         isamb_merge(p->isamb, &p->isam_p, &isamc_i);
330     }
331     else
332     {
333         zint pos = (sysno-1)*itemsize;
334         int off = CAST_ZINT_TO_INT(pos%RIDX_CHUNK);
335         int sz1 = RIDX_CHUNK - off;    /* sz1 is size of buffer to read.. */
336         
337         if (sz1 > itemsize)
338             sz1 = itemsize;  /* no more than itemsize bytes */
339         
340         bf_write(p->index_BFile, 1+pos/RIDX_CHUNK, off, sz1, buf);
341         if (sz1 < itemsize)   /* boundary? must write second part */
342             bf_write(p->index_BFile, 2+pos/RIDX_CHUNK, 0, itemsize - sz1,
343                      (char*) buf + sz1);
344     }
345 }
346
347
348 /*
349  * Local variables:
350  * c-basic-offset: 4
351  * indent-tabs-mode: nil
352  * End:
353  * vim: shiftwidth=4 tabstop=8 expandtab
354  */
355