445 lines
11 KiB
Java
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
|