New method result set method rs_hits that returns the number of
[idzebra-moved-to-github.git] / rset / rstemp.c
1 /*
2  * Copyright (C) 1994-1997, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: rstemp.c,v $
7  * Revision 1.23  1997-12-18 10:54:25  adam
8  * New method result set method rs_hits that returns the number of
9  * hits in result-set (if known). The ranked result set returns real
10  * number of hits but only when not combined with other operands.
11  *
12  * Revision 1.22  1997/10/31 12:38:12  adam
13  * Bug fix: added missing xfree() call.
14  *
15  * Revision 1.21  1997/09/17 12:19:23  adam
16  * Zebra version corresponds to YAZ version 1.4.
17  * Changed Zebra server so that it doesn't depend on global common_resource.
18  *
19  * Revision 1.20  1997/09/09 13:38:17  adam
20  * Partial port to WIN95/NT.
21  *
22  * Revision 1.19  1997/09/04 13:58:57  adam
23  * Added O_BINARY for open calls.
24  *
25  * Revision 1.18  1996/10/29 13:54:52  adam
26  * Changed name of setting tempSetDir to setTmpDir.
27  *
28  * Revision 1.17  1995/12/11 09:15:28  adam
29  * New set types: sand/sor/snot - ranked versions of and/or/not in
30  * ranked/semi-ranked result sets.
31  * Note: the snot not finished yet.
32  * New rset member: flag.
33  * Bug fix: r_delete in rsrel.c did free bad memory block.
34  *
35  * Revision 1.16  1995/11/28  14:47:02  adam
36  * New setting: tempSetPath. Location of temporary result sets.
37  *
38  * Revision 1.15  1995/10/12  12:41:58  adam
39  * Private info (buf) moved from struct rset_control to struct rset.
40  * Bug fixes in relevance.
41  *
42  * Revision 1.14  1995/10/10  14:00:04  adam
43  * Function rset_open changed its wflag parameter to general flags.
44  *
45  * Revision 1.13  1995/10/06  14:38:06  adam
46  * New result set method: r_score.
47  * Local no (sysno) and score is transferred to retrieveCtrl.
48  *
49  * Revision 1.12  1995/09/28  09:52:11  adam
50  * xfree/xmalloc used everywhere.
51  *
52  * Revision 1.11  1995/09/18  14:17:56  adam
53  * Bug fixes.
54  *
55  * Revision 1.10  1995/09/15  14:45:39  adam
56  * Bug fixes.
57  *
58  * Revision 1.9  1995/09/15  09:20:42  adam
59  * Bug fixes.
60  *
61  * Revision 1.8  1995/09/08  14:52:42  adam
62  * Work on relevance feedback.
63  *
64  * Revision 1.7  1995/09/07  13:58:44  adam
65  * New parameter: result-set file descriptor (RSFD) to support multiple
66  * positions within the same result-set.
67  * Boolean operators: and, or, not implemented.
68  *
69  * Revision 1.6  1995/09/06  16:11:56  adam
70  * More work on boolean sets.
71  *
72  * Revision 1.5  1995/09/05  16:36:59  adam
73  * Minor changes.
74  *
75  * Revision 1.4  1995/09/05  11:43:24  adam
76  * Complete version of temporary sets. Not tested yet though.
77  *
78  * Revision 1.3  1995/09/04  15:20:40  adam
79  * More work on temp sets. is_open member removed.
80  *
81  * Revision 1.2  1995/09/04  09:10:56  adam
82  * Minor changes.
83  *
84  * Revision 1.1  1994/11/04  13:21:30  quinn
85  * Working.
86  *
87  */
88
89 #include <fcntl.h>
90 #include <assert.h>
91 #ifdef WINDOWS
92 #include <io.h>
93 #else
94 #include <unistd.h>
95 #endif
96 #include <string.h>
97 #include <sys/types.h>
98 #include <stdio.h>
99
100 #include <zebrautl.h>
101 #include <rstemp.h>
102
103 static void *r_create(const struct rset_control *sel, void *parms,
104                       int *flags);
105 static RSFD r_open (RSET ct, int flag);
106 static void r_close (RSFD rfd);
107 static void r_delete (RSET ct);
108 static void r_rewind (RSFD rfd);
109 static int r_count (RSET ct);
110 static int r_hits (RSET ct, void *oi);
111 static int r_read (RSFD rfd, void *buf);
112 static int r_write (RSFD rfd, const void *buf);
113 static int r_score (RSFD rfd, int *score);
114
115 static const 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_hits,
125     r_read,
126     r_write,
127     r_score
128 };
129
130 const rset_control *rset_kind_temp = &control;
131
132 struct rset_temp_info {
133     int     fd;
134     char   *fname;
135     size_t  key_size;      /* key size */
136     char   *buf_mem;       /* window buffer */
137     size_t  buf_size;      /* size of window */
138     size_t  pos_end;       /* last position in set */
139     size_t  pos_cur;       /* current position in set */
140     size_t  pos_buf;       /* position of first byte in window */
141     size_t  pos_border;    /* position of last byte+1 in window */
142     int     dirty;         /* window is dirty */
143     int     hits;          /* no of hits */
144     char   *temp_path;
145 };
146
147 struct rset_temp_rfd {
148     struct rset_temp_info *info;
149     struct rset_temp_rfd *next;
150 };
151
152 static void *r_create(const struct rset_control *sel, void *parms, int *flags)
153 {
154     rset_temp_parms *temp_parms = parms;
155     struct rset_temp_info *info;
156    
157     info = xmalloc (sizeof(struct rset_temp_info));
158     info->fd = -1;
159     info->fname = NULL;
160     info->key_size = temp_parms->key_size;
161     info->buf_size = 4096;
162     info->buf_mem = xmalloc (info->buf_size);
163     info->pos_cur = 0;
164     info->pos_end = 0;
165     info->pos_buf = 0;
166     info->dirty = 0;
167     info->hits = -1;
168     if (!temp_parms->temp_path)
169         info->temp_path = NULL;
170     else
171     {
172         info->temp_path = xmalloc (strlen(temp_parms->temp_path)+1);
173         strcpy (info->temp_path, temp_parms->temp_path);
174     }
175
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     xfree (info);
280 }
281
282 /* r_reread:
283       read from file to window if file is assocated with set -
284       indicated by fname
285  */
286 static void r_reread (RSFD rfd)
287 {
288     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
289
290     if (info->fname)
291     {
292         size_t r, count;
293
294         info->pos_border = info->pos_cur + info->buf_size;
295         if (info->pos_border > info->pos_end)
296             info->pos_border = info->pos_end;
297         count = info->pos_border - info->pos_buf;
298         if (count > 0)
299         {
300             if (lseek (info->fd, info->pos_buf, SEEK_SET) == -1)
301             {
302                 logf (LOG_FATAL|LOG_ERRNO, "lseek %s", info->fname);
303                 exit (1);
304             }
305             if ((r = read (info->fd, info->buf_mem, count)) < count)
306             {
307                 if (r == -1)
308                     logf (LOG_FATAL|LOG_ERRNO, "read %s", info->fname);
309                 else
310                     logf (LOG_FATAL, "read of %ld but got %ld",
311                           (long) count, (long) r);
312                 exit (1);
313             }
314         }
315     }
316     else
317         info->pos_border = info->pos_end;
318 }
319
320 static void r_rewind (RSFD rfd)
321 {
322     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
323
324     r_flush (rfd, 0);
325     info->pos_cur = 0;
326     info->pos_buf = 0;
327     r_reread (rfd);
328 }
329
330 static int r_count (RSET ct)
331 {
332     struct rset_temp_info *info = ct->buf;
333
334     return info->pos_end / info->key_size;
335 }
336
337 static int r_hits (RSET ct, void *oi)
338 {
339     struct rset_temp_info *info = ct->buf;
340
341     return info->hits;
342 }
343
344 static int r_read (RSFD rfd, void *buf)
345 {
346     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
347
348     size_t nc = info->pos_cur + info->key_size;
349
350     if (nc > info->pos_border)
351     {
352         if (nc > info->pos_end)
353             return 0;
354         r_flush (rfd, 0);
355         info->pos_buf = info->pos_cur;
356         r_reread (rfd);
357     }
358     memcpy (buf, info->buf_mem + (info->pos_cur - info->pos_buf),
359             info->key_size);
360     info->pos_cur = nc;
361     return 1;
362 }
363
364 static int r_write (RSFD rfd, const void *buf)
365 {
366     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
367
368     size_t nc = info->pos_cur + info->key_size;
369
370     if (nc > info->pos_buf + info->buf_size)
371     {
372         r_flush (rfd, 1);
373         info->pos_buf = info->pos_cur;
374         if (info->pos_buf < info->pos_end)
375             r_reread (rfd);
376     }
377     info->dirty = 1;
378     memcpy (info->buf_mem + (info->pos_cur - info->pos_buf), buf,
379             info->key_size);
380     info->pos_cur = nc;
381     if (nc > info->pos_end)
382         info->pos_border = info->pos_end = nc;
383     return 1;
384 }
385
386 static int r_score (RSFD rfd, int *score)
387 {
388     *score = -1;
389     return -1;
390 }