/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/search/trunk/search-impl/impl/src/java/org/sakaiproject/search/journal/impl/RefCountIndexSearcher.java $
* $Id: RefCountIndexSearcher.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.journal.impl;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.IndexSearcher;
import org.sakaiproject.search.journal.api.IndexCloser;
import org.sakaiproject.search.journal.api.ManagementOperation;
import org.sakaiproject.search.journal.api.ThreadBinder;
import org.sakaiproject.thread_local.api.ThreadBound;
import org.sakaiproject.thread_local.api.ThreadLocalManager;
/**
* @author ieb
*/
public class RefCountIndexSearcher extends IndexSearcher implements ThreadBound,
ThreadBinder, IndexCloser
{
private static final Log log = LogFactory.getLog(RefCountIndexSearcher.class);
private int count = 0;
private boolean doclose = false;
private JournaledFSIndexStorage storage;
private IndexReader indexReader;
private boolean closing = false;
private ThreadLocalManager threadLocalManager;
private ThreadLocal<String> unbindingMonitor = new ThreadLocal<String>();
private Object closeMonitor = new Object();
private ManagementOperation managementOperation;
private static int opened = 0;
/**
* @param storage
* @param ir
*/
public RefCountIndexSearcher(IndexReader indexReader, JournaledFSIndexStorage storage)
{
super(indexReader);
opened++;
this.managementOperation = ConcurrentIndexManager.getCurrentManagementOperation();
this.storage = storage;
this.indexReader = indexReader;
if (indexReader instanceof IndexCloser)
{
((IndexCloser) indexReader).addParent(this);
}
}
/*
* (non-Javadoc)
*
* @see org.apache.lucene.search.IndexSearcher#close()
*/
@Override
public void close() throws IOException
{
doclose = true;
unbind();
storage.fireIndexSearcherClose(this);
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.thread_local.api.ThreadBound#unbind()
*/
public void unbind()
{
Object unbinding = unbindingMonitor.get();
if (unbinding == null)
{
try
{
unbindingMonitor.set("unbinding");
if (threadLocalManager != null)
{
Object o = threadLocalManager.get(String.valueOf(this));
if (o != null)
{
count--;
if (log.isDebugEnabled())
log.debug("Unbound " + this + " " + count);
threadLocalManager.set(String.valueOf(this), null); // unbind
// the
// dependents
}
if (indexReader instanceof ThreadBound)
{
((ThreadBound) indexReader).unbind();
}
}
if (canClose())
{
forceClose();
}
}
finally
{
unbindingMonitor.set(null);
}
}
}
public void bind(ThreadLocalManager tlm)
{
threadLocalManager = tlm;
Object o = tlm.get(String.valueOf(this));
if (o == null)
{
count++;
tlm.set(String.valueOf(this), this);
if (log.isDebugEnabled())
log.debug("Bind " + this + " " + indexReader + " " + count);
}
else if (o != this)
{
log.warn(" More than one object bound to the same key ");
}
if (indexReader instanceof ThreadBinder)
{
((ThreadBinder) indexReader).bind(tlm);
}
}
/**
*
*/
public boolean doFinalClose()
{
if (canClose())
{
return forceClose();
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.search.journal.impl.IndexCloser#canClose()
*/
public boolean canClose()
{
return (count <= 0 && doclose);
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.search.journal.impl.IndexCloser#forceClose()
*/
public boolean forceClose()
{
synchronized (closeMonitor)
{
if (closing) return true;
closing = true;
}
opened --;
if (indexReader instanceof IndexCloser)
{
((IndexCloser) indexReader).removeParent(this);
}
if (log.isDebugEnabled()) log.debug("Closing Index " + this);
try
{
super.close();
}
catch (IOException ioex)
{
log.debug(ioex);
}
try
{
if (indexReader != null) indexReader.close();
}
catch (IOException ioex)
{
}
return true;
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.search.journal.api.IndexCloser#addParent(org.apache.lucene.search.IndexSearcher)
*/
public void addParent(Object searcher)
{
// searchers cant have parents
log.debug("Index Searchers may not have parents, ignored");
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.search.journal.api.IndexCloser#removeParent(java.lang.Object)
*/
public void removeParent(Object searcher)
{
log.debug("Index Searchers may not have parents, ignored");
}
/**
* @return
*/
public static int getOpened()
{
return opened;
}
/* (non-Javadoc)
* @see org.sakaiproject.search.journal.api.IndexCloser#getName()
*/
public String getName()
{
return managementOperation+" "+toString()+" Refcount:"+count;
}
}