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