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