#include "mfile.h"
#include "cfile.h"
-/* set to 1 if extra commit/shadow check is to be performed */
+/** \brief set to 1 if extra commit/shadow check is to be performed */
#define EXTRA_CHECK 0
static int write_head(CFile cf)
if (ret == 0 || !cf->head.state)
{
*firstp = 1;
- cf->head.state = 1;
+ cf->head.state = CFILE_STATE_HASH;
cf->head.block_size = block_size;
cf->head.hash_size = 199;
hash_bytes = cf->head.hash_size * sizeof(zint);
hash_bytes = cf->head.hash_size * sizeof(zint);
assert(cf->head.next_bucket > 0);
assert(cf->head.next_block > 0);
- if (cf->head.state == 1)
+ if (cf->head.state == CFILE_STATE_HASH)
cf->array = (zint *) xmalloc(hash_bytes);
else
cf->array = NULL;
return 0;
}
}
- if (cf->head.state == 1)
+ if (cf->head.state == CFILE_STATE_HASH)
{
cf->parray = (struct CFile_hash_bucket **)
xmalloc(cf->head.hash_size * sizeof(*cf->parray));
ZINT_FORMAT,
cf->no_hits, cf->no_miss, cf->bucket_in_memory,
cf->head.next_bucket - cf->head.first_bucket);
- assert(cf->head.state == 1);
+ assert(cf->head.state == CFILE_STATE_HASH);
if (flush_bucket(cf, -1))
return -1;
assert(cf->bucket_in_memory == 0);
cf->array = NULL;
xfree(cf->parray);
cf->parray = NULL;
- cf->head.state = 2;
+ cf->head.state = CFILE_STATE_FLAT;
cf->dirty = 1;
return 0;
}
YAZ_BEGIN_CDECL
+/** \brief number of blocks in hash bucket */
#define HASH_BUCKET 15
-struct CFile_ph_bucket { /* structure on disc */
- zint no[HASH_BUCKET]; /* block number in original file */
- zint vno[HASH_BUCKET]; /* block number in shadow file */
- zint this_bucket; /* this bucket number */
- zint next_bucket; /* next bucket number */
+/** \brief CFile hash structure on disc */
+struct CFile_ph_bucket {
+ zint no[HASH_BUCKET]; /**< block number in original file */
+ zint vno[HASH_BUCKET];/**< block number in shadow file */
+ zint this_bucket; /**< this bucket number */
+ zint next_bucket; /**< next bucket number */
};
+/** \brief CFile hash structure info in memory */
struct CFile_hash_bucket {
struct CFile_ph_bucket ph;
int dirty;
#define HASH_BSIZE sizeof(struct CFile_ph_bucket)
-#define CFILE_FLAT 1
+/** \brief state of CFile is a hash structure */
+#define CFILE_STATE_HASH 1
+
+/** \brief state of CFile is a flat file file */
+#define CFILE_STATE_FLAT 2
+
+/** \brief CFile file header */
+struct CFile_head {
+ int state; /**< CFILE_STATE_HASH, CFILE_STATE_FLAT, .. */
+ zint next_block; /**< next free block / last block */
+ int block_size; /**< mfile/bfile block size */
+ int hash_size; /**< no of chains in hash table */
+ zint first_bucket; /**< first hash bucket */
+ zint next_bucket; /**< last hash bucket + 1 = first flat bucket */
+ zint flat_bucket; /**< last flat bucket + 1 */
+};
+/** \brief All in-memory information per CFile */
typedef struct CFile_struct
{
- struct CFile_head {
- int state; /* 1 = hash, 2 = flat */
- zint next_block; /* next free block / last block */
- int block_size; /* mfile/bfile block size */
- int hash_size; /* no of chains in hash table */
- zint first_bucket; /* first hash bucket */
- zint next_bucket; /* last hash bucket + 1 = first flat bucket */
- zint flat_bucket; /* last flat bucket + 1 */
- } head;
- MFile block_mf;
- MFile hash_mf;
- zint *array;
- struct CFile_hash_bucket **parray;
- struct CFile_hash_bucket *bucket_lru_front, *bucket_lru_back;
- int dirty;
- zint bucket_in_memory;
- zint max_bucket_in_memory;
- char *iobuf;
- MFile rmf;
- int no_hits;
- int no_miss;
+ struct CFile_head head;
+
+ MFile block_mf; /**< block meta file */
+ MFile hash_mf; /**< hash or index file (depending on state) */
+ zint *array; /**< array for hash */
+ struct CFile_hash_bucket **parray; /**< holds all hash bucket in memory */
+ struct CFile_hash_bucket *bucket_lru_front; /**< LRU front for hash */
+ struct CFile_hash_bucket *bucket_lru_back; /**< LRU back for hash */
+ int dirty; /**< whether CFile is dirty / header must be rewritten */
+ zint bucket_in_memory; /**< number of buckets in memory */
+ zint max_bucket_in_memory; /**< max number of buckets in memory */
+ char *iobuf; /**< data block .. of size block size */
+ MFile rmf; /**< read meta file (original data / not dirty) */
+ int no_hits; /**< number of bucket cache hits */
+ int no_miss; /**< number of bucket cache misses */
Zebra_mutex mutex;
} *CFile;
int cf_close (CFile cf);
+
CFile cf_open (MFile mf, MFile_area area, const char *fname, int block_size,
int wflag, int *firstp);
int cf_read (CFile cf, zint no, int offset, int nbytes, void *buf);
return -1;
}
yaz_log(log_level, "cf_commit: state=%d", cf->head.state);
- if (cf->head.state == 1)
+ if (cf->head.state == CFILE_STATE_HASH)
return cf_commit_hash(cf);
- else if (cf->head.state == 2)
+ else if (cf->head.state == CFILE_STATE_FLAT)
return cf_commit_flat(cf);
else
{
attset: explain.att
recordtype: grs.sgml
-isam: c
+isam: b
# Flags for the non-authenticated user. w=write (allows ES Updates)
perm.anonymous: rw
}
fprintf (stdout, "%7d- %7d\n",
prev, stat_info.isam_occurrences[i]);
+ rec_prstat(zh->reg->records, 0);
xmalloc_trav("unfreed"); /*! while hunting memory leaks */
zebra_end_read (zh);
return 0;
Records rec_open(BFiles bfs, int rw, int compression_method);
char *rec_strdup(const char *s, size_t *len);
-void rec_prstat(Records p);
+void rec_prstat(Records p, int verbose);
zint rec_sysno_to_int(zint sysno);
memcpy(block_and_ref + sizeof(freeblock), &ref, sizeof(ref));
if (ref)
{
+ /* there is still a reference to this block.. */
if (bf_write(p->data_BFile[dst_type], freeblock, 0,
sizeof(block_and_ref), block_and_ref))
{
}
return ZEBRA_OK;
}
- first = 0;
+ /* the list of blocks can all be removed (ref == 0) */
+ first = 0;
}
if (bf_write(p->data_BFile[dst_type], freeblock, 0, sizeof(freeblock),
e->flag = recordFlagNop;
break;
- default:
+ case recordFlagNop:
break;
+ default:
+ break;
}
}
return p;
}
-void rec_prstat(Records records)
+void rec_prstat(Records records, int verbose)
{
int i;
zint total_bytes = 0;
records->head.block_used[i] * records->head.block_size[i]);
total_bytes +=
records->head.block_used[i] * records->head.block_size[i];
+
+ yaz_log(YLOG_LOG, " Block Last " ZINT_FORMAT, records->head.block_last[i]);
+ if (verbose)
+ { /* analyse free lists */
+ zint no_free = 0;
+ zint block_free = records->head.block_free[i];
+ WRBUF w = wrbuf_alloc();
+ while (block_free)
+ {
+ zint nblock;
+ no_free++;
+ wrbuf_printf(w, " " ZINT_FORMAT, block_free);
+ if (bf_read(records->data_BFile[i],
+ block_free, 0, sizeof(nblock), &nblock) != 1)
+ {
+ yaz_log(YLOG_FATAL|YLOG_ERRNO, "read in %s at free block "
+ ZINT_FORMAT,
+ records->data_fname[i], block_free);
+ break;
+ }
+ block_free = nblock;
+ }
+ yaz_log (YLOG_LOG,
+ " Number in free list %8" ZINT_FORMAT0, no_free);
+ if (no_free)
+ yaz_log(YLOG_LOG, "%s", wrbuf_cstr(w));
+ wrbuf_destroy(w);
+ }
}
yaz_log (YLOG_LOG,
"Total size of record index in bytes %8" ZINT_FORMAT0,
{
ZebraHandle zh = (ZebraHandle) handle;
ISAM_P pos;
- ASSERTZH;
if (*info == sizeof(pos))
{
return 0;
}
-static int delete_SU_handle(void *handle, int ord)
+int delete_w_all_handle(const char *info, void *handle)
+{
+ ZebraHandle zh = (ZebraHandle) handle;
+ ISAM_P pos;
+
+ if (*info == sizeof(pos))
+ {
+ ISAMB_PP pt;
+ memcpy(&pos, info+1, sizeof(pos));
+ pt = isamb_pp_open(zh->reg->isamb, pos, 2);
+ if (pt)
+ {
+ struct it_key key;
+ key.mem[0] = 0;
+ while (isamb_pp_read(pt, &key))
+ {
+ Record rec;
+ rec = rec_get(zh->reg->records, key.mem[0]);
+ rec_del(zh->reg->records, &rec);
+ }
+ isamb_pp_close(pt);
+ }
+ }
+ return delete_w_handle(info, handle);
+}
+
+static int delete_SU_handle(void *handle, int ord,
+ const char *index_type, const char *string_index,
+ zinfo_index_category_t cat)
{
ZebraHandle zh = (ZebraHandle) handle;
char ord_buf[20];
int ord_len;
-
+#if 0
+ yaz_log(YLOG_LOG, "ord=%d index_type=%s index=%s cat=%d", ord,
+ index_type, string_index, (int) cat);
+#endif
ord_len = key_SU_encode(ord, ord_buf);
ord_buf[ord_len] = '\0';
assert(zh->reg->isamb);
+ assert(zh->reg->records);
dict_delete_subtree(zh->reg->dict, ord_buf,
- zh, delete_w_handle);
+ zh,
+ !strcmp(string_index, "_ALLRECORDS") ?
+ delete_w_all_handle : delete_w_handle);
return 0;
}
rec = rec_get(zei->records, zad->sysno);
(*zei->updateFunc)(zei->updateHandle, rec, 0);
- rec_free(&rec);
+ rec_del(zei->records, &rec);
}
/* remove database record keys and delete it */
rec = rec_get(zei->records, zdi->sysno);
(*zei->updateFunc)(zei->updateHandle, rec, 0);
- rec_free(&rec);
+ rec_del(zei->records, &rec);
/* remove from list */
*zdip = zdi->next;
}
int zebraExplain_trav_ord(ZebraExplainInfo zei, void *handle,
- int (*f)(void *handle, int ord))
+ int (*f)(void *handle, int ord,
+ const char *index_type,
+ const char *string_index,
+ zinfo_index_category_t cat))
{
struct zebDatabaseInfoB *zdb = zei->curDatabaseInfo;
if (zdb)
{
struct zebSUInfoB *zsui = zdb->attributeDetails->SUInfo;
for ( ;zsui; zsui = zsui->next)
- (*f)(handle, zsui->info.ordinal);
+ (*f)(handle, zsui->info.ordinal,
+ zsui->info.index_type, zsui->info.str,
+ zsui->info.cat);
}
return 0;
}
zint zebraExplain_ord_get_doc_occurrences(ZebraExplainInfo zei, int ord);
int zebraExplain_trav_ord(ZebraExplainInfo zei, void *handle,
- int (*f)(void *handle, int ord));
+ int (*f)(void *handle, int ord,
+ const char *index_type,
+ const char *string_index,
+ zinfo_index_category_t cat));
int zebraExplain_get_database_ord(ZebraExplainInfo zei);
int zebraExplain_removeDatabase(ZebraExplainInfo zei, void *updateHandle);