searchengine/oss/cl/clucene/src/clucene/index/indexreader.cpp
changeset 0 671dee74050a
child 24 65456528cac2
equal deleted inserted replaced
-1:000000000000 0:671dee74050a
       
     1 /*------------------------------------------------------------------------------
       
     2 * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team
       
     3 * 
       
     4 * Distributable under the terms of either the Apache License (Version 2.0) or 
       
     5 * the GNU Lesser General Public License, as specified in the COPYING file.
       
     6 ------------------------------------------------------------------------------*/
       
     7 #include "clucene/stdheader.h"
       
     8 #include "IndexReader.h"
       
     9 #include "IndexWriter.h"
       
    10 
       
    11 #include "clucene/store/directory.h"
       
    12 #include "CLucene/store/FSDirectory.h"
       
    13 #include "CLucene/store/Lock.h"
       
    14 #include "clucene/document/document.h"
       
    15 #include "clucene/search/similarity.h"
       
    16 #include "SegmentInfos.h"
       
    17 #include "MultiReader.h"
       
    18 #include "Terms.h"
       
    19 
       
    20 CL_NS_USE(util)
       
    21 CL_NS_USE(store)
       
    22 CL_NS_DEF(index)
       
    23 
       
    24   IndexReader::IndexReader(Directory* dir):
       
    25    directory(_CL_POINTER(dir)){
       
    26   //Constructor.
       
    27   //Func - Creates an instance of IndexReader
       
    28   //Pre  - true
       
    29   //Post - An instance has been created with writeLock = NULL
       
    30 
       
    31       writeLock = NULL;
       
    32       segmentInfos = NULL;
       
    33       directoryOwner = false;
       
    34       closeDirectory = false;
       
    35       stale = false;
       
    36       hasChanges = false;
       
    37   }
       
    38 
       
    39    IndexReader::IndexReader(Directory* directory, SegmentInfos* segmentInfos, bool closeDirectory) {
       
    40     this->directory = _CL_POINTER(directory);
       
    41     this->segmentInfos = segmentInfos;
       
    42     directoryOwner = true;
       
    43     this->closeDirectory = closeDirectory;
       
    44     stale = false;
       
    45     hasChanges = false;
       
    46     writeLock = NULL;
       
    47   }
       
    48 
       
    49   IndexReader::~IndexReader(){
       
    50   //Func - Destructor
       
    51   //       Destroys the instance and releases the writeLock if needed
       
    52   //Pre  - true
       
    53   //Post - The instance has been destroyed if pre(writeLock) exists is has been released
       
    54       if (writeLock != NULL) {
       
    55 		  //release writeLock
       
    56           writeLock->release();
       
    57 		  _CLDELETE(writeLock);
       
    58       }
       
    59 	  _CLDELETE(segmentInfos);
       
    60 	  _CLDECDELETE(directory);
       
    61   }
       
    62 
       
    63   IndexReader* IndexReader::open(const char* path){
       
    64   //Func - Static method.
       
    65   //       Returns an IndexReader reading the index in an FSDirectory in the named path. 
       
    66   //Pre  - path != NULL and contains the path of the index for which an IndexReader must be 
       
    67   //       instantiated
       
    68   //       closeDir indicates if the directory needs to be closed
       
    69   //Post - An IndexReader has been returned that reads tnhe index located at path
       
    70 
       
    71 	  CND_PRECONDITION(path != NULL, "path is NULL");
       
    72 
       
    73 	  Directory* dir = FSDirectory::getDirectory(path,false);
       
    74      IndexReader* reader = open(dir,true);
       
    75      //because fsdirectory will now have a refcount of 1 more than
       
    76      //if the reader had been opened with a directory object,
       
    77      //we need to do a refdec
       
    78      _CLDECDELETE(dir);
       
    79      return reader;
       
    80   }
       
    81 
       
    82   IndexReader* IndexReader::open( Directory* directory, bool closeDirectory){
       
    83   //Func - Static method.
       
    84   //       Returns an IndexReader reading the index in an FSDirectory in the named path. 
       
    85   //Pre  - directory represents a directory 
       
    86   //       closeDir indicates if the directory needs to be closed
       
    87   //Post - An IndexReader has been returned that reads the index located at directory
       
    88 
       
    89 	  // in- & inter-process sync
       
    90       // CPIXASYNC SCOPED_LOCK_MUTEX(directory->THIS_LOCK)
       
    91       SCOPED_LOCK_CRUCIAL_MUTEX(directory->Directory_THIS_LOCK)
       
    92       
       
    93      IndexReader* ret = NULL;     
       
    94 
       
    95 	  LuceneLock* lock = directory->makeLock("commit.lock");
       
    96 
       
    97 	  //Instantiate an IndexReader::LockWith which can produce an IndexReader
       
    98       IndexReader::LockWith with(lock,directory);
       
    99 
       
   100 	  try{
       
   101 	  //Create an IndexReader reading the index
       
   102 		ret = with.runAndReturn();
       
   103 	  }_CLFINALLY(
       
   104         _CLDELETE( lock );
       
   105 	  );
       
   106 
       
   107 	  ret->closeDirectory = closeDirectory;
       
   108 
       
   109 	   CND_CONDITION(ret != NULL,"ret is NULL");
       
   110 	   //return reference 
       
   111        return ret;
       
   112   }
       
   113   
       
   114   CL_NS(document)::Document* IndexReader::document(const int32_t n){
       
   115     CL_NS(document)::Document* ret = _CLNEW CL_NS(document)::Document;
       
   116     if (!document(n,ret) )
       
   117         _CLDELETE(ret);
       
   118     return ret;
       
   119   }
       
   120 
       
   121   IndexReader* IndexReader::LockWith::doBody() {
       
   122   //Func - Reads the segmentinfo file and depending on the number of segments found
       
   123   //       it returns a SegmentsReader or a SegmentReader
       
   124   //Pre  - directory != NULL
       
   125   //Post - Depending on the number of Segments present in directory this method
       
   126   //       returns an empty SegmentsReader when there are no segments, a SegmentReader when
       
   127   //       directory contains 1 segment and a nonempty SegmentsReader when directory
       
   128   //       contains multiple segements
       
   129 
       
   130 	   CND_PRECONDITION(directory != NULL, "directory is NULL");
       
   131 
       
   132 	   //Instantiate SegmentInfos
       
   133        SegmentInfos* infos = _CLNEW SegmentInfos;
       
   134 	   try{
       
   135 			//Have SegmentInfos read the segments file in directory
       
   136 			infos->read(directory);
       
   137 	   }catch(...){
       
   138 	        //make sure infos is cleaned up
       
   139 			_CLDELETE(infos);
       
   140 			throw;
       
   141 	   }
       
   142 
       
   143        // If there is at least one segment (if infos.size() >= 1), the last
       
   144        // SegmentReader object will close the directory when the SegmentReader
       
   145        // object itself is closed (see SegmentReader::doClose).
       
   146        // If there are no segments, there will be no "last SegmentReader object"
       
   147        // to fulfill this responsibility, so we need to explicitly close the
       
   148        // directory in the segmentsreader.close
       
   149        
       
   150 	   //Count the number segments in the directory
       
   151 	   const uint32_t nSegs = infos->size();
       
   152 
       
   153        if (nSegs == 1 ) {
       
   154 			// index is optimized 
       
   155             return _CLNEW SegmentReader(infos, infos->info(0));
       
   156 	    }else{
       
   157 			//Instantiate an array of pointers to SegmentReaders of size nSegs (The number of segments in the index)
       
   158 			IndexReader** readers = NULL;
       
   159 
       
   160 			if (nSegs > 0){
       
   161 				uint32_t infosize=infos->size();
       
   162 				readers = _CL_NEWARRAY(IndexReader*,infosize+1);
       
   163 				for (uint32_t i = 0; i < infosize; ++i) {
       
   164 					//Instantiate a SegementReader responsible for reading the i-th segment and store it in
       
   165 					//the readers array
       
   166 					readers[i] = _CLNEW SegmentReader(infos->info(i));
       
   167 				}
       
   168 				readers[infosize] = NULL;
       
   169 			}
       
   170 
       
   171 			//return an instance of SegmentsReader which is a reader that manages all Segments
       
   172 			return _CLNEW MultiReader(directory, infos, readers);
       
   173         }// end if
       
   174   }
       
   175 
       
   176   uint64_t IndexReader::lastModified(const char* directory) {
       
   177   //Func - Static method
       
   178   //       Returns the time the index in the named directory was last modified. 
       
   179   //Pre  - directory != NULL and contains the path name of the directory to check
       
   180   //Post - The last modified time of the index has been returned
       
   181 
       
   182       CND_PRECONDITION(directory != NULL, "directory is NULL");
       
   183 
       
   184 	  return FSDirectory::fileModified(directory,"segments");
       
   185   }
       
   186 
       
   187   int64_t IndexReader::getCurrentVersion(Directory* directory) {
       
   188       // CPIXASYNC SCOPED_LOCK_MUTEX(directory->THIS_LOCK)                 // in- & inter-process sync
       
   189       SCOPED_LOCK_CRUCIAL_MUTEX(directory->Directory_THIS_LOCK)                 // in- & inter-process sync
       
   190 	LuceneLock* commitLock=directory->makeLock(IndexWriter::COMMIT_LOCK_NAME);
       
   191 	bool locked=false;
       
   192 	int64_t ret = 0;
       
   193 	try {
       
   194 		locked=commitLock->obtain(IndexWriter::COMMIT_LOCK_TIMEOUT);
       
   195 		ret = SegmentInfos::readCurrentVersion(directory);
       
   196 	}_CLFINALLY(
       
   197 		if (locked) {
       
   198 			commitLock->release();
       
   199 		}
       
   200 		_CLDELETE(commitLock);
       
   201 	)
       
   202 	return ret;
       
   203   }
       
   204 
       
   205 
       
   206    int64_t IndexReader::getCurrentVersion(const char* directory){
       
   207       Directory* dir = FSDirectory::getDirectory(directory, false);
       
   208       int64_t version = getCurrentVersion(dir);
       
   209 	  dir->close();
       
   210       _CLDECDELETE(dir);
       
   211       return version;
       
   212    }
       
   213     int64_t IndexReader::getVersion() {
       
   214 		return segmentInfos->getVersion();
       
   215 	}
       
   216 	
       
   217 	bool IndexReader::isCurrent() {
       
   218             // CPIXASYNC SCOPED_LOCK_MUTEX(directory->THIS_LOCK)                 // in- & inter-process sync
       
   219             SCOPED_LOCK_CRUCIAL_MUTEX(directory->Directory_THIS_LOCK)                 // in- & inter-process sync
       
   220 		LuceneLock* commitLock = directory->makeLock(IndexWriter::COMMIT_LOCK_NAME);
       
   221 		bool locked=false;
       
   222 		bool ret = false;
       
   223 		try {
       
   224 			locked=commitLock->obtain(IndexWriter::COMMIT_LOCK_TIMEOUT);
       
   225 			ret = SegmentInfos::readCurrentVersion(directory) == segmentInfos->getVersion();
       
   226 		} _CLFINALLY(
       
   227 			if (locked) {
       
   228 				commitLock->release();
       
   229 			}
       
   230 		)
       
   231 		return ret;
       
   232 	}
       
   233 
       
   234   uint64_t IndexReader::lastModified(const Directory* directory) {
       
   235   //Func - Static method
       
   236   //       Returns the time the index in this directory was last modified. 
       
   237   //Pre  - directory contains a valid reference
       
   238   //Post - The last modified time of the index has been returned
       
   239 
       
   240       return directory->fileModified("segments");
       
   241   }
       
   242 
       
   243 
       
   244   bool IndexReader::indexExists(const char* directory){
       
   245   //Func - Static method
       
   246   //       Checks if an index exists in the named directory
       
   247   //Pre  - directory != NULL
       
   248   //Post - Returns true if an index exists at the specified directory->
       
   249   //       If the directory does not exist or if there is no index in it.
       
   250   //       false is returned.
       
   251 
       
   252        CND_PRECONDITION(directory != NULL, "directory is NULL");
       
   253 
       
   254 	   //Create a buffer of length CL_MAXDIR
       
   255        char f[CL_MAX_PATH];
       
   256 	   //Copy the directory string to the buffer. leave room for /segments
       
   257        strncpy(f,directory,CL_MAX_PATH-10);
       
   258 	   //Cat the name of the segments to buffer
       
   259        strcat(f, "/segments");
       
   260 	   //Check if the segments file exists
       
   261        return Misc::dir_Exists(f);
       
   262   }
       
   263     
       
   264 
       
   265   void IndexReader::setNorm(int32_t doc, const TCHAR* field, uint8_t value){
       
   266       // CPIXASYNC SCOPED_LOCK_MUTEX(THIS_LOCK)
       
   267       SCOPED_LOCK_CRUCIAL_MUTEX(IndexReader_THIS_LOCK)
       
   268     if(directoryOwner)
       
   269       aquireWriteLock();
       
   270     doSetNorm(doc, field, value);
       
   271     hasChanges = true;
       
   272   }
       
   273 
       
   274  void IndexReader::aquireWriteLock() {
       
   275     if (stale)
       
   276       _CLTHROWA(CL_ERR_IO,"IndexReader out of date and no longer valid for delete, undelete, or setNorm operations");
       
   277 
       
   278     if (writeLock == NULL) {
       
   279       LuceneLock* writeLock = directory->makeLock("write.lock");
       
   280       if (!writeLock->obtain(IndexWriter::WRITE_LOCK_TIMEOUT)) // obtain write lock
       
   281        _CLTHROWA(CL_ERR_IO,"Index locked for write"); // + writeLock
       
   282       this->writeLock = writeLock;
       
   283 
       
   284       // we have to check whether index has changed since this reader was opened.
       
   285       // if so, this reader is no longer valid for deletion
       
   286       if (SegmentInfos::readCurrentVersion(directory) > segmentInfos->getVersion()) {
       
   287         stale = true;
       
   288         this->writeLock->release();
       
   289         _CLDELETE(this->writeLock);
       
   290         _CLTHROWA(CL_ERR_IO,"IndexReader out of date and no longer valid for delete, undelete, or setNorm operations");
       
   291       }
       
   292     }
       
   293   }
       
   294   
       
   295 
       
   296   void IndexReader::setNorm(int32_t doc, const TCHAR* field, float_t value){
       
   297      setNorm(doc, field, CL_NS(search)::Similarity::encodeNorm(value));
       
   298   }
       
   299 
       
   300   bool IndexReader::indexExists(const Directory* directory){
       
   301   //Func - Static method
       
   302   //       Checks if an index exists in the directory
       
   303   //Pre  - directory is a valid reference
       
   304   //Post - Returns true if an index exists at the specified directory->
       
   305   //       If the directory does not exist or if there is no index in it.
       
   306   //       false is returned.
       
   307 
       
   308       return directory->fileExists("segments");
       
   309   }
       
   310 
       
   311   TermDocs* IndexReader::termDocs(Term* term) const {
       
   312   //Func - Returns an enumeration of all the documents which contain
       
   313   //       term. For each document, the document number, the frequency of
       
   314   //       the term in that document is also provided, for use in search scoring.
       
   315   //       Thus, this method implements the mapping: 
       
   316   //
       
   317   //       Term => <docNum, freq>*
       
   318   //	   The enumeration is ordered by document number.  Each document number
       
   319   //       is greater than all that precede it in the enumeration. 
       
   320   //Pre  - term != NULL
       
   321   //Post - A reference to TermDocs containing an enumeration of all found documents
       
   322   //       has been returned
       
   323 
       
   324       CND_PRECONDITION(term != NULL, "term is NULL");
       
   325 
       
   326       //Reference an instantiated TermDocs instance
       
   327       TermDocs* _termDocs = termDocs();
       
   328       //Seek all documents containing term
       
   329       _termDocs->seek(term);
       
   330       //return the enumaration
       
   331       return _termDocs;
       
   332   }
       
   333 
       
   334   TermPositions* IndexReader::termPositions(Term* term) const{
       
   335   //Func - Returns an enumeration of all the documents which contain  term. For each 
       
   336   //       document, in addition to the document number and frequency of the term in 
       
   337   //       that document, a list of all of the ordinal positions of the term in the document 
       
   338   //       is available.  Thus, this method implements the mapping:
       
   339   //
       
   340   //       Term => <docNum, freq,<pos 1, pos 2, ...pos freq-1>>*
       
   341   //
       
   342   //       This positional information faciliates phrase and proximity searching.
       
   343   //       The enumeration is ordered by document number.  Each document number is greater than 
       
   344   //       all that precede it in the enumeration. 
       
   345   //Pre  - term != NULL
       
   346   //Post - A reference to TermPositions containing an enumeration of all found documents
       
   347   //       has been returned
       
   348 
       
   349       CND_PRECONDITION(term != NULL, "term is NULL");
       
   350 
       
   351       //Reference an instantiated termPositions instance
       
   352       TermPositions* _termPositions = termPositions();
       
   353 	  //Seek all documents containing term
       
   354       _termPositions->seek(term);
       
   355 	  //return the enumeration
       
   356       return _termPositions;
       
   357   }
       
   358 
       
   359   void IndexReader::deleteDocument(const int32_t docNum) {
       
   360   //Func - Deletes the document numbered docNum.  Once a document is deleted it will not appear 
       
   361   //       in TermDocs or TermPostitions enumerations. Attempts to read its field with the document 
       
   362   //       method will result in an error.  The presence of this document may still be reflected in 
       
   363   //       the docFreq statistic, though this will be corrected eventually as the index is further modified.  
       
   364   //Pre  - docNum >= 0
       
   365   //Post - If successful the document identified by docNum has been deleted. If no writelock
       
   366   //       could be obtained an exception has been thrown stating that the index was locked or has no write access
       
   367 
       
   368       // CPIXASYNC SCOPED_LOCK_MUTEX(THIS_LOCK)
       
   369       SCOPED_LOCK_CRUCIAL_MUTEX(IndexReader_THIS_LOCK)
       
   370 
       
   371      CND_PRECONDITION(docNum >= 0, "docNum is negative");
       
   372 
       
   373       if (directoryOwner)
       
   374 		  aquireWriteLock();
       
   375 
       
   376 	  //Have the document identified by docNum deleted
       
   377       doDelete(docNum);
       
   378       hasChanges = true;
       
   379   }
       
   380 
       
   381   /**
       
   382    * Commit changes resulting from delete, undeleteAll, or setNorm operations
       
   383    * 
       
   384    * @throws IOException
       
   385    */
       
   386    void IndexReader::commit(){
       
   387        // CPIXASYNC SCOPED_LOCK_MUTEX(THIS_LOCK)
       
   388        SCOPED_LOCK_CRUCIAL_MUTEX(IndexReader_THIS_LOCK)
       
   389     if(hasChanges){
       
   390       if(directoryOwner){
       
   391         {
       
   392             // CPIXASYNC SCOPED_LOCK_MUTEX(directory->THIS_LOCK)      // in- & inter-process sync
       
   393             SCOPED_LOCK_CRUCIAL_MUTEX(directory->Directory_THIS_LOCK)      // in- & inter-process sync
       
   394 	
       
   395 	        LuceneLock* commitLock = directory->makeLock("commit.lock");
       
   396 	        IndexReader::CommitLockWith cl(commitLock,this);
       
   397 	        cl.run();
       
   398 			_CLDELETE(commitLock);
       
   399 	
       
   400 	    }
       
   401         if (writeLock != NULL) {
       
   402           writeLock->release();  // release write lock
       
   403           _CLDELETE(writeLock);
       
   404         }
       
   405       }else
       
   406         doCommit();
       
   407     }
       
   408     hasChanges = false;
       
   409   }
       
   410 
       
   411 
       
   412   void IndexReader::undeleteAll(){
       
   413       // CPIXASYNC SCOPED_LOCK_MUTEX(THIS_LOCK)
       
   414       SCOPED_LOCK_CRUCIAL_MUTEX(IndexReader_THIS_LOCK)
       
   415     if(directoryOwner)
       
   416       aquireWriteLock();
       
   417     doUndeleteAll();
       
   418     hasChanges = true;
       
   419   }
       
   420 
       
   421   int32_t IndexReader::deleteDocuments(Term* term) {
       
   422   //Func - Deletes all documents containing term. This is useful if one uses a 
       
   423   //       document field to hold a unique ID string for the document.  Then to delete such  
       
   424   //       a document, one merely constructs a term with the appropriate field and the unique 
       
   425   //       ID string as its text and passes it to this method.  
       
   426   //Pre  - term != NULL
       
   427   //Post - All documents containing term have been deleted. The number of deleted documents
       
   428   //       has been returned
       
   429 
       
   430       CND_PRECONDITION(term != NULL, "term is NULL");
       
   431 
       
   432 	  //Search for the documents contain term
       
   433       TermDocs* docs = termDocs(term);
       
   434 
       
   435 	  //Check if documents have been found
       
   436 	  if ( docs == NULL ){
       
   437           return 0;
       
   438 	  }
       
   439     
       
   440 	  //initialize
       
   441 	  int32_t Counter = 0;
       
   442       try {
       
   443 		  //iterate through the found documents
       
   444           while (docs->next()) {
       
   445 			  //Delete the document
       
   446               deleteDocument(docs->doc());
       
   447               ++Counter;
       
   448           }
       
   449       }_CLFINALLY(
       
   450 		  //Close the enumeration
       
   451           docs->close();
       
   452           );
       
   453 
       
   454     //Delete the enumeration of found documents
       
   455     _CLDELETE( docs );
       
   456 
       
   457 	//Return the number of deleted documents
       
   458     return Counter;
       
   459   }
       
   460   
       
   461 	TCHAR** IndexReader::getFieldNames(){
       
   462 		CL_NS(util)::StringArrayWithDeletor array;
       
   463 		getFieldNames(IndexReader::ALL, array);
       
   464 		
       
   465 		array.setDoDelete(false);
       
   466 		TCHAR** ret = _CL_NEWARRAY(TCHAR*,array.size()+1);
       
   467 		int j=0;
       
   468   		CL_NS(util)::StringArrayWithDeletor::iterator itr = array.begin();
       
   469   		while ( itr != array.end() ){
       
   470   			ret[j]=*itr;
       
   471 			++j;++itr;
       
   472  		}
       
   473 		ret[j]=NULL;
       
   474 		return ret;
       
   475 	}
       
   476 	TCHAR** IndexReader::getFieldNames(bool indexed){
       
   477 		CL_NS(util)::StringArrayWithDeletor array;
       
   478 		getFieldNames(indexed?IndexReader::INDEXED:IndexReader::UNINDEXED, array);
       
   479 		
       
   480 		array.setDoDelete(false);
       
   481 		TCHAR** ret = _CL_NEWARRAY(TCHAR*,array.size()+1);
       
   482 		int j=0;
       
   483   		CL_NS(util)::StringArrayWithDeletor::iterator itr = array.begin();
       
   484   		while ( itr != array.end() ){
       
   485   			ret[j]=*itr;
       
   486 			++j;++itr;
       
   487  		}
       
   488 		ret[j]=NULL;
       
   489 		return ret;
       
   490 	}
       
   491   
       
   492 
       
   493   void IndexReader::close() {
       
   494   //Func - Closes files associated with this index and also saves any new deletions to disk.
       
   495   //       No other methods should be called after this has been called.
       
   496   //Pre  - true
       
   497   //Post - All files associated with this index have been deleted and new deletions have been 
       
   498   //       saved to disk
       
   499       // CPIXASYNC SCOPED_LOCK_MUTEX(THIS_LOCK)
       
   500       SCOPED_LOCK_CRUCIAL_MUTEX(IndexReader_THIS_LOCK)
       
   501 
       
   502 	CloseCallbackMap::iterator iter = closeCallbacks.begin();
       
   503 	for ( ;iter!=closeCallbacks.end();iter++){
       
   504 		CloseCallback callback = *iter->first;
       
   505 		callback(this,iter->second);
       
   506 	}
       
   507 	
       
   508     commit();
       
   509     doClose();
       
   510 
       
   511 	if(closeDirectory){
       
   512       directory->close();
       
   513 	  _CLDECDELETE(directory);
       
   514 	}
       
   515   }
       
   516    
       
   517   bool IndexReader::isLocked(Directory* directory) {
       
   518   //Func - Static method 
       
   519   //       Checks if the index in the directory is currently locked.
       
   520   //Pre  - directory is a valid reference to a directory to check for a lock
       
   521   //Post - Returns true if the index in the named directory is locked otherwise false
       
   522 
       
   523 	  //Check the existence of the file write.lock and return true when it does and false
       
   524 	  //when it doesn't
       
   525      LuceneLock* l1 = directory->makeLock("write.lock");
       
   526      LuceneLock* l2 = directory->makeLock("commit.lock");
       
   527 
       
   528 	 bool ret = l1->isLocked() || l2->isLocked();
       
   529 
       
   530      _CLDELETE(l1);
       
   531      _CLDELETE(l2);
       
   532      return ret;
       
   533   }
       
   534 
       
   535   bool IndexReader::isLocked(const char* directory) {
       
   536   //Func - Static method 
       
   537   //       Checks if the index in the named directory is currently locked.
       
   538   //Pre  - directory != NULL and contains the directory to check for a lock
       
   539   //Post - Returns true if the index in the named directory is locked otherwise false
       
   540 
       
   541       CND_PRECONDITION(directory != NULL, "directory is NULL");
       
   542 
       
   543 	  //Create a buffer of length CL_MAXDIR
       
   544       char f[CL_MAX_PATH]; //todo: potential buffer overflow
       
   545 	  //Copy the directory string to the buffer. leave room for /write.lock
       
   546       strncpy(f,directory,CL_MAX_PATH-12);
       
   547 	  //Cat the name of the write.lock file to buffer
       
   548       strcat ( f,"/write.lock" );
       
   549 
       
   550       Directory* dir = FSDirectory::getDirectory(directory,false);
       
   551       bool ret = isLocked(dir);
       
   552 	  dir->close();
       
   553       _CLDECDELETE(dir);
       
   554 
       
   555 	  return ret;
       
   556   }
       
   557   
       
   558 /** Returns true if there are norms stored for this field. */
       
   559 bool IndexReader::hasNorms(const TCHAR* field) {
       
   560 	// backward compatible implementation.
       
   561 	// SegmentReader has an efficient implementation.
       
   562 	return norms(field) != NULL;
       
   563 }
       
   564 
       
   565 void IndexReader::unlock(const char* path){
       
   566 	FSDirectory* dir = FSDirectory::getDirectory(path,false);
       
   567 	unlock(dir);
       
   568 	dir->close();
       
   569 	_CLDECDELETE(dir);
       
   570 }
       
   571   void IndexReader::unlock(Directory* directory){
       
   572   //Func - Static method
       
   573   //       Forcibly unlocks the index in the named directory->
       
   574   //       Caution: this should only be used by failure recovery code,
       
   575   //       when it is known that no other process nor thread is in fact
       
   576   //       currently accessing this index.
       
   577   //Pre  - directory is a valid reference to a directory 
       
   578   //Post - The directory has been forcibly unlocked
       
   579       LuceneLock* lock;
       
   580 
       
   581 	  lock = directory->makeLock("write.lock");
       
   582       lock->release();
       
   583       _CLDELETE(lock);
       
   584 
       
   585       lock = directory->makeLock("commit.lock");
       
   586       lock->release();
       
   587       _CLDELETE(lock);
       
   588   }
       
   589 
       
   590 bool IndexReader::isLuceneFile(const char* filename){
       
   591 	if ( !filename )
       
   592 		return false;
       
   593 	size_t len = strlen(filename);
       
   594 	if ( len < 6 ) //need at least x.frx
       
   595 		return false;
       
   596 	const char* ext=filename+len;
       
   597 	while(*ext != '.' && ext!=filename)
       
   598 		ext--;
       
   599 
       
   600 	if ( strcmp(ext, ".cfs") == 0 )
       
   601 		return true;
       
   602 	else if ( strcmp(ext, ".fnm") == 0 )
       
   603 		return true;
       
   604 	else if ( strcmp(ext, ".fdx") == 0 )
       
   605 		return true;
       
   606 	else if ( strcmp(ext, ".fdt") == 0 )
       
   607 		return true;
       
   608 	else if ( strcmp(ext, ".tii") == 0 )
       
   609 		return true;
       
   610 	else if ( strcmp(ext, ".tis") == 0 )
       
   611 		return true;
       
   612 	else if ( strcmp(ext, ".frq") == 0 )
       
   613 		return true;
       
   614 	else if ( strcmp(ext, ".prx") == 0 )
       
   615 		return true;
       
   616 	else if ( strcmp(ext, ".del") == 0 )
       
   617 		return true;
       
   618 	else if ( strcmp(ext, ".tvx") == 0 )
       
   619 		return true;
       
   620 	else if ( strcmp(ext, ".tvd") == 0 )
       
   621 		return true;
       
   622 	else if ( strcmp(ext, ".tvf") == 0 )
       
   623 		return true;
       
   624 	else if ( strcmp(ext, ".tvp") == 0 )
       
   625 		return true;
       
   626 
       
   627 	else if ( strcmp(filename, "segments") == 0 )
       
   628 		return true;
       
   629 	else if ( strcmp(filename, "segments.new") == 0 )
       
   630 		return true;
       
   631 	else if ( strcmp(filename, "deletable") == 0 )
       
   632 		return true;
       
   633 
       
   634 	else if ( strncmp(ext,".f",2)==0 ){
       
   635 		const char* n = ext+2;
       
   636 		if ( *n && _istdigit(*n) )
       
   637 			return true;	
       
   638 	}
       
   639 
       
   640 	return false;
       
   641 }
       
   642 
       
   643 	void IndexReader::addCloseCallback(CloseCallback callback, void* parameter){
       
   644 		closeCallbacks.put(callback, parameter);	
       
   645 	}
       
   646 
       
   647 
       
   648 	//Constructor	
       
   649     IndexReader::LockWith::LockWith(CL_NS(store)::LuceneLock* lock, CL_NS(store)::Directory* dir):
       
   650 		CL_NS(store)::LuceneLockWith<IndexReader*>(lock,IndexWriter::COMMIT_LOCK_TIMEOUT)
       
   651 	{
       
   652 		this->directory = dir;
       
   653 	}	
       
   654 	//Constructor	
       
   655 	IndexReader::CommitLockWith::CommitLockWith( CL_NS(store)::LuceneLock* lock, IndexReader* r ):
       
   656 		CL_NS(store)::LuceneLockWith<void>(lock,IndexWriter::COMMIT_LOCK_TIMEOUT),
       
   657 		reader(r)
       
   658 	{
       
   659 	}
       
   660 	void IndexReader::CommitLockWith::doBody(){
       
   661 		reader->doCommit();
       
   662 		reader->segmentInfos->write(reader->getDirectory());
       
   663 	}
       
   664 
       
   665 CL_NS_END