Happy new year
[idzebra-moved-to-github.git] / index / sortidx.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 <assert.h> 
22 #include <string.h>
23
24 #include <yaz/log.h>
25 #include <yaz/xmalloc.h>
26 #include <idzebra/isamb.h>
27 #include <idzebra/bfile.h>
28 #include <sortidx.h>
29 #include "recindex.h"
30
31 #define SORT_MAX_TERM 110
32 #define SORT_MAX_MULTI 4096
33
34 #define SORT_IDX_BLOCKSIZE 64
35
36 struct sort_term {
37     zint sysno;
38     zint section_id;
39     zint length;
40     char term[SORT_MAX_MULTI];
41 };
42
43
44 static void sort_term_log_item(int level, const void *b, const char *txt)
45 {
46     struct sort_term a1;
47
48     memcpy(&a1, b, sizeof(a1));
49
50     yaz_log(level, "%s " ZINT_FORMAT " " ZINT_FORMAT " %.*s", txt, a1.sysno,
51             a1.section_id, (int) a1.length-1, a1.term);
52 }
53
54 static int sort_term_compare(const void *a, const void *b)
55 {
56     struct sort_term a1, b1;
57
58     memcpy(&a1, a, sizeof(a1));
59     memcpy(&b1, b, sizeof(b1));
60
61     if (a1.sysno > b1.sysno)
62         return 1;
63     else if (a1.sysno < b1.sysno)
64         return -1;
65     if (a1.section_id > b1.section_id)
66         return 1;
67     else if (a1.section_id < b1.section_id)
68         return -1;
69
70     return 0;
71 }
72
73 static void *sort_term_code_start(void)
74 {
75     return 0;
76 }
77
78 static void sort_term_encode1(void *p, char **dst, const char **src)
79 {
80     struct sort_term a1;
81
82     memcpy(&a1, *src, sizeof(a1));
83     *src += sizeof(a1);
84
85     zebra_zint_encode(dst, a1.sysno); /* encode record id */
86     strcpy(*dst, a1.term); /* then sort term, 0 terminated */
87     *dst += strlen(a1.term) + 1;
88 }
89
90 static void sort_term_encode2(void *p, char **dst, const char **src)
91 {
92     struct sort_term a1;
93
94     memcpy(&a1, *src, sizeof(a1));
95     *src += sizeof(a1);
96
97     zebra_zint_encode(dst, a1.sysno);
98     zebra_zint_encode(dst, a1.section_id);
99     zebra_zint_encode(dst, a1.length); /* encode length */
100     memcpy(*dst, a1.term, a1.length);
101     *dst += a1.length;
102 }
103
104 static void sort_term_decode1(void *p, char **dst, const char **src)
105 {
106     struct sort_term a1;
107     size_t slen;
108
109     zebra_zint_decode(src, &a1.sysno);
110     a1.section_id = 0;
111
112     strcpy(a1.term, *src);
113     slen = 1 + strlen(a1.term);
114     *src += slen;
115     a1.length = slen;
116
117     memcpy(*dst, &a1, sizeof(a1));
118     *dst += sizeof(a1);
119 }
120
121 static void sort_term_decode2(void *p, char **dst, const char **src)
122 {
123     struct sort_term a1;
124
125     zebra_zint_decode(src, &a1.sysno);
126     zebra_zint_decode(src, &a1.section_id);
127     zebra_zint_decode(src, &a1.length);
128
129     memcpy(a1.term, *src, a1.length);
130     *src += a1.length;
131
132     memcpy(*dst, &a1, sizeof(a1));
133     *dst += sizeof(a1);
134 }
135
136 static void sort_term_code_reset(void *p)
137 {
138 }
139
140 static void sort_term_code_stop(void *p)
141 {
142 }
143
144 struct sort_term_stream {
145     int no;
146     int insert_flag;
147     struct sort_term st;
148 };
149
150 static int sort_term_code_read(void *vp, char **dst, int *insertMode)
151 {
152     struct sort_term_stream *s = (struct sort_term_stream *) vp;
153
154     if (s->no == 0)
155         return 0;
156
157     (s->no)--;
158     
159     *insertMode = s->insert_flag;
160     memcpy(*dst, &s->st, sizeof(s->st));
161     *dst += sizeof(s->st);
162     return 1;
163 }
164
165 struct sortFileHead {
166     zint sysno_max;
167 };
168
169 struct sortFile {
170     int id;
171     union {
172         BFile bf;
173         ISAMB isamb;
174     } u;
175     ISAM_P isam_p;
176     ISAMB_PP isam_pp;
177     struct sortFile *next;
178     struct sortFileHead head;
179     int no_inserted;
180     int no_deleted;
181 };
182
183 struct zebra_sort_index {
184     BFiles bfs;
185     int write_flag;
186     zint sysno;
187     int type;
188     char *entry_buf;
189     struct sortFile *current_file;
190     struct sortFile *files;
191 };
192
193 zebra_sort_index_t zebra_sort_open(BFiles bfs, int write_flag, int type)
194 {
195     zebra_sort_index_t si = (zebra_sort_index_t) xmalloc(sizeof(*si));
196     si->bfs = bfs;
197     si->write_flag = write_flag;
198     si->current_file = NULL;
199     si->files = NULL;
200     si->type = type;
201     si->entry_buf = (char *) xmalloc(SORT_IDX_ENTRYSIZE);
202     return si;
203 }
204
205 void zebra_sort_close(zebra_sort_index_t si)
206 {
207     struct sortFile *sf = si->files;
208     while (sf)
209     {
210         struct sortFile *sf_next = sf->next;
211         switch(si->type)
212         {
213         case ZEBRA_SORT_TYPE_FLAT:
214             bf_close(sf->u.bf);
215             break;
216         case ZEBRA_SORT_TYPE_ISAMB:
217         case ZEBRA_SORT_TYPE_MULTI:
218             if (sf->isam_pp)
219                 isamb_pp_close(sf->isam_pp);
220             isamb_set_root_ptr(sf->u.isamb, sf->isam_p);
221             isamb_close(sf->u.isamb);
222             break;
223         }
224         xfree(sf);
225         sf = sf_next;
226     }
227     xfree(si->entry_buf);
228     xfree(si);
229 }
230
231 int zebra_sort_type(zebra_sort_index_t si, int id)
232 {
233     int isam_block_size = 4096;
234
235     ISAMC_M method;
236     char fname[80];
237     struct sortFile *sf;
238
239     method.compare_item = sort_term_compare;
240     method.log_item = sort_term_log_item;
241     method.codec.reset = sort_term_code_reset;
242     method.codec.start = sort_term_code_start;
243     method.codec.stop = sort_term_code_stop;
244
245     if (si->current_file && si->current_file->id == id)
246         return 0;
247     for (sf = si->files; sf; sf = sf->next)
248         if (sf->id == id)
249         {
250             si->current_file = sf;
251             return 0;
252         }
253     sf = (struct sortFile *) xmalloc(sizeof(*sf));
254     sf->id = id;
255
256     switch(si->type)
257     {
258     case ZEBRA_SORT_TYPE_FLAT:
259         sf->u.bf = NULL;
260         sprintf(fname, "sort%d", id);
261         yaz_log(YLOG_DEBUG, "sort idx %s wr=%d", fname, si->write_flag);
262         sf->u.bf = bf_open(si->bfs, fname, SORT_IDX_BLOCKSIZE, si->write_flag);
263         if (!sf->u.bf)
264         {
265             xfree(sf);
266             return -1;
267         }
268         if (!bf_read(sf->u.bf, 0, 0, sizeof(sf->head), &sf->head))
269         {
270             sf->head.sysno_max = 0;
271             if (!si->write_flag)
272             {
273                 bf_close(sf->u.bf);
274                 xfree(sf);
275                 return -1;
276             }
277         }
278         break;
279     case ZEBRA_SORT_TYPE_ISAMB:
280         method.codec.encode = sort_term_encode1;
281         method.codec.decode = sort_term_decode1;
282         
283         sprintf(fname, "sortb%d", id);
284         sf->u.isamb = isamb_open2(si->bfs, fname, si->write_flag, &method,
285                                   /* cache */ 0,
286                                   /* no_cat */ 1, &isam_block_size,
287                                   /* use_root_ptr */ 1);
288         if (!sf->u.isamb)
289         {
290             xfree(sf);
291             return -1;
292         }
293         else
294         {
295             sf->isam_p = isamb_get_root_ptr(sf->u.isamb);
296         }
297         break;
298     case ZEBRA_SORT_TYPE_MULTI:
299         isam_block_size = 32768;
300         method.codec.encode = sort_term_encode2;
301         method.codec.decode = sort_term_decode2;
302         
303         sprintf(fname, "sortm%d", id);
304         sf->u.isamb = isamb_open2(si->bfs, fname, si->write_flag, &method,
305                                   /* cache */ 0,
306                                   /* no_cat */ 1, &isam_block_size,
307                                   /* use_root_ptr */ 1);
308         if (!sf->u.isamb)
309         {
310             xfree(sf);
311             return -1;
312         }
313         else
314         {
315             sf->isam_p = isamb_get_root_ptr(sf->u.isamb);
316         }
317         break;
318     }
319     sf->isam_pp = 0;
320     sf->no_inserted = 0;
321     sf->no_deleted = 0;
322     sf->next = si->files;
323     si->current_file = si->files = sf;
324     return 0;
325 }
326
327 static void zebra_sortf_rewind(struct sortFile *sf)
328 {
329     if (sf->isam_pp)
330         isamb_pp_close(sf->isam_pp);
331     sf->isam_pp = 0;
332     sf->no_inserted = 0;
333     sf->no_deleted = 0;
334 }
335
336 void zebra_sort_sysno(zebra_sort_index_t si, zint sysno)
337 {
338     zint new_sysno = rec_sysno_to_int(sysno);
339     struct sortFile *sf;
340
341     for (sf = si->files; sf; sf = sf->next)
342     {
343         if (sf->no_inserted || sf->no_deleted)
344             zebra_sortf_rewind(sf);
345         else if (sf->isam_pp && new_sysno <= si->sysno)
346             zebra_sortf_rewind(sf);
347     }
348     si->sysno = new_sysno;
349 }
350
351
352 void zebra_sort_delete(zebra_sort_index_t si, zint section_id)
353 {
354     struct sortFile *sf = si->current_file;
355
356     if (!sf || !sf->u.bf)
357         return;
358     switch(si->type)
359     {
360     case ZEBRA_SORT_TYPE_FLAT:
361         memset(si->entry_buf, 0, SORT_IDX_ENTRYSIZE);
362         bf_write(sf->u.bf, si->sysno+1, 0, 0, si->entry_buf);
363         break;
364     case ZEBRA_SORT_TYPE_ISAMB:
365     case ZEBRA_SORT_TYPE_MULTI:
366         assert(sf->u.isamb);
367         if (sf->no_deleted == 0)
368         {
369             struct sort_term_stream s;
370             ISAMC_I isamc_i;
371
372             s.st.sysno = si->sysno;
373             s.st.section_id = section_id;
374             s.st.length = 0;
375             s.st.term[0] = '\0';
376             
377             s.no = 1;
378             s.insert_flag = 0;
379             isamc_i.clientData = &s;
380             isamc_i.read_item = sort_term_code_read;
381             
382             isamb_merge(sf->u.isamb, &sf->isam_p, &isamc_i);
383             sf->no_deleted++;
384         }
385         break;
386     }
387 }
388
389 void zebra_sort_add(zebra_sort_index_t si, zint section_id, WRBUF wrbuf)
390 {
391     struct sortFile *sf = si->current_file;
392     int len;
393
394     if (!sf || !sf->u.bf)
395         return;
396     switch(si->type)
397     {
398     case ZEBRA_SORT_TYPE_FLAT:
399         /* take first entry from wrbuf - itself is 0-terminated */
400         len = strlen(wrbuf_buf(wrbuf));
401         if (len > SORT_IDX_ENTRYSIZE)
402             len = SORT_IDX_ENTRYSIZE;
403         
404         memcpy(si->entry_buf, wrbuf_buf(wrbuf), len);
405         if (len < SORT_IDX_ENTRYSIZE-len)
406             memset(si->entry_buf+len, 0, SORT_IDX_ENTRYSIZE-len);
407         bf_write(sf->u.bf, si->sysno+1, 0, 0, si->entry_buf);
408         break;
409     case ZEBRA_SORT_TYPE_ISAMB:
410         assert(sf->u.isamb);
411
412         if (sf->no_inserted == 0)
413         {
414             struct sort_term_stream s;
415             ISAMC_I isamc_i;
416             /* take first entry from wrbuf - itself is 0-terminated */
417
418             len = wrbuf_len(wrbuf);
419             if (len > SORT_MAX_TERM)
420             {
421                 len = SORT_MAX_TERM;
422                 wrbuf_buf(wrbuf)[len-1] = '\0';
423             }
424             memcpy(s.st.term, wrbuf_buf(wrbuf), len);
425             s.st.length = len;
426             s.st.sysno = si->sysno;
427             s.st.section_id = 0;
428             s.no = 1;
429             s.insert_flag = 1;
430             isamc_i.clientData = &s;
431             isamc_i.read_item = sort_term_code_read;
432             
433             isamb_merge(sf->u.isamb, &sf->isam_p, &isamc_i);
434             sf->no_inserted++;
435         }
436         break;
437     case ZEBRA_SORT_TYPE_MULTI:
438         assert(sf->u.isamb);
439         if (sf->no_inserted == 0)
440         {
441             struct sort_term_stream s;
442             ISAMC_I isamc_i;
443             len = wrbuf_len(wrbuf);
444             if (len > SORT_MAX_MULTI)
445             {
446                 len = SORT_MAX_MULTI;
447                 wrbuf_buf(wrbuf)[len-1] = '\0';
448             }
449             memcpy(s.st.term, wrbuf_buf(wrbuf), len);
450             s.st.length = len;
451             s.st.sysno = si->sysno;
452             s.st.section_id = section_id;
453             s.no = 1;
454             s.insert_flag = 1;
455             isamc_i.clientData = &s;
456             isamc_i.read_item = sort_term_code_read;
457             
458             isamb_merge(sf->u.isamb, &sf->isam_p, &isamc_i);
459             sf->no_inserted++;
460         }
461         break;
462     }
463 }
464
465
466 int zebra_sort_read(zebra_sort_index_t si, zint *section_id, WRBUF w)
467 {
468     int r;
469     struct sortFile *sf = si->current_file;
470     char tbuf[SORT_IDX_ENTRYSIZE];
471
472     assert(sf);
473     assert(sf->u.bf);
474
475     switch(si->type)
476     {
477     case ZEBRA_SORT_TYPE_FLAT:
478         r = bf_read(sf->u.bf, si->sysno+1, 0, 0, tbuf);
479         if (r && *tbuf)
480         {
481             wrbuf_puts(w, tbuf);
482             wrbuf_putc(w, '\0');
483             return 1;
484         }
485         break;
486     case ZEBRA_SORT_TYPE_ISAMB:
487     case ZEBRA_SORT_TYPE_MULTI:
488         if (sf->isam_p)
489         {
490
491             if (!sf->isam_pp)
492                 sf->isam_pp = isamb_pp_open(sf->u.isamb, sf->isam_p, 1);
493             if (sf->isam_pp)
494             {
495                 struct sort_term st, st_untilbuf;
496
497                 st_untilbuf.sysno = si->sysno;
498                 st_untilbuf.section_id = 0;
499                 st_untilbuf.length = 0;
500                 st_untilbuf.term[0] = '\0';
501                 r = isamb_pp_forward(sf->isam_pp, &st, &st_untilbuf);
502                 if (r && st.sysno == si->sysno)
503                 {
504                     wrbuf_write(w, st.term, st.length);
505                     if (section_id)
506                         *section_id = st.section_id;
507                     return 1;
508                 }
509             }
510         }
511         break;
512     }
513     return 0;
514 }
515 /*
516  * Local variables:
517  * c-basic-offset: 4
518  * indent-tabs-mode: nil
519  * End:
520  * vim: shiftwidth=4 tabstop=8 expandtab
521  */
522