/*------------------------------------------------------------------------------ * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team * * Distributable under the terms of either the Apache License (Version 2.0) or * the GNU Lesser General Public License, as specified in the COPYING file. ------------------------------------------------------------------------------*/ #include "CLucene/StdHeader.h" #include "SegmentInfos.h" #include "CLucene/store/Directory.h" #include "CLucene/util/VoidMap.h" #include "CLucene/util/Misc.h" CL_NS_USE(store) CL_NS_USE(util) CL_NS_DEF(index) SegmentInfo::SegmentInfo(const char* Name, const int32_t DocCount, CL_NS(store)::Directory* Dir): docCount(DocCount),dir(Dir){ //Func - Constructor. Initialises SegmentInfo. //Pre - Name holds the unique name in the directory Dir // DocCount holds the number of documents in the segment // Dir holds the Directory where the segment resides //Post - The instance has been created. name contains the duplicated string Name. // docCount = DocCount and dir references Dir STRCPY_AtoA(name,Name,CL_MAX_NAME); } SegmentInfo::~SegmentInfo(){ } SegmentInfos::SegmentInfos(bool deleteMembers) : infos(deleteMembers){ //Func - Constructor //Pre - deleteMembers indicates if the instance to be created must delete // all SegmentInfo instances it manages when the instance is destroyed or not // true -> must delete, false may not delete //Post - An instance of SegmentInfos has been created. //initialize counter to 0 counter = 0; version = Misc::currentTimeMillis(); } SegmentInfos::~SegmentInfos(){ //Func - Destructor //Pre - true //Post - The instance has been destroyed. Depending on the constructor used // the SegmentInfo instances that this instance managed have been deleted or not. //Clear the list of SegmentInfo instances - make sure everything is deleted infos.clear(); } SegmentInfo* SegmentInfos::info(int32_t i) { //Func - Returns a reference to the i-th SegmentInfo in the list. //Pre - i >= 0 //Post - A reference to the i-th SegmentInfo instance has been returned CND_PRECONDITION(i >= 0, "i contains negative number"); //Get the i-th SegmentInfo instance SegmentInfo *ret = infos[i]; //Condition check to see if the i-th SegmentInfo has been retrieved CND_CONDITION(ret != NULL,"No SegmentInfo instance found"); return ret; } void SegmentInfos::clearto(size_t min){ while ( infos.size() > min ){ segmentInfosType::iterator itr = infos.end(); if ( itr != infos.begin()) itr --; _CLLDELETE((*itr)); infos.erase(itr); } } void SegmentInfos::add(SegmentInfo* info){ infos.push_back(info); } int32_t SegmentInfos::size() const{ return infos.size(); } void SegmentInfos::read(Directory* directory){ //Func - Reads segments file that resides in directory. //Pre - directory contains a valid reference //Post - The segments file has been read and for each segment found // a SegmentsInfo intance has been created and stored. //Open an IndexInput to the segments file IndexInput* input = directory->openInput("segments"); //Check if input is valid if (input){ try { int32_t format = input->readInt(); if(format < 0){ // file contains explicit format info // check that it is a format we can understand if (format < FORMAT){ TCHAR err[30]; _sntprintf(err,30,_T("Unknown format version: %d"),format); _CLTHROWT(CL_ERR_Runtime,err); } version = input->readLong(); // read version counter = input->readInt(); // read counter } else{ // file is in old format without explicit format info counter = format; } //Temporary variable for storing the name of the segment TCHAR tname[CL_MAX_PATH]; char aname[CL_MAX_PATH]; SegmentInfo* si = NULL; //read segmentInfos for (int32_t i = input->readInt(); i > 0; i--){ // read the name of the segment input->readString(tname, CL_MAX_PATH); STRCPY_TtoA(aname,tname,CL_MAX_PATH); //Instantiate a new SegmentInfo Instance si = _CLNEW SegmentInfo(aname, input->readInt(),directory); //Condition check to see if si points to an instance CND_CONDITION(si != NULL, "Memory allocation for si failed") ; //store SegmentInfo si infos.push_back(si); } if(format >= 0){ // in old format the version number may be at the end of the file if (input->getFilePointer() >= input->length()) version = Misc::currentTimeMillis(); // old file format without version number else version = input->readLong(); // read version } } _CLFINALLY( //destroy the inputStream input. The destructor of IndexInput will //also close the Inputstream input _CLDELETE( input ); ); } } void SegmentInfos::write(Directory* directory){ //Func - Writes a new segments file based upon the SegmentInfo instances it manages //Pre - directory is a valid reference to a Directory //Post - The new segment has been written to disk //Open an IndexOutput to the segments file IndexOutput* output = directory->createOutput("segments.new"); //Check if output is valid if (output){ try { output->writeInt(FORMAT); // write FORMAT output->writeLong(++version); // every write changes the index output->writeInt(counter); //Write the counter //Write the number of SegmentInfo Instances //which is equal to the number of segments in directory as //each SegmentInfo manages a single segment output->writeInt(infos.size()); SegmentInfo *si = NULL; //temporary value for wide segment name TCHAR tname[CL_MAX_PATH]; //Iterate through all the SegmentInfo instances for (uint32_t i = 0; i < infos.size(); i++) { //Retrieve the SegmentInfo si = info(i); //Condition check to see if si has been retrieved CND_CONDITION(si != NULL,"No SegmentInfo instance found"); //Write the name of the current segment STRCPY_AtoT(tname,si->name,CL_MAX_PATH); output->writeString(tname,_tcslen(tname)); //Write the number of documents in the segment output->writeInt(si->docCount); } } _CLFINALLY( output->close(); _CLDELETE( output ); ); // install new segment info directory->renameFile("segments.new","segments"); } } int64_t SegmentInfos::readCurrentVersion(Directory* directory){ IndexInput* input = directory->openInput("segments"); int32_t format = 0; int64_t version = 0; try { format = input->readInt(); if(format < 0){ if(format < FORMAT){ TCHAR err[30]; _sntprintf(err,30,_T("Unknown format version: %d"),format); _CLTHROWT(CL_ERR_Runtime,err); } version = input->readLong(); // read version } } _CLFINALLY( input->close(); _CLDELETE(input); ); if(format < 0) return version; // We cannot be sure about the format of the file. // Therefore we have to read the whole file and cannot simply seek to the version entry. SegmentInfos* sis = _CLNEW SegmentInfos(); sis->read(directory); version = sis->getVersion(); _CLDELETE(sis); return version; } CL_NS_END