RPM: get version from IDMETA
[idzebra-moved-to-github.git] / rset / rstemp.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 1994-2011 Index Data
3
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
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             zebra_exit("r_open");
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
172         *template = '\0';
173
174         if (info->temp_path)
175             sprintf(template, "%s/", info->temp_path);
176         strcat(template, "zrs_");
177 #if HAVE_UNISTD_H
178         sprintf(template + strlen(template), "%ld_", (long) getpid());
179 #endif
180         strcat(template, "XXXXXX");
181
182         info->fd = mkstemp(template);
183         if (info->fd == -1)
184         {
185             yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: mkstemp %s", template);
186             zebra_exit("r_flush");
187         }
188         info->fname = nmem_strdup(rfd->rset->nmem, template);
189 #else
190         char *s = (char*) tempnam(info->temp_path, "zrs");
191         info->fname= nmem_strdup(rfd->rset->nmem, s);
192
193         yaz_log(log_level, "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             yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: open %s", info->fname);
198             zebra_exit("r_flush");
199         }
200 #endif
201     }
202     if (info->fname && info->fd != -1 && info->dirty)
203     {
204         size_t count;
205         int r;
206         
207         if (lseek(info->fd, info->pos_buf, SEEK_SET) == -1)
208         {
209             yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: lseek (1) %s", info->fname);
210             zebra_exit("r_flusxh");
211         }
212         count = info->buf_size;
213         if (count > info->pos_end - info->pos_buf)
214             count = info->pos_end - info->pos_buf;
215         if ((r = write(info->fd, info->buf_mem, count)) < (int) count)
216         {
217             if (r == -1)
218                 yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: write %s", info->fname);
219             else
220                 yaz_log(YLOG_FATAL, "rstemp: write of %ld but got %ld",
221                       (long) count, (long) r);
222             zebra_exit("r_flush");
223         }
224         info->dirty = 0;
225     }
226 }
227
228 static void r_close(RSFD rfd)
229 {
230     struct rset_private *info = (struct rset_private *)rfd->rset->priv;
231     if (rfd_is_last(rfd))
232     {
233         r_flush(rfd, 0);
234         if (info->fname && info->fd != -1)
235         {
236             close(info->fd);
237             info->fd = -1;
238         }
239     }
240 }
241
242
243 /* r_reread:
244       read from file to window if file is assocated with set -
245       indicated by fname
246  */
247 static void r_reread(RSFD rfd)
248 {
249     struct rfd_private *mrfd = (struct rfd_private*) rfd->priv; 
250     struct rset_private *info = (struct rset_private *)rfd->rset->priv;
251
252     if (info->fname)
253     {
254         size_t count;
255         int r;
256
257         info->pos_border = mrfd->pos_cur +
258             info->buf_size;
259         if (info->pos_border > info->pos_end)
260             info->pos_border = info->pos_end;
261         count = info->pos_border - info->pos_buf;
262         if (count > 0)
263         {
264             if (lseek(info->fd, info->pos_buf, SEEK_SET) == -1)
265             {
266                 yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: lseek (2) %s fd=%d", info->fname, info->fd);
267                 zebra_exit("r_reread");
268             }
269             if ((r = read(info->fd, info->buf_mem, count)) < (int) count)
270             {
271                 if (r == -1)
272                     yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: read %s", info->fname);
273                 else
274                     yaz_log(YLOG_FATAL, "read of %ld but got %ld",
275                           (long) count, (long) r);
276                 zebra_exit("r_reread");
277             }
278         }
279     }
280     else
281         info->pos_border = info->pos_end;
282 }
283
284 static int r_read(RSFD rfd, void *buf, TERMID *term)
285 {
286     struct rfd_private *mrfd = (struct rfd_private*) rfd->priv;  
287     struct rset_private *info = (struct rset_private *)rfd->rset->priv;
288
289     size_t nc = mrfd->pos_cur + rfd->rset->keycontrol->key_size;
290
291     if (mrfd->pos_cur < info->pos_buf || nc > info->pos_border)
292     {
293         if (nc > info->pos_end)
294             return 0;
295         r_flush(rfd, 0);
296         info->pos_buf = mrfd->pos_cur;
297         r_reread(rfd);
298     }
299     memcpy(buf, info->buf_mem + (mrfd->pos_cur - info->pos_buf),
300             rfd->rset->keycontrol->key_size);
301     if (term)
302         *term = rfd->rset->term; 
303         /* FIXME - should we store and return terms ?? */
304     mrfd->pos_cur = nc;
305     mrfd->cur++;
306     return 1;
307 }
308
309 static int r_write(RSFD rfd, const void *buf)
310 {
311     struct rfd_private *mrfd = (struct rfd_private*) rfd->priv;  
312     struct rset_private *info = (struct rset_private *)rfd->rset->priv;
313
314     size_t nc = mrfd->pos_cur + rfd->rset->keycontrol->key_size;
315
316     if (nc > info->pos_buf + info->buf_size)
317     {
318         r_flush(rfd, 1);
319         info->pos_buf = mrfd->pos_cur;
320         if (info->pos_buf < info->pos_end)
321             r_reread(rfd);
322     }
323     info->dirty = 1;
324     memcpy(info->buf_mem + (mrfd->pos_cur - info->pos_buf), buf,
325             rfd->rset->keycontrol->key_size);
326     mrfd->pos_cur = nc;
327     if (nc > info->pos_end)
328         info->pos_border = info->pos_end = nc;
329     info->hits++;
330     return 1;
331 }
332
333 static void r_pos(RSFD rfd, double  *current, double  *total)
334 {
335     struct rfd_private *mrfd = (struct rfd_private*) rfd->priv;  
336     struct rset_private *info = (struct rset_private *)rfd->rset->priv;
337     
338     *current = (double) mrfd->cur;
339     *total = (double) info->hits;
340 }
341 /*
342  * Local variables:
343  * c-basic-offset: 4
344  * c-file-style: "Stroustrup"
345  * indent-tabs-mode: nil
346  * End:
347  * vim: shiftwidth=4 tabstop=8 expandtab
348  */
349