d844198afaf81183d747684801cf6d32a131ef88
[idzebra-moved-to-github.git] / isamc / isams.c
1 /*
2  * Copyright (c) 1995-1999, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: isams.c,v $
7  * Revision 1.3  1999-05-20 12:57:18  adam
8  * Implemented TCL filter. Updated recctrl system.
9  *
10  * Revision 1.2  1999/05/15 14:35:48  adam
11  * Minor changes.
12  *
13  * Revision 1.1  1999/05/12 13:08:06  adam
14  * First version of ISAMS.
15  *
16  */
17 #include <stdlib.h>
18 #include <assert.h>
19 #include <string.h>
20 #include <stdio.h>
21
22 #include <log.h>
23 #include <isams.h>
24
25 typedef struct {
26     int last_offset;
27     int last_block;
28 } ISAMS_head;
29
30 typedef unsigned ISAMS_BLOCK_SIZE;
31
32 struct ISAMS_s {
33     ISAMS_M method;
34     ISAMS_head head;
35     ISAMS_head head_old;
36     char *merge_buf;
37
38     int block_size;
39     int debug;
40     BFile bf;
41 }; 
42
43 struct ISAMS_PP_s {
44     ISAMS is;
45     char *buf;
46     int block_offset;
47     int block_no;
48     void *decodeClientData;
49     int numKeys;
50     int numRead;
51 };
52
53 ISAMS_M isams_getmethod (void)
54 {
55     ISAMS_M m = xmalloc (sizeof(*m));
56
57     m->code_start = NULL;
58     m->code_item = NULL;
59     m->code_stop = NULL;
60
61     m->compare_item = NULL;
62
63     m->debug = 1;
64     m->block_size = 128;
65
66     return m;
67 }
68
69 ISAMS isams_open (BFiles bfs, const char *name, int writeflag,
70                   ISAMS_M method)
71 {
72     ISAMS is = xmalloc (sizeof(*is));
73
74     is->method = xmalloc (sizeof(*is->method));
75     memcpy (is->method, method, sizeof(*method));
76     is->block_size = is->method->block_size;
77     is->debug = is->method->debug;
78
79     is->bf = bf_open (bfs, name, is->block_size, writeflag);
80
81     if (!bf_read (is->bf, 0, 0, sizeof(ISAMS_head), &is->head))
82     {
83         is->head.last_block = 1;
84         is->head.last_offset = 0;
85     }
86     memcpy (&is->head_old, &is->head, sizeof(is->head));
87     is->merge_buf = xmalloc(2*is->block_size);
88     memset(is->merge_buf, 0, 2*is->block_size);
89     return is;
90 }
91
92 int isams_close (ISAMS is)
93 {
94     if (memcmp(&is->head, &is->head_old, sizeof(is->head)))
95     {
96         if (is->head.last_offset)
97             bf_write(is->bf, is->head.last_block, 0, is->head.last_offset,
98                      is->merge_buf);
99         bf_write (is->bf, 0, 0, sizeof(is->head), &is->head);
100     }
101     bf_close (is->bf);
102     xfree (is->merge_buf);
103     xfree (is->method);
104     xfree (is);
105     return 0;
106 }
107
108 ISAMS_P isams_merge (ISAMS is, ISAMS_I data)
109 {
110     char i_item[128], *i_item_ptr;
111     int i_more, i_mode;
112     void *r_clientData;
113     int first_block = is->head.last_block;
114     int first_offset = is->head.last_offset;
115     int count = 0;
116
117     r_clientData = (*is->method->code_start)(ISAMC_ENCODE);
118
119     is->head.last_offset += sizeof(int);
120     if (is->head.last_offset > is->block_size)
121     {
122         if (is->debug > 2)
123             logf (LOG_LOG, "first_block=%d", first_block);
124         bf_write(is->bf, is->head.last_block, 0, 0, is->merge_buf);
125         (is->head.last_block)++;
126         is->head.last_offset -= is->block_size;
127         memcpy (is->merge_buf, is->merge_buf + is->block_size,
128                 is->head.last_offset);
129     }
130     while (1)
131     {
132         i_item_ptr = i_item;
133         i_more = (*data->read_item)(data->clientData, &i_item_ptr, &i_mode);
134         assert (i_mode);
135         
136         if (!i_more)
137             break;
138         else
139         {
140             char *r_out_ptr = is->merge_buf + is->head.last_offset;
141             
142             i_item_ptr = i_item;
143             (*is->method->code_item)(ISAMC_ENCODE, r_clientData,
144                                      &r_out_ptr, &i_item_ptr);
145             is->head.last_offset = r_out_ptr - is->merge_buf;
146             if (is->head.last_offset > is->block_size)
147             {
148                 bf_write(is->bf, is->head.last_block, 0, 0, is->merge_buf);
149                 (is->head.last_block)++;
150                 is->head.last_offset -= is->block_size;
151                 memcpy (is->merge_buf, is->merge_buf + is->block_size,
152                         is->head.last_offset);
153             }
154             count++;
155         }
156     }
157     (*is->method->code_stop)(ISAMC_ENCODE, r_clientData);
158     if (first_block == is->head.last_block)
159         memcpy(is->merge_buf + first_offset, &count, sizeof(int));
160     else if (first_block == is->head.last_block-1)
161     {
162         int gap = first_offset + sizeof(int) - is->block_size;
163         assert (gap <= (int) sizeof(int));
164         if (gap > 0)
165         {
166             if (gap < sizeof(int))
167                 bf_write(is->bf, first_block, first_offset, sizeof(int)-gap,
168                          &count);
169             memcpy (is->merge_buf, ((char*)&count)+(sizeof(int)-gap), gap);
170         }
171         else
172             bf_write(is->bf, first_block, first_offset, sizeof(int), &count);
173     }
174     else
175     {
176         bf_write(is->bf, first_block, first_offset, sizeof(int), &count);
177     }
178     return first_block * is->block_size + first_offset;
179 }
180
181 ISAMS_PP isams_pp_open (ISAMS is, ISAMS_P pos)
182 {
183     ISAMS_PP pp = xmalloc (sizeof(*pp));
184
185     if (is->debug > 1)
186         logf (LOG_LOG, "isams: isams_pp_open pos=%ld", (long) pos);
187     pp->is = is;
188     pp->decodeClientData = (*is->method->code_start)(ISAMC_DECODE);
189     pp->numKeys = 0;
190     pp->numRead = 0;
191     pp->buf = xmalloc(is->block_size*2);
192     pp->block_no = pos/is->block_size;
193     pp->block_offset = pos - pp->block_no * is->block_size;
194     logf (LOG_LOG, "isams: isams_pp_open off=%d no=%d",
195           pp->block_offset, pp->block_no);
196     if (pos)
197     {
198         bf_read (is->bf, pp->block_no, 0, 0, pp->buf);
199         bf_read (is->bf, pp->block_no+1, 0, 0, pp->buf + is->block_size);
200         memcpy(&pp->numKeys, pp->buf + pp->block_offset, sizeof(int));
201         logf (LOG_LOG, "isams: isams_pp_open numKeys=%d", pp->numKeys);
202         pp->block_offset += sizeof(int);
203     }
204     return pp;
205 }
206
207 void isams_pp_close (ISAMS_PP pp)
208 {
209     (*pp->is->method->code_stop)(ISAMC_DECODE, pp->decodeClientData);
210     xfree(pp->buf);
211     xfree(pp);
212 }
213
214 int isams_pp_num (ISAMS_PP pp)
215 {
216     return pp->numKeys;
217 }
218
219 int isams_pp_read (ISAMS_PP pp, void *buf)
220 {
221     return isams_read_item (pp, (char **) &buf);
222 }
223
224 int isams_read_item (ISAMS_PP pp, char **dst)
225 {
226     char *src;
227     if (pp->numRead >= pp->numKeys)
228         return 0;
229     (pp->numRead)++;
230     if (pp->block_offset > pp->is->block_size)
231     {
232         pp->block_offset -= pp->is->block_size;
233         (pp->block_no)++;
234         memcpy (pp->buf, pp->buf + pp->is->block_size, pp->is->block_size);
235         bf_read (pp->is->bf, pp->block_no+1, 0, 0,
236                  pp->buf + pp->is->block_size);
237     }
238     src = pp->buf + pp->block_offset;
239     (*pp->is->method->code_item)(ISAMC_DECODE, pp->decodeClientData,
240                                  dst, &src);
241     pp->block_offset = src - pp->buf; 
242     return 1;
243 }
244
245