IDZEBRA  2.2.7
key_block.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 <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <ctype.h>
28 
29 #if YAZ_POSIX_THREADS
30 #include <pthread.h>
31 #endif
32 
33 #include "key_block.h"
34 #include <yaz/nmem.h>
35 #include <yaz/xmalloc.h>
36 #include <yaz/snprintf.h>
37 
39  char **key_buf;
40  size_t ptr_top;
41  size_t ptr_i;
42  size_t key_buf_used;
44  char *key_tmp_dir;
46  char **alt_buf;
47 #if YAZ_POSIX_THREADS
48  char **thread_key_buf;
49  size_t thread_ptr_top;
50  size_t thread_ptr_i;
51  int exit_flag;
52  pthread_t thread_id;
53  pthread_mutex_t mutex;
54 
55  pthread_cond_t work_available;
56 
57  pthread_cond_t cond_sorting;
58  int is_sorting;
59 #endif
60 };
61 
62 #define ENCODE_BUFLEN 768
63 struct encode_info {
67 };
68 
69 #define USE_SHELLSORT 0
70 
71 #if USE_SHELLSORT
72 static void shellsort(void *ar, int r, size_t s,
73  int (*cmp)(const void *a, const void *b))
74 {
75  char *a = ar;
76  char v[100];
77  int h, i, j, k;
78  static const int incs[16] = { 1391376, 463792, 198768, 86961, 33936,
79  13776, 4592, 1968, 861, 336,
80  112, 48, 21, 7, 3, 1 };
81  for ( k = 0; k < 16; k++)
82  for (h = incs[k], i = h; i < r; i++)
83  {
84  memcpy (v, a+s*i, s);
85  j = i;
86  while (j > h && (*cmp)(a + s*(j-h), v) > 0)
87  {
88  memcpy (a + s*j, a + s*(j-h), s);
89  j -= h;
90  }
91  memcpy (a+s*j, v, s);
92  }
93 }
94 #endif
95 
96 
97 static void encode_key_init(struct encode_info *i)
98 {
100  i->decode_handle = iscz1_start();
101 }
102 
103 static void encode_key_write(const char *k, struct encode_info *i, FILE *outf)
104 {
105  struct it_key key;
106  char *bp = i->buf, *bp0;
107  const char *src = (char *) &key;
108  size_t klen = strlen(k);
109 
110  if (fwrite (k, klen+1, 1, outf) != 1)
111  {
112  yaz_log (YLOG_FATAL|YLOG_ERRNO, "fwrite");
113  zebra_exit("encode_key_write");
114  }
115 
116  k = k + klen+1;
117 
118  /* and copy & align key so we can mangle */
119  memcpy (&key, k+1, sizeof(struct it_key)); /* *k is insert/delete */
120 
121 #if 0
122  /* debugging */
123  key_logdump_txt(YLOG_LOG, &key, *k ? "i" : "d");
124 #endif
125  assert(key.mem[0] >= 0);
126 
127  bp0 = bp++;
128  iscz1_encode(i->encode_handle, &bp, &src);
129 
130  *bp0 = (*k * 128) + bp - bp0 - 1; /* length and insert/delete combined */
131  if (fwrite (i->buf, bp - i->buf, 1, outf) != 1)
132  {
133  yaz_log (YLOG_FATAL|YLOG_ERRNO, "fwrite");
134  zebra_exit("encode_key_write");
135  }
136 
137 #if 0
138  /* debugging */
139  if (1)
140  {
141  struct it_key key2;
142  const char *src = bp0+1;
143  char *dst = (char*) &key2;
144  iscz1_decode(i->decode_handle, &dst, &src);
145 
146  key_logdump_txt(YLOG_LOG, &key2, *k ? "i" : "d");
147 
148  assert(key2.mem[1]);
149  }
150 #endif
151 }
152 
153 static void encode_key_flush (struct encode_info *i, FILE *outf)
154 {
157 }
158 
160  char **key_buf, size_t ptr_top, size_t ptr_i);
161 
162 #if YAZ_POSIX_THREADS
163 static void *thread_func(void *vp)
164 {
166  while (1)
167  {
168  pthread_mutex_lock(&p->mutex);
169 
170  while (!p->is_sorting && !p->exit_flag)
171  pthread_cond_wait(&p->work_available, &p->mutex);
172 
173  if (p->exit_flag)
174  break;
175 
176  pthread_mutex_unlock(&p->mutex);
177 
178  key_block_flush_int(p, p->thread_key_buf,
179  p->thread_ptr_top, p->thread_ptr_i);
180 
181  pthread_mutex_lock(&p->mutex);
182  p->is_sorting = 0;
183  pthread_cond_signal(&p->cond_sorting);
184  pthread_mutex_unlock(&p->mutex);
185  }
186  pthread_mutex_unlock(&p->mutex);
187  return 0;
188 }
189 #endif
190 
191 zebra_key_block_t key_block_create(size_t mem, const char *key_tmp_dir,
192  int use_threads)
193 {
194  zebra_key_block_t p = xmalloc(sizeof(*p));
195 
196 #if YAZ_POSIX_THREADS
197  /* we'll be making two memory areas so cut in half */
198  if (use_threads)
199  mem = mem / 2;
200 #endif
201  p->key_buf = (char**) xmalloc (mem);
202  p->ptr_top = mem/sizeof(char*);
203  p->ptr_i = 0;
204  p->key_buf_used = 0;
205  p->key_tmp_dir = xstrdup(key_tmp_dir);
206  p->key_file_no = 0;
207  p->alt_buf = 0;
208  p->use_threads = 0;
209  if (use_threads)
210  {
211 #if YAZ_POSIX_THREADS
212  p->use_threads = use_threads;
213  p->is_sorting = 0;
214  p->exit_flag = 0;
215  pthread_mutex_init(&p->mutex, 0);
216  pthread_cond_init(&p->work_available, 0);
217  pthread_cond_init(&p->cond_sorting, 0);
218  pthread_create(&p->thread_id, 0, thread_func, p);
219  p->alt_buf = (char**) xmalloc (mem);
220 #endif
221  }
222  yaz_log(YLOG_DEBUG, "key_block_create t=%d", p->use_threads);
223  return p;
224 }
225 
227 {
228  zebra_key_block_t p = *pp;
229  if (p)
230  {
231  if (p->use_threads)
232  {
233 #if YAZ_POSIX_THREADS
234  pthread_mutex_lock(&p->mutex);
235 
236  while (p->is_sorting)
237  pthread_cond_wait(&p->cond_sorting, &p->mutex);
238 
239  p->exit_flag = 1;
240 
241  pthread_cond_broadcast(&p->work_available);
242 
243  pthread_mutex_unlock(&p->mutex);
244  pthread_join(p->thread_id, 0);
245  pthread_cond_destroy(&p->work_available);
246  pthread_cond_destroy(&p->cond_sorting);
247  pthread_mutex_destroy(&p->mutex);
248 
249 #endif
250  xfree(p->alt_buf);
251  }
252  xfree(p->key_buf);
253  xfree(p->key_tmp_dir);
254  xfree(p);
255  *pp = 0;
256  }
257 }
258 
259 void key_block_write(zebra_key_block_t p, zint sysno, struct it_key *key_in,
260  int cmd, const char *str_buf, size_t str_len,
261  zint staticrank, int static_rank_enable)
262 {
263  int ch;
264  int i, j = 0;
265  struct it_key key_out;
266 
267  if (p->key_buf_used + 1024 > (p->ptr_top -p->ptr_i)*sizeof(char*))
268  key_block_flush(p, 0);
269  ++(p->ptr_i);
270  assert(p->ptr_i > 0);
271  (p->key_buf)[p->ptr_top - p->ptr_i] =
272  (char*)p->key_buf + p->key_buf_used;
273 
274  /* key_in->mem[0] ord/ch */
275  /* key_in->mem[1] filter specified record ID */
276 
277  /* encode the ordinal value (field/use/attribute) .. */
278  ch = CAST_ZINT_TO_INT(key_in->mem[0]);
279  p->key_buf_used +=
280  key_SU_encode(ch, (char*)p->key_buf +
281  p->key_buf_used);
282 
283  /* copy the 0-terminated stuff from str to output */
284  memcpy((char*)p->key_buf + p->key_buf_used, str_buf, str_len);
285  p->key_buf_used += str_len;
286  ((char*)p->key_buf)[(p->key_buf_used)++] = '\0';
287 
288  /* the delete/insert indicator */
289  ((char*)p->key_buf)[(p->key_buf_used)++] = cmd;
290 
291  if (static_rank_enable)
292  {
293  assert(staticrank >= 0);
294  key_out.mem[j++] = staticrank;
295  }
296 
297  if (key_in->mem[1]) /* filter specified record ID */
298  key_out.mem[j++] = key_in->mem[1];
299  else
300  key_out.mem[j++] = sysno;
301  for (i = 2; i < key_in->len; i++)
302  key_out.mem[j++] = key_in->mem[i];
303  key_out.len = j;
304 
305  memcpy((char*)p->key_buf + p->key_buf_used,
306  &key_out, sizeof(key_out));
307  (p->key_buf_used) += sizeof(key_out);
308 }
309 
310 
312  char **key_buf, size_t ptr_top, size_t ptr_i)
313 {
314  FILE *outf;
315  char out_fname[200];
316  char *prevcp, *cp;
317  struct encode_info encode_info;
318 
319  if (ptr_i == 0)
320  return ;
321 
322  (p->key_file_no)++;
323  yaz_log(YLOG_DEBUG, "sorting section %d", (p->key_file_no));
324 
325  assert(ptr_i > 0);
326 
327 #if USE_SHELLSORT
328  shellsort(key_buf + ptr_top - ptr_i, ptr_i,
329  sizeof(char*), key_qsort_compare);
330 #else
331  qsort(key_buf + ptr_top - ptr_i, ptr_i,
332  sizeof(char*), key_qsort_compare);
333 #endif
334  yaz_snprintf(out_fname, sizeof(out_fname), "%s/key%d.tmp",
335  p->key_tmp_dir, p->key_file_no);
336 
337  if (!(outf = fopen (out_fname, "wb")))
338  {
339  yaz_log (YLOG_FATAL|YLOG_ERRNO, "fopen %s", out_fname);
340  zebra_exit("key_block_flush");
341  }
342  yaz_log(YLOG_DEBUG, "writing section %d", p->key_file_no);
343  prevcp = cp = (key_buf)[ptr_top - ptr_i];
344 
347 
348  while (--ptr_i > 0)
349  {
350  cp = (key_buf)[ptr_top - ptr_i];
351  if (strcmp (cp, prevcp))
352  {
356  prevcp = cp;
357  }
358  else
359  encode_key_write (cp + strlen(cp), &encode_info, outf);
360  }
362  if (fclose (outf))
363  {
364  yaz_log (YLOG_FATAL|YLOG_ERRNO, "fclose %s", out_fname);
365  zebra_exit("key_block_flush");
366  }
367  yaz_log(YLOG_DEBUG, "finished section %d", p->key_file_no);
368 }
369 
370 void key_block_flush(zebra_key_block_t p, int is_final)
371 {
372  if (!p)
373  return;
374 
375  if (p->use_threads)
376  {
377 #if YAZ_POSIX_THREADS
378  char **tmp;
379 
380  pthread_mutex_lock(&p->mutex);
381 
382  while (p->is_sorting)
383  pthread_cond_wait(&p->cond_sorting, &p->mutex);
384 
385  p->is_sorting = 1;
386 
387  p->thread_ptr_top = p->ptr_top;
388  p->thread_ptr_i = p->ptr_i;
389  p->thread_key_buf = p->key_buf;
390 
391  tmp = p->key_buf;
392  p->key_buf = p->alt_buf;
393  p->alt_buf = tmp;
394 
395  pthread_cond_signal(&p->work_available);
396 
397  if (is_final)
398  {
399  while (p->is_sorting)
400  pthread_cond_wait(&p->cond_sorting, &p->mutex);
401  }
402  pthread_mutex_unlock(&p->mutex);
403 #endif
404  }
405  else
406  key_block_flush_int(p, p->key_buf, p->ptr_top, p->ptr_i);
407  p->ptr_i = 0;
408  p->key_buf_used = 0;
409 }
410 
412 {
413  if (p)
414  return p->key_file_no;
415  return 0;
416 }
417 
418 /*
419  * Local variables:
420  * c-basic-offset: 4
421  * c-file-style: "Stroustrup"
422  * indent-tabs-mode: nil
423  * End:
424  * vim: shiftwidth=4 tabstop=8 expandtab
425  */
426 
void * iscz1_start(void)
Definition: it_key.c:130
void iscz1_decode(void *vp, char **dst, const char **src)
Definition: it_key.c:238
void iscz1_encode(void *vp, char **dst, const char **src)
Definition: it_key.c:190
int key_qsort_compare(const void *p1, const void *p2)
Definition: it_key.c:111
void key_logdump_txt(int logmask, const void *p, const char *txt)
Definition: it_key.c:38
int key_SU_encode(int ch, char *out)
Definition: su_codec.c:31
void iscz1_stop(void *p)
Definition: it_key.c:155
#define ENCODE_BUFLEN
Definition: key_block.c:62
void key_block_flush(zebra_key_block_t p, int is_final)
Definition: key_block.c:370
void key_block_flush_int(zebra_key_block_t p, char **key_buf, size_t ptr_top, size_t ptr_i)
Definition: key_block.c:311
zebra_key_block_t key_block_create(size_t mem, const char *key_tmp_dir, int use_threads)
Definition: key_block.c:191
static void encode_key_flush(struct encode_info *i, FILE *outf)
Definition: key_block.c:153
void key_block_write(zebra_key_block_t p, zint sysno, struct it_key *key_in, int cmd, const char *str_buf, size_t str_len, zint staticrank, int static_rank_enable)
Definition: key_block.c:259
static void encode_key_init(struct encode_info *i)
Definition: key_block.c:97
void key_block_destroy(zebra_key_block_t *pp)
Definition: key_block.c:226
int key_block_get_no_files(zebra_key_block_t p)
Definition: key_block.c:411
static void encode_key_write(const char *k, struct encode_info *i, FILE *outf)
Definition: key_block.c:103
struct zebra_key_block * zebra_key_block_t
Definition: key_block.h:27
static FILE * outf
Definition: readfile.c:38
void * decode_handle
Definition: key_block.c:65
char buf[ENCODE_BUFLEN]
Definition: key_block.c:66
void * encode_handle
Definition: key_block.c:64
Definition: it_key.h:30
int len
Definition: it_key.h:31
zint mem[IT_KEY_LEVEL_MAX]
Definition: it_key.h:32
char * key_tmp_dir
Definition: key_block.c:44
size_t ptr_top
Definition: key_block.c:40
size_t ptr_i
Definition: key_block.c:41
char ** alt_buf
Definition: key_block.c:46
char ** key_buf
Definition: key_block.c:39
size_t key_buf_used
Definition: key_block.c:42
long zint
Zebra integer.
Definition: util.h:66
void zebra_exit(const char *msg)
Definition: exit.c:26
#define CAST_ZINT_TO_INT(x)
Definition: util.h:96