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