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