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