Added other sort index test.
[idzebra-moved-to-github.git] / index / sortidx.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 1995-2008 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
33 #define SORT_IDX_BLOCKSIZE 64
34
35 struct sort_term {
36     zint sysno;
37     char term[SORT_MAX_TERM];
38 };
39
40
41 static void sort_term_log_item(int level, const void *b, const char *txt)
42 {
43     struct sort_term a1;
44
45     memcpy(&a1, b, sizeof(a1));
46
47     yaz_log(level, "%s " ZINT_FORMAT " %s", txt, a1.sysno, a1.term);
48 }
49
50 static int sort_term_compare(const void *a, const void *b)
51 {
52     struct sort_term a1, b1;
53
54     memcpy(&a1, a, sizeof(a1));
55     memcpy(&b1, b, sizeof(b1));
56
57     if (a1.sysno > b1.sysno)
58         return 1;
59     else if (a1.sysno < b1.sysno)
60         return -1;
61     return 0;
62 }
63
64 static void *sort_term_code_start(void)
65 {
66     return 0;
67 }
68
69 static void sort_term_encode(void *p, char **dst, const char **src)
70 {
71     struct sort_term a1;
72
73     memcpy(&a1, *src, sizeof(a1));
74     *src += sizeof(a1);
75
76     zebra_zint_encode(dst, a1.sysno); /* encode record id */
77     strcpy(*dst, a1.term); /* then sort term, 0 terminated */
78     *dst += strlen(a1.term) + 1;
79 }
80
81 static void sort_term_decode(void *p, char **dst, const char **src)
82 {
83     struct sort_term a1;
84
85     zebra_zint_decode(src, &a1.sysno);
86
87     strcpy(a1.term, *src);
88     *src += strlen(a1.term) + 1;
89
90     memcpy(*dst, &a1, sizeof(a1));
91     *dst += sizeof(a1);
92 }
93
94 static void sort_term_code_reset(void *p)
95 {
96 }
97
98 static void sort_term_code_stop(void *p)
99 {
100 }
101
102 struct sort_term_stream {
103     int no;
104     int insert_flag;
105     struct sort_term st;
106 };
107
108 static int sort_term_code_read(void *vp, char **dst, int *insertMode)
109 {
110     struct sort_term_stream *s = (struct sort_term_stream *) vp;
111
112     if (s->no == 0)
113         return 0;
114
115     (s->no)--;
116     
117     *insertMode = s->insert_flag;
118     memcpy(*dst, &s->st, sizeof(s->st));
119     *dst += sizeof(s->st);
120     return 1;
121 }
122
123 struct sortFileHead {
124     zint sysno_max;
125 };
126
127 struct sortFile {
128     int id;
129     union {
130         BFile bf;
131         ISAMB isamb;
132     } u;
133     ISAM_P isam_p;
134     ISAMB_PP isam_pp;
135     struct sortFile *next;
136     struct sortFileHead head;
137     int no_inserted;
138     int no_deleted;
139 };
140
141 struct zebra_sort_index {
142     BFiles bfs;
143     int write_flag;
144     zint sysno;
145     int type;
146     char *entry_buf;
147     struct sortFile *current_file;
148     struct sortFile *files;
149 };
150
151 zebra_sort_index_t zebra_sort_open(BFiles bfs, int write_flag, int type)
152 {
153     zebra_sort_index_t si = (zebra_sort_index_t) xmalloc(sizeof(*si));
154     si->bfs = bfs;
155     si->write_flag = write_flag;
156     si->current_file = NULL;
157     si->files = NULL;
158     si->type = type;
159     si->entry_buf = (char *) xmalloc(SORT_IDX_ENTRYSIZE);
160     return si;
161 }
162
163 void zebra_sort_close(zebra_sort_index_t si)
164 {
165     struct sortFile *sf = si->files;
166     while (sf)
167     {
168         struct sortFile *sf_next = sf->next;
169         switch(si->type)
170         {
171         case ZEBRA_SORT_TYPE_FLAT:
172             bf_close(sf->u.bf);
173             break;
174         case ZEBRA_SORT_TYPE_ISAMB:
175             if (sf->isam_pp)
176                 isamb_pp_close(sf->isam_pp);
177             isamb_set_root_ptr(sf->u.isamb, sf->isam_p);
178             isamb_close(sf->u.isamb);
179             break;
180         }
181         xfree(sf);
182         sf = sf_next;
183     }
184     xfree(si->entry_buf);
185     xfree(si);
186 }
187
188 int zebra_sort_type(zebra_sort_index_t si, int id)
189 {
190     int isam_block_size = 4096;
191
192     ISAMC_M method;
193     char fname[80];
194     struct sortFile *sf;
195     if (si->current_file && si->current_file->id == id)
196         return 0;
197     for (sf = si->files; sf; sf = sf->next)
198         if (sf->id == id)
199         {
200             si->current_file = sf;
201             return 0;
202         }
203     sf = (struct sortFile *) xmalloc(sizeof(*sf));
204     sf->id = id;
205
206     switch(si->type)
207     {
208     case ZEBRA_SORT_TYPE_FLAT:
209         sf->u.bf = NULL;
210         sprintf(fname, "sort%d", id);
211         yaz_log(YLOG_DEBUG, "sort idx %s wr=%d", fname, si->write_flag);
212         sf->u.bf = bf_open(si->bfs, fname, SORT_IDX_BLOCKSIZE, si->write_flag);
213         if (!sf->u.bf)
214         {
215             xfree(sf);
216             return -1;
217         }
218         if (!bf_read(sf->u.bf, 0, 0, sizeof(sf->head), &sf->head))
219         {
220             sf->head.sysno_max = 0;
221             if (!si->write_flag)
222             {
223                 bf_close(sf->u.bf);
224                 xfree(sf);
225                 return -1;
226             }
227         }
228         break;
229     case ZEBRA_SORT_TYPE_ISAMB:
230         method.compare_item = sort_term_compare;
231         method.log_item = sort_term_log_item;
232         method.codec.start = sort_term_code_start;
233         method.codec.encode = sort_term_encode;
234         method.codec.decode = sort_term_decode;
235         method.codec.reset = sort_term_code_reset;
236         method.codec.stop = sort_term_code_stop;
237         
238         sprintf(fname, "sortb%d", id);
239         sf->u.isamb = isamb_open2(si->bfs, fname, si->write_flag, &method,
240                                   /* cache */ 0,
241                                   /* no_cat */ 1, &isam_block_size,
242                                   /* use_root_ptr */ 1);
243         if (!sf->u.isamb)
244         {
245             xfree(sf);
246             return -1;
247         }
248         else
249         {
250             sf->isam_p = isamb_get_root_ptr(sf->u.isamb);
251         }
252         break;
253     }
254     sf->isam_pp = 0;
255     sf->no_inserted = 0;
256     sf->no_deleted = 0;
257     sf->next = si->files;
258     si->current_file = si->files = sf;
259     return 0;
260 }
261
262 void zebra_sort_sysno(zebra_sort_index_t si, zint sysno)
263 {
264     struct sortFile *sf = si->current_file;
265     zint new_sysno = rec_sysno_to_int(sysno);
266
267     for (sf = si->files; sf; sf = sf->next)
268     {
269         sf->no_inserted = 0;
270         sf->no_deleted = 0;
271         if (sf->isam_pp && new_sysno < si->sysno && sf->isam_pp)
272         {
273             isamb_pp_close(sf->isam_pp);
274             sf->isam_pp = 0;
275         }
276     }
277     si->sysno = new_sysno;
278 }
279
280
281 void zebra_sort_delete(zebra_sort_index_t si)
282 {
283     struct sortFile *sf = si->current_file;
284
285     if (!sf || !sf->u.bf)
286         return;
287     switch(si->type)
288     {
289     case ZEBRA_SORT_TYPE_FLAT:
290         zebra_sort_add(si, "", 0);
291         break;
292     case ZEBRA_SORT_TYPE_ISAMB:
293         assert(sf->u.isamb);
294         if (sf->no_deleted == 0)
295         {
296             struct sort_term_stream s;
297             ISAMC_I isamc_i;
298
299             s.st.sysno = si->sysno;
300             s.st.term[0] = '\0';
301             
302             s.no = 1;
303             s.insert_flag = 0;
304             isamc_i.clientData = &s;
305             isamc_i.read_item = sort_term_code_read;
306             
307             isamb_merge(sf->u.isamb, &sf->isam_p, &isamc_i);
308             sf->no_deleted++;
309         }
310         break;
311     }
312 }
313
314 void zebra_sort_add(zebra_sort_index_t si, const char *buf, int len)
315 {
316     struct sortFile *sf = si->current_file;
317
318     if (!sf || !sf->u.bf)
319         return;
320     switch(si->type)
321     {
322     case ZEBRA_SORT_TYPE_FLAT:
323         if (len > SORT_IDX_ENTRYSIZE)
324         {
325             len = SORT_IDX_ENTRYSIZE;
326             memcpy(si->entry_buf, buf, len);
327         }
328         else
329         {
330             memcpy(si->entry_buf, buf, len);
331             memset(si->entry_buf+len, 0, SORT_IDX_ENTRYSIZE-len);
332         }
333         bf_write(sf->u.bf, si->sysno+1, 0, 0, si->entry_buf);
334         break;
335     case ZEBRA_SORT_TYPE_ISAMB:
336         assert(sf->u.isamb);
337         if (sf->no_inserted == 0)
338         {
339             struct sort_term_stream s;
340             ISAMC_I isamc_i;
341
342             s.st.sysno = si->sysno;
343             if (len >= SORT_MAX_TERM)
344                 len = SORT_MAX_TERM-1;
345             memcpy(s.st.term, buf, len);
346             s.st.term[len] = '\0';
347             s.no = 1;
348             s.insert_flag = 1;
349             isamc_i.clientData = &s;
350             isamc_i.read_item = sort_term_code_read;
351             
352             isamb_merge(sf->u.isamb, &sf->isam_p, &isamc_i);
353             sf->no_inserted++;
354         }
355         break;
356     }
357 }
358
359 int zebra_sort_read(zebra_sort_index_t si, char *buf)
360 {
361     int r;
362     struct sortFile *sf = si->current_file;
363
364     assert(sf);
365     assert(sf->u.bf);
366
367     switch(si->type)
368     {
369     case ZEBRA_SORT_TYPE_FLAT:
370         r = bf_read(sf->u.bf, si->sysno+1, 0, 0, buf);
371         if (!r)
372             memset(buf, 0, SORT_IDX_ENTRYSIZE);
373         if (buf[0] == 0)
374             return 0;
375         break;
376     case ZEBRA_SORT_TYPE_ISAMB:
377         memset(buf, 0, SORT_IDX_ENTRYSIZE);
378         if (!sf->isam_p)
379             return 0;
380         else
381         {
382             struct sort_term st, st_untilbuf;
383
384             if (!sf->isam_pp)
385                 sf->isam_pp = isamb_pp_open(sf->u.isamb, sf->isam_p, 1);
386             if (!sf->isam_pp)
387                 return 0;
388
389             st_untilbuf.sysno = si->sysno;
390             st_untilbuf.term[0] = '\0';
391             r = isamb_pp_forward(sf->isam_pp, &st, &st_untilbuf);
392             if (!r)
393                 return 0;
394             if (r)
395             {
396                 if (st.sysno != si->sysno)
397                 {
398                     yaz_log(YLOG_LOG, "Received sysno=" ZINT_FORMAT " looking for "
399                             ZINT_FORMAT, st.sysno, si->sysno);
400                     return 0;
401                 }
402                 if (strlen(st.term) < SORT_IDX_ENTRYSIZE)
403                     strcpy(buf, st.term);
404                 else
405                     memcpy(buf, st.term, SORT_IDX_ENTRYSIZE);
406             }
407         }
408         break;
409     }
410     return 1;
411 }
412 /*
413  * Local variables:
414  * c-basic-offset: 4
415  * indent-tabs-mode: nil
416  * End:
417  * vim: shiftwidth=4 tabstop=8 expandtab
418  */
419