IDZEBRA 2.2.11
benchindex1.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 <yaz/options.h>
24#include <ctype.h>
25#include <stdlib.h>
26#include <string.h>
27#include <yaz/log.h>
28#include <yaz/nmem.h>
29#include <yaz/xmalloc.h>
30#include <yaz/marcdisp.h>
31#include <yaz/timing.h>
32#include <it_key.h>
33#include <idzebra/isamb.h>
34#include <idzebra/dict.h>
35#include <idzebra/version.h>
36#include <assert.h>
37
39 NMEM nmem;
44 struct index_term **ar;
45 int round;
46};
47
48struct index_term {
49 const char *term;
54};
55
56struct index_block *index_block_new(int memory)
57{
58 struct index_block *b = xmalloc(sizeof(*b));
59 b->no_entries = 0;
60 b->current_max = memory * 1024 * 1024;
61 b->terms = 0;
62 b->nmem = nmem_create();
63 b->round = 0;
64 return b;
65}
66
68{
69 if (*bp)
70 {
71 nmem_destroy((*bp)->nmem);
72 xfree(*bp);
73 *bp = 0;
74 }
75}
76
77static int cmp_ar(const void *p1, const void *p2)
78{
79 struct index_term *t1 = *(struct index_term **) p1;
80 struct index_term *t2 = *(struct index_term **) p2;
81 int d = strcmp(t1->term, t2->term);
82 if (d)
83 return d;
84
85 if (t1->docid > t2->docid)
86 return 1;
87 else if (t1->docid < t2->docid)
88 return -1;
89 if (t1->seqno > t2->seqno)
90 return 1;
91 else if (t1->seqno < t2->seqno)
92 return -1;
93 return 0;
94}
95
96
97int code_read(void *vp, char **dst, int *insertMode)
98{
99 struct index_block *b = (struct index_block *)vp;
100 struct index_term *t;
101 struct it_key key;
102
103 if (b->current_entry >= b->no_entries)
104 return 0;
105
106 t = b->ar[b->current_entry];
107 b->current_entry++;
108
109 key.len = 3;
110 key.mem[0] = t->word_id;
111 key.mem[1] = t->docid;
112 key.mem[2] = t->seqno;
113 key.mem[3] = 0;
114
115 memcpy(*dst, &key, sizeof(key));
116
117 (*dst) += sizeof(key);
118 *insertMode = 1;
119#if 0
120 yaz_log(YLOG_LOG, "returning " ZINT_FORMAT " " ZINT_FORMAT "\n",
121 key.mem[0], key.mem[1]);
122#endif
123 return 1;
124}
125
127 int no_docs)
128{
129 struct index_term *t = b->terms;
130 int i;
131 int word_id_seq = 0;
132 int no_words = 0, no_new_words = 0;
133 const char *dict_info = 0;
134 ISAM_P isamc_p = 0;
135 yaz_timing_t tim_dict = 0;
136 yaz_timing_t tim_isamb = 0;
137 zint number_of_int_splits = isamb_get_int_splits(isb);
138 zint number_of_leaf_splits = isamb_get_leaf_splits(isb);
139 zint number_of_dict_splits = dict_get_no_split(dict);
140
141 b->ar = xmalloc(sizeof(*b->ar) * b->no_entries);
142 for (i = 0; i < b->no_entries; i++, t = t->next)
143 {
144 assert(t);
145 b->ar[i] = t;
146 }
147 assert(!t);
148
149 qsort(b->ar, b->no_entries, sizeof(*b->ar), cmp_ar);
150 tim_dict = yaz_timing_create();
151#if 0
152 for (i = 0; i < b->no_entries; i++)
153 {
154 printf("%s " ZINT_FORMAT " " ZINT_FORMAT "\n",
155 ar[i]->term, ar[i]->docid, ar[i]->seqno);
156 }
157#endif
158 dict_info = dict_lookup(dict, "_w");
159 if (dict_info)
160 {
161 assert(*dict_info == sizeof(word_id_seq));
162 memcpy(&word_id_seq, dict_info+1, sizeof(word_id_seq));
163 }
164
165 dict_info = dict_lookup(dict, "_i");
166 if (dict_info)
167 {
168 assert(*dict_info == sizeof(isamc_p));
169 memcpy(&isamc_p, dict_info+1, sizeof(isamc_p));
170 }
171
172 for (i = 0; i < b->no_entries; i++)
173 {
174 if (i > 0 && strcmp(b->ar[i-1]->term, b->ar[i]->term) == 0)
175 b->ar[i]->word_id = b->ar[i-1]->word_id;
176 else
177 {
178 const char *dict_info = dict_lookup(dict, b->ar[i]->term);
179 if (dict_info)
180 {
181 memcpy(&b->ar[i]->word_id, dict_info+1, sizeof(int));
182 }
183 else
184 {
185 word_id_seq++;
186 no_new_words++;
187 dict_insert(dict, b->ar[i]->term, sizeof(int), &word_id_seq);
188 b->ar[i]->word_id = word_id_seq;
189 }
190 no_words++;
191 }
192 }
193 dict_insert(dict, "_w", sizeof(word_id_seq), &word_id_seq);
194
195 yaz_timing_stop(tim_dict);
196 tim_isamb = yaz_timing_create();
197
198 b->current_entry = 0;
199
200 if (b->no_entries)
201 {
202 ISAMC_I isamc_i;
203
204 isamc_i.clientData = b;
205 isamc_i.read_item = code_read;
206
207 isamb_merge (isb, &isamc_p, &isamc_i);
208
209 assert(isamc_p);
210 dict_insert(dict, "_i", sizeof(isamc_p), &isamc_p);
211 }
212
213 yaz_timing_stop(tim_isamb);
214
215 number_of_int_splits = isamb_get_int_splits(isb) - number_of_int_splits;
216 number_of_leaf_splits = isamb_get_leaf_splits(isb) - number_of_leaf_splits;
217 number_of_dict_splits = dict_get_no_split(dict) - number_of_dict_splits;
218
219 if (b->round == 0)
220 {
221 printf("# run total dict-real user sys isam-real user sys "
222 " intsp leafsp docs postings words new d-spl\n");
223 }
224 b->round++;
225 printf("%5d %9.6f %9.6f %5.2f %5.2f %9.6f %5.2f %5.2f "
226 "%6" ZINT_FORMAT0 " %6" ZINT_FORMAT0
227 " %8d %8d %6d %6d" " %5" ZINT_FORMAT0 "\n",
228 b->round,
229 yaz_timing_get_real(tim_dict) + yaz_timing_get_real(tim_isamb),
230 yaz_timing_get_real(tim_dict),
231 yaz_timing_get_user(tim_dict),
232 yaz_timing_get_sys(tim_dict),
233 yaz_timing_get_real(tim_isamb),
234 yaz_timing_get_user(tim_isamb),
235 yaz_timing_get_sys(tim_isamb),
236 number_of_int_splits,
237 number_of_leaf_splits,
238 no_docs,
239 b->no_entries,
240 no_words,
241 no_new_words,
242 number_of_dict_splits
243 );
244 fflush(stdout);
245
246 xfree(b->ar);
247 b->ar = 0;
248 nmem_reset(b->nmem);
249 b->no_entries = 0;
250 b->terms = 0;
251
252 yaz_timing_destroy(&tim_isamb);
253 yaz_timing_destroy(&tim_dict);
254}
255
257 int no_docs)
258{
259 int total = nmem_total(b->nmem);
260 int max = b->current_max;
261 if (total > max)
262 {
263 index_block_flush(b, isb, dict, no_docs);
264 }
265}
266
268 const char *term, zint docid, zint seqno)
269{
270 struct index_term *t = nmem_malloc(b->nmem, sizeof(*t));
271 t->term = nmem_strdup(b->nmem, term);
272 t->docid = docid;
273 t->seqno = seqno;
274 t->next = b->terms;
275 b->terms = t;
276 b->no_entries++;
277}
278
279void index_term(struct index_block *b, const char *term,
281{
282#if 0
283 printf("%s " ZINT_FORMAT " " ZINT_FORMAT "\n", term,
284 docid, *seqno);
285#endif
287 (*seqno)++;
288}
289
290void index_wrbuf(struct index_block *b, WRBUF wrbuf, zint docid,
291 int subfield_char)
292{
293 int nl = 1;
294 const char *cp = wrbuf_buf(wrbuf);
295 char term[4096];
296 size_t sz = 0;
297 zint seqno = 0;
298
299 while (*cp)
300 {
301 if (nl)
302 {
303 int i;
304 if (cp[0] != ' ')
305 { /* skip field+indicator (e.g. 245 00) */
306 for (i = 0; i<6 && *cp; i++, cp++)
307 ;
308 }
309 else
310 { /* continuation line */
311 for (i = 0; i<4 && *cp; i++, cp++)
312 ;
313 }
314 }
315 nl = 0;
316 if (*cp == '\n')
317 {
318 if (sz)
319 {
320 index_term(b, term, docid, &seqno);
321 sz = 0;
322 }
323 nl = 1;
324 cp++;
325 }
326 else if (*cp == subfield_char && cp[1])
327 {
328 if (sz)
329 {
330 index_term(b, term, docid, &seqno);
331 sz = 0;
332 }
333 cp += 2;
334 }
335 else if (strchr("$*/-;,.:[]\"&(){} ", *cp))
336 {
337 if (sz)
338 {
339 index_term(b, term, docid, &seqno);
340 sz = 0;
341 }
342 cp++;
343 }
344 else
345 {
346 unsigned ch = *(const unsigned char *)cp;
347 if (sz < sizeof(term))
348 {
349 term[sz] = tolower(ch);
350 term[sz+1] = '\0';
351 sz++;
352 }
353 cp++;
354 }
355 }
356 if (sz)
357 index_term(b, term, docid, &seqno);
358}
359
361 Dict dict,
362 zint *docid_seq,
363 FILE *inf,
364 int memory)
365{
366 WRBUF wrbuf = wrbuf_alloc();
367 int no_docs = 0;
368 int new_rec = 1;
369 char line[4096];
370 struct index_block *b = index_block_new(memory);
371 while(fgets(line, sizeof(line)-1, inf))
372 {
373 if (line[0] == '$')
374 {
375 if (!new_rec)
376 new_rec = 1;
377 else
378 new_rec = 0;
379 continue;
380 }
381 if (new_rec)
382 {
383 (*docid_seq)++;
384 no_docs++;
385 index_block_check_flush(b, isb, dict, no_docs);
386 new_rec = 0;
387 }
388
389 if (line[0] == ' ')
390 {
391 /* continuation */
392 wrbuf_puts(wrbuf, line);
393 continue;
394 }
395 else
396 {
397 /* index existing buffer (if any) */
398 if (wrbuf_len(wrbuf))
399 {
400 index_wrbuf(b, wrbuf, *docid_seq, '*');
401 wrbuf_rewind(wrbuf);
402 }
403 if (line[0] != ' ' && line[1] != ' ' && line[2] != ' ' &&
404 line[3] == ' ')
405 {
406 /* normal field+indicator line */
407 wrbuf_puts(wrbuf, line);
408 }
409 }
410 }
411 if (wrbuf_len(wrbuf))
412 {
413 index_wrbuf(b, wrbuf, *docid_seq, '*');
414 wrbuf_rewind(wrbuf);
415 }
416 (*docid_seq)++;
417 no_docs++;
418 index_block_flush(b, isb, dict, no_docs);
420}
421
423 Dict dict,
424 zint *docid_seq,
425 FILE *inf,
426 int memory,
427 int verbose, int print_offset)
428{
429 yaz_marc_t mt = yaz_marc_create();
430 WRBUF wrbuf = wrbuf_alloc();
431 struct index_block *b = index_block_new(memory);
432 int no_docs = 0;
433
434 while (1)
435 {
436 size_t r;
437 char buf[100001];
438 int len, rlen;
439
440 r = fread (buf, 1, 5, inf);
441 if (r < 5)
442 {
443 if (r && print_offset && verbose)
444 printf ("<!-- Extra %ld bytes at end of file -->\n",
445 (long) r);
446 break;
447 }
448 while (*buf < '0' || *buf > '9')
449 {
450 int i;
451 long off = ftell(inf) - 5;
452 if (verbose || print_offset)
453 printf("<!-- Skipping bad byte %d (0x%02X) at offset "
454 "%ld (0x%lx) -->\n",
455 *buf & 0xff, *buf & 0xff,
456 off, off);
457 for (i = 0; i<4; i++)
458 buf[i] = buf[i+1];
459 r = fread(buf+4, 1, 1, inf);
460 if (r < 1)
461 break;
462 }
463 if (r < 1)
464 {
465 if (verbose || print_offset)
466 printf ("<!-- End of file with data -->\n");
467 break;
468 }
469 len = atoi_n(buf, 5);
470 if (len < 25 || len > 100000)
471 {
472 long off = ftell(inf) - 5;
473 printf("Bad Length %ld read at offset %ld (%lx)\n",
474 (long)len, (long) off, (long) off);
475 break;
476 }
477 rlen = len - 5;
478 r = fread (buf + 5, 1, rlen, inf);
479 if (r < rlen)
480 break;
481 yaz_marc_read_iso2709(mt, buf, len);
482
483 if (yaz_marc_write_line(mt, wrbuf))
484 break;
485
486 index_wrbuf(b, wrbuf, *docid_seq, '$');
487 wrbuf_rewind(wrbuf);
488 (*docid_seq)++;
489
490 no_docs++;
491 index_block_check_flush(b, isb, dict, no_docs);
492 }
493 index_block_flush(b, isb, dict, no_docs);
494 wrbuf_destroy(wrbuf);
495 yaz_marc_destroy(mt);
497}
498
499void exit_usage(void)
500{
501 fprintf(stderr, "benchindex1 [-t type] [-c d:i] [-m mem] [-i] [inputfile]\n");
502 exit(1);
503}
504
505int main(int argc, char **argv)
506{
507 BFiles bfs;
508 ISAMB isb_postings;
509 ISAMC_M method_postings;
510 Dict dict;
511 int ret;
512 int reset = 0;
513 char *arg;
514 int memory = 5;
515 int isam_cache_size = 40;
516 int dict_cache_size = 50;
517 const char *fname = 0;
518 FILE *inf = stdin;
519 yaz_timing_t tim = 0;
520 zint docid_seq = 1;
521 const char *dict_info;
522 const char *type = "iso2709";
523 int int_count_enable = 1;
524 char version_str[16];
525
526 zebra_get_version(version_str, NULL);
527 while ((ret = options("im:t:c:N", argv, argc, &arg)) != -2)
528 {
529 switch(ret)
530 {
531 case 'm':
532 memory = atoi(arg);
533 break;
534 case 'i':
535 reset = 1;
536 break;
537 case 't':
538 if (!strcmp(arg, "iso2709"))
539 type = "iso2709";
540 else if (!strcmp(arg, "line"))
541 type = "line";
542 else
543 {
544 fprintf(stderr, "bad type: %s.\n", arg);
545 exit_usage();
546 }
547 break;
548 case 'c':
549 if (sscanf(arg, "%d:%d", &dict_cache_size, &isam_cache_size)
550 != 2)
551 {
552 fprintf(stderr, "bad cache sizes for -c\n");
553 exit_usage();
554 }
555 break;
556 case 0:
557 fname = arg;
558 break;
559 case 'N':
560 int_count_enable = 0;
561 break;
562 default:
563 fprintf(stderr, "bad option.\n");
564 exit_usage();
565 }
566 }
567
568 if (fname)
569 {
570 inf = fopen(fname, "rb");
571 if (!inf)
572 {
573 fprintf(stderr, "Cannot open %s\n", fname);
574 exit(1);
575 }
576 }
577 printf("# benchindex1 %s\n", version_str);
578 printf("# isam_cache_size = %d\n", isam_cache_size);
579 printf("# dict_cache_size = %d\n", dict_cache_size);
580 printf("# int_count_enable = %d\n", int_count_enable);
581 printf("# memory = %d\n", memory);
582
583 /* setup postings isamb attributes */
584 method_postings.compare_item = key_compare;
585 method_postings.log_item = key_logdump_txt;
586
587 method_postings.codec.start = iscz1_start;
588 method_postings.codec.decode = iscz1_decode;
589 method_postings.codec.encode = iscz1_encode;
590 method_postings.codec.stop = iscz1_stop;
591 method_postings.codec.reset = iscz1_reset;
592
593 method_postings.debug = 0;
594
595 /* create block system */
596 bfs = bfs_create(0, 0);
597 if (!bfs)
598 {
599 yaz_log(YLOG_WARN, "bfs_create failed");
600 exit(1);
601 }
602
603 if (reset)
604 bf_reset(bfs);
605
606 tim = yaz_timing_create();
607 /* create isam handle */
608 isb_postings = isamb_open (bfs, "isamb", isam_cache_size ? 1 : 0,
609 &method_postings, 0);
610 if (!isb_postings)
611 {
612 yaz_log(YLOG_WARN, "isamb_open failed");
613 exit(2);
614 }
615 isamb_set_cache_size(isb_postings, isam_cache_size);
616 isamb_set_int_count(isb_postings, int_count_enable);
617 dict = dict_open(bfs, "dict", dict_cache_size, 1, 0, 4096);
618
619 dict_info = dict_lookup(dict, "_s");
620 if (dict_info)
621 {
622 assert(*dict_info == sizeof(docid_seq));
623 memcpy(&docid_seq, dict_info+1, sizeof(docid_seq));
624 }
625
626 if (!strcmp(type, "iso2709"))
627 index_marc_from_file(isb_postings, dict, &docid_seq, inf, memory,
628 0 /* verbose */ , 0 /* print_offset */);
629 else if (!strcmp(type, "line"))
630 index_marc_line_records(isb_postings, dict, &docid_seq, inf, memory);
631
632 printf("# Total " ZINT_FORMAT " documents\n", docid_seq);
633 dict_insert(dict, "_s", sizeof(docid_seq), &docid_seq);
634
636 isamb_close(isb_postings);
637
638 if (fname)
639 fclose(inf);
640 /* exit block system */
641 bfs_destroy(bfs);
642 yaz_timing_stop(tim);
643
644 printf("# Total timings real=%8.6f user=%3.2f system=%3.2f\n",
645 yaz_timing_get_real(tim),
646 yaz_timing_get_user(tim),
647 yaz_timing_get_sys(tim));
648
649 yaz_timing_destroy(&tim);
650
651 exit(0);
652 return 0;
653}
654/*
655 * Local variables:
656 * c-basic-offset: 4
657 * c-file-style: "Stroustrup"
658 * indent-tabs-mode: nil
659 * End:
660 * vim: shiftwidth=4 tabstop=8 expandtab
661 */
662
void index_term(struct index_block *b, const char *term, zint docid, zint *seqno)
static int cmp_ar(const void *p1, const void *p2)
Definition benchindex1.c:77
void exit_usage(void)
void index_block_add(struct index_block *b, const char *term, zint docid, zint seqno)
void index_block_flush(struct index_block *b, ISAMB isb, Dict dict, int no_docs)
int main(int argc, char **argv)
void index_marc_from_file(ISAMB isb, Dict dict, zint *docid_seq, FILE *inf, int memory, int verbose, int print_offset)
void index_marc_line_records(ISAMB isb, Dict dict, zint *docid_seq, FILE *inf, int memory)
void index_block_destroy(struct index_block **bp)
Definition benchindex1.c:67
void index_wrbuf(struct index_block *b, WRBUF wrbuf, zint docid, int subfield_char)
void index_block_check_flush(struct index_block *b, ISAMB isb, Dict dict, int no_docs)
int code_read(void *vp, char **dst, int *insertMode)
Definition benchindex1.c:97
struct index_block * index_block_new(int memory)
Definition benchindex1.c:56
struct BFiles_struct * BFiles
A collection of BFile(s).
Definition bfile.h:38
void bf_reset(BFiles bfs)
Removes register and shadow completely.
Definition bfile.c:268
BFiles bfs_create(const char *spec, const char *base)
creates a Block files collection
Definition bfile.c:56
void bfs_destroy(BFiles bfiles)
destroys a block files handle
Definition bfile.c:73
Zebra dictionary.
zint dict_get_no_split(Dict dict)
get number of page split operations, since dict_open
Definition open.c:133
Dict dict_open(BFiles bfs, const char *name, int cache, int rw, int compact_flag, int page_size)
open dictionary
Definition open.c:50
struct Dict_struct * Dict
Dictionary handle.
Definition dict.h:41
int dict_insert(Dict dict, const char *p, int userlen, void *userinfo)
insert item into dictionary
Definition insert.c:439
char * dict_lookup(Dict dict, const char *p)
lookup item in dictionary
Definition lookup.c:100
int dict_close(Dict dict)
closes dictionary
Definition close.c:32
static Dict dict
Definition dicttest.c:35
void isamb_set_int_count(ISAMB b, int v)
Definition isamb.c:195
zint isamb_get_leaf_splits(ISAMB b)
Definition isamb.c:1664
ISAMB isamb_open(BFiles bfs, const char *name, int writeflag, ISAMC_M *method, int cache)
Definition isamb.c:351
zint isamb_get_int_splits(ISAMB b)
Definition isamb.c:1659
struct ISAMB_s * ISAMB
Definition isamb.h:28
void isamb_close(ISAMB isamb)
Definition isamb.c:455
void isamb_set_cache_size(ISAMB b, int sz)
Definition isamb.c:200
void isamb_merge(ISAMB b, ISAM_P *pos, ISAMC_I *data)
Definition isamb.c:1266
struct ISAMC_M_s ISAMC_M
zint ISAM_P
Definition isamc.h:28
struct ISAMC_I_s ISAMC_I
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_compare(const void *p1, const void *p2)
Definition it_key.c:74
void key_logdump_txt(int logmask, const void *p, const char *txt)
Definition it_key.c:38
void iscz1_reset(void *vp)
Definition it_key.c:146
void iscz1_stop(void *p)
Definition it_key.c:155
static FILE * inf
Definition readfile.c:37
int(* read_item)(void *clientData, char **dst, int *insertMode)
Definition isamc.h:53
void * clientData
Definition isamc.h:54
int(* compare_item)(const void *a, const void *b)
Definition isamc.h:43
ISAM_CODEC codec
Definition isamc.h:46
void(* log_item)(int logmask, const void *p, const char *txt)
Definition isamc.h:44
int debug
Definition isamc.h:49
void(* decode)(void *p, char **dst, const char **src)
Definition isam-codec.h:26
void(* stop)(void *p)
Definition isam-codec.h:25
void *(* start)(void)
Definition isam-codec.h:24
void(* encode)(void *p, char **dst, const char **src)
Definition isam-codec.h:27
void(* reset)(void *p)
Definition isam-codec.h:28
struct index_term ** ar
Definition benchindex1.c:44
struct index_term * terms
Definition benchindex1.c:43
size_t current_entry
Definition benchindex1.c:41
size_t current_max
Definition benchindex1.c:42
const char * term
Definition benchindex1.c:49
struct index_term * next
Definition benchindex1.c:53
int len
Definition it_key.h:31
zint mem[IT_KEY_LEVEL_MAX]
Definition it_key.h:32
#define ZINT_FORMAT
Definition util.h:72
#define ZINT_FORMAT0
Definition util.h:67
long zint
Zebra integer.
Definition util.h:66
void zebra_get_version(char *version_str, char *sha1_str)
Returns Zebra version and SHA1 ID as generated by Git.
Definition version.c:32