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