Hits per term. Returned in SearchResult-1
[idzebra-moved-to-github.git] / rset / rstemp.c
1 /*
2  * Copyright (C) 1994-2002, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Id: rstemp.c,v 1.30 2002-03-20 20:24:30 adam Exp $
7  */
8
9 #include <fcntl.h>
10 #include <assert.h>
11 #ifdef WIN32
12 #include <io.h>
13 #else
14 #include <unistd.h>
15 #endif
16 #include <string.h>
17 #include <sys/types.h>
18 #include <stdio.h>
19
20 #include <zebrautl.h>
21 #include <rstemp.h>
22
23 static void *r_create(RSET ct, const struct rset_control *sel, void *parms);
24 static RSFD r_open (RSET ct, int flag);
25 static void r_close (RSFD rfd);
26 static void r_delete (RSET ct);
27 static void r_rewind (RSFD rfd);
28 static int r_count (RSET ct);
29 static int r_read (RSFD rfd, void *buf, int *term_index);
30 static int r_write (RSFD rfd, const void *buf);
31
32 static const struct rset_control control = 
33 {
34     "temp",
35     r_create,
36     r_open,
37     r_close,
38     r_delete,
39     r_rewind,
40     r_count,
41     r_read,
42     r_write,
43 };
44
45 const struct rset_control *rset_kind_temp = &control;
46
47 struct rset_temp_info {
48     int     fd;
49     char   *fname;
50     size_t  key_size;      /* key size */
51     char   *buf_mem;       /* window buffer */
52     size_t  buf_size;      /* size of window */
53     size_t  pos_end;       /* last position in set */
54     size_t  pos_cur;       /* current position in set */
55     size_t  pos_buf;       /* position of first byte in window */
56     size_t  pos_border;    /* position of last byte+1 in window */
57     int     dirty;         /* window is dirty */
58     int     hits;          /* no of hits */
59     char   *temp_path;
60     int     (*cmp)(const void *p1, const void *p2);
61 };
62
63 struct rset_temp_rfd {
64     struct rset_temp_info *info;
65     struct rset_temp_rfd *next;
66     int *countp;
67     void *buf;
68 };
69
70 static void *r_create(RSET ct, const struct rset_control *sel, void *parms)
71 {
72     rset_temp_parms *temp_parms = (rset_temp_parms *) parms;
73     struct rset_temp_info *info;
74    
75     info = (struct rset_temp_info *) xmalloc (sizeof(struct rset_temp_info));
76     info->fd = -1;
77     info->fname = NULL;
78     info->key_size = temp_parms->key_size;
79     info->buf_size = 4096;
80     info->buf_mem = (char *) xmalloc (info->buf_size);
81     info->pos_cur = 0;
82     info->pos_end = 0;
83     info->pos_buf = 0;
84     info->dirty = 0;
85     info->hits = -1;
86     info->cmp = temp_parms->cmp;
87     if (!temp_parms->temp_path)
88         info->temp_path = NULL;
89     else
90     {
91         info->temp_path = (char *) xmalloc (strlen(temp_parms->temp_path)+1);
92         strcpy (info->temp_path, temp_parms->temp_path);
93     }
94     ct->no_rset_terms = 1;
95     ct->rset_terms = (RSET_TERM *) xmalloc (sizeof(*ct->rset_terms));
96     ct->rset_terms[0] = temp_parms->rset_term;
97
98     return info;
99 }
100
101 static RSFD r_open (RSET ct, int flag)
102 {
103     struct rset_temp_info *info = (struct rset_temp_info *) ct->buf;
104     struct rset_temp_rfd *rfd;
105
106     assert (info->fd == -1);
107     if (info->fname)
108     {
109         if (flag & RSETF_WRITE)
110             info->fd = open (info->fname, O_BINARY|O_RDWR|O_CREAT, 0666);
111         else
112             info->fd = open (info->fname, O_BINARY|O_RDONLY);
113         if (info->fd == -1)
114         {
115             logf (LOG_FATAL|LOG_ERRNO, "open %s", info->fname);
116             exit (1);
117         }
118     }
119     rfd = (struct rset_temp_rfd *) xmalloc (sizeof(*rfd));
120     rfd->info = info;
121     r_rewind (rfd);
122
123     rfd->countp = &ct->rset_terms[0]->count;
124     rfd->buf = xmalloc (info->key_size);
125
126     return rfd;
127 }
128
129 /* r_flush:
130       flush current window to file if file is assocated with set
131  */
132 static void r_flush (RSFD rfd, int mk)
133 {
134     struct rset_temp_info *info = ((struct rset_temp_rfd*) rfd)->info;
135
136     if (!info->fname && mk)
137     {
138 #if HAVE_MKSTEMP
139         char template[1024];
140
141         sprintf (template, "%s/zrsXXXXXX", info->temp_path);
142
143         info->fd = mkstemp (template);
144
145         if (info->fd == -1)
146         {
147             logf (LOG_FATAL|LOG_ERRNO, "mkstemp %s", template);
148             exit (1);
149         }
150         info->fname = (char *) xmalloc (strlen(template)+1);
151         strcpy (info->fname, template);
152 #else
153         char *s = (char*) tempnam (info->temp_path, "zrs");
154         info->fname = (char *) xmalloc (strlen(s)+1);
155         strcpy (info->fname, s);
156
157         logf (LOG_DEBUG, "creating tempfile %s", info->fname);
158         info->fd = open (info->fname, O_BINARY|O_RDWR|O_CREAT, 0666);
159         if (info->fd == -1)
160         {
161             logf (LOG_FATAL|LOG_ERRNO, "open %s", info->fname);
162             exit (1);
163         }
164 #endif
165     }
166     if (info->fname && info->fd != -1 && info->dirty)
167     {
168         size_t count;
169         int r;
170         
171         if (lseek (info->fd, info->pos_buf, SEEK_SET) == -1)
172         {
173             logf (LOG_FATAL|LOG_ERRNO, "lseek %s", info->fname);
174             exit (1);
175         }
176         count = info->buf_size;
177         if (count > info->pos_end - info->pos_buf)
178             count = info->pos_end - info->pos_buf;
179         if ((r = write (info->fd, info->buf_mem, count)) < (int) count)
180         {
181             if (r == -1)
182                 logf (LOG_FATAL|LOG_ERRNO, "read %s", info->fname);
183             else
184                 logf (LOG_FATAL, "write of %ld but got %ld",
185                       (long) count, (long) r);
186             exit (1);
187         }
188         info->dirty = 0;
189     }
190 }
191
192 static void r_close (RSFD rfd)
193 {
194     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
195
196     r_flush (rfd, 0);
197     if (info->fname && info->fd != -1)
198     {
199         close (info->fd);
200         info->fd = -1;
201     }
202     xfree (((struct rset_temp_rfd *)rfd)->buf);
203     xfree (rfd);
204 }
205
206 static void r_delete (RSET ct)
207 {
208     struct rset_temp_info *info = (struct rset_temp_info*) ct->buf;
209
210     if (info->fname)
211         unlink (info->fname);        
212     xfree (info->buf_mem);
213     logf (LOG_DEBUG, "r_delete: set size %ld", (long) info->pos_end);
214     if (info->fname)
215     {
216         logf (LOG_DEBUG, "r_delete: unlink %s", info->fname);
217         unlink (info->fname);
218         xfree (info->fname);
219     }
220     if (info->temp_path)
221         xfree (info->temp_path);
222     rset_term_destroy (ct->rset_terms[0]);
223     xfree (ct->rset_terms);
224     xfree (info);
225 }
226
227 /* r_reread:
228       read from file to window if file is assocated with set -
229       indicated by fname
230  */
231 static void r_reread (RSFD rfd)
232 {
233     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
234
235     if (info->fname)
236     {
237         size_t count;
238         int r;
239
240         info->pos_border = info->pos_cur + info->buf_size;
241         if (info->pos_border > info->pos_end)
242             info->pos_border = info->pos_end;
243         count = info->pos_border - info->pos_buf;
244         if (count > 0)
245         {
246             if (lseek (info->fd, info->pos_buf, SEEK_SET) == -1)
247             {
248                 logf (LOG_FATAL|LOG_ERRNO, "lseek %s", info->fname);
249                 exit (1);
250             }
251             if ((r = read (info->fd, info->buf_mem, count)) < (int) count)
252             {
253                 if (r == -1)
254                     logf (LOG_FATAL|LOG_ERRNO, "read %s", info->fname);
255                 else
256                     logf (LOG_FATAL, "read of %ld but got %ld",
257                           (long) count, (long) r);
258                 exit (1);
259             }
260         }
261     }
262     else
263         info->pos_border = info->pos_end;
264 }
265
266 static void r_rewind (RSFD rfd)
267 {
268     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
269
270     r_flush (rfd, 0);
271     info->pos_cur = 0;
272     info->pos_buf = 0;
273     r_reread (rfd);
274 }
275
276 static int r_count (RSET ct)
277 {
278     struct rset_temp_info *info = (struct rset_temp_info *) ct->buf;
279
280     return info->pos_end / info->key_size;
281 }
282
283 static int r_read (RSFD rfd, void *buf, int *term_index)
284 {
285     struct rset_temp_rfd *mrfd = (struct rset_temp_rfd*) rfd;
286     struct rset_temp_info *info = mrfd->info;
287
288     size_t nc = info->pos_cur + info->key_size;
289
290     if (nc > info->pos_border)
291     {
292         if (nc > info->pos_end)
293             return 0;
294         r_flush (rfd, 0);
295         info->pos_buf = info->pos_cur;
296         r_reread (rfd);
297     }
298     memcpy (buf, info->buf_mem + (info->pos_cur - info->pos_buf),
299             info->key_size);
300     info->pos_cur = nc;
301     *term_index = 0;
302
303     if (*mrfd->countp == 0 || (*info->cmp)(buf, mrfd->buf) > 1)
304     {
305         memcpy (mrfd->buf, buf, mrfd->info->key_size);
306         (*mrfd->countp)++;
307     }
308     return 1;
309 }
310
311 static int r_write (RSFD rfd, const void *buf)
312 {
313     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
314
315     size_t nc = info->pos_cur + info->key_size;
316
317     if (nc > info->pos_buf + info->buf_size)
318     {
319         r_flush (rfd, 1);
320         info->pos_buf = info->pos_cur;
321         if (info->pos_buf < info->pos_end)
322             r_reread (rfd);
323     }
324     info->dirty = 1;
325     memcpy (info->buf_mem + (info->pos_cur - info->pos_buf), buf,
326             info->key_size);
327     info->pos_cur = nc;
328     if (nc > info->pos_end)
329         info->pos_border = info->pos_end = nc;
330     return 1;
331 }