76b08c2c6d5c620e345d3842f9d48ddafde97a85
[idzebra-moved-to-github.git] / rset / rstemp.c
1 /* $Id: rstemp.c,v 1.36 2004-01-16 15:27:35 heikki Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23 #include <fcntl.h>
24 #include <assert.h>
25 #ifdef WIN32
26 #include <io.h>
27 #else
28 #include <unistd.h>
29 #endif
30 #include <string.h>
31 #include <sys/types.h>
32 #include <stdio.h>
33
34 #include <zebrautl.h>
35 #include <rstemp.h>
36
37 static void *r_create(RSET ct, const struct rset_control *sel, void *parms);
38 static RSFD r_open (RSET ct, int flag);
39 static void r_close (RSFD rfd);
40 static void r_delete (RSET ct);
41 static void r_rewind (RSFD rfd);
42 static int r_count (RSET ct);
43 static int r_read (RSFD rfd, void *buf, int *term_index);
44 static int r_write (RSFD rfd, const void *buf);
45
46 static const struct rset_control control = 
47 {
48     "temp",
49     r_create,
50     r_open,
51     r_close,
52     r_delete,
53     r_rewind,
54     rset_default_forward,
55     r_count,
56     r_read,
57     r_write,
58 };
59
60 const struct rset_control *rset_kind_temp = &control;
61
62 struct rset_temp_info {
63     int     fd;
64     char   *fname;
65     size_t  key_size;      /* key size */
66     char   *buf_mem;       /* window buffer */
67     size_t  buf_size;      /* size of window */
68     size_t  pos_end;       /* last position in set */
69     size_t  pos_buf;       /* position of first byte in window */
70     size_t  pos_border;    /* position of last byte+1 in window */
71     int     dirty;         /* window is dirty */
72     int     hits;          /* no of hits */
73     char   *temp_path;
74     int     (*cmp)(const void *p1, const void *p2);
75     struct rset_temp_rfd *rfd_list;
76 };
77
78 struct rset_temp_rfd {
79     struct rset_temp_info *info;
80     struct rset_temp_rfd *next;
81     int *countp;
82     void *buf;
83     size_t  pos_cur;       /* current position in set */
84 };
85
86 static void *r_create(RSET ct, const struct rset_control *sel, void *parms)
87 {
88     rset_temp_parms *temp_parms = (rset_temp_parms *) parms;
89     struct rset_temp_info *info;
90    
91     info = (struct rset_temp_info *) xmalloc (sizeof(struct rset_temp_info));
92     info->fd = -1;
93     info->fname = NULL;
94     info->key_size = temp_parms->key_size;
95     info->buf_size = 4096;
96     info->buf_mem = (char *) xmalloc (info->buf_size);
97     info->pos_end = 0;
98     info->pos_buf = 0;
99     info->dirty = 0;
100     info->hits = -1;
101     info->cmp = temp_parms->cmp;
102     info->rfd_list = NULL;
103
104     if (!temp_parms->temp_path)
105         info->temp_path = NULL;
106     else
107     {
108         info->temp_path = (char *) xmalloc (strlen(temp_parms->temp_path)+1);
109         strcpy (info->temp_path, temp_parms->temp_path);
110     }
111     ct->no_rset_terms = 1;
112     ct->rset_terms = (RSET_TERM *) xmalloc (sizeof(*ct->rset_terms));
113     ct->rset_terms[0] = temp_parms->rset_term;
114
115     return info;
116 }
117
118 static RSFD r_open (RSET ct, int flag)
119 {
120     struct rset_temp_info *info = (struct rset_temp_info *) ct->buf;
121     struct rset_temp_rfd *rfd;
122
123     if (info->fd == -1 && info->fname)
124     {
125         if (flag & RSETF_WRITE)
126             info->fd = open (info->fname, O_BINARY|O_RDWR|O_CREAT, 0666);
127         else
128             info->fd = open (info->fname, O_BINARY|O_RDONLY);
129         if (info->fd == -1)
130         {
131             logf (LOG_FATAL|LOG_ERRNO, "open %s", info->fname);
132             exit (1);
133         }
134     }
135     rfd = (struct rset_temp_rfd *) xmalloc (sizeof(*rfd));
136     rfd->next = info->rfd_list;
137     info->rfd_list = rfd;
138     rfd->info = info;
139     r_rewind (rfd);
140
141     rfd->countp = &ct->rset_terms[0]->count;
142     *rfd->countp = 0;
143     rfd->buf = xmalloc (info->key_size);
144
145     return rfd;
146 }
147
148 /* r_flush:
149       flush current window to file if file is assocated with set
150  */
151 static void r_flush (RSFD rfd, int mk)
152 {
153     struct rset_temp_info *info = ((struct rset_temp_rfd*) rfd)->info;
154
155     if (!info->fname && mk)
156     {
157 #if HAVE_MKSTEMP
158         char template[1024];
159
160         if (info->temp_path)
161             sprintf (template, "%s/zrsXXXXXX", info->temp_path);
162         else
163             sprintf (template, "zrsXXXXXX");
164
165         info->fd = mkstemp (template);
166
167         if (info->fd == -1)
168         {
169             logf (LOG_FATAL|LOG_ERRNO, "mkstemp %s", template);
170             exit (1);
171         }
172         info->fname = (char *) xmalloc (strlen(template)+1);
173         strcpy (info->fname, template);
174 #else
175         char *s = (char*) tempnam (info->temp_path, "zrs");
176         info->fname = (char *) xmalloc (strlen(s)+1);
177         strcpy (info->fname, s);
178
179         logf (LOG_DEBUG, "creating tempfile %s", info->fname);
180         info->fd = open (info->fname, O_BINARY|O_RDWR|O_CREAT, 0666);
181         if (info->fd == -1)
182         {
183             logf (LOG_FATAL|LOG_ERRNO, "open %s", info->fname);
184             exit (1);
185         }
186 #endif
187     }
188     if (info->fname && info->fd != -1 && info->dirty)
189     {
190         size_t count;
191         int r;
192         
193         if (lseek (info->fd, info->pos_buf, SEEK_SET) == -1)
194         {
195             logf (LOG_FATAL|LOG_ERRNO, "lseek %s", info->fname);
196             exit (1);
197         }
198         count = info->buf_size;
199         if (count > info->pos_end - info->pos_buf)
200             count = info->pos_end - info->pos_buf;
201         if ((r = write (info->fd, info->buf_mem, count)) < (int) count)
202         {
203             if (r == -1)
204                 logf (LOG_FATAL|LOG_ERRNO, "read %s", info->fname);
205             else
206                 logf (LOG_FATAL, "write of %ld but got %ld",
207                       (long) count, (long) r);
208             exit (1);
209         }
210         info->dirty = 0;
211     }
212 }
213
214 static void r_close (RSFD rfd)
215 {
216     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
217     struct rset_temp_rfd **rfdp;
218
219     for (rfdp = &info->rfd_list; *rfdp; rfdp = &(*rfdp)->next)
220         if (*rfdp == rfd)
221         {
222             r_flush (*rfdp, 0);
223             xfree ((*rfdp)->buf);
224
225             *rfdp = (*rfdp)->next;
226             xfree (rfd);
227
228             if (!info->rfd_list && info->fname && info->fd != -1)
229             {
230                 close (info->fd);
231                 info->fd = -1;
232             }
233             return;
234         }
235     logf (LOG_FATAL, "r_close but no rfd match!");
236     assert (0);
237 }
238
239 static void r_delete (RSET ct)
240 {
241     struct rset_temp_info *info = (struct rset_temp_info*) ct->buf;
242
243     if (info->fname)
244         unlink (info->fname);        
245     xfree (info->buf_mem);
246     logf (LOG_DEBUG, "r_delete: set size %ld", (long) info->pos_end);
247     if (info->fname)
248     {
249         logf (LOG_DEBUG, "r_delete: unlink %s", info->fname);
250         unlink (info->fname);
251         xfree (info->fname);
252     }
253     if (info->temp_path)
254         xfree (info->temp_path);
255     rset_term_destroy (ct->rset_terms[0]);
256     xfree (ct->rset_terms);
257     xfree (info);
258 }
259
260 /* r_reread:
261       read from file to window if file is assocated with set -
262       indicated by fname
263  */
264 static void r_reread (RSFD rfd)
265 {
266     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
267
268     if (info->fname)
269     {
270         size_t count;
271         int r;
272
273         info->pos_border = ((struct rset_temp_rfd *)rfd)->pos_cur +
274             info->buf_size;
275         if (info->pos_border > info->pos_end)
276             info->pos_border = info->pos_end;
277         count = info->pos_border - info->pos_buf;
278         if (count > 0)
279         {
280             if (lseek (info->fd, info->pos_buf, SEEK_SET) == -1)
281             {
282                 logf (LOG_FATAL|LOG_ERRNO, "lseek %s", info->fname);
283                 exit (1);
284             }
285             if ((r = read (info->fd, info->buf_mem, count)) < (int) count)
286             {
287                 if (r == -1)
288                     logf (LOG_FATAL|LOG_ERRNO, "read %s", info->fname);
289                 else
290                     logf (LOG_FATAL, "read of %ld but got %ld",
291                           (long) count, (long) r);
292                 exit (1);
293             }
294         }
295     }
296     else
297         info->pos_border = info->pos_end;
298 }
299
300 static void r_rewind (RSFD rfd)
301 {
302     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
303
304     r_flush (rfd, 0);
305     ((struct rset_temp_rfd *)rfd)->pos_cur = 0;
306     info->pos_buf = 0;
307     r_reread (rfd);
308 }
309
310 static int r_count (RSET ct)
311 {
312     struct rset_temp_info *info = (struct rset_temp_info *) ct->buf;
313
314     return info->pos_end / info->key_size;
315 }
316
317 static int r_read (RSFD rfd, void *buf, int *term_index)
318 {
319     struct rset_temp_rfd *mrfd = (struct rset_temp_rfd*) rfd;
320     struct rset_temp_info *info = mrfd->info;
321
322     size_t nc = mrfd->pos_cur + info->key_size;
323
324     if (mrfd->pos_cur < info->pos_buf || nc > info->pos_border)
325     {
326         if (nc > info->pos_end)
327             return 0;
328         r_flush (rfd, 0);
329         info->pos_buf = mrfd->pos_cur;
330         r_reread (rfd);
331     }
332     memcpy (buf, info->buf_mem + (mrfd->pos_cur - info->pos_buf),
333             info->key_size);
334     mrfd->pos_cur = nc;
335     *term_index = 0;
336
337     if (*mrfd->countp == 0 || (*info->cmp)(buf, mrfd->buf) > 1)
338     {
339         memcpy (mrfd->buf, buf, mrfd->info->key_size);
340         (*mrfd->countp)++;
341     }
342     return 1;
343 }
344
345 static int r_write (RSFD rfd, const void *buf)
346 {
347     struct rset_temp_rfd *mrfd = (struct rset_temp_rfd*) rfd;
348     struct rset_temp_info *info = mrfd->info;
349
350     size_t nc = mrfd->pos_cur + info->key_size;
351
352     if (nc > info->pos_buf + info->buf_size)
353     {
354         r_flush (rfd, 1);
355         info->pos_buf = mrfd->pos_cur;
356         if (info->pos_buf < info->pos_end)
357             r_reread (rfd);
358     }
359     info->dirty = 1;
360     memcpy (info->buf_mem + (mrfd->pos_cur - info->pos_buf), buf,
361             info->key_size);
362     mrfd->pos_cur = nc;
363     if (nc > info->pos_end)
364         info->pos_border = info->pos_end = nc;
365     return 1;
366 }