122c0b4c0a2938ea787cb5938e27dab40e5fcef9
[idzebra-moved-to-github.git] / rset / rstemp.c
1 /* $Id: rstemp.c,v 1.68 2006-08-14 10:40:21 adam Exp $
2    Copyright (C) 1995-2006
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 this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
21 */
22
23 #include <assert.h>
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #ifdef WIN32
29 #include <io.h>
30 #endif
31 #if HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #include <sys/types.h>
35
36 #include <idzebra/util.h>
37 #include <rset.h>
38
39 static RSFD r_open(RSET ct, int flag);
40 static void r_close(RSFD rfd);
41 static void r_delete(RSET ct);
42 static int r_read(RSFD rfd, void *buf, TERMID *term);
43 static int r_write(RSFD rfd, const void *buf);
44 static void r_pos(RSFD rfd, double *current, double  *total);
45 static void r_flush(RSFD rfd, int mk);
46 static void r_reread(RSFD rfd);
47
48 static const struct rset_control control = 
49 {
50     "temp",
51     r_delete,
52     rset_get_one_term,
53     r_open,
54     r_close,
55     0, /* no forward */
56     r_pos, 
57     r_read,
58     r_write,
59 };
60
61 struct rset_private {
62     int     fd;            /* file descriptor for temp file */
63     char   *fname;         /* name of temp file */
64     char   *buf_mem;       /* window buffer */
65     size_t  buf_size;      /* size of window */
66     size_t  pos_end;       /* last position in set */
67     size_t  pos_buf;       /* position of first byte in window */
68     size_t  pos_border;    /* position of last byte+1 in window */
69     int     dirty;         /* window is dirty */
70     zint    hits;          /* no of hits */
71     char   *temp_path;
72 };
73
74 struct rfd_private {
75     void *buf;
76     size_t  pos_cur;       /* current position in set */
77                            /* FIXME - term pos or what ??  */
78     zint cur; /* number of the current hit */
79 };
80
81 static int log_level = 0;
82 static int log_level_initialized = 0;
83
84 RSET rset_create_temp(NMEM nmem, struct rset_key_control *kcontrol,
85                       int scope, const char *temp_path, TERMID term)
86 {
87     RSET rnew = rset_create_base(&control, nmem, kcontrol, scope, term,
88                                  0, 0);
89     struct rset_private *info;
90     if (!log_level_initialized)
91     {
92         log_level = yaz_log_module_level("rstemp");
93         log_level_initialized = 1;
94     }
95     info = (struct rset_private *) nmem_malloc(rnew->nmem, sizeof(*info));
96     info->fd = -1;
97     info->fname = NULL;
98     info->buf_size = 4096;
99     info->buf_mem = (char *) nmem_malloc(rnew->nmem, info->buf_size);
100     info->pos_end = 0;
101     info->pos_buf = 0;
102     info->dirty = 0;
103     info->hits = 0;
104
105     if (!temp_path)
106         info->temp_path = NULL;
107     else
108         info->temp_path = nmem_strdup(rnew->nmem, temp_path);
109     rnew->priv = info; 
110     return rnew;
111 } /* rstemp_create */
112
113 static void r_delete(RSET ct)
114 {
115     struct rset_private *info = (struct rset_private*) ct->priv;
116
117     yaz_log(log_level, "r_delete: set size %ld", (long) info->pos_end);
118     if (info->fname)
119     {
120         yaz_log(log_level, "r_delete: unlink %s", info->fname);
121         unlink(info->fname);
122     }
123 }
124
125 static RSFD r_open(RSET ct, int flag)
126 {
127     struct rset_private *info = (struct rset_private *) ct->priv;
128     RSFD rfd;
129     struct rfd_private *prfd;
130
131     if (info->fd == -1 && info->fname)
132     {
133         if (flag & RSETF_WRITE)
134             info->fd = open(info->fname, O_BINARY|O_RDWR|O_CREAT, 0666);
135         else
136             info->fd = open(info->fname, O_BINARY|O_RDONLY);
137         if (info->fd == -1)
138         {
139             yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: open failed %s", info->fname);
140             exit(1);
141         }
142     }
143     rfd = rfd_create_base(ct);
144     if (!rfd->priv)
145     {
146         prfd = (struct rfd_private *) nmem_malloc(ct->nmem, sizeof(*prfd));
147         rfd->priv = (void *)prfd;
148         prfd->buf = nmem_malloc(ct->nmem,ct->keycontrol->key_size);
149     } 
150     else
151         prfd= rfd->priv;
152     r_flush(rfd, 0);
153     prfd->pos_cur = 0;
154     info->pos_buf = 0;
155     r_reread(rfd);
156     prfd->cur = 0;
157     return rfd;
158 }
159
160 /* r_flush:
161       flush current window to file if file is assocated with set
162  */
163 static void r_flush(RSFD rfd, int mk)
164 {
165     struct rset_private *info = rfd->rset->priv;
166
167     if (!info->fname && mk)
168     {
169 #if HAVE_MKSTEMP
170         char template[1024];
171         if (info->temp_path)
172             sprintf(template, "%s/zrsXXXXXX", info->temp_path);
173         else
174             sprintf(template, "zrsXXXXXX");
175
176         info->fd = mkstemp(template);
177
178         if (info->fd == -1)
179         {
180             yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: mkstemp %s", template);
181             exit(1);
182         }
183         info->fname = nmem_strdup(rfd->rset->nmem, template);
184 #else
185         char *s = (char*) tempnam(info->temp_path, "zrs");
186         info->fname= nmem_strdup(rfd->rset->nmem, s);
187
188         yaz_log(log_level, "creating tempfile %s", info->fname);
189         info->fd = open(info->fname, O_BINARY|O_RDWR|O_CREAT, 0666);
190         if (info->fd == -1)
191         {
192             yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: open %s", info->fname);
193             exit(1);
194         }
195 #endif
196     }
197     if (info->fname && info->fd != -1 && info->dirty)
198     {
199         size_t count;
200         int r;
201         
202         if (lseek(info->fd, info->pos_buf, SEEK_SET) == -1)
203         {
204             yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: lseek (1) %s", info->fname);
205             exit(1);
206         }
207         count = info->buf_size;
208         if (count > info->pos_end - info->pos_buf)
209             count = info->pos_end - info->pos_buf;
210         if ((r = write(info->fd, info->buf_mem, count)) < (int) count)
211         {
212             if (r == -1)
213                 yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: write %s", info->fname);
214             else
215                 yaz_log(YLOG_FATAL, "rstemp: write of %ld but got %ld",
216                       (long) count, (long) r);
217             exit(1);
218         }
219         info->dirty = 0;
220     }
221 }
222
223 static void r_close(RSFD rfd)
224 {
225     struct rset_private *info = (struct rset_private *)rfd->rset->priv;
226     if (rfd_is_last(rfd))
227     {
228         r_flush(rfd, 0);
229         if (info->fname && info->fd != -1)
230         {
231             close(info->fd);
232             info->fd = -1;
233         }
234     }
235 }
236
237
238 /* r_reread:
239       read from file to window if file is assocated with set -
240       indicated by fname
241  */
242 static void r_reread(RSFD rfd)
243 {
244     struct rfd_private *mrfd = (struct rfd_private*) rfd->priv; 
245     struct rset_private *info = (struct rset_private *)rfd->rset->priv;
246
247     if (info->fname)
248     {
249         size_t count;
250         int r;
251
252         info->pos_border = mrfd->pos_cur +
253             info->buf_size;
254         if (info->pos_border > info->pos_end)
255             info->pos_border = info->pos_end;
256         count = info->pos_border - info->pos_buf;
257         if (count > 0)
258         {
259             if (lseek(info->fd, info->pos_buf, SEEK_SET) == -1)
260             {
261                 yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: lseek (2) %s fd=%d", info->fname, info->fd);
262                 exit(1);
263             }
264             if ((r = read(info->fd, info->buf_mem, count)) < (int) count)
265             {
266                 if (r == -1)
267                     yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: read %s", info->fname);
268                 else
269                     yaz_log(YLOG_FATAL, "read of %ld but got %ld",
270                           (long) count, (long) r);
271                 exit(1);
272             }
273         }
274     }
275     else
276         info->pos_border = info->pos_end;
277 }
278
279 static int r_read(RSFD rfd, void *buf, TERMID *term)
280 {
281     struct rfd_private *mrfd = (struct rfd_private*) rfd->priv;  
282     struct rset_private *info = (struct rset_private *)rfd->rset->priv;
283
284     size_t nc = mrfd->pos_cur + rfd->rset->keycontrol->key_size;
285
286     if (mrfd->pos_cur < info->pos_buf || nc > info->pos_border)
287     {
288         if (nc > info->pos_end)
289             return 0;
290         r_flush(rfd, 0);
291         info->pos_buf = mrfd->pos_cur;
292         r_reread(rfd);
293     }
294     memcpy(buf, info->buf_mem + (mrfd->pos_cur - info->pos_buf),
295             rfd->rset->keycontrol->key_size);
296     if (term)
297         *term = rfd->rset->term; 
298         /* FIXME - should we store and return terms ?? */
299     mrfd->pos_cur = nc;
300     mrfd->cur++;
301     return 1;
302 }
303
304 static int r_write(RSFD rfd, const void *buf)
305 {
306     struct rfd_private *mrfd = (struct rfd_private*) rfd->priv;  
307     struct rset_private *info = (struct rset_private *)rfd->rset->priv;
308
309     size_t nc = mrfd->pos_cur + rfd->rset->keycontrol->key_size;
310
311     if (nc > info->pos_buf + info->buf_size)
312     {
313         r_flush(rfd, 1);
314         info->pos_buf = mrfd->pos_cur;
315         if (info->pos_buf < info->pos_end)
316             r_reread(rfd);
317     }
318     info->dirty = 1;
319     memcpy(info->buf_mem + (mrfd->pos_cur - info->pos_buf), buf,
320             rfd->rset->keycontrol->key_size);
321     mrfd->pos_cur = nc;
322     if (nc > info->pos_end)
323         info->pos_border = info->pos_end = nc;
324     info->hits++;
325     return 1;
326 }
327
328 static void r_pos(RSFD rfd, double  *current, double  *total)
329 {
330     struct rfd_private *mrfd = (struct rfd_private*) rfd->priv;  
331     struct rset_private *info = (struct rset_private *)rfd->rset->priv;
332     
333     *current = (double) mrfd->cur;
334     *total = (double) info->hits;
335 }
336 /*
337  * Local variables:
338  * c-basic-offset: 4
339  * indent-tabs-mode: nil
340  * End:
341  * vim: shiftwidth=4 tabstop=8 expandtab
342  */
343