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