package org.solbase.cache;
import java.lang.management.ManagementFactory;
import java.util.Set;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import org.apache.log4j.Logger;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.solr.search.DocList;
import org.apache.solr.search.LRUCache;
import org.apache.solr.search.SolrCacheWithReader;
import org.solbase.lucenehbase.CompactedTermDocMetadataArray;
import org.solbase.lucenehbase.ReaderCache;
import org.solbase.lucenehbase.TermDocMetadataVersionIdentifier;
public class QueryResultCache extends LRUCache implements SolrCacheWithReader, QueryResultCacheMBean{
private String indexName;
private int startDocId;
private int endDocId;
// 2 hours query result cache expiration;
// TODO: making it 2 hours since we have cross shard version update issue
// if one of shard updates version identifier, replication only picks up version changes, but not actual term vector changes,
// it will cache stale version of term vector and never expire query result cache
public static final long QUERY_RESULT_CACHE_TIMEOUT = 1000 * 60 * 120;
private final static Logger logger = Logger.getLogger(QueryResultCache.class);
public QueryResultCache(){
super();
// register mbean here
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName objName;
try {
objName = new ObjectName("org.solbase.cache:type=QueryResultCache"+Math.random());
mbs.registerMBean(this, objName);
} catch (InstanceAlreadyExistsException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MBeanRegistrationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NotCompliantMBeanException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedObjectNameException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (NullPointerException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
@Override
public void setReader(IndexReader reader) {
this.indexName = ((org.solbase.lucenehbase.IndexReader)reader).getIndexName();
this.startDocId = ((org.solbase.lucenehbase.IndexReader)reader).getStartDocId();
this.endDocId = ((org.solbase.lucenehbase.IndexReader)reader).getEndDocId();
}
public Object put(Object key, Object value, Set terms) {
try {
return super.put(key, new DocListCachedWrapper((DocList)value, terms, indexName, startDocId, endDocId));
} catch (Exception e) {
return null;
}
}
public Object get(Object key, Set terms) {
DocListCachedWrapper dlcw = (DocListCachedWrapper)this.get(key);
if (dlcw == null) {
// we don't have query result cache given query
return null;
}
long dlcwTs = dlcw.getTimestamp();
long currentTs = System.currentTimeMillis();
if((currentTs - dlcwTs) > QUERY_RESULT_CACHE_TIMEOUT) {
// we are blindly expiring query result cache if time has passed
return null;
}
for (Term term : (Set<Term>) terms) {
CachedObjectWrapper<CompactedTermDocMetadataArray, TermDocMetadataVersionIdentifier> cow;
try {
cow = ReaderCache.getTermDocsMetadata(term, indexName, startDocId, endDocId);
} catch (Exception e) {
return null;
}
Long cachedVersion = dlcw.getVersionId(term);
if (cachedVersion == null || cow.getVersionIdentifier().getVersionIdentifier() != cachedVersion) {
return null;
}
}
return dlcw.getDocList();
}
@Override
public Object put(Object key, Object value) {
throw new UnsupportedOperationException();
}
public void acquireLock(Set terms){
for (Term term : (Set<Term>) terms) {
CachedObjectWrapper<CompactedTermDocMetadataArray, TermDocMetadataVersionIdentifier> cow;
CompactedTermDocMetadataArray ctdm = null;
try {
cow = ReaderCache.getTermDocsMetadata(term, indexName, startDocId, endDocId);
ctdm = cow.getValue();
if(ctdm.readWriteLock.getReadLockCount() > 10){
logger.debug(term.toString() + " has this many read locks currently: " + ctdm.readWriteLock.getReadLockCount());
}
if(ctdm != null){
ctdm.readWriteLock.readLock().lock();
}
} catch (Exception e) {
}
}
}
public void releaseLock(Set terms){
for (Term term : (Set<Term>) terms) {
CachedObjectWrapper<CompactedTermDocMetadataArray, TermDocMetadataVersionIdentifier> cow;
CompactedTermDocMetadataArray ctdm = null;
try {
cow = ReaderCache.getTermDocsMetadata(term, indexName, startDocId, endDocId);
ctdm = cow.getValue();
if(ctdm != null){
ctdm.readWriteLock.readLock().unlock();
}
} catch (Exception e) {
}
}
}
}