/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/search/trunk/search-impl/impl/src/java/org/sakaiproject/search/index/impl/FSIndexStorage.java $ * $Id: FSIndexStorage.java 105078 2012-02-24 23:00:38Z ottenhoff@longsight.com $ *********************************************************************************** * * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaiproject.search.index.impl; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.sakaiproject.search.api.SearchService; /** * A local only filestore implementation. This is a simple IndexImplementation * that performs all its indexing in a single, unoptimized segment on the local * filesystem To set the location use * location@org.sakaiproject.search.api.SearchService.LocalIndexStorage in * sakai.properties Check that the bean name is correct in the spring * components.xml file * * @author ieb */ public class FSIndexStorage extends BaseIndexStorage { private static Log log = LogFactory.getLog(FSIndexStorage.class); protected String searchIndexDirectory = "searchindex"; protected boolean recoverCorruptedIndex = false; private long lastUpdate = System.currentTimeMillis(); public void init() { } public void doPreIndexUpdate() throws IOException { log.debug("Starting process List on " + searchIndexDirectory); File f = new File(searchIndexDirectory); if (!f.exists()) { if (!f.mkdirs()) { log.warn("doPreIndexUpdate() couldn't delete " + f.getPath()); } log.debug("Indexing in " + f.getAbsolutePath()); } if (IndexWriter.isLocked(FSDirectory.open(f))) { // this could be dangerous, I am assuming that // the locking mechanism implemented here is // robust and // already prevents multiple modifiers. // A more IndexWriter.unlock(FSDirectory.open(f)); log.warn("Unlocked Lucene Directory for update, hope this is Ok"); } } public IndexReader getIndexReader() throws IOException { File f = new File(searchIndexDirectory); return IndexReader.open(FSDirectory.open(f), true); } public IndexWriter getIndexWriter(boolean create) throws IOException { File f = new File(searchIndexDirectory); return new IndexWriter(FSDirectory.open(f), getAnalyzer(), create, IndexWriter.MaxFieldLength.UNLIMITED); } public void doPostIndexUpdate() throws IOException { lastUpdate = System.currentTimeMillis(); } /** * @return Returns the searchIndexDirectory. */ public String getSearchIndexDirectory() { return searchIndexDirectory; } protected IndexSearcher getIndexSearcher() throws IOException { IndexSearcher indexSearcher = null; try { long reloadStart = System.currentTimeMillis(); File indexDirectoryFile = new File(searchIndexDirectory); if (!indexDirectoryFile.exists()) { if (!indexDirectoryFile.mkdirs()) { log.warn("getIdexSearch couldn't create directory " + indexDirectoryFile.getPath()); } } File f = new File(searchIndexDirectory); indexSearcher = new IndexSearcher(FSDirectory.open(f), false); if (indexSearcher == null) { log.warn("No search Index exists at this time"); } long reloadEnd = System.currentTimeMillis(); if (diagnostics) { log.info("Reload Complete " + indexSearcher.getIndexReader().numDocs() + " in " + (reloadEnd - reloadStart)); } } catch (FileNotFoundException e) { log.error("There has been a major poblem with the" + " Search Index which has become corrupted ", e); if (doIndexRecovery()) { File f = new File(searchIndexDirectory); indexSearcher = new IndexSearcher(FSDirectory.open(f), false); } } catch (IOException e) { log.error("There has been a major poblem with the " + "Search Index which has become corrupted", e); if (doIndexRecovery()) { Directory dir = FSDirectory.open(new File(searchIndexDirectory)); indexSearcher = new IndexSearcher(dir, false); } } return indexSearcher; } protected boolean doIndexRecovery() throws IOException { if (recoverCorruptedIndex) { IndexWriter iw = getIndexWriter(true); Document doc = new Document(); String message = "Index Recovery performed on " + (new Date()).toString(); doc.add(new Field(SearchService.FIELD_CONTENTS, message, Field.Store.NO, Field.Index.ANALYZED)); iw.addDocument(doc); iw.close(); log.error("Sucess fully recoverd From a corrupted index, " + "the index will be empty and require a " + "complete rebuild"); return true; } return false; } public boolean indexExists() { Directory dir; try { dir = FSDirectory.open(new File(searchIndexDirectory)); return IndexReader.indexExists(dir); } catch (IOException e) { return false; } } /** * @return Returns the recoverCorruptedIndex. */ public boolean isRecoverCorruptedIndex() { return recoverCorruptedIndex; } /** * @param recoverCorruptedIndex * The recoverCorruptedIndex to set. */ public void setRecoverCorruptedIndex(boolean recoverCorruptedIndex) { log.info("Using FSIndexStorage, storing the index " + "on the local file system in " + searchIndexDirectory + " if the index is corrupted recovery will " + (recoverCorruptedIndex ? "" : "NOT ") + " be automatic"); this.recoverCorruptedIndex = recoverCorruptedIndex; } public void setLocation(String location) { searchIndexDirectory = location; } public long getLastUpdate() { // not really relevant in the non cluster environment return lastUpdate; } public List getSegmentInfoList() { List<Object[]> l = new ArrayList<Object[]>(); l .add(new Object[] { "Index Segment Info is not implemented for Local file system index stores", "", "" }); return l; } public void closeIndexReader(IndexReader indexReader) throws IOException { if (indexReader != null) { indexReader.close(); } } public void closeIndexWriter(IndexWriter indexWrite) throws IOException { if (indexWrite != null) { indexWrite.close(); } } public boolean isMultipleIndexers() { return false; } public void closeIndexSearcher(IndexSearcher indexSearcher) { IndexReader indexReader = indexSearcher.getIndexReader(); boolean closedAlready = false; try { if (indexReader != null) { indexReader.close(); closedAlready = true; } } catch (Exception ex) { log.error("Failed to close Index Reader " + ex.getMessage()); } try { indexSearcher.close(); } catch (Exception ex) { if (closedAlready) { log.debug("Failed to close Index Searcher " + ex.getMessage()); } else { log.error("Failed to close Index Searcher " + ex.getMessage()); } } } /* * (non-Javadoc) * * @see org.sakaiproject.search.index.IndexStorage#centralIndexExists() */ public boolean centralIndexExists() { return indexExists(); } private Directory spellDirectory = null; public Directory getSpellDirectory() { return spellDirectory; } }