1 /* This file is part of the Zebra server.
2 Copyright (C) 1994-2011 Index Data
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
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
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
21 * Format of first block (assumes a 512 block size)
26 * Format of subsequent blocks
30 * Format of each record
32 * (length, data) - pairs
33 * length = 0 if same as previous
40 #include <yaz/yaz-util.h>
41 #include <idzebra/bfile.h>
51 #define REC_BLOCK_TYPES 2
52 #define REC_HEAD_MAGIC "recindex"
57 int compression_method;
61 char *data_fname[REC_BLOCK_TYPES];
62 BFile data_BFile[REC_BLOCK_TYPES];
67 struct record_cache_entry *record_cache;
72 int compression_chunk_size;
79 zint block_size[REC_BLOCK_TYPES];
80 zint block_free[REC_BLOCK_TYPES];
81 zint block_last[REC_BLOCK_TYPES];
82 zint block_used[REC_BLOCK_TYPES];
83 zint block_move[REC_BLOCK_TYPES];
93 enum recordCacheFlag { recordFlagNop, recordFlagWrite, recordFlagNew,
96 struct record_cache_entry {
98 enum recordCacheFlag flag;
101 struct record_index_entry {
102 zint next; /* first block of record info / next free entry */
103 int size; /* size of record or 0 if free entry */
106 Record rec_cp(Record rec);
108 /* Modify argument to if below: 1=normal, 0=sysno testing */
110 /* If this is used sysno are not converted (no testing) */
111 #define FAKE_OFFSET 0
112 #define USUAL_RANGE 6000000000LL
115 /* Use a fake > 2^32 offset so we can test for proper 64-bit handling */
116 #define FAKE_OFFSET 6000000000LL
117 #define USUAL_RANGE 2000000000LL
120 static zint rec_sysno_to_ext(zint sysno)
122 assert(sysno >= 0 && sysno <= USUAL_RANGE);
123 return sysno + FAKE_OFFSET;
126 zint rec_sysno_to_int(zint sysno)
128 assert(sysno >= FAKE_OFFSET && sysno <= FAKE_OFFSET + USUAL_RANGE);
129 return sysno - FAKE_OFFSET;
132 static void rec_tmp_expand(Records p, int size)
134 if (p->tmp_size < size + 2048 ||
135 p->tmp_size < p->head.block_size[REC_BLOCK_TYPES-1]*2)
138 p->tmp_size = size + (int)
139 (p->head.block_size[REC_BLOCK_TYPES-1])*2 + 2048;
140 p->tmp_buf = (char *) xmalloc(p->tmp_size);
144 static ZEBRA_RES rec_release_blocks(Records p, zint sysno)
146 struct record_index_entry entry;
148 char block_and_ref[sizeof(zint) + sizeof(short)];
152 if (recindex_read_indx(p->recindex, sysno, &entry, sizeof(entry), 1) != 1)
155 freeblock = entry.next;
156 assert(freeblock > 0);
157 dst_type = CAST_ZINT_TO_INT(freeblock & 7);
158 assert(dst_type < REC_BLOCK_TYPES);
159 freeblock = freeblock / 8;
162 if (bf_read(p->data_BFile[dst_type], freeblock, 0,
163 first ? sizeof(block_and_ref) : sizeof(zint),
166 yaz_log(YLOG_FATAL|YLOG_ERRNO, "read in rec_del_single");
172 memcpy(&ref, block_and_ref + sizeof(freeblock), sizeof(ref));
174 memcpy(block_and_ref + sizeof(freeblock), &ref, sizeof(ref));
177 /* there is still a reference to this block.. */
178 if (bf_write(p->data_BFile[dst_type], freeblock, 0,
179 sizeof(block_and_ref), block_and_ref))
181 yaz_log(YLOG_FATAL|YLOG_ERRNO, "write in rec_del_single");
186 /* the list of blocks can all be removed (ref == 0) */
190 if (bf_write(p->data_BFile[dst_type], freeblock, 0, sizeof(freeblock),
191 &p->head.block_free[dst_type]))
193 yaz_log(YLOG_FATAL|YLOG_ERRNO, "write in rec_del_single");
196 p->head.block_free[dst_type] = freeblock;
197 memcpy(&freeblock, block_and_ref, sizeof(freeblock));
199 p->head.block_used[dst_type]--;
201 p->head.total_bytes -= entry.size;
205 static ZEBRA_RES rec_delete_single(Records p, Record rec)
207 struct record_index_entry entry;
209 /* all data in entry must be reset, since it's written verbatim */
210 memset(&entry, '\0', sizeof(entry));
211 if (rec_release_blocks(p, rec_sysno_to_int(rec->sysno)) != ZEBRA_OK)
214 entry.next = p->head.index_free;
216 p->head.index_free = rec_sysno_to_int(rec->sysno);
217 recindex_write_indx(p->recindex, rec_sysno_to_int(rec->sysno), &entry, sizeof(entry));
221 static ZEBRA_RES rec_write_tmp_buf(Records p, int size, zint *sysnos)
223 struct record_index_entry entry;
225 char *cptr = p->tmp_buf;
226 zint block_prev = -1, block_free;
230 /* all data in entry must be reset, since it's written verbatim */
231 memset(&entry, '\0', sizeof(entry));
233 for (i = 1; i<REC_BLOCK_TYPES; i++)
234 if (size >= p->head.block_move[i])
236 while (no_written < size)
238 block_free = p->head.block_free[dst_type];
241 if (bf_read(p->data_BFile[dst_type],
242 block_free, 0, sizeof(*p->head.block_free),
243 &p->head.block_free[dst_type]) != 1)
245 yaz_log(YLOG_FATAL|YLOG_ERRNO, "read in %s at free block "
247 p->data_fname[dst_type], block_free);
252 block_free = p->head.block_last[dst_type]++;
253 if (block_prev == -1)
255 entry.next = block_free*8 + dst_type;
257 p->head.total_bytes += size;
260 recindex_write_indx(p->recindex, *sysnos, &entry, sizeof(entry));
266 memcpy(cptr, &block_free, sizeof(block_free));
267 bf_write(p->data_BFile[dst_type], block_prev, 0, 0, cptr);
268 cptr = p->tmp_buf + no_written;
270 block_prev = block_free;
271 no_written += CAST_ZINT_TO_INT(p->head.block_size[dst_type])
273 p->head.block_used[dst_type]++;
275 assert(block_prev != -1);
277 memcpy(cptr, &block_free, sizeof(block_free));
278 bf_write(p->data_BFile[dst_type], block_prev, 0,
279 sizeof(block_free) + (p->tmp_buf+size) - cptr, cptr);
283 int rec_check_compression_method(int compression_method)
285 switch(compression_method)
287 case REC_COMPRESS_ZLIB:
293 case REC_COMPRESS_BZIP2:
299 case REC_COMPRESS_NONE:
305 Records rec_open(BFiles bfs, int rw, int compression_method)
310 ZEBRA_RES ret = ZEBRA_OK;
312 p = (Records) xmalloc(sizeof(*p));
313 memset(&p->head, '\0', sizeof(p->head));
314 p->compression_method = compression_method;
317 p->tmp_buf = (char *) xmalloc(p->tmp_size);
318 p->compression_chunk_size = 0;
319 if (compression_method == REC_COMPRESS_BZIP2)
320 p->compression_chunk_size = 90000;
321 p->recindex = recindex_open(bfs, rw, 0 /* 1=isamb for recindex */);
322 r = recindex_read_head(p->recindex, p->tmp_buf);
326 memcpy(p->head.magic, REC_HEAD_MAGIC, sizeof(p->head.magic));
327 sprintf(p->head.version, "%3d", REC_VERSION);
328 p->head.index_free = 0;
329 p->head.index_last = 1;
330 p->head.no_records = 0;
331 p->head.total_bytes = 0;
332 for (i = 0; i<REC_BLOCK_TYPES; i++)
334 p->head.block_free[i] = 0;
335 p->head.block_last[i] = 1;
336 p->head.block_used[i] = 0;
338 p->head.block_size[0] = 256;
339 p->head.block_move[0] = 0;
340 for (i = 1; i<REC_BLOCK_TYPES; i++)
342 p->head.block_size[i] = p->head.block_size[i-1] * 8;
343 p->head.block_move[i] = p->head.block_size[i] * 2;
347 if (recindex_write_head(p->recindex,
348 &p->head, sizeof(p->head)) != ZEBRA_OK)
353 memcpy(&p->head, p->tmp_buf, sizeof(p->head));
354 if (memcmp(p->head.magic, REC_HEAD_MAGIC, sizeof(p->head.magic)))
356 yaz_log(YLOG_FATAL, "file %s has bad format",
357 recindex_get_fname(p->recindex));
360 version = atoi(p->head.version);
361 if (version != REC_VERSION)
363 yaz_log(YLOG_FATAL, "file %s is version %d, but version"
365 recindex_get_fname(p->recindex), version, REC_VERSION);
370 for (i = 0; i<REC_BLOCK_TYPES; i++)
373 sprintf(str, "recd%c", i + 'A');
374 p->data_fname[i] = (char *) xmalloc(strlen(str)+1);
375 strcpy(p->data_fname[i], str);
376 p->data_BFile[i] = NULL;
378 for (i = 0; i<REC_BLOCK_TYPES; i++)
380 if (!(p->data_BFile[i] =
381 bf_open(bfs, p->data_fname[i],
382 CAST_ZINT_TO_INT(p->head.block_size[i]), rw)))
384 yaz_log(YLOG_FATAL|YLOG_ERRNO, "bf_open %s", p->data_fname[i]);
391 p->record_cache = (struct record_cache_entry *)
392 xmalloc(sizeof(*p->record_cache)*p->cache_max);
393 zebra_mutex_init(&p->mutex);
394 if (ret == ZEBRA_FAIL)
399 static void rec_encode_unsigned(unsigned n, unsigned char *buf, int *len)
404 buf[*len] = 128 + (n & 127);
412 static void rec_decode_unsigned(unsigned *np, unsigned char *buf, int *len)
418 while (buf[*len] > 127)
420 n += w*(buf[*len] & 127);
429 static void rec_encode_zint(zint n, unsigned char *buf, int *len)
434 buf[*len] = (unsigned) (128 + (n & 127));
438 buf[*len] = (unsigned) n;
442 static void rec_decode_zint(zint *np, unsigned char *buf, int *len)
448 while (buf[*len] > 127)
450 n += w*(buf[*len] & 127);
459 static void rec_cache_flush_block1(Records p, Record rec, Record last_rec,
460 char **out_buf, int *out_size,
466 for (i = 0; i<REC_NO_INFO; i++)
468 if (*out_offset + CAST_ZINT_TO_INT(rec->size[i]) + 20 > *out_size)
470 int new_size = *out_offset + rec->size[i] + 65536;
471 char *np = (char *) xmalloc(new_size);
473 memcpy(np, *out_buf, *out_offset);
475 *out_size = new_size;
480 rec_encode_zint(rec_sysno_to_int(rec->sysno),
481 (unsigned char *) *out_buf + *out_offset, &len);
482 (*out_offset) += len;
484 if (rec->size[i] == 0)
486 rec_encode_unsigned(1, (unsigned char *) *out_buf + *out_offset,
488 (*out_offset) += len;
490 else if (last_rec && rec->size[i] == last_rec->size[i] &&
491 !memcmp(rec->info[i], last_rec->info[i], rec->size[i]))
493 rec_encode_unsigned(0, (unsigned char *) *out_buf + *out_offset,
495 (*out_offset) += len;
499 rec_encode_unsigned(rec->size[i]+1,
500 (unsigned char *) *out_buf + *out_offset,
502 (*out_offset) += len;
503 memcpy(*out_buf + *out_offset, rec->info[i], rec->size[i]);
504 (*out_offset) += rec->size[i];
509 static ZEBRA_RES rec_flush_shared(Records p, short ref_count, zint *sysnos,
510 char *out_buf, int out_offset)
512 ZEBRA_RES ret = ZEBRA_OK;
516 unsigned int csize = 0; /* indicate compression "not performed yet" */
517 char compression_method = p->compression_method;
518 switch (compression_method)
520 case REC_COMPRESS_ZLIB:
522 csize = out_offset + (out_offset >> 6) + 620;
526 uLongf destLen = csize;
527 rec_tmp_expand(p, csize);
528 r = compress((Bytef *) p->tmp_buf+sizeof(zint)+sizeof(short)+
530 &destLen, (const Bytef *) out_buf, out_offset);
536 if (r != Z_MEM_ERROR)
538 yaz_log(YLOG_WARN, "compress error: %d", r);
546 case REC_COMPRESS_BZIP2:
548 csize = out_offset + (out_offset >> 6) + 620;
549 rec_tmp_expand(p, csize);
550 #ifdef BZ_CONFIG_ERROR
551 i = BZ2_bzBuffToBuffCompress
553 i = bzBuffToBuffCompress
555 (p->tmp_buf+sizeof(zint)+sizeof(short)+
557 &csize, out_buf, out_offset, 1, 0, 30);
560 yaz_log(YLOG_WARN, "bzBuffToBuffCompress error code=%d", i);
565 case REC_COMPRESS_NONE:
570 /* either no compression or compression not supported ... */
572 rec_tmp_expand(p, csize);
573 memcpy(p->tmp_buf + sizeof(zint) + sizeof(short) + sizeof(char),
574 out_buf, out_offset);
576 compression_method = REC_COMPRESS_NONE;
578 memcpy(p->tmp_buf + sizeof(zint), &ref_count, sizeof(ref_count));
579 memcpy(p->tmp_buf + sizeof(zint)+sizeof(short),
580 &compression_method, sizeof(compression_method));
582 /* -------- compression */
583 if (rec_write_tmp_buf(p, csize + sizeof(short) + sizeof(char), sysnos)
590 static ZEBRA_RES rec_write_multiple(Records p, int saveCount)
597 char *out_buf = (char *) xmalloc(out_size);
598 zint *sysnos = (zint *) xmalloc(sizeof(*sysnos) * (p->cache_cur + 1));
599 zint *sysnop = sysnos;
600 ZEBRA_RES ret = ZEBRA_OK;
602 for (i = 0; i<p->cache_cur - saveCount; i++)
604 struct record_cache_entry *e = p->record_cache + i;
608 rec_cache_flush_block1(p, e->rec, last_rec, &out_buf,
609 &out_size, &out_offset);
610 *sysnop++ = rec_sysno_to_int(e->rec->sysno);
612 e->flag = recordFlagNop;
615 case recordFlagWrite:
616 if (rec_release_blocks(p, rec_sysno_to_int(e->rec->sysno))
620 rec_cache_flush_block1(p, e->rec, last_rec, &out_buf,
621 &out_size, &out_offset);
622 *sysnop++ = rec_sysno_to_int(e->rec->sysno);
624 e->flag = recordFlagNop;
627 case recordFlagDelete:
628 if (rec_delete_single(p, e->rec) != ZEBRA_OK)
631 e->flag = recordFlagNop;
641 rec_flush_shared(p, ref_count, sysnos, out_buf, out_offset);
647 static ZEBRA_RES rec_cache_flush(Records p, int saveCount)
652 if (saveCount >= p->cache_cur)
655 ret = rec_write_multiple(p, saveCount);
657 for (i = 0; i<p->cache_cur - saveCount; i++)
659 struct record_cache_entry *e = p->record_cache + i;
662 /* i still being used ... */
663 for (j = 0; j<saveCount; j++, i++)
664 memcpy(p->record_cache+j, p->record_cache+i,
665 sizeof(*p->record_cache));
666 p->cache_cur = saveCount;
670 static Record *rec_cache_lookup(Records p, zint sysno,
671 enum recordCacheFlag flag)
674 for (i = 0; i<p->cache_cur; i++)
676 struct record_cache_entry *e = p->record_cache + i;
677 if (e->rec->sysno == sysno)
679 if (flag != recordFlagNop && e->flag == recordFlagNop)
687 static ZEBRA_RES rec_cache_insert(Records p, Record rec, enum recordCacheFlag flag)
689 struct record_cache_entry *e;
690 ZEBRA_RES ret = ZEBRA_OK;
692 if (p->cache_cur == p->cache_max)
693 ret = rec_cache_flush(p, 1);
694 else if (p->cache_cur > 0)
698 for (i = 0; i<p->cache_cur; i++)
700 Record r = (p->record_cache + i)->rec;
701 for (j = 0; j<REC_NO_INFO; j++)
704 if (used > p->compression_chunk_size)
705 ret = rec_cache_flush(p, 1);
707 assert(p->cache_cur < p->cache_max);
709 e = p->record_cache + (p->cache_cur)++;
711 e->rec = rec_cp(rec);
715 ZEBRA_RES rec_close(Records *pp)
719 ZEBRA_RES ret = ZEBRA_OK;
724 zebra_mutex_destroy(&p->mutex);
725 if (rec_cache_flush(p, 0) != ZEBRA_OK)
728 xfree(p->record_cache);
732 if (recindex_write_head(p->recindex, &p->head, sizeof(p->head)) != ZEBRA_OK)
736 recindex_close(p->recindex);
738 for (i = 0; i<REC_BLOCK_TYPES; i++)
740 if (p->data_BFile[i])
741 bf_close(p->data_BFile[i]);
742 xfree(p->data_fname[i]);
750 static Record rec_get_int(Records p, zint sysno)
754 struct record_index_entry entry;
760 char compression_method;
765 if ((recp = rec_cache_lookup(p, sysno, recordFlagNop)))
766 return rec_cp(*recp);
768 if (recindex_read_indx(p->recindex, rec_sysno_to_int(sysno), &entry, sizeof(entry), 1) < 1)
769 return NULL; /* record is not there! */
772 return NULL; /* record is deleted */
774 dst_type = (int) (entry.next & 7);
775 assert(dst_type < REC_BLOCK_TYPES);
776 freeblock = entry.next / 8;
778 assert(freeblock > 0);
780 rec_tmp_expand(p, entry.size);
783 r = bf_read(p->data_BFile[dst_type], freeblock, 0, 0, cptr);
786 memcpy(&freeblock, cptr, sizeof(freeblock));
792 cptr += p->head.block_size[dst_type] - sizeof(freeblock);
794 memcpy(&tmp, cptr, sizeof(tmp));
795 r = bf_read(p->data_BFile[dst_type], freeblock, 0, 0, cptr);
798 memcpy(&freeblock, cptr, sizeof(freeblock));
799 memcpy(cptr, &tmp, sizeof(tmp));
802 rec = (Record) xmalloc(sizeof(*rec));
804 memcpy(&compression_method, p->tmp_buf + sizeof(zint) + sizeof(short),
805 sizeof(compression_method));
806 in_buf = p->tmp_buf + sizeof(zint) + sizeof(short) + sizeof(char);
807 in_size = entry.size - sizeof(short) - sizeof(char);
808 switch (compression_method)
810 case REC_COMPRESS_ZLIB:
814 unsigned int bz_size = entry.size * 20 + 100;
817 uLongf destLen = bz_size;
818 bz_buf = (char *) xmalloc(bz_size);
819 i = uncompress((Bytef *) bz_buf, &destLen,
820 (const Bytef *) in_buf, in_size);
826 yaz_log(YLOG_LOG, "failed");
834 yaz_log(YLOG_FATAL, "cannot decompress record(s) in ZLIB format");
838 case REC_COMPRESS_BZIP2:
842 unsigned int bz_size = entry.size * 20 + 100;
845 bz_buf = (char *) xmalloc(bz_size);
846 #ifdef BZ_CONFIG_ERROR
847 i = BZ2_bzBuffToBuffDecompress
849 i = bzBuffToBuffDecompress
851 (bz_buf, &bz_size, in_buf, in_size, 0, 0);
854 yaz_log(YLOG_LOG, "failed");
862 yaz_log(YLOG_FATAL, "cannot decompress record(s) in BZIP2 format");
866 case REC_COMPRESS_NONE:
869 for (i = 0; i<REC_NO_INFO; i++)
872 nptr = in_buf; /* skip ref count */
873 while (nptr < in_buf + in_size)
877 rec_decode_zint(&this_sysno, (unsigned char *) nptr, &len);
880 for (i = 0; i < REC_NO_INFO; i++)
882 unsigned int this_size;
883 rec_decode_unsigned(&this_size, (unsigned char *) nptr, &len);
888 rec->size[i] = this_size-1;
893 nptr += rec->size[i];
898 if (this_sysno == rec_sysno_to_int(sysno))
901 for (i = 0; i<REC_NO_INFO; i++)
903 if (rec->info[i] && rec->size[i])
905 char *np = xmalloc(rec->size[i]+1);
906 memcpy(np, rec->info[i], rec->size[i]);
907 np[rec->size[i]] = '\0';
912 assert(rec->info[i] == 0);
913 assert(rec->size[i] == 0);
917 if (rec_cache_insert(p, rec, recordFlagNop) != ZEBRA_OK)
922 Record rec_get(Records p, zint sysno)
925 zebra_mutex_lock(&p->mutex);
927 rec = rec_get_int(p, sysno);
928 zebra_mutex_unlock(&p->mutex);
932 Record rec_get_root(Records p)
934 return rec_get(p, rec_sysno_to_ext(1));
937 Record rec_get_next(Records p, Record rec)
940 zint next_sysno_int = rec_sysno_to_int(rec->sysno);
945 if (next_sysno_int == p->head.index_last)
947 next = rec_get(p, rec_sysno_to_ext(next_sysno_int));
952 static Record rec_new_int(Records p)
959 rec = (Record) xmalloc(sizeof(*rec));
960 if (1 || p->head.index_free == 0)
961 sysno = (p->head.index_last)++;
964 struct record_index_entry entry;
966 if (recindex_read_indx(p->recindex, p->head.index_free, &entry, sizeof(entry), 0) < 1)
971 sysno = p->head.index_free;
972 p->head.index_free = entry.next;
974 (p->head.no_records)++;
975 rec->sysno = rec_sysno_to_ext(sysno);
976 for (i = 0; i < REC_NO_INFO; i++)
981 rec_cache_insert(p, rec, recordFlagNew);
985 Record rec_new(Records p)
988 zebra_mutex_lock(&p->mutex);
990 rec = rec_new_int(p);
991 zebra_mutex_unlock(&p->mutex);
995 ZEBRA_RES rec_del(Records p, Record *recpp)
998 ZEBRA_RES ret = ZEBRA_OK;
1000 zebra_mutex_lock(&p->mutex);
1001 (p->head.no_records)--;
1002 if ((recp = rec_cache_lookup(p, (*recpp)->sysno, recordFlagDelete)))
1009 ret = rec_cache_insert(p, *recpp, recordFlagDelete);
1012 zebra_mutex_unlock(&p->mutex);
1017 ZEBRA_RES rec_put(Records p, Record *recpp)
1020 ZEBRA_RES ret = ZEBRA_OK;
1022 zebra_mutex_lock(&p->mutex);
1023 if ((recp = rec_cache_lookup(p, (*recpp)->sysno, recordFlagWrite)))
1030 ret = rec_cache_insert(p, *recpp, recordFlagWrite);
1033 zebra_mutex_unlock(&p->mutex);
1038 void rec_free(Record *recpp)
1044 for (i = 0; i < REC_NO_INFO; i++)
1045 xfree((*recpp)->info[i]);
1050 Record rec_cp(Record rec)
1055 n = (Record) xmalloc(sizeof(*n));
1056 n->sysno = rec->sysno;
1057 for (i = 0; i < REC_NO_INFO; i++)
1065 n->size[i] = rec->size[i];
1066 n->info[i] = (char *) xmalloc(rec->size[i]+1);
1067 memcpy(n->info[i], rec->info[i], rec->size[i]);
1068 n->info[i][rec->size[i]] = '\0';
1074 char *rec_strdup(const char *s, size_t *len)
1084 p = (char *) xmalloc(*len);
1089 void rec_prstat(Records records, int verbose)
1092 zint total_bytes = 0;
1095 "Total records %8" ZINT_FORMAT0,
1096 records->head.no_records);
1098 for (i = 0; i< REC_BLOCK_TYPES; i++)
1100 yaz_log (YLOG_LOG, "Record blocks of size "ZINT_FORMAT,
1101 records->head.block_size[i]);
1103 " Used/Total/Bytes used "
1104 ZINT_FORMAT "/" ZINT_FORMAT "/" ZINT_FORMAT,
1105 records->head.block_used[i], records->head.block_last[i]-1,
1106 records->head.block_used[i] * records->head.block_size[i]);
1108 records->head.block_used[i] * records->head.block_size[i];
1110 yaz_log(YLOG_LOG, " Block Last " ZINT_FORMAT, records->head.block_last[i]);
1112 { /* analyse free lists */
1114 zint block_free = records->head.block_free[i];
1115 WRBUF w = wrbuf_alloc();
1120 wrbuf_printf(w, " " ZINT_FORMAT, block_free);
1121 if (bf_read(records->data_BFile[i],
1122 block_free, 0, sizeof(nblock), &nblock) != 1)
1124 yaz_log(YLOG_FATAL|YLOG_ERRNO, "read in %s at free block "
1126 records->data_fname[i], block_free);
1129 block_free = nblock;
1132 " Number in free list %8" ZINT_FORMAT0, no_free);
1134 yaz_log(YLOG_LOG, "%s", wrbuf_cstr(w));
1139 "Total size of record index in bytes %8" ZINT_FORMAT0,
1140 records->head.total_bytes);
1142 "Total size with overhead %8" ZINT_FORMAT0,
1149 * c-file-style: "Stroustrup"
1150 * indent-tabs-mode: nil
1152 * vim: shiftwidth=4 tabstop=8 expandtab