#include "KinoSearch/Util/ToolSet.h"
#include <math.h>
#define KINO_WANT_DELDOCS_VTABLE
#include "KinoSearch/Index/DelDocs.r"
#include "KinoSearch/InvIndex.r"
#include "KinoSearch/Index/IndexFileNames.h"
#include "KinoSearch/Index/SegInfo.r"
#include "KinoSearch/Index/PostingList.r"
#include "KinoSearch/Util/IntMap.r"
#include "KinoSearch/Store/Folder.r"
#include "KinoSearch/Store/InStream.r"
#include "KinoSearch/Store/OutStream.r"
DelDocs*
DelDocs_new(InvIndex *invindex, SegInfo *seg_info)
{
Hash *metadata
= (Hash*)Hash_Fetch(seg_info->metadata, "deldocs", 7);
CREATE(self, DelDocs, DELDOCS);
/* super construct - no initial allocation in case no deletions */
BitVec_init_base((BitVector*)self, 0);
/* use either defaults or extracted metadata */
if (metadata == NULL) {
self->del_gen = 0;
}
else {
/* check format, get generation */
if ( Hash_Fetch_I64(metadata, "format", 6) > DELDOCS_FORMAT ) {
CONFESS("Unsupported deldocs format: %ld",
(long)Hash_Fetch_I64(metadata, "format", 6));
}
self->del_gen = Hash_Fetch_I64(metadata, "del_gen", 7);
}
/* assign */
self->invindex = REFCOUNT_INC(invindex);
self->seg_info = REFCOUNT_INC(seg_info);
/* read file if generation so indicates */
if (self->del_gen)
DelDocs_Read_Deldocs(self);
return self;
}
void
DelDocs_read_deldocs(DelDocs *self)
{
ByteBuf ext = { &BYTEBUF, 0, ".del", 4, 0 };
ByteBuf *filename = IxFileNames_filename_from_gen(
self->seg_info->seg_name, self->del_gen, &ext);
/* bail if del_gen is 0 (and therefore filename is null) */
if (filename == NULL) {
return;
}
else if (!Folder_File_Exists(self->invindex->folder, filename)) {
CONFESS("file '%s' is not available", filename->ptr);
}
else {
InStream *instream
= Folder_Open_InStream(self->invindex->folder, filename);
size_t byte_size = InStream_SLength(instream);
u32_t new_max = byte_size * 8 - 1;
/* allocate space */
DelDocs_Grow(self, new_max);
/* read in bit vector */
InStream_Read_Bytes(instream, (char*)self->bits, byte_size);
InStream_SClose(instream);
/* clean up */
REFCOUNT_DEC(filename);
REFCOUNT_DEC(instream);
}
}
void
DelDocs_write_deldocs(DelDocs *self)
{
Hash *metadata = Hash_new(0);
size_t byte_size = ceil( self->seg_info->doc_count / 8.0 );
u32_t new_max = byte_size * 8 - 1;
ByteBuf ext = { &BYTEBUF, 0, ".del", 4, 0 };
ByteBuf *filename;
OutStream *outstream;
/* increment generation, get an outstream; */
self->del_gen++;
filename = IxFileNames_filename_from_gen( self->seg_info->seg_name,
self->del_gen, &ext);
outstream = Folder_Open_OutStream(self->invindex->folder, filename);
REFCOUNT_DEC(filename);
/* make sure that we have 1 bit for each doc in segment */
DelDocs_Grow(self, new_max);
/* write deletions data and clean up */
OutStream_Write_Bytes(outstream, (char*)self->bits, byte_size);
OutStream_SClose(outstream);
REFCOUNT_DEC(outstream);
/* store metadata in seg_info */
Hash_Store_I64(metadata, "del_gen", 7, (i64_t)self->del_gen);
Hash_Store_I64(metadata, "format", 6, (i64_t)DELDOCS_FORMAT);
Hash_Store_I64(metadata, "num_deletions", 13, (i64_t)DelDocs_Count(self));
SegInfo_Add_Metadata(self->seg_info, "deldocs", 7, (Obj*)metadata);
REFCOUNT_DEC(metadata);
}
IntMap*
DelDocs_generate_doc_map(DelDocs *self, i32_t offset)
{
i32_t max = self->seg_info->doc_count;
i32_t *doc_map = MALLOCATE(max, i32_t);
i32_t new_doc_num;
i32_t i;
/* -1 for a deleted doc, a new number otherwise */
for (i = 0, new_doc_num = 0; i < max; i++) {
if (DelDocs_Get(self, i))
doc_map[i] = -1;
else
doc_map[i] = offset + new_doc_num++;
}
return IntMap_new(doc_map, max);
}
void
DelDocs_delete_postinglist(DelDocs* self, PostingList *plist)
{
/* iterate through postings, marking each doc as deleted */
while (PList_Next(plist)) {
i32_t doc = PList_Get_Doc_Num(plist);
DelDocs_Set(self, doc);
}
}
void
DelDocs_destroy(DelDocs *self)
{
REFCOUNT_DEC(self->invindex);
REFCOUNT_DEC(self->seg_info);
BitVec_destroy((BitVector*)self);
}
/* Copyright 2006-2007 Marvin Humphrey
*
* This program is free software; you can redistribute it and/or modify
* under the same terms as Perl itself.
*/