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