IDZEBRA  2.2.7
rstemp.c
Go to the documentation of this file.
1 /* This file is part of the Zebra server.
2  Copyright (C) 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 <yaz/snprintf.h>
37 
38 #include <idzebra/util.h>
39 #include <rset.h>
40 
41 static RSFD r_open(RSET ct, int flag);
42 static void r_close(RSFD rfd);
43 static void r_delete(RSET ct);
44 static int r_read(RSFD rfd, void *buf, TERMID *term);
45 static int r_write(RSFD rfd, const void *buf);
46 static void r_pos(RSFD rfd, double *current, double *total);
47 static void r_flush(RSFD rfd, int mk);
48 static void r_reread(RSFD rfd);
49 
50 static const struct rset_control control =
51 {
52  "temp",
53  r_delete,
55  r_open,
56  r_close,
57  0, /* no forward */
58  r_pos,
59  r_read,
60  r_write,
61 };
62 
63 struct rset_private {
64  int fd; /* file descriptor for temp file */
65  char *fname; /* name of temp file */
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  zint hits; /* no of hits */
73  char *temp_path;
74 };
75 
76 struct rfd_private {
77  void *buf;
78  size_t pos_cur; /* current position in set */
79  /* FIXME - term pos or what ?? */
80  zint cur; /* number of the current hit */
81 };
82 
83 static int log_level = 0;
84 static int log_level_initialized = 0;
85 
86 RSET rset_create_temp(NMEM nmem, struct rset_key_control *kcontrol,
87  int scope, const char *temp_path, TERMID term)
88 {
89  RSET rnew = rset_create_base(&control, nmem, kcontrol, scope, term,
90  0, 0);
91  struct rset_private *info;
93  {
94  log_level = yaz_log_module_level("rstemp");
96  }
97  info = (struct rset_private *) nmem_malloc(rnew->nmem, sizeof(*info));
98  info->fd = -1;
99  info->fname = NULL;
100  info->buf_size = 4096;
101  info->buf_mem = (char *) nmem_malloc(rnew->nmem, info->buf_size);
102  info->pos_end = 0;
103  info->pos_buf = 0;
104  info->dirty = 0;
105  info->hits = 0;
106 
107  if (!temp_path)
108  info->temp_path = NULL;
109  else
110  info->temp_path = nmem_strdup(rnew->nmem, temp_path);
111  rnew->priv = info;
112  return rnew;
113 } /* rstemp_create */
114 
115 static void r_delete(RSET ct)
116 {
117  struct rset_private *info = (struct rset_private*) ct->priv;
118 
119  yaz_log(log_level, "r_delete: set size %ld", (long) info->pos_end);
120  if (info->fname)
121  {
122  yaz_log(log_level, "r_delete: unlink %s", info->fname);
123  unlink(info->fname);
124  }
125 }
126 
127 static RSFD r_open(RSET ct, int flag)
128 {
129  struct rset_private *info = (struct rset_private *) ct->priv;
130  RSFD rfd;
131  struct rfd_private *prfd;
132 
133  if (info->fd == -1 && info->fname)
134  {
135  if (flag & RSETF_WRITE)
136  info->fd = open(info->fname, O_BINARY|O_RDWR|O_CREAT, 0666);
137  else
138  info->fd = open(info->fname, O_BINARY|O_RDONLY);
139  if (info->fd == -1)
140  {
141  yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: open failed %s", info->fname);
142  zebra_exit("r_open");
143  }
144  }
145  rfd = rfd_create_base(ct);
146  if (!rfd->priv)
147  {
148  prfd = (struct rfd_private *) nmem_malloc(ct->nmem, sizeof(*prfd));
149  rfd->priv = (void *)prfd;
150  prfd->buf = nmem_malloc(ct->nmem,ct->keycontrol->key_size);
151  }
152  else
153  prfd= rfd->priv;
154  r_flush(rfd, 0);
155  prfd->pos_cur = 0;
156  info->pos_buf = 0;
157  r_reread(rfd);
158  prfd->cur = 0;
159  return rfd;
160 }
161 
162 /* r_flush:
163  flush current window to file if file is assocated with set
164  */
165 static void r_flush(RSFD rfd, int mk)
166 {
167  struct rset_private *info = rfd->rset->priv;
168 
169  if (!info->fname && mk)
170  {
171 #if HAVE_MKSTEMP
172  char template[1024];
173 
174  if (info->temp_path)
175  yaz_snprintf(template, sizeof(template) - 80,
176  "%s/", info->temp_path);
177  else
178  strcpy(template, "");
179  strcat(template, "zrs_");
180 #if HAVE_UNISTD_H
181  yaz_snprintf(template + strlen(template), 40, "%ld_", (long) getpid());
182 #endif
183  strcat(template, "XXXXXX");
184 
185  info->fd = mkstemp(template);
186  if (info->fd == -1)
187  {
188  yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: mkstemp %s", template);
189  zebra_exit("r_flush");
190  }
191  info->fname = nmem_strdup(rfd->rset->nmem, template);
192 #else
193  char *s = (char*) tempnam(info->temp_path, "zrs");
194 
195  yaz_log(log_level, "creating tempfile %s", s);
196  info->fd = open(s, O_BINARY|O_RDWR|O_CREAT, 0666);
197  if (info->fd == -1)
198  {
199  yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: open %s", s);
200  zebra_exit("r_flush");
201  }
202  info->fname= nmem_strdup(rfd->rset->nmem, s);
203 #endif
204  }
205  if (info->fname && info->fd != -1 && info->dirty)
206  {
207  size_t count;
208  int r;
209 
210  if (lseek(info->fd, info->pos_buf, SEEK_SET) == -1)
211  {
212  yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: lseek (1) %s", info->fname);
213  zebra_exit("r_flusxh");
214  }
215  count = info->buf_size;
216  if (count > info->pos_end - info->pos_buf)
217  count = info->pos_end - info->pos_buf;
218  if ((r = write(info->fd, info->buf_mem, count)) < (int) count)
219  {
220  if (r == -1)
221  yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: write %s", info->fname);
222  else
223  yaz_log(YLOG_FATAL, "rstemp: write of %ld but got %ld",
224  (long) count, (long) r);
225  zebra_exit("r_flush");
226  }
227  info->dirty = 0;
228  }
229 }
230 
231 static void r_close(RSFD rfd)
232 {
233  struct rset_private *info = (struct rset_private *)rfd->rset->priv;
234  if (rfd_is_last(rfd))
235  {
236  r_flush(rfd, 0);
237  if (info->fname && info->fd != -1)
238  {
239  close(info->fd);
240  info->fd = -1;
241  }
242  }
243 }
244 
245 
246 /* r_reread:
247  read from file to window if file is assocated with set -
248  indicated by fname
249  */
250 static void r_reread(RSFD rfd)
251 {
252  struct rfd_private *mrfd = (struct rfd_private*) rfd->priv;
253  struct rset_private *info = (struct rset_private *)rfd->rset->priv;
254 
255  if (info->fname)
256  {
257  size_t count;
258  int r;
259 
260  info->pos_border = mrfd->pos_cur +
261  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  yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: lseek (2) %s fd=%d", info->fname, info->fd);
270  zebra_exit("r_reread");
271  }
272  if ((r = read(info->fd, info->buf_mem, count)) < (int) count)
273  {
274  if (r == -1)
275  yaz_log(YLOG_FATAL|YLOG_ERRNO, "rstemp: read %s", info->fname);
276  else
277  yaz_log(YLOG_FATAL, "read of %ld but got %ld",
278  (long) count, (long) r);
279  zebra_exit("r_reread");
280  }
281  }
282  }
283  else
284  info->pos_border = info->pos_end;
285 }
286 
287 static int r_read(RSFD rfd, void *buf, TERMID *term)
288 {
289  struct rfd_private *mrfd = (struct rfd_private*) rfd->priv;
290  struct rset_private *info = (struct rset_private *)rfd->rset->priv;
291 
292  size_t nc = mrfd->pos_cur + rfd->rset->keycontrol->key_size;
293 
294  if (mrfd->pos_cur < info->pos_buf || nc > info->pos_border)
295  {
296  if (nc > info->pos_end)
297  return 0;
298  r_flush(rfd, 0);
299  info->pos_buf = mrfd->pos_cur;
300  r_reread(rfd);
301  }
302  memcpy(buf, info->buf_mem + (mrfd->pos_cur - info->pos_buf),
303  rfd->rset->keycontrol->key_size);
304  if (term)
305  *term = rfd->rset->term;
306  /* FIXME - should we store and return terms ?? */
307  mrfd->pos_cur = nc;
308  mrfd->cur++;
309  return 1;
310 }
311 
312 static int r_write(RSFD rfd, const void *buf)
313 {
314  struct rfd_private *mrfd = (struct rfd_private*) rfd->priv;
315  struct rset_private *info = (struct rset_private *)rfd->rset->priv;
316 
317  size_t nc = mrfd->pos_cur + rfd->rset->keycontrol->key_size;
318 
319  if (nc > info->pos_buf + info->buf_size)
320  {
321  r_flush(rfd, 1);
322  info->pos_buf = mrfd->pos_cur;
323  if (info->pos_buf < info->pos_end)
324  r_reread(rfd);
325  }
326  info->dirty = 1;
327  memcpy(info->buf_mem + (mrfd->pos_cur - info->pos_buf), buf,
328  rfd->rset->keycontrol->key_size);
329  mrfd->pos_cur = nc;
330  if (nc > info->pos_end)
331  info->pos_border = info->pos_end = nc;
332  info->hits++;
333  return 1;
334 }
335 
336 static void r_pos(RSFD rfd, double *current, double *total)
337 {
338  struct rfd_private *mrfd = (struct rfd_private*) rfd->priv;
339  struct rset_private *info = (struct rset_private *)rfd->rset->priv;
340 
341  *current = (double) mrfd->cur;
342  *total = (double) info->hits;
343 }
344 /*
345  * Local variables:
346  * c-basic-offset: 4
347  * c-file-style: "Stroustrup"
348  * indent-tabs-mode: nil
349  * End:
350  * vim: shiftwidth=4 tabstop=8 expandtab
351  */
352 
#define O_BINARY
Definition: agrep.c:46
int rfd_is_last(RSFD rfd)
Test for last use of RFD.
Definition: rset.c:242
RSET rset_create_base(const struct rset_control *sel, NMEM nmem, struct rset_key_control *kcontrol, int scope, TERMID term, int no_children, RSET *children)
Common constuctor for RSETs.
Definition: rset.c:164
#define RSETF_WRITE
Definition: rset.h:200
RSFD rfd_create_base(RSET rs)
Common constuctor for RFDs.
Definition: rset.c:43
void rset_get_one_term(RSET ct, TERMID *terms, int maxterms, int *curterm)
is a getterms function for those that don't have any
Definition: rset.c:291
static const struct rset_control control
Definition: rstemp.c:50
static int r_write(RSFD rfd, const void *buf)
Definition: rstemp.c:312
static int r_read(RSFD rfd, void *buf, TERMID *term)
Definition: rstemp.c:287
static void r_delete(RSET ct)
Definition: rstemp.c:115
static void r_flush(RSFD rfd, int mk)
Definition: rstemp.c:165
static void r_reread(RSFD rfd)
Definition: rstemp.c:250
static int log_level
Definition: rstemp.c:83
RSET rset_create_temp(NMEM nmem, struct rset_key_control *kcontrol, int scope, const char *temp_path, TERMID term)
Definition: rstemp.c:86
static void r_pos(RSFD rfd, double *current, double *total)
Definition: rstemp.c:336
static int log_level_initialized
Definition: rstemp.c:84
static RSFD r_open(RSET ct, int flag)
Definition: rstemp.c:127
static void r_close(RSFD rfd)
Definition: rstemp.c:231
zint cur
Definition: rstemp.c:80
void * buf
Definition: rsisamb.c:65
size_t pos_cur
Definition: rstemp.c:78
int key_size
Definition: rset.h:128
size_t pos_border
Definition: rstemp.c:70
char * temp_path
Definition: rstemp.c:73
int fd
Definition: rstemp.c:64
size_t pos_buf
Definition: rstemp.c:69
zint hits
Definition: rstemp.c:72
char * buf_mem
Definition: rstemp.c:66
char * fname
Definition: rstemp.c:65
size_t pos_end
Definition: rstemp.c:68
int dirty
Definition: rstemp.c:71
size_t buf_size
Definition: rstemp.c:67
Definition: rset.h:50
Definition: rset.h:151
TERMID term
Definition: rset.h:160
NMEM nmem
Definition: rset.h:156
struct rset_key_control * keycontrol
Definition: rset.h:153
void * priv
Definition: rset.h:155
Definition: rset.h:73
void * priv
Definition: rset.h:75
RSET rset
Definition: rset.h:74
const char * scope
Definition: tstlockscope.c:40
long zint
Zebra integer.
Definition: util.h:66
void zebra_exit(const char *msg)
Definition: exit.c:26