You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by st...@apache.org on 2006/01/18 14:59:53 UTC
svn commit: r370144 - in /incubator/jackrabbit/trunk/jackrabbit/src:
main/config/ main/java/org/apache/jackrabbit/core/
main/java/org/apache/jackrabbit/core/config/
test/java/org/apache/jackrabbit/core/config/
Author: stefan
Date: Wed Jan 18 05:59:42 2006
New Revision: 370144
URL: http://svn.apache.org/viewcvs?rev=370144&view=rev
Log:
JCR-305: provide option to automatically dispose idle workspaces
Modified:
incubator/jackrabbit/trunk/jackrabbit/src/main/config/repository.xml
incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java
incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/config.dtd
incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/config/repository.xml
Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/config/repository.xml
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/config/repository.xml?rev=370144&r1=370143&r2=370144&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/config/repository.xml (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/config/repository.xml Wed Jan 18 05:59:42 2006
@@ -80,7 +80,9 @@
<!--
the Workspaces element specifies the physical workspaces root directory
(rootPath attribute), the name of the default workspace
- (defaultWorkspace attribute) and optionally the workspace configuration
+ (defaultWorkspace attribute), the (optional) maximum amount of time in
+ seconds before an idle workspace is automatically shutdown
+ (maxIdleTime attribute) and the (optional) workspace configuration
root directory within the virtual repository file system (configRootPath
attribute).
@@ -97,7 +99,8 @@
<!ATTLIST Workspaces
rootPath CDATA #REQUIRED
defaultWorkspace CDATA #REQUIRED
- configRootPath CDATA #IMPLIED>
+ configRootPath CDATA #IMPLIED
+ maxIdleTime CDATA #IMPLIED>
<!--
the Workspace element serves as a workspace configuration template;
Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java?rev=370144&r1=370143&r2=370144&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java Wed Jan 18 05:59:42 2006
@@ -72,6 +72,8 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
+import java.util.Set;
+import java.util.HashSet;
import java.nio.channels.FileLock;
import java.nio.channels.FileChannel;
@@ -151,6 +153,13 @@
private final ReferenceMap activeSessions =
new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
+ /**
+ * workspace janitor thread that is responsible for temporarily
+ * shutting down workspaces that have been idle for a specific
+ * amount of time
+ */
+ private Thread wspJanitor;
+
// misc. statistics
private long nodesCount = 0;
private long propsCount = 0;
@@ -170,9 +179,11 @@
*/
protected RepositoryImpl(RepositoryConfig repConfig) throws RepositoryException {
+ log.info("Starting repository...");
+
this.repConfig = repConfig;
- this.acquireRepositoryLock() ;
+ acquireRepositoryLock() ;
// setup file systems
repStore = repConfig.getFileSystem();
@@ -212,7 +223,7 @@
vMgr = createVersionManager(repConfig.getVersioningConfig(),
delegatingDispatcher);
- // init virtual nodetype manager
+ // init virtual node type manager
virtNTMgr = new VirtualNodeTypeStateManager(getNodeTypeRegistry(),
delegatingDispatcher, NODETYPES_NODE_UUID, SYSTEM_ROOT_NODE_UUID);
@@ -228,12 +239,23 @@
throw e;
}
+ // amount of time in seconds before an idle workspace is automatically
+ // shut down
+ int maxIdleTime = repConfig.getWorkspaceMaxIdleTime();
+ if (maxIdleTime != 0) {
+ // start workspace janitor thread
+ wspJanitor = new WorkspaceJanitor(maxIdleTime * 1000);
+ wspJanitor.start();
+ }
+
// after the workspace is initialized we pass a system session to
// the virtual node type manager
// todo FIXME it seems odd that the *global* virtual node type manager
// is using a session that is bound to a single specific workspace
virtNTMgr.setSession(getSystemSession(repConfig.getDefaultWorkspaceName()));
+
+ log.info("Repository started");
}
/**
@@ -266,7 +288,7 @@
if (lock.exists()) {
log.warn("Existing lock file at " + lock.getAbsolutePath() +
- " deteteced. Repository was not shutdown properly.");
+ " deteteced. Repository was not shut down properly.");
} else {
try {
lock.createNewFile();
@@ -486,7 +508,7 @@
// add version storage
nt = sysSession.getNodeTypeManager().getNodeType(QName.REP_VERSIONSTORAGE);
sysRoot.internalAddChildNode(QName.JCR_VERSIONSTORAGE, nt, VERSION_STORAGE_NODE_UUID);
- // add nodetypes
+ // add node types
nt = sysSession.getNodeTypeManager().getNodeType(QName.REP_NODETYPES);
sysRoot.internalAddChildNode(QName.JCR_NODETYPES, nt, NODETYPES_NODE_UUID);
rootNode.save();
@@ -721,7 +743,7 @@
* workspace
* @throws RepositoryException if another error occurs
*/
- protected final SessionImpl createSession(AuthContext loginContext,
+ protected synchronized final SessionImpl createSession(AuthContext loginContext,
String workspaceName)
throws NoSuchWorkspaceException, AccessDeniedException,
RepositoryException {
@@ -729,6 +751,8 @@
SessionImpl ses = createSessionInstance(loginContext, wspInfo.getConfig());
ses.addListener(this);
activeSessions.put(ses, ses);
+ // reset idle timestamp
+ wspInfo.setIdleTimestamp(0);
return ses;
}
@@ -749,7 +773,7 @@
* workspace
* @throws RepositoryException if another error occurs
*/
- protected final SessionImpl createSession(Subject subject,
+ protected synchronized final SessionImpl createSession(Subject subject,
String workspaceName)
throws NoSuchWorkspaceException, AccessDeniedException,
RepositoryException {
@@ -757,6 +781,8 @@
SessionImpl ses = createSessionInstance(subject, wspInfo.getConfig());
ses.addListener(this);
activeSessions.put(ses, ses);
+ // reset idle timestamp
+ wspInfo.setIdleTimestamp(0);
return ses;
}
@@ -770,6 +796,8 @@
return;
}
+ log.info("Shutting down repository...");
+
// close active user sessions
while (!activeSessions.isEmpty()) {
((Session) activeSessions.values().iterator().next()).logout();
@@ -820,8 +848,15 @@
// make sure this instance is not used anymore
disposed = true;
+ if (wspJanitor != null) {
+ wspJanitor.interrupt();
+ wspJanitor = null;
+ }
+
// finally release repository lock
releaseRepositoryLock();
+
+ log.info("Repository has been shutdown");
}
/**
@@ -942,8 +977,12 @@
* @throws RepositoryException if the persistence manager could
* not be instantiated/initialized
*/
- private static PersistenceManager createPersistenceManager(File homeDir, FileSystem fs, PersistenceManagerConfig pmConfig,
- String rootNodeUUID, NamespaceRegistry nsReg, NodeTypeRegistry ntReg)
+ private static PersistenceManager createPersistenceManager(File homeDir,
+ FileSystem fs,
+ PersistenceManagerConfig pmConfig,
+ String rootNodeUUID,
+ NamespaceRegistry nsReg,
+ NodeTypeRegistry ntReg)
throws RepositoryException {
try {
PersistenceManager pm = (PersistenceManager) pmConfig.newInstance();
@@ -1066,7 +1105,7 @@
/**
* {@inheritDoc}
*/
- public void loggedOut(SessionImpl session) {
+ public synchronized void loggedOut(SessionImpl session) {
// remove session from active sessions
activeSessions.remove(session);
}
@@ -1209,6 +1248,11 @@
private boolean initialized;
/**
+ * timestamp when the workspace has been determined being idle
+ */
+ private long idleTimestamp;
+
+ /**
* Creates a new <code>WorkspaceInfo</code> based on the given
* <code>config</code>.
*
@@ -1216,6 +1260,7 @@
*/
protected WorkspaceInfo(WorkspaceConfig config) {
this.config = config;
+ idleTimestamp = 0;
initialized = false;
}
@@ -1238,6 +1283,28 @@
}
/**
+ * Returns the timestamp when the workspace has become idle or zero
+ * if the workspace is currently not idle.
+ *
+ * @return the timestamp when the workspace has become idle or zero if
+ * the workspace is not idle.
+ */
+ long getIdleTimestamp() {
+ return idleTimestamp;
+ }
+
+ /**
+ * Sets the timestamp when the workspace has become idle. if
+ * <code>ts == 0</code> the workspace is marked as being currently
+ * active.
+ *
+ * @param ts timestamp when workspace has become idle.
+ */
+ void setIdleTimestamp(long ts) {
+ idleTimestamp = ts;
+ }
+
+ /**
* Returns <code>true</code> if this workspace info is initialized,
* otherwise returns <code>false</code>.
*
@@ -1395,6 +1462,8 @@
throw new IllegalStateException("already initialized");
}
+ log.info("initializing workspace '" + getName() + "'...");
+
FileSystemConfig fsConfig = config.getFileSystemConfig();
fsConfig.init();
fs = fsConfig.getFileSystem();
@@ -1427,6 +1496,8 @@
obsMgrFactory = new ObservationManagerFactory();
initialized = true;
+
+ log.info("workspace '" + getName() + "' initialized");
}
/**
@@ -1437,6 +1508,8 @@
throw new IllegalStateException("not initialized");
}
+ log.info("shutting down workspace '" + getName() + "'...");
+
// dispose observation manager factory
obsMgrFactory.dispose();
obsMgrFactory = null;
@@ -1477,6 +1550,106 @@
FileSystemConfig fsConfig = config.getFileSystemConfig();
fsConfig.dispose();
fs = null;
+
+ // reset idle timestamp
+ idleTimestamp = 0;
+
+ initialized = false;
+
+ log.info("workspace '" + getName() + "' has been shutdown");
+ }
+ }
+
+ /**
+ * The workspace janitor thread that will shutdown workspaces that have
+ * been idle for a certain amount of time.
+ */
+ private class WorkspaceJanitor extends Thread {
+
+ /**
+ * amount of time in mmilliseconds before an idle workspace is
+ * automatically shutdown.
+ */
+ private long maxIdleTime;
+ /**
+ * interval in mmilliseconds between checks for idle workspaces.
+ */
+ private long checkInterval;
+
+ /**
+ * Creates a new <code>WorkspaceJanitor</code> instance responsible for
+ * shutting down idle workspaces.
+ *
+ * @param maxIdleTime amount of time in mmilliseconds before an idle
+ * workspace is automatically shutdown.
+ */
+ WorkspaceJanitor(long maxIdleTime) {
+ super("WorkspaceJanitor");
+ setPriority(Thread.MIN_PRIORITY);
+ setDaemon(true);
+ this.maxIdleTime = maxIdleTime;
+ // compute check interval as 10% of maxIdleTime
+ checkInterval = (long) (0.1 * maxIdleTime);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * Performs the following tasks in a <code>while (true)</code> loop:
+ * <ol>
+ * <li>wait for <code>checkInterval</code> milliseconds</li>
+ * <li>build list of initialized but currently inactive workspaces
+ * (excluding the default workspace)</li>
+ * <li>shutdown those workspaces that have been idle for at least
+ * <code>maxIdleTime</code> milliseconds</li>
+ * </ol>
+ */
+ public void run() {
+ while (!disposed) {
+ try {
+ Thread.sleep(checkInterval);
+ } catch (InterruptedException e) {
+ /* ignore */
+ }
+
+ synchronized (RepositoryImpl.this) {
+ if (disposed) {
+ return;
+ }
+ // get names of workspaces
+ Set wspNames = new HashSet(wspInfos.keySet());
+ // remove default workspace (will never be shutdown when idle)
+ wspNames.remove(repConfig.getDefaultWorkspaceName());
+ // remove workspaces with active sessions
+ for (Iterator it = activeSessions.values().iterator(); it.hasNext();) {
+ SessionImpl ses = (SessionImpl) it.next();
+ wspNames.remove(ses.getWorkspace().getName());
+ }
+ // remove uninitialized workspaces
+ for (Iterator it = wspInfos.values().iterator(); it.hasNext();) {
+ WorkspaceInfo wspInfo = (WorkspaceInfo) it.next();
+ if (!wspInfo.isInitialized()) {
+ wspNames.remove(wspInfo.getName());
+ }
+ }
+
+ // remaining names denote workspaces which are currently idle
+ for (Iterator it = wspNames.iterator(); it.hasNext();) {
+ WorkspaceInfo wspInfo = (WorkspaceInfo) wspInfos.get(it.next());
+ long currentTS = System.currentTimeMillis();
+ long idleTS = wspInfo.getIdleTimestamp();
+ if (idleTS == 0) {
+ // set idle timestamp
+ wspInfo.setIdleTimestamp(currentTS);
+ } else {
+ if ((currentTS - idleTS) > maxIdleTime) {
+ // temporarily shutdown workspace
+ wspInfo.dispose();
+ }
+ }
+ }
+ }
+ }
}
}
}
Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java?rev=370144&r1=370143&r2=370144&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java Wed Jan 18 05:59:42 2006
@@ -100,6 +100,9 @@
/** Name of the config root path configuration attribute. */
public static final String CONFIG_ROOT_PATH_ATTRIBUTE = "configRootPath";
+ /** Name of the maximum idle time configuration attribute. */
+ public static final String MAX_IDLE_TIME_ATTRIBUTE = "maxIdleTime";
+
/** Name of the default workspace configuration attribute. */
public static final String DEFAULT_WORKSPACE_ATTRIBUTE =
"defaultWorkspace";
@@ -228,6 +231,9 @@
String defaultWorkspace = replaceVariables(
getAttribute(workspaces, DEFAULT_WORKSPACE_ATTRIBUTE));
+ int maxIdleTime = Integer.parseInt(
+ getAttribute(workspaces, MAX_IDLE_TIME_ATTRIBUTE, "0"));
+
// Workspace configuration template
Element template = getElement(root, WORKSPACE_ELEMENT);
@@ -239,7 +245,7 @@
return new RepositoryConfig(home, appName, amc, lmc, fsc,
workspaceDirectory, workspaceConfigDirectory, defaultWorkspace,
- template, vc, sc, this);
+ maxIdleTime, template, vc, sc, this);
}
/**
Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java?rev=370144&r1=370143&r2=370144&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java Wed Jan 18 05:59:42 2006
@@ -196,6 +196,12 @@
private final String workspaceConfigDirectory;
/**
+ * Amount of time in seconds after which an idle workspace is automatically
+ * shutdown.
+ */
+ private final int workspaceMaxIdleTime;
+
+ /**
* The workspace configuration template. Used in creating new workspace
* configuration files.
*/
@@ -222,6 +228,7 @@
* @param fsc file system configuration
* @param workspaceDirectory workspace root directory
* @param workspaceConfigDirectory optional workspace configuration directory
+ * @param workspaceMaxIdleTime maximum workspace idle time in seconds
* @param defaultWorkspace name of the default workspace
* @param vc versioning configuration
* @param sc search configuration for system search manager.
@@ -230,8 +237,9 @@
RepositoryConfig(String home, String name,
AccessManagerConfig amc, LoginModuleConfig lmc, FileSystemConfig fsc,
String workspaceDirectory, String workspaceConfigDirectory,
- String defaultWorkspace, Element template, VersioningConfig vc,
- SearchConfig sc, ConfigurationParser parser) {
+ String defaultWorkspace, int workspaceMaxIdleTime,
+ Element template, VersioningConfig vc, SearchConfig sc,
+ ConfigurationParser parser) {
this.workspaces = new HashMap();
this.home = home;
this.name = name;
@@ -240,6 +248,7 @@
this.fsc = fsc;
this.workspaceDirectory = workspaceDirectory;
this.workspaceConfigDirectory = workspaceConfigDirectory;
+ this.workspaceMaxIdleTime = workspaceMaxIdleTime;
this.defaultWorkspace = defaultWorkspace;
this.template = template;
this.vc = vc;
@@ -597,6 +606,17 @@
*/
public String getDefaultWorkspaceName() {
return defaultWorkspace;
+ }
+
+ /**
+ * Returns the amount of time in seconds after which an idle workspace is
+ * automatically shutdown. If zero then idle workspaces will never be
+ * automatically shutdown.
+ *
+ * @return maximum workspace idle time in seconds
+ */
+ public int getWorkspaceMaxIdleTime() {
+ return workspaceMaxIdleTime;
}
/**
Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/config.dtd
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/config.dtd?rev=370144&r1=370143&r2=370144&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/config.dtd (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/config/config.dtd Wed Jan 18 05:59:42 2006
@@ -96,7 +96,9 @@
<!--
the Workspaces element specifies the physical workspaces root directory
(rootPath attribute), the name of the default workspace
- (defaultWorkspace attribute) and optionally the workspace configuration
+ (defaultWorkspace attribute), the (optional) maximum amount of time in
+ seconds before an idle workspace is automatically shutdown
+ (maxIdleTime attribute) and the (optional) workspace configuration
root directory within the virtual repository file system (configRootPath
attribute).
@@ -113,7 +115,8 @@
<!ATTLIST Workspaces
rootPath CDATA #REQUIRED
defaultWorkspace CDATA #REQUIRED
- configRootPath CDATA #IMPLIED>
+ configRootPath CDATA #IMPLIED
+ maxIdleTime CDATA #IMPLIED>
<!--
the Workspace element serves as a workspace configuration template;
Modified: incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/config/repository.xml
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/config/repository.xml?rev=370144&r1=370143&r2=370144&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/config/repository.xml (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/config/repository.xml Wed Jan 18 05:59:42 2006
@@ -80,7 +80,9 @@
<!--
the Workspaces element specifies the physical workspaces root directory
(rootPath attribute), the name of the default workspace
- (defaultWorkspace attribute) and optionally the workspace configuration
+ (defaultWorkspace attribute), the (optional) maximum amount of time in
+ seconds before an idle workspace is automatically shutdown
+ (maxIdleTime attribute) and the (optional) workspace configuration
root directory within the virtual repository file system (configRootPath
attribute).
@@ -97,7 +99,8 @@
<!ATTLIST Workspaces
rootPath CDATA #REQUIRED
defaultWorkspace CDATA #REQUIRED
- configRootPath CDATA #IMPLIED>
+ configRootPath CDATA #IMPLIED
+ maxIdleTime CDATA #IMPLIED>
<!--
the Workspace element serves as a workspace configuration template;