Merge branch 'master' of ssh://git.indexdata.com/home/git/pub/idzebra
[idzebra-moved-to-github.git] / index / recindex.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 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 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
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     if (p->isamb)
230     {
231         if (p->isam_p)
232         {
233             char item[256];
234             char *st = item;
235             char untilbuf[sizeof(zint) + 1];
236
237             ISAMB_PP isam_pp = isamb_pp_open(p->isamb, p->isam_p, 1);
238
239             memcpy(untilbuf, &sysno, sizeof(sysno));
240             untilbuf[sizeof(sysno)] = 0;
241             r = isamb_pp_forward(isam_pp, st, untilbuf);
242
243             isamb_pp_close(isam_pp);
244             if (!r)
245                 return 0;
246
247             if (item[sizeof(sysno)] != itemsize)
248             {
249                 yaz_log(YLOG_WARN, "unexpected entry size %d != %d",
250                         item[sizeof(sysno)], itemsize);
251                 return 0;
252             }
253             memcpy(buf, item + sizeof(sysno) + 1, itemsize);
254         }
255     }
256     else
257     {
258         zint pos = (sysno-1)*itemsize;
259         int off = CAST_ZINT_TO_INT(pos%RIDX_CHUNK);
260         int sz1 = RIDX_CHUNK - off;    /* sz1 is size of buffer to read.. */
261
262         if (sz1 > itemsize)
263             sz1 = itemsize;  /* no more than itemsize bytes */
264
265         r = bf_read(p->index_BFile, 1+pos/RIDX_CHUNK, off, sz1, buf);
266         if (r == 1 && sz1 < itemsize) /* boundary? - must read second part */
267             r = bf_read(p->index_BFile, 2+pos/RIDX_CHUNK, 0, itemsize - sz1,
268                         (char*) buf + sz1);
269         if (r != 1 && !ignoreError)
270         {
271             yaz_log(YLOG_FATAL|YLOG_ERRNO, "read in %s at pos %ld",
272                     p->index_fname, (long) pos);
273         }
274     }
275 #if 0
276     {
277         struct record_index_entry *ep = buf;
278         yaz_log(YLOG_LOG, "read r=%d sysno=" ZINT_FORMAT " next=" ZINT_FORMAT
279             " sz=%d", r, sysno, ep->next, ep->size);
280     }
281 #endif
282     return r;
283 }
284
285 struct code_read_data {
286     int no;
287     zint sysno;
288     void *buf;
289     int itemsize;
290     int insert_flag;
291 };
292
293 int bt_code_read(void *vp, char **dst, int *insertMode)
294 {
295     struct code_read_data *s = (struct code_read_data *) vp;
296
297     if (s->no == 0)
298         return 0;
299
300     (s->no)--;
301
302     memcpy(*dst, &s->sysno, sizeof(zint));
303     *dst += sizeof(zint);
304     **dst = s->itemsize;
305     (*dst)++;
306     memcpy(*dst, s->buf, s->itemsize);
307     *dst += s->itemsize;
308     *insertMode = s->insert_flag;
309     return 1;
310 }
311
312 void recindex_write_indx(recindex_t p, zint sysno, void *buf, int itemsize)
313 {
314 #if 0
315     yaz_log(YLOG_LOG, "write_indx sysno=" ZINT_FORMAT, sysno);
316 #endif
317     if (p->isamb)
318     {
319         struct code_read_data input;
320         ISAMC_I isamc_i;
321
322         input.sysno = sysno;
323         input.buf = buf;
324         input.itemsize = itemsize;
325
326         isamc_i.clientData = &input;
327         isamc_i.read_item = bt_code_read;
328
329         input.no = 1;
330         input.insert_flag = 2;
331         isamb_merge(p->isamb, &p->isam_p, &isamc_i);
332     }
333     else
334     {
335         zint pos = (sysno-1)*itemsize;
336         int off = CAST_ZINT_TO_INT(pos%RIDX_CHUNK);
337         int sz1 = RIDX_CHUNK - off;    /* sz1 is size of buffer to read.. */
338
339         if (sz1 > itemsize)
340             sz1 = itemsize;  /* no more than itemsize bytes */
341
342         bf_write(p->index_BFile, 1+pos/RIDX_CHUNK, off, sz1, buf);
343         if (sz1 < itemsize)   /* boundary? must write second part */
344             bf_write(p->index_BFile, 2+pos/RIDX_CHUNK, 0, itemsize - sz1,
345                      (char*) buf + sz1);
346     }
347 }
348
349
350 /*
351  * Local variables:
352  * c-basic-offset: 4
353  * c-file-style: "Stroustrup"
354  * indent-tabs-mode: nil
355  * End:
356  * vim: shiftwidth=4 tabstop=8 expandtab
357  */
358