/*******************************************************************************
* Copyright (c) 2008 Cambridge Semantics Incorporated.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* File: $Source$
* Created by: Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com </a>)
* Created on: Dec 17, 2008
* Revision: $Id$
*
* Contributors:
* Cambridge Semantics Incorporated - initial API and implementation
*******************************************************************************/
package org.openanzo.datasource.services;
import java.util.Collection;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.openanzo.cache.ICache;
import org.openanzo.cache.ICacheProvider;
import org.openanzo.exceptions.AnzoException;
import org.openanzo.exceptions.LogUtils;
import org.openanzo.glitter.dataset.QueryDataset;
import org.openanzo.rdf.Constants;
import org.openanzo.rdf.Statement;
import org.openanzo.rdf.URI;
import org.openanzo.rdf.utils.UriGenerator;
import org.openanzo.services.IOperationContext;
import org.openanzo.services.IUpdateResultListener;
import org.openanzo.services.IUpdateTransaction;
import org.openanzo.services.IUpdates;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Cache for the model service
*
* @author Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com</a>)
*
*/
public class ModelServiceCache implements IUpdateResultListener {
private static final Logger log = LoggerFactory.getLogger(ModelServiceCache.class);
ICache<String, Collection<Statement>> findCache;
ICache<URI, Long> sizeCache;
ICache<URI, Boolean> containsCache;
ICache<URI, URI> uuidCache;
ICache<String, Collection<Statement>> revisionCache;
ICache<URI, QueryDataset> datasetCache;
private final Lock lock = new ReentrantLock();
ModelServiceCache(String name, ICacheProvider cacheProvider) {
this.findCache = cacheProvider.<String, Collection<Statement>> openCache(name + "ModelServiceFindCache", 5000, true);
this.sizeCache = cacheProvider.<URI, Long> openCache(name + "ModelServiceSizeCache", 10000, true);
this.containsCache = cacheProvider.<URI, Boolean> openCache(name + "ModelServiceContainsCache", 10000, true);
this.uuidCache = cacheProvider.<URI, URI> openCache(name + "ModelServiceUUIDCache", 25000, true);
this.revisionCache = cacheProvider.<String, Collection<Statement>> openCache(name + "ModelServiceRevisionCache", 5000, true);
this.datasetCache = cacheProvider.<URI, QueryDataset> openCache(name + "ModelServiceDatasetCache", 5000, true);
}
void reset() {
lock.lock();
try {
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "QueryCache reset");
}
findCache.clear();
sizeCache.clear();
containsCache.clear();
uuidCache.clear();
revisionCache.clear();
datasetCache.clear();
} finally {
lock.unlock();
}
}
private ThreadLocal<ClassLoader> oldLoader = new ThreadLocal<ClassLoader>();
private void entry() {
oldLoader.set(Thread.currentThread().getContextClassLoader());
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
}
private void exit() {
Thread.currentThread().setContextClassLoader(oldLoader.get());
oldLoader.remove();
}
Long getSize(URI namedGraphURI) {
entry();
try {
Long result = sizeCache.get(namedGraphURI);
if (result != null && log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "CacheHit Size:" + namedGraphURI + ":" + result.toString());
}
return result;
} finally {
exit();
}
}
void cacheSize(URI namedGraphURI, Long size) {
entry();
try {
sizeCache.put(namedGraphURI, size);
} finally {
exit();
}
}
Collection<Statement> getGraph(URI namedGraphURI, long revision) {
entry();
try {
Collection<Statement> result = revisionCache.get(namedGraphURI.toString() + ":" + revision);
if (result != null && log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "CacheHit Graph:" + namedGraphURI + ":" + result.toString());
}
return result;
} finally {
exit();
}
}
void cacheGraph(URI namedGraphURI, Collection<Statement> graph, long revision) {
entry();
try {
revisionCache.put(namedGraphURI.toString() + ":" + revision, graph);
} finally {
exit();
}
}
Collection<Statement> getFindStatements(String queryString) {
entry();
try {
Collection<Statement> result = findCache.get(queryString);
if (result != null && log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "CacheHit Find:" + queryString + ":" + result.toString());
}
return result;
} finally {
exit();
}
}
void cacheFind(String queryString, Collection<Statement> stmts) {
entry();
try {
findCache.put(queryString, stmts);
} finally {
exit();
}
}
Boolean getContains(URI namedGraphURI) {
entry();
try {
Boolean result = containsCache.get(namedGraphURI);
if (result != null && log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "CacheHit Contains:" + namedGraphURI + ":" + result.toString());
}
return result;
} finally {
exit();
}
}
void cacheContains(URI namedGraphURI, Boolean contains) {
entry();
try {
containsCache.put(namedGraphURI, contains);
} finally {
exit();
}
}
URI getUriForUUID(URI uuid) {
entry();
try {
URI result = uuidCache.get(uuid);
if (result != null && log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "CacheHit UUID:" + uuid + ":" + result.toString());
}
return result;
} finally {
exit();
}
}
void cacheUriForUUID(URI uuid, URI uri) {
entry();
try {
uuidCache.put(uuid, uri);
} finally {
exit();
}
}
URI getUUIDforURI(URI uri) {
entry();
try {
URI result = uuidCache.get(uri);
if (result != null && log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "CacheHit URI:" + uri + ":" + result.toString());
}
return result;
} finally {
exit();
}
}
void cacheUUIDforURI(URI uri, URI uuid) {
entry();
try {
uuidCache.put(uri, uuid);
} finally {
exit();
}
}
public QueryDataset getNamedDataset(URI namedDatasetURI) {
entry();
try {
QueryDataset result = datasetCache.get(namedDatasetURI);
if (result != null && log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "CacheHit Dataset:" + namedDatasetURI + ":" + result.toString());
}
return result;
} finally {
exit();
}
}
public void cacheNamedDataset(URI namedDatasetURI, QueryDataset uris) {
entry();
try {
datasetCache.put(namedDatasetURI, uris);
} finally {
exit();
}
}
public void updateComplete(IOperationContext context, IUpdates results) throws AnzoException {
lock.lock();
long start = 0;
if (log.isDebugEnabled()) {
start = System.currentTimeMillis();
}
entry();
try {
for (IUpdateTransaction transaction : results.getTransactions()) {
for (URI ngUri : transaction.getUpdatedNamedGraphs().keySet()) {
URI mdGraph = UriGenerator.generateMetadataGraphUri(ngUri);
updateCache(ngUri);
updateCache(mdGraph);
if (null != uuidCache.remove(transaction.getUpdatedNamedGraphs().get(ngUri))) {
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing uuid:" + mdGraph.toString());
}
}
}
for (URI ngUri : transaction.getRemovedNamedGraphs().keySet()) {
URI mdGraph = UriGenerator.generateMetadataGraphUri(ngUri);
removeCache(ngUri);
removeCache(mdGraph);
if (null != uuidCache.remove(transaction.getUpdatedNamedGraphs().get(ngUri))) {
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing uuid:" + mdGraph.toString());
}
}
}
if (transaction.getRemovedNamedGraphs().size() > 0) {
removeCache(Constants.GRAPHS.GRAPHS_DATASET);
removeCache(Constants.GRAPHS.METADATA_GRAPHS_DATASET);
}
for (Long rev : transaction.getUpdatedNamedGraphRevisions().values()) {
if (rev.longValue() == 0) {
removeCache(Constants.GRAPHS.GRAPHS_DATASET);
removeCache(Constants.GRAPHS.METADATA_GRAPHS_DATASET);
break;
}
}
}
} finally {
if (log.isDebugEnabled()) {
log.debug(LogUtils.TIMING_MARKER, "MODEL CACHE UPDATE,{}", (System.currentTimeMillis() - start));
}
lock.unlock();
exit();
}
}
private void updateCache(URI ngUri) {
if (null != sizeCache.remove(ngUri))
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing size:" + ngUri.toString());
}
if (null != revisionCache.remove(ngUri.toString() + ":-1"))
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing revision:" + ngUri.toString());
}
if (null != uuidCache.remove(ngUri))
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing uuid:" + ngUri.toString());
}
if (null != datasetCache.remove(ngUri))
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing dataset:" + ngUri.toString());
}
if (null != containsCache.remove(ngUri))
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing contains:" + ngUri.toString());
}
for (String obj : findCache.keySet()) {
if (obj.toString().contains(ngUri.toString())) {
if (null != findCache.remove(obj))
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing find:" + obj);
}
}
}
}
private void removeCache(URI ngUri) {
if (null != sizeCache.remove(ngUri))
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing size:" + ngUri.toString());
}
if (null != revisionCache.remove(ngUri.toString() + ":-1"))
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing revision:" + ngUri.toString());
}
if (null != uuidCache.remove(ngUri))
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing uuid:" + ngUri.toString());
}
if (null != datasetCache.remove(ngUri))
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing dataset:" + ngUri.toString());
}
if (null != containsCache.remove(ngUri))
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing contains:" + ngUri.toString());
}
for (String obj : findCache.keySet()) {
if (obj.toString().contains(ngUri.toString())) {
if (null != findCache.remove(obj))
if (log.isDebugEnabled()) {
log.debug(LogUtils.DATASOURCE_MARKER, "Removing find:" + obj);
}
}
}
}
}