/* * The contents of this file are subject to the Mozilla Public License Version 1.1 * (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at . * * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT * WARRANTY OF ANY KIND, either express or implied. See the License for the specific * language governing rights and limitations under the License. * * The Original Code is the Venice Web Communities System. * * The Initial Developer of the Original Code is Eric J. Bowersox , * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. * * Contributor(s): */ package com.silverwrist.dynamo.index; import java.io.*; import java.util.*; import org.apache.log4j.Logger; import org.apache.lucene.store.*; import com.silverwrist.dynamo.except.*; import com.silverwrist.dynamo.iface.*; class IndexDirectoryImpl extends Directory { /*-------------------------------------------------------------------------------- * Internal class implementing the Lock object *-------------------------------------------------------------------------------- */ private class MyLock extends Lock { /*==================================================================== * Attributes *==================================================================== */ private String m_name; /*==================================================================== * Constructor *==================================================================== */ MyLock(String name) { m_name = name; } // end constructor /*==================================================================== * Abstract implementations from class Lock *==================================================================== */ public boolean obtain() throws IOException { try { // call through to the database return m_ops.obtainLock(m_ndx,m_name); } // end try catch (DatabaseException e) { // turn it into an I/O exception throw translateException(e); } // end catch } // end obtain public void release() { try { // call through to the database m_ops.releaseLock(m_ndx,m_name); } // end try catch (DatabaseException e) { // just log the exception logger.warn("IndexDirectoryImpl.MyLock.release(): failed operation",e); } // end catch } // end release } // end class MyLock /*-------------------------------------------------------------------------------- * Static data members *-------------------------------------------------------------------------------- */ private static Logger logger = Logger.getLogger(IndexDirectoryImpl.class); /*-------------------------------------------------------------------------------- * Attributes *-------------------------------------------------------------------------------- */ private IndexOps m_ops; private int m_ndx; private Hashtable m_current = new Hashtable(); /*-------------------------------------------------------------------------------- * Constructor *-------------------------------------------------------------------------------- */ IndexDirectoryImpl(int ndx, IndexOps ops) { super(); m_ops = ops; m_ndx = ndx; } // end constructor /*-------------------------------------------------------------------------------- * Internal operations *-------------------------------------------------------------------------------- */ private static final IOException translateException(DatabaseException e) { logger.info("database operation threw exception",e); IOException ie = new IOException("Database error on file operation"); ie.initCause(e); return ie; } // end translateException /*-------------------------------------------------------------------------------- * Abstract implementations from class Directory *-------------------------------------------------------------------------------- */ public String[] list() throws IOException { try { // call through to the database return m_ops.listFiles(m_ndx); } // end try catch (DatabaseException e) { // turn it into an I/O exception throw translateException(e); } // end catch } // end list public boolean fileExists(String name) throws IOException { try { // call through to the database CurrentFile cf = (CurrentFile)(m_current.get(name)); if (cf!=null) return true; return (m_ops.getModTime(m_ndx,name)>=0); } // end try catch (DatabaseException e) { // turn it into an I/O exception throw translateException(e); } // end catch } // end fileExists public long fileModified(String name) throws IOException { try { // call through to the database CurrentFile cf = (CurrentFile)(m_current.get(name)); if (cf!=null) return cf.getModTime(); return m_ops.getModTime(m_ndx,name); } // end try catch (DatabaseException e) { // turn it into an I/O exception throw translateException(e); } // end catch } // end fileModified public void touchFile(String name) throws IOException { try { // call through to the database long mtime = System.currentTimeMillis(); CurrentFile cf = (CurrentFile)(m_current.get(name)); if (cf!=null) cf.setModTime(mtime); else m_ops.setModTime(m_ndx,name,mtime); } // end try catch (DatabaseException e) { // turn it into an I/O exception throw translateException(e); } // end catch } // end touchFile public void deleteFile(String name) throws IOException { try { // call through to the database m_ops.deleteFile(m_ndx,name); CurrentFile cf = (CurrentFile)(m_current.get(name)); if (cf!=null) { // detach file from current and make sure we don't update m_current.remove(name); cf.noUpdate(); } // end if } // end try catch (DatabaseException e) { // turn it into an I/O exception throw translateException(e); } // end catch } // end deleteFile public void renameFile(String from, String to) throws IOException { try { // call through to the database m_ops.renameFile(m_ndx,from,to); CurrentFile cf = (CurrentFile)(m_current.get(to)); if (cf!=null) { // this file was deleted - detach file from current and make sure we don't update m_current.remove(to); cf.noUpdate(); } // end if cf = (CurrentFile)(m_current.get(from)); if (cf!=null) { // reset the name and juggle things m_current.remove(from); cf.setName(to); m_current.put(to,cf); } // end if } // end try catch (DatabaseException e) { // turn it into an I/O exception throw translateException(e); } // end catch } // end renameFile public long fileLength(String name) throws IOException { try { // call through to the database CurrentFile cf = (CurrentFile)(m_current.get(name)); if (cf!=null) return cf.length(); return m_ops.getLength(m_ndx,name); } // end try catch (DatabaseException e) { // turn it into an I/O exception throw translateException(e); } // end catch } // end fileLength public org.apache.lucene.store.OutputStream createFile(String name) throws IOException { long mtime = -1L; CurrentFile cf = null; try { // create the file entry mtime = m_ops.createNewEntry(m_ndx,name); if (mtime==-1L) throw new IOException("file " + name + " already exists"); // now create a CurrentFile object cf = new CurrentFile(this,File.createTempFile("dynamo-index",null),name,0L,mtime); m_current.put(name,cf); // and open it for writing org.apache.lucene.store.OutputStream rc = cf.openOutput(); cf.release(); cf = null; mtime = -1L; return rc; } // end try catch (DatabaseException e) { // turn it into an I/O exception throw translateException(e); } // end catch finally { // if we screwed up, back out of stuff try { // but do it without raising any more exceptions if (cf!=null) cf.abandon(); if (mtime>=0) m_ops.deleteFile(m_ndx,name); } // end try catch (Exception e) { // just ignore exceptions here logger.warn("IndexDirectoryImpl.createFile(): error recovery threw exception",e); } // end catch } // end finally } // end try public org.apache.lucene.store.InputStream openFile(String name) throws IOException { File tempfile = null; CurrentFile cf = null; try { // first see if the file's already open CurrentFile cf2 = (CurrentFile)(m_current.get(name)); if (cf2!=null) return cf2.openInput(); // open it again // load the file data tempfile = File.createTempFile("dynamo-index",null); long mtime = m_ops.loadFile(m_ndx,name,tempfile); if (mtime==-1) throw new IOException("file " + name + " does not exist"); // now create a CurrentFile object cf = new CurrentFile(this,tempfile,name,tempfile.length(),mtime); tempfile = null; // done with tempfile m_current.put(name,cf); // and open it for reading org.apache.lucene.store.InputStream rc = cf.openInput(); cf.release(); cf = null; return rc; } // end try catch (DatabaseException e) { // turn it into an I/O exception throw translateException(e); } // end catch finally { // if we screwed up, back out of stuff if (cf!=null) cf.abandon(); if (tempfile!=null) tempfile.delete(); } // end finally } // end openFile public Lock makeLock(String name) { return new MyLock(name); } // end makeLock public void close() throws IOException { try { // Get all the "current" files and close them. LinkedList files = new LinkedList(m_current.values()); m_current.clear(); while (!(files.isEmpty())) { // get each file in turn and release it till it dies CurrentFile cf = (CurrentFile)(files.removeFirst()); int foo = 1; while (foo>0) foo = cf.release(); } // end while // release any outstanding locks m_ops.releaseAllLocks(m_ndx); } // end try catch (DatabaseException e) { // turn it into an I/O exception throw translateException(e); } // end catch } // end close /*-------------------------------------------------------------------------------- * External operations *-------------------------------------------------------------------------------- */ void storeFile(String name, long mtime, File data) throws IOException { try { // call through to the database m_ops.storeFile(m_ndx,name,mtime,data); } // end try catch (DatabaseException e) { // turn it into an I/O exception throw translateException(e); } // end catch } // end storeFile void detach(String name) { m_current.remove(name); } // end detach void abandon() { LinkedList files = new LinkedList(m_current.values()); m_current.clear(); while (!(files.isEmpty())) { // get each file in turn and release it till it dies CurrentFile cf = (CurrentFile)(files.removeFirst()); cf.abandon(); } // end while } // end abandon } // end class IndexDirectoryImpl