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