New result set model.
[idzebra-moved-to-github.git] / rset / rstemp.c
1 /*
2  * Copyright (C) 1994-1998, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: rstemp.c,v $
7  * Revision 1.24  1998-03-05 08:36:28  adam
8  * New result set model.
9  *
10  * Revision 1.23  1997/12/18 10:54:25  adam
11  * New method result set method rs_hits that returns the number of
12  * hits in result-set (if known). The ranked result set returns real
13  * number of hits but only when not combined with other operands.
14  *
15  * Revision 1.22  1997/10/31 12:38:12  adam
16  * Bug fix: added missing xfree() call.
17  *
18  * Revision 1.21  1997/09/17 12:19:23  adam
19  * Zebra version corresponds to YAZ version 1.4.
20  * Changed Zebra server so that it doesn't depend on global common_resource.
21  *
22  * Revision 1.20  1997/09/09 13:38:17  adam
23  * Partial port to WIN95/NT.
24  *
25  * Revision 1.19  1997/09/04 13:58:57  adam
26  * Added O_BINARY for open calls.
27  *
28  * Revision 1.18  1996/10/29 13:54:52  adam
29  * Changed name of setting tempSetDir to setTmpDir.
30  *
31  * Revision 1.17  1995/12/11 09:15:28  adam
32  * New set types: sand/sor/snot - ranked versions of and/or/not in
33  * ranked/semi-ranked result sets.
34  * Note: the snot not finished yet.
35  * New rset member: flag.
36  * Bug fix: r_delete in rsrel.c did free bad memory block.
37  *
38  * Revision 1.16  1995/11/28  14:47:02  adam
39  * New setting: tempSetPath. Location of temporary result sets.
40  *
41  * Revision 1.15  1995/10/12  12:41:58  adam
42  * Private info (buf) moved from struct rset_control to struct rset.
43  * Bug fixes in relevance.
44  *
45  * Revision 1.14  1995/10/10  14:00:04  adam
46  * Function rset_open changed its wflag parameter to general flags.
47  *
48  * Revision 1.13  1995/10/06  14:38:06  adam
49  * New result set method: r_score.
50  * Local no (sysno) and score is transferred to retrieveCtrl.
51  *
52  * Revision 1.12  1995/09/28  09:52:11  adam
53  * xfree/xmalloc used everywhere.
54  *
55  * Revision 1.11  1995/09/18  14:17:56  adam
56  * Bug fixes.
57  *
58  * Revision 1.10  1995/09/15  14:45:39  adam
59  * Bug fixes.
60  *
61  * Revision 1.9  1995/09/15  09:20:42  adam
62  * Bug fixes.
63  *
64  * Revision 1.8  1995/09/08  14:52:42  adam
65  * Work on relevance feedback.
66  *
67  * Revision 1.7  1995/09/07  13:58:44  adam
68  * New parameter: result-set file descriptor (RSFD) to support multiple
69  * positions within the same result-set.
70  * Boolean operators: and, or, not implemented.
71  *
72  * Revision 1.6  1995/09/06  16:11:56  adam
73  * More work on boolean sets.
74  *
75  * Revision 1.5  1995/09/05  16:36:59  adam
76  * Minor changes.
77  *
78  * Revision 1.4  1995/09/05  11:43:24  adam
79  * Complete version of temporary sets. Not tested yet though.
80  *
81  * Revision 1.3  1995/09/04  15:20:40  adam
82  * More work on temp sets. is_open member removed.
83  *
84  * Revision 1.2  1995/09/04  09:10:56  adam
85  * Minor changes.
86  *
87  * Revision 1.1  1994/11/04  13:21:30  quinn
88  * Working.
89  *
90  */
91
92 #include <fcntl.h>
93 #include <assert.h>
94 #ifdef WINDOWS
95 #include <io.h>
96 #else
97 #include <unistd.h>
98 #endif
99 #include <string.h>
100 #include <sys/types.h>
101 #include <stdio.h>
102
103 #include <zebrautl.h>
104 #include <rstemp.h>
105
106 static void *r_create(RSET ct, const struct rset_control *sel, void *parms);
107 static RSFD r_open (RSET ct, int flag);
108 static void r_close (RSFD rfd);
109 static void r_delete (RSET ct);
110 static void r_rewind (RSFD rfd);
111 static int r_count (RSET ct);
112 static int r_read (RSFD rfd, void *buf, int *term_index);
113 static int r_write (RSFD rfd, const void *buf);
114
115 static const struct rset_control control = 
116 {
117     "temp",
118     r_create,
119     r_open,
120     r_close,
121     r_delete,
122     r_rewind,
123     r_count,
124     r_read,
125     r_write,
126 };
127
128 const struct rset_control *rset_kind_temp = &control;
129
130 struct rset_temp_info {
131     int     fd;
132     char   *fname;
133     size_t  key_size;      /* key size */
134     char   *buf_mem;       /* window buffer */
135     size_t  buf_size;      /* size of window */
136     size_t  pos_end;       /* last position in set */
137     size_t  pos_cur;       /* current position in set */
138     size_t  pos_buf;       /* position of first byte in window */
139     size_t  pos_border;    /* position of last byte+1 in window */
140     int     dirty;         /* window is dirty */
141     int     hits;          /* no of hits */
142     char   *temp_path;
143 };
144
145 struct rset_temp_rfd {
146     struct rset_temp_info *info;
147     struct rset_temp_rfd *next;
148 };
149
150 static void *r_create(RSET ct, const struct rset_control *sel, void *parms)
151 {
152     rset_temp_parms *temp_parms = parms;
153     struct rset_temp_info *info;
154    
155     info = xmalloc (sizeof(struct rset_temp_info));
156     info->fd = -1;
157     info->fname = NULL;
158     info->key_size = temp_parms->key_size;
159     info->buf_size = 4096;
160     info->buf_mem = xmalloc (info->buf_size);
161     info->pos_cur = 0;
162     info->pos_end = 0;
163     info->pos_buf = 0;
164     info->dirty = 0;
165     info->hits = -1;
166     if (!temp_parms->temp_path)
167         info->temp_path = NULL;
168     else
169     {
170         info->temp_path = xmalloc (strlen(temp_parms->temp_path)+1);
171         strcpy (info->temp_path, temp_parms->temp_path);
172     }
173     ct->no_rset_terms = 1;
174     ct->rset_terms = xmalloc (sizeof(*ct->rset_terms));
175     ct->rset_terms[0] = temp_parms->rset_term;
176     return info;
177 }
178
179 static RSFD r_open (RSET ct, int flag)
180 {
181     struct rset_temp_info *info = ct->buf;
182     struct rset_temp_rfd *rfd;
183
184     assert (info->fd == -1);
185     if (info->fname)
186     {
187         if (flag & RSETF_WRITE)
188             info->fd = open (info->fname, O_BINARY|O_RDWR|O_CREAT, 0666);
189         else
190             info->fd = open (info->fname, O_BINARY|O_RDONLY);
191         if (info->fd == -1)
192         {
193             logf (LOG_FATAL|LOG_ERRNO, "open %s", info->fname);
194             exit (1);
195         }
196     }
197     rfd = xmalloc (sizeof(*rfd));
198     rfd->info = info;
199     r_rewind (rfd);
200     return rfd;
201 }
202
203 /* r_flush:
204       flush current window to file if file is assocated with set
205  */
206 static void r_flush (RSFD rfd, int mk)
207 {
208     struct rset_temp_info *info = ((struct rset_temp_rfd*) rfd)->info;
209
210     if (!info->fname && mk)
211     {
212         char *s = (char*) tempnam (info->temp_path, "zrs");
213
214         info->fname = xmalloc (strlen(s)+1);
215         strcpy (info->fname, s);
216
217         logf (LOG_DEBUG, "creating tempfile %s", info->fname);
218         info->fd = open (info->fname, O_BINARY|O_RDWR|O_CREAT, 0666);
219         if (info->fd == -1)
220         {
221             logf (LOG_FATAL|LOG_ERRNO, "open %s", info->fname);
222             exit (1);
223         }
224     }
225     if (info->fname && info->fd != -1 && info->dirty)
226     {
227         size_t r, count;
228         
229         if (lseek (info->fd, info->pos_buf, SEEK_SET) == -1)
230         {
231             logf (LOG_FATAL|LOG_ERRNO, "lseek %s", info->fname);
232             exit (1);
233         }
234         count = info->buf_size;
235         if (count > info->pos_end - info->pos_buf)
236             count = info->pos_end - info->pos_buf;
237         if ((r = write (info->fd, info->buf_mem, count)) < count)
238         {
239             if (r == -1)
240                 logf (LOG_FATAL|LOG_ERRNO, "read %s", info->fname);
241             else
242                 logf (LOG_FATAL, "write of %ld but got %ld",
243                       (long) count, (long) r);
244             exit (1);
245         }
246         info->dirty = 0;
247     }
248 }
249
250 static void r_close (RSFD rfd)
251 {
252     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
253
254     r_flush (rfd, 0);
255     if (info->fname && info->fd != -1)
256     {
257         close (info->fd);
258         info->fd = -1;
259     }
260     xfree (rfd);
261 }
262
263 static void r_delete (RSET ct)
264 {
265     struct rset_temp_info *info = ct->buf;
266
267     if (info->fname)
268         unlink (info->fname);        
269     xfree (info->buf_mem);
270     logf (LOG_DEBUG, "r_delete: set size %ld", (long) info->pos_end);
271     if (info->fname)
272     {
273         logf (LOG_DEBUG, "r_delete: unlink %s", info->fname);
274         unlink (info->fname);
275         xfree (info->fname);
276     }
277     if (info->temp_path)
278         xfree (info->temp_path);
279     rset_term_destroy (ct->rset_terms[0]);
280     xfree (ct->rset_terms);
281     xfree (info);
282 }
283
284 /* r_reread:
285       read from file to window if file is assocated with set -
286       indicated by fname
287  */
288 static void r_reread (RSFD rfd)
289 {
290     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
291
292     if (info->fname)
293     {
294         size_t r, count;
295
296         info->pos_border = info->pos_cur + info->buf_size;
297         if (info->pos_border > info->pos_end)
298             info->pos_border = info->pos_end;
299         count = info->pos_border - info->pos_buf;
300         if (count > 0)
301         {
302             if (lseek (info->fd, info->pos_buf, SEEK_SET) == -1)
303             {
304                 logf (LOG_FATAL|LOG_ERRNO, "lseek %s", info->fname);
305                 exit (1);
306             }
307             if ((r = read (info->fd, info->buf_mem, count)) < count)
308             {
309                 if (r == -1)
310                     logf (LOG_FATAL|LOG_ERRNO, "read %s", info->fname);
311                 else
312                     logf (LOG_FATAL, "read of %ld but got %ld",
313                           (long) count, (long) r);
314                 exit (1);
315             }
316         }
317     }
318     else
319         info->pos_border = info->pos_end;
320 }
321
322 static void r_rewind (RSFD rfd)
323 {
324     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
325
326     r_flush (rfd, 0);
327     info->pos_cur = 0;
328     info->pos_buf = 0;
329     r_reread (rfd);
330 }
331
332 static int r_count (RSET ct)
333 {
334     struct rset_temp_info *info = ct->buf;
335
336     return info->pos_end / info->key_size;
337 }
338
339 static int r_read (RSFD rfd, void *buf, int *term_index)
340 {
341     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
342
343     size_t nc = info->pos_cur + info->key_size;
344
345     if (nc > info->pos_border)
346     {
347         if (nc > info->pos_end)
348             return 0;
349         r_flush (rfd, 0);
350         info->pos_buf = info->pos_cur;
351         r_reread (rfd);
352     }
353     memcpy (buf, info->buf_mem + (info->pos_cur - info->pos_buf),
354             info->key_size);
355     info->pos_cur = nc;
356     *term_index = 0;
357     return 1;
358 }
359
360 static int r_write (RSFD rfd, const void *buf)
361 {
362     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
363
364     size_t nc = info->pos_cur + info->key_size;
365
366     if (nc > info->pos_buf + info->buf_size)
367     {
368         r_flush (rfd, 1);
369         info->pos_buf = info->pos_cur;
370         if (info->pos_buf < info->pos_end)
371             r_reread (rfd);
372     }
373     info->dirty = 1;
374     memcpy (info->buf_mem + (info->pos_cur - info->pos_buf), buf,
375             info->key_size);
376     info->pos_cur = nc;
377     if (nc > info->pos_end)
378         info->pos_border = info->pos_end = nc;
379     return 1;
380 }