2003-06-14 08:05:34 +00:00

445 lines
11 KiB
Java

/*
* 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 <http://www.mozilla.org/MPL/>.
*
* 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 <erbo@silcom.com>,
* 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