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