All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bigdata.rdf.sail.SailBase Maven / Gradle / Ivy

/*
 * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2009.
 *
 * Licensed under the Aduna BSD-style license.
 */
package com.bigdata.rdf.sail;

import java.io.File;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.openrdf.sail.Sail;
import org.openrdf.sail.SailConnection;
import org.openrdf.sail.SailException;

/**
 * SailBase is an abstract Sail implementation that takes care of common sail
 * tasks, including proper closing of active connections and a grace period for
 * active connections during shutdown of the store.
 * 
 * @author Herko ter Horst
 * @author jeen
 * @author Arjohn Kampman
 */
public abstract class SailBase implements Sail {

	/*-----------*
	 * Constants *
	 *-----------*/

	/**
	 * Default connection timeout on shutdown: 20,000 milliseconds.
	 */
	protected final static long DEFAULT_CONNECTION_TIMEOUT = 20000L;

	// Note: the following variable and method are package protected so that they
	// can be removed when open connections no longer block other connections and
	// they can be closed silently (just like in JDBC).
	static final String DEBUG_PROP = "org.openrdf.repository.debug";

	protected static boolean debugEnabled() {
		try {
			String value = System.getProperty(DEBUG_PROP);
			return value != null && !value.equals("false");
		}
		catch (SecurityException e) {
			// Thrown when not allowed to read system properties, for example when
			// running in applets
			return false;
		}
	}

	/*-----------*
	 * Variables *
	 *-----------*/

	protected final Logger logger = LoggerFactory.getLogger(this.getClass());

	/**
	 * Directory to store information related to this sail in (if any).
	 */
	private volatile File dataDir;

	/**
	 * Flag indicating whether the Sail has been initialized. Sails are
	 * initialized from {@link #initialize() initialization} until
	 * {@link #shutDown() shutdown}.
	 */
	private volatile boolean initialized = false;

	/**
	 * Lock used to synchronize the initialization state of a sail.
	 * 
    *
  • write lock: initialize(), shutDown() *
  • read lock: getConnection() *
*/ protected final ReentrantReadWriteLock initializationLock = new ReentrantReadWriteLock(); /** * Connection timeout on shutdown (in ms). Defaults to * {@link #DEFAULT_CONNECTION_TIMEOUT}. */ protected volatile long connectionTimeOut = DEFAULT_CONNECTION_TIMEOUT; /** * Map used to track active connections and where these were acquired. The * Throwable value may be null in case debugging was disable at the time the * connection was acquired. */ private final Map activeConnections = new IdentityHashMap(); /*---------* * Methods * *---------*/ public void setDataDir(File dataDir) { if (isInitialized()) { throw new IllegalStateException("sail has already been initialized"); } this.dataDir = dataDir; } public File getDataDir() { return dataDir; } @Override public String toString() { if (dataDir == null) { return super.toString(); } else { return dataDir.toString(); } } /** * Checks whether the Sail has been initialized. Sails are initialized from * {@link #initialize() initialization} until {@link #shutDown() shutdown}. * * @return true if the Sail has been initialized, false * otherwise. */ protected boolean isInitialized() { return initialized; } public void initialize() throws SailException { initializationLock.writeLock().lock(); try { if (isInitialized()) { throw new IllegalStateException("sail has already been intialized"); } initializeInternal(); initialized = true; } finally { initializationLock.writeLock().unlock(); } } /** * Do store-specific operations to initialize the store. The default * implementation of this method does nothing. */ protected void initializeInternal() throws SailException { } public void shutDown() throws SailException { initializationLock.writeLock().lock(); try { if (!isInitialized()) { return; } synchronized (activeConnections) { // Check if any active connections exist. If so, wait for a grace // period for them to finish. if (!activeConnections.isEmpty()) { logger.debug("Waiting for active connections to close before shutting down..."); try { activeConnections.wait(DEFAULT_CONNECTION_TIMEOUT); } catch (InterruptedException e) { // ignore and continue } } // Forcefully close any connections that are still open Iterator> iter = activeConnections.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); SailConnection con = entry.getKey(); Throwable stackTrace = entry.getValue(); iter.remove(); if (stackTrace == null) { logger.warn( "Closing active connection due to shut down; consider setting the {} system property", DEBUG_PROP); } else { logger.warn("Closing active connection due to shut down, connection was acquired in", stackTrace); } try { con.close(); } catch (SailException e) { logger.error("Failed to close connection", e); } } } shutDownInternal(); } finally { initialized = false; initializationLock.writeLock().unlock(); } } /** * Do store-specific operations to ensure proper shutdown of the store. */ protected abstract void shutDownInternal() throws SailException; public SailConnection getConnection() throws SailException { initializationLock.readLock().lock(); try { if (!isInitialized()) { throw new IllegalStateException("Sail is not initialized or has been shut down"); } SailConnection connection = getConnectionInternal(); Throwable stackTrace = debugEnabled() ? new Throwable() : null; synchronized (activeConnections) { activeConnections.put(connection, stackTrace); } return connection; } finally { initializationLock.readLock().unlock(); } } /** * Returns a store-specific SailConnection object. * * @return A connection to the store. */ protected abstract SailConnection getConnectionInternal() throws SailException; /** * Signals to the store that the supplied connection has been closed; called * by {@link SailConnectionBase#close()}. * * @param connection * The connection that has been closed. */ protected void connectionClosed(SailConnection connection) { synchronized (activeConnections) { if (activeConnections.containsKey(connection)) { activeConnections.remove(connection); if (activeConnections.isEmpty()) { // only notify waiting threads if all active connections have // been closed. activeConnections.notifyAll(); } } else { // logger.warn("tried to remove unknown connection object from store."); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy