IDZEBRA 2.2.8
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
4Zebra is free software; you can redistribute it and/or modify it under
5the terms of the GNU General Public License as published by the Free
6Software Foundation; either version 2, or (at your option) any later
7version.
8
9Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or
11FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, 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;
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
68
69#define USE_SHELLSORT 0
70
71#if USE_SHELLSORT
72static 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
97static void encode_key_init(struct encode_info *i)
98{
101}
102
103static 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
153static 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
163static 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
191zebra_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
259void 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;
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
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
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
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
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