From c18a12322895e4ea2a23366174de782e0565e8f9 Mon Sep 17 00:00:00 2001 From: Gary Spencer Date: Thu, 22 Apr 2010 12:16:04 +0000 Subject: [PATCH] Refactor of the file state cache code. (Part 2 of 2). Removed the repo specific file state cache code. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@19949 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/network-protocol-context.xml | 7 - .../filesys/ServerConfigurationBean.java | 22 +- .../filesys/alfresco/AlfrescoContext.java | 73 -- .../filesys/alfresco/AlfrescoDiskDriver.java | 25 - .../filesys/alfresco/AlfrescoNetworkFile.java | 5 +- .../filesys/alfresco/HomeShareMapper.java | 2 +- .../alfresco/MultiTenantShareMapper.java | 2 +- .../filesys/alfresco/PseudoFileImpl.java | 14 +- .../org/alfresco/filesys/avm/AVMContext.java | 14 +- .../alfresco/filesys/avm/AVMDiskDriver.java | 32 +- .../alfresco/filesys/avm/AVMShareMapper.java | 2 +- .../config/ServerConfigurationBean.java | 23 +- .../repo/CacheLookupSearchContext.java | 8 +- .../filesys/repo/ContentDiskDriver.java | 338 ++++--- .../filesys/repo/HomeShareMapper.java | 2 +- .../alfresco/filesys/repo/NodeMonitor.java | 8 +- .../repo/desk/CheckInOutDesktopAction.java | 10 +- .../org/alfresco/filesys/state/FileState.java | 841 ------------------ .../filesys/state/FileStateListener.java | 44 - .../filesys/state/FileStateLockManager.java | 490 ---------- .../filesys/state/FileStateReaper.java | 216 ----- .../filesys/state/FileStateTable.java | 419 --------- 22 files changed, 287 insertions(+), 2310 deletions(-) delete mode 100644 source/java/org/alfresco/filesys/state/FileState.java delete mode 100644 source/java/org/alfresco/filesys/state/FileStateListener.java delete mode 100644 source/java/org/alfresco/filesys/state/FileStateLockManager.java delete mode 100644 source/java/org/alfresco/filesys/state/FileStateReaper.java delete mode 100644 source/java/org/alfresco/filesys/state/FileStateTable.java diff --git a/config/alfresco/network-protocol-context.xml b/config/alfresco/network-protocol-context.xml index 42d4894c8d..c00e5e7271 100644 --- a/config/alfresco/network-protocol-context.xml +++ b/config/alfresco/network-protocol-context.xml @@ -62,7 +62,6 @@ - @@ -93,7 +92,6 @@ - @@ -101,9 +99,4 @@ - - - - diff --git a/source/java/org/alfresco/filesys/ServerConfigurationBean.java b/source/java/org/alfresco/filesys/ServerConfigurationBean.java index 9e677eb27b..6db8a61d6c 100644 --- a/source/java/org/alfresco/filesys/ServerConfigurationBean.java +++ b/source/java/org/alfresco/filesys/ServerConfigurationBean.java @@ -1925,6 +1925,15 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean { filesys = new DiskSharedDevice(filesysName, filesysDriver, filesysContext); + // Check if the filesystem uses the file state cache, if so then add to the file state reaper + + if ( filesysContext.hasStateCache()) { + + // Register the state cache with the reaper thread + + fsysConfig.addFileStateCache( filesysName, filesysContext.getStateCache()); + } + // Start the filesystem filesysContext.startFilesystem(filesys); @@ -1999,6 +2008,15 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean { filesysContext.enableChangeHandler(changeNotify); + // Check if the filesystem uses the file state cache, if so then add to the file state reaper + + if ( filesysContext.hasStateCache()) { + + // Register the state cache with the reaper thread + + fsysConfig.addFileStateCache( filesysName, filesysContext.getStateCache()); + } + // Start the filesystem filesysContext.startFilesystem(filesys); @@ -2046,10 +2064,10 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean { if ( fsysConfig.getShares().findShare( storeName, ShareType.DISK, true) == null) { - // Create the new share for the store + // Create the new share for the store AVMContext avmContext = new AVMContext( storeName, storeName + ":/", AVMContext.VERSION_HEAD); - avmContext.enableStateTable( true, avmDriver.getStateReaper()); + avmContext.enableStateCache( true); // Create the shared filesystem diff --git a/source/java/org/alfresco/filesys/alfresco/AlfrescoContext.java b/source/java/org/alfresco/filesys/alfresco/AlfrescoContext.java index a71cc95a88..90d78cd64a 100644 --- a/source/java/org/alfresco/filesys/alfresco/AlfrescoContext.java +++ b/source/java/org/alfresco/filesys/alfresco/AlfrescoContext.java @@ -24,8 +24,6 @@ import java.util.StringTokenizer; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.filesys.config.GlobalDesktopActionConfigBean; -import org.alfresco.filesys.state.FileStateReaper; -import org.alfresco.filesys.state.FileStateTable; import org.alfresco.jlan.server.filesys.DiskDeviceContext; import org.alfresco.jlan.server.filesys.DiskInterface; import org.alfresco.jlan.server.filesys.FileSystem; @@ -58,11 +56,6 @@ public abstract class AlfrescoContext extends DiskDeviceContext private static final String m_filesysDebugStr[] = { "FILE", "FILEIO", "SEARCH", "INFO", "LOCK", "PSEUDO", "RENAME" }; - // File state table and associated file state reaper - - private FileStateTable m_stateTable; - private FileStateReaper m_stateReaper; - // URL pseudo file web path prefix (server/port/webapp) and link file name private String m_urlFileName; @@ -147,57 +140,6 @@ public abstract class AlfrescoContext extends DiskDeviceContext return FileSystem.TypeNTFS; } - /** - * Determine if the file state table is enabled - * - * @return boolean - */ - public final boolean hasStateTable() - { - return m_stateTable != null ? true : false; - } - - /** - * Return the file state table - * - * @return FileStateTable - */ - public final FileStateTable getStateTable() - { - return m_stateTable; - } - - /** - * Enable/disable the file state table - * - * @param ena boolean - * @param stateReaper FileStateReaper - */ - public final void enableStateTable(boolean ena, FileStateReaper stateReaper) - { - if ( ena == false) - { - // Remove the state table from the reaper - - stateReaper.removeStateTable( getShareName()); - m_stateTable = null; - } - else if ( m_stateTable == null) - { - // Create the file state table - - m_stateTable = new FileStateTable(); - - // Register with the file state reaper - - stateReaper.addStateTable( getShareName(), m_stateTable); - } - - // Save the reaper, for deregistering when the filesystem is closed - - m_stateReaper = stateReaper; - } - /** * Determine if the pseudo file interface is enabled * @@ -482,19 +424,4 @@ public abstract class AlfrescoContext extends DiskDeviceContext { return (m_debug & flg) != 0 ? true : false; } - - /** - * Close the filesystem context - */ - public void CloseContext() { - - // Deregister the file state table from the reaper - - if ( m_stateTable != null) - enableStateTable( false, m_stateReaper); - - // Call the base class - - super.CloseContext(); - } } diff --git a/source/java/org/alfresco/filesys/alfresco/AlfrescoDiskDriver.java b/source/java/org/alfresco/filesys/alfresco/AlfrescoDiskDriver.java index 1dbe0f0767..023e4da668 100644 --- a/source/java/org/alfresco/filesys/alfresco/AlfrescoDiskDriver.java +++ b/source/java/org/alfresco/filesys/alfresco/AlfrescoDiskDriver.java @@ -22,7 +22,6 @@ import javax.transaction.Status; import javax.transaction.UserTransaction; import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.filesys.state.FileStateReaper; import org.alfresco.jlan.server.SrvSession; import org.alfresco.jlan.server.core.DeviceContext; import org.alfresco.jlan.server.core.DeviceContextException; @@ -56,10 +55,6 @@ public abstract class AlfrescoDiskDriver implements IOCtlInterface, Transactiona private ServiceRegistry m_serviceRegistry; - // File state reaper - - private FileStateReaper m_stateReaper; - // Transaction service private TransactionService m_transactionService; @@ -74,16 +69,6 @@ public abstract class AlfrescoDiskDriver implements IOCtlInterface, Transactiona return m_serviceRegistry; } - /** - * Return the file state reaper - * - * @return FileStateReaper - */ - public final FileStateReaper getStateReaper() - { - return m_stateReaper; - } - /** * Return the transaction service * @@ -104,16 +89,6 @@ public abstract class AlfrescoDiskDriver implements IOCtlInterface, Transactiona m_serviceRegistry = serviceRegistry; } - /** - * Set the file state reaper - * - * @param stateReaper FileStateReaper - */ - public final void setStateReaper(FileStateReaper stateReaper) - { - m_stateReaper = stateReaper; - } - /** * @param transactionService the transaction service */ diff --git a/source/java/org/alfresco/filesys/alfresco/AlfrescoNetworkFile.java b/source/java/org/alfresco/filesys/alfresco/AlfrescoNetworkFile.java index 4d79bd58b6..65aa86f9fe 100644 --- a/source/java/org/alfresco/filesys/alfresco/AlfrescoNetworkFile.java +++ b/source/java/org/alfresco/filesys/alfresco/AlfrescoNetworkFile.java @@ -1,7 +1,8 @@ package org.alfresco.filesys.alfresco; import org.alfresco.jlan.server.filesys.NetworkFile; -import org.alfresco.filesys.state.FileState; +import org.alfresco.jlan.server.filesys.cache.FileState; +import org.alfresco.jlan.server.filesys.cache.NetworkFileStateInterface; /* * Copyright (C) 2007-2010 Alfresco Software Limited. @@ -27,7 +28,7 @@ import org.alfresco.filesys.state.FileState; * *

Adds Alfresco extensions to the network file. */ -public abstract class AlfrescoNetworkFile extends NetworkFile { +public abstract class AlfrescoNetworkFile extends NetworkFile implements NetworkFileStateInterface { // Associated file state diff --git a/source/java/org/alfresco/filesys/alfresco/HomeShareMapper.java b/source/java/org/alfresco/filesys/alfresco/HomeShareMapper.java index dd6d37da43..7aa7c1a1d2 100644 --- a/source/java/org/alfresco/filesys/alfresco/HomeShareMapper.java +++ b/source/java/org/alfresco/filesys/alfresco/HomeShareMapper.java @@ -352,7 +352,7 @@ public class HomeShareMapper implements ShareMapper ContentDiskDriver diskDrv = ( ContentDiskDriver) getRepoDiskInterface(); ContentContext diskCtx = new ContentContext( getHomeFolderName(), "", "", client.getHomeFolder()); - diskCtx.enableStateTable( true, diskDrv.getStateReaper()); + diskCtx.enableStateCache( true); // Create a temporary shared device for the users home directory diff --git a/source/java/org/alfresco/filesys/alfresco/MultiTenantShareMapper.java b/source/java/org/alfresco/filesys/alfresco/MultiTenantShareMapper.java index 30bd409ff3..2a2c239544 100644 --- a/source/java/org/alfresco/filesys/alfresco/MultiTenantShareMapper.java +++ b/source/java/org/alfresco/filesys/alfresco/MultiTenantShareMapper.java @@ -420,7 +420,7 @@ public class MultiTenantShareMapper implements ShareMapper, ConfigurationListene // Enable file state caching - diskCtx.enableStateTable( true, diskDrv.getStateReaper()); + diskCtx.enableStateCache( true); // Initialize the I/O control handler diff --git a/source/java/org/alfresco/filesys/alfresco/PseudoFileImpl.java b/source/java/org/alfresco/filesys/alfresco/PseudoFileImpl.java index 080ec61219..0d0685b0b0 100644 --- a/source/java/org/alfresco/filesys/alfresco/PseudoFileImpl.java +++ b/source/java/org/alfresco/filesys/alfresco/PseudoFileImpl.java @@ -23,14 +23,15 @@ import java.util.Enumeration; import org.alfresco.jlan.server.SrvSession; import org.alfresco.jlan.server.filesys.FileName; import org.alfresco.jlan.server.filesys.TreeConnection; +import org.alfresco.jlan.server.filesys.cache.FileState; import org.alfresco.jlan.server.filesys.pseudo.MemoryPseudoFile; import org.alfresco.jlan.server.filesys.pseudo.PseudoFile; import org.alfresco.jlan.server.filesys.pseudo.PseudoFileInterface; import org.alfresco.jlan.smb.server.SMBSrvSession; +import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.filesys.alfresco.DesktopAction; import org.alfresco.filesys.alfresco.DesktopActionTable; import org.alfresco.filesys.repo.ContentContext; -import org.alfresco.filesys.state.FileState; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -170,7 +171,7 @@ public class PseudoFileImpl implements PseudoFileInterface // If the file state is null create a file state for the path if ( fstate == null) - ctx.getStateTable().findFileState( path, true, true); + ctx.getStateCache().findFileState( path, true); // Add the desktop action pseudo files @@ -205,17 +206,18 @@ public class PseudoFileImpl implements PseudoFileInterface { // Make sure the state has the associated node details - if ( fstate.getNodeRef() != null) + if ( fstate.hasFilesystemObject()) { // Build the URL file data + NodeRef nodeRef = (NodeRef) fstate.getFilesystemObject(); StringBuilder urlStr = new StringBuilder(); urlStr.append("[InternetShortcut]\r\n"); urlStr.append("URL="); urlStr.append(ctx.getURLPrefix()); urlStr.append("navigate/browse/workspace/SpacesStore/"); - urlStr.append( fstate.getNodeRef().getId()); + urlStr.append( nodeRef.getId()); urlStr.append("\r\n"); // Create the in memory pseudo file for the URL link @@ -282,11 +284,11 @@ public class PseudoFileImpl implements PseudoFileInterface FileState fstate = null; - if ( ctx.hasStateTable()) + if ( ctx.hasStateCache()) { // Get the file state for a file/folder - fstate = ctx.getStateTable().findFileState(path); + fstate = ctx.getStateCache().findFileState(path); } // Return the file state diff --git a/source/java/org/alfresco/filesys/avm/AVMContext.java b/source/java/org/alfresco/filesys/avm/AVMContext.java index 6010efc7b6..49d2f3be0b 100644 --- a/source/java/org/alfresco/filesys/avm/AVMContext.java +++ b/source/java/org/alfresco/filesys/avm/AVMContext.java @@ -25,12 +25,12 @@ import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.filesys.alfresco.AlfrescoContext; import org.alfresco.filesys.alfresco.AlfrescoDiskDriver; import org.alfresco.filesys.alfresco.IOControlHandler; -import org.alfresco.filesys.state.FileState; -import org.alfresco.filesys.state.FileStateTable; import org.alfresco.jlan.server.filesys.DiskInterface; import org.alfresco.jlan.server.filesys.FileName; import org.alfresco.jlan.server.filesys.FileSystem; import org.alfresco.jlan.server.filesys.NotifyChange; +import org.alfresco.jlan.server.filesys.cache.FileState; +import org.alfresco.jlan.server.filesys.cache.FileStateCache; import org.alfresco.jlan.util.StringList; import org.alfresco.repo.avm.CreateStoreCallback; import org.alfresco.repo.avm.CreateVersionCallback; @@ -440,13 +440,13 @@ public class AVMContext extends AlfrescoContext // Make sure the file state cache is enabled - FileStateTable fsTable = getStateTable(); + FileStateCache fsTable = getStateCache(); if ( fsTable == null) return; // Find the file state for the root folder - FileState rootState = fsTable.findFileState( FileName.DOS_SEPERATOR_STR, true, true); + FileState rootState = fsTable.findFileState( FileName.DOS_SEPERATOR_STR, true); if ( rootState != null) { @@ -481,7 +481,7 @@ public class AVMContext extends AlfrescoContext // Make sure the file state cache is enabled - FileStateTable fsTable = getStateTable(); + FileStateCache fsTable = getStateCache(); if ( fsTable == null) return; @@ -542,7 +542,7 @@ public class AVMContext extends AlfrescoContext // Make sure the file state cache is enabled - FileStateTable fsTable = getStateTable(); + FileStateCache fsTable = getStateCache(); if ( fsTable == null) return; @@ -612,7 +612,7 @@ public class AVMContext extends AlfrescoContext // Make sure the file state cache is enabled - FileStateTable fsTable = getStateTable(); + FileStateCache fsTable = getStateCache(); if ( fsTable == null) return; diff --git a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java index 8926f97a57..dbb7b04fa6 100644 --- a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java +++ b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java @@ -29,7 +29,6 @@ import javax.transaction.UserTransaction; import org.springframework.extensions.config.ConfigElement; import org.alfresco.filesys.alfresco.AlfrescoDiskDriver; -import org.alfresco.filesys.state.FileState; import org.alfresco.jlan.server.SrvSession; import org.alfresco.jlan.server.auth.ClientInfo; import org.alfresco.jlan.server.core.DeviceContext; @@ -47,6 +46,7 @@ import org.alfresco.jlan.server.filesys.NetworkFile; import org.alfresco.jlan.server.filesys.PathNotFoundException; import org.alfresco.jlan.server.filesys.SearchContext; import org.alfresco.jlan.server.filesys.TreeConnection; +import org.alfresco.jlan.server.filesys.cache.FileState; import org.alfresco.jlan.server.filesys.pseudo.PseudoFile; import org.alfresco.jlan.server.filesys.pseudo.PseudoFileList; import org.alfresco.jlan.server.filesys.pseudo.PseudoFolderNetworkFile; @@ -394,7 +394,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Enable file state caching - context.enableStateTable(true, getStateReaper()); + context.enableStateCache( true); } } @@ -452,7 +452,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Enable file state caching - context.enableStateTable(true, getStateReaper()); + context.enableStateCache(true); // Plug the virtualization view context into the various store/version call back listeners // so that store/version pseudo folders can be kept in sync with AVM @@ -584,7 +584,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Enable file state caching - context.enableStateTable(true, getStateReaper()); + context.enableStateCache(true); } // Commit the transaction @@ -2111,7 +2111,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Get the root folder file state - fstate = avmCtx.getStateTable().findFileState(FileName.DOS_SEPERATOR_STR); + fstate = avmCtx.getStateCache().findFileState(FileName.DOS_SEPERATOR_STR); if (fstate != null && fstate.hasPseudoFiles()) psFile = fstate.getPseudoFileList().findFile(avmPath.getStoreName(), false); @@ -2329,7 +2329,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Get the root path file state - fstate = avmCtx.getStateTable().findFileState( FileName.DOS_SEPERATOR_STR); + fstate = avmCtx.getStateCache().findFileState( FileName.DOS_SEPERATOR_STR); // Check if the root file state is valid @@ -2337,7 +2337,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface { // Create a file state for the root folder - fstate = avmCtx.getStateTable().findFileState( FileName.DOS_SEPERATOR_STR, true, true); + fstate = avmCtx.getStateCache().findFileState( FileName.DOS_SEPERATOR_STR, true); fstate.setExpiryTime( FileState.NoTimeout); // Get a list of the available AVM stores @@ -2565,13 +2565,13 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Search for the file state for the store pseudo folder relPath = str.toString(); - fstate = avmCtx.getStateTable().findFileState( relPath); + fstate = avmCtx.getStateCache().findFileState( relPath); if ( fstate == null) { // Create a file state for the store path - fstate = avmCtx.getStateTable().findFileState( str.toString(), true, true); + fstate = avmCtx.getStateCache().findFileState( str.toString(), true); // Add a pseudo file for the head version @@ -2606,13 +2606,13 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface relPath = str.toString(); - fstate = avmCtx.getStateTable().findFileState( relPath); + fstate = avmCtx.getStateCache().findFileState( relPath); if ( fstate == null) { // Create a file state for the store head folder path - fstate = avmCtx.getStateTable().findFileState( str.toString(), true, true); + fstate = avmCtx.getStateCache().findFileState( str.toString(), true); // Add a pseudo file for the data pseudo folder @@ -2650,7 +2650,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Create a file state for the store path relPath = str.toString(); - fstate = avmCtx.getStateTable().findFileState( relPath, true, true); + fstate = avmCtx.getStateCache().findFileState( relPath, true); // Add pseudo folders if the list is empty @@ -2720,13 +2720,13 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Search for the file state for the version pseudo folder relPath = str.toString(); - fstate = avmCtx.getStateTable().findFileState( relPath); + fstate = avmCtx.getStateCache().findFileState( relPath); if ( fstate == null) { // Create a file state for the version folder path - fstate = avmCtx.getStateTable().findFileState( str.toString(), true, true); + fstate = avmCtx.getStateCache().findFileState( str.toString(), true); // Add a pseudo file for the data pseudo folder @@ -2852,7 +2852,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Get root file state, get the store pseudo folder details - FileState rootState = avmCtx.getStateTable().findFileState( FileName.DOS_SEPERATOR_STR); + FileState rootState = avmCtx.getStateCache().findFileState( FileName.DOS_SEPERATOR_STR); if ( rootState == null){ // Recreate the root file state, new stores may have been added @@ -3073,7 +3073,7 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface // Get the root folder file state - FileState fstate = avmCtx.getStateTable().findFileState( FileName.DOS_SEPERATOR_STR, true, false); + FileState fstate = avmCtx.getStateCache().findFileState( FileName.DOS_SEPERATOR_STR, true); if ( fstate == null) return; diff --git a/source/java/org/alfresco/filesys/avm/AVMShareMapper.java b/source/java/org/alfresco/filesys/avm/AVMShareMapper.java index fa95225c38..34be8c6068 100644 --- a/source/java/org/alfresco/filesys/avm/AVMShareMapper.java +++ b/source/java/org/alfresco/filesys/avm/AVMShareMapper.java @@ -284,7 +284,7 @@ public class AVMShareMapper implements ShareMapper, InitializingBean { // Create a dynamic share mapped to the AVM store/version AVMContext avmCtx = new AVMContext( name, storePath, storeVersion); - avmCtx.enableStateTable( true, m_driver.getStateReaper()); + avmCtx.enableStateCache( true); // Create a dynamic shared device for the store version diff --git a/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java b/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java index 1e1d599230..067cb75601 100644 --- a/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java +++ b/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java @@ -62,6 +62,7 @@ import org.alfresco.jlan.server.core.DeviceContext; import org.alfresco.jlan.server.core.DeviceContextException; import org.alfresco.jlan.server.core.ShareMapper; import org.alfresco.jlan.server.core.ShareType; +import org.alfresco.jlan.server.filesys.DiskDeviceContext; import org.alfresco.jlan.server.filesys.DiskSharedDevice; import org.alfresco.jlan.server.filesys.FilesystemsConfigSection; import org.alfresco.jlan.server.thread.ThreadRequestPool; @@ -1559,6 +1560,17 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean filesys = new DiskSharedDevice(filesystem.getDeviceName(), filesysDriver, (AVMContext)filesystem); + // Check if the filesystem uses the file state cache, if so then add to the file state reaper + + DiskDeviceContext diskCtx = (DiskDeviceContext) filesystem; + + if ( diskCtx.hasStateCache()) { + + // Register the state cache with the reaper thread + + fsysConfig.addFileStateCache( filesystem.getDeviceName(), diskCtx.getStateCache()); + } + // Start the filesystem ((AVMContext)filesystem).startFilesystem(filesys); @@ -1596,6 +1608,15 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean filesys.setAccessControlList(acls); + // Check if the filesystem uses the file state cache, if so then add to the file state reaper + + if ( filesysContext.hasStateCache()) { + + // Register the state cache with the reaper thread + + fsysConfig.addFileStateCache( filesystem.getDeviceName(), filesysContext.getStateCache()); + } + // Start the filesystem filesysContext.startFilesystem(filesys); @@ -1647,7 +1668,7 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean // Create the new share for the store AVMContext avmContext = new AVMContext(storeName, storeName + ":/", AVMContext.VERSION_HEAD); - avmContext.enableStateTable(true, avmDriver.getStateReaper()); + avmContext.enableStateCache(true); // Create the shared filesystem diff --git a/source/java/org/alfresco/filesys/repo/CacheLookupSearchContext.java b/source/java/org/alfresco/filesys/repo/CacheLookupSearchContext.java index 874a345dc7..09adeff820 100644 --- a/source/java/org/alfresco/filesys/repo/CacheLookupSearchContext.java +++ b/source/java/org/alfresco/filesys/repo/CacheLookupSearchContext.java @@ -21,9 +21,9 @@ package org.alfresco.filesys.repo; import java.util.List; -import org.alfresco.filesys.state.FileState; -import org.alfresco.filesys.state.FileStateTable; import org.alfresco.jlan.server.filesys.FileInfo; +import org.alfresco.jlan.server.filesys.cache.FileState; +import org.alfresco.jlan.server.filesys.cache.FileStateCache; import org.alfresco.jlan.server.filesys.pseudo.PseudoFileList; import org.alfresco.service.cmr.repository.NodeRef; import org.apache.commons.logging.Log; @@ -45,7 +45,7 @@ public class CacheLookupSearchContext extends ContentSearchContext { // File state cache - private FileStateTable m_stateCache; + private FileStateCache m_stateCache; // File information for the '.' and '..' pseduo entries, returned during a wildcard search @@ -68,7 +68,7 @@ public class CacheLookupSearchContext extends ContentSearchContext { String searchStr, PseudoFileList pseudoList, String relPath, - FileStateTable stateCache) + FileStateCache stateCache) { super(cifsHelper, results, searchStr, pseudoList, relPath); super.setSearchString(searchStr); diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java index 475c4cde33..3f3a1e0f18 100644 --- a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java +++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java @@ -33,9 +33,6 @@ import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.filesys.alfresco.AlfrescoContext; import org.alfresco.filesys.alfresco.AlfrescoDiskDriver; import org.alfresco.filesys.alfresco.AlfrescoNetworkFile; -import org.alfresco.filesys.state.FileState; -import org.alfresco.filesys.state.FileStateLockManager; -import org.alfresco.filesys.state.FileState.FileStateStatus; import org.alfresco.jlan.server.SrvSession; import org.alfresco.jlan.server.core.DeviceContext; import org.alfresco.jlan.server.core.DeviceContextException; @@ -53,7 +50,8 @@ import org.alfresco.jlan.server.filesys.FileStatus; import org.alfresco.jlan.server.filesys.NetworkFile; import org.alfresco.jlan.server.filesys.SearchContext; import org.alfresco.jlan.server.filesys.TreeConnection; -import org.alfresco.jlan.server.filesys.db.DBFileInfo; +import org.alfresco.jlan.server.filesys.cache.FileState; +import org.alfresco.jlan.server.filesys.cache.FileStateLockManager; import org.alfresco.jlan.server.filesys.pseudo.MemoryNetworkFile; import org.alfresco.jlan.server.filesys.pseudo.PseudoFile; import org.alfresco.jlan.server.filesys.pseudo.PseudoFileInterface; @@ -102,7 +100,7 @@ import org.springframework.extensions.config.ConfigElement; * *

Provides a filesystem interface for various protocols such as SMB/CIFS and FTP. * - * @author Derek Hulley + * @author gkspencer */ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterface, FileLockingInterface, OpLockInterface { @@ -116,6 +114,21 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa private static final String KEY_ROOT_PATH = "rootPath"; private static final String KEY_RELATIVE_PATH = "relativePath"; + // File status values used in the file state cache + + public static final int FileUnknown = FileStatus.Unknown; + public static final int FileNotExist = FileStatus.NotExist; + public static final int FileExists = FileStatus.FileExists; + public static final int DirectoryExists = FileStatus.DirectoryExists; + + public static final int CustomFileStatus= FileStatus.MaxStatus + 1; + public static final int FileRenamed = CustomFileStatus; + public static final int DeleteOnClose = CustomFileStatus + 1; + + // File state attributes + + public static final String AttrLinkNode = "ContentLinkNode"; + // Services and helpers private CifsHelper cifsHelper; @@ -139,7 +152,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Lock manager - private static FileStateLockManager _lockManager = new FileStateLockManager(); + private static FileStateLockManager _lockManager; /** * Class constructor @@ -626,7 +639,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Enable file state caching - context.enableStateTable( true, getStateReaper()); + context.enableStateCache( true); // Initialize the I/O control handler @@ -643,15 +656,13 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa context.setNodeMonitor( nodeMonitor); } + // Create the lock manager + + _lockManager = new FileStateLockManager( context.getStateCache()); + // Check if oplocks are enabled - if ( context.getDisableOplocks() == false) { - - // Enable oplock support - - _lockManager.setStateTable( context.getStateTable()); - } - else + if ( context.getDisableOplocks() == true) logger.warn("Oplock support disabled for filesystem " + ctx.getDeviceName()); // Start the quota manager, if enabled @@ -749,7 +760,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Make sure the parent folder has a file state, and the path exists String[] paths = FileName.splitPath( path); - FileState fstate = ctx.getStateTable().findFileState( paths[0]); + FileState fstate = ctx.getStateCache().findFileState( paths[0]); if ( fstate == null) { @@ -764,10 +775,10 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Create the file state - fstate = ctx.getStateTable().findFileState( paths[0], true, true); + fstate = ctx.getStateCache().findFileState( paths[0], true); - fstate.setFileStatus( FileStatus.DirectoryExists); - fstate.setNodeRef( nodeRef); + fstate.setFileStatus( DirectoryExists); + fstate.setFilesystemObject( nodeRef); // Add pseudo files to the folder @@ -782,11 +793,11 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Make sure the file state has the node ref - if ( fstate.hasNodeRef() == false) + if ( fstate.hasFilesystemObject() == false) { // Get the node for the folder path - fstate.setNodeRef( getNodeForPath( tree, paths[0])); + fstate.setFilesystemObject( getNodeForPath( tree, paths[0])); } // Add pseudo files for the parent folder @@ -897,9 +908,12 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Create a file state for the file/folder - fstate = ctx.getStateTable().findFileState( path, finfo.isDirectory(), true); - - fstate.setNodeRef( nodeRef); + fstate = ctx.getStateCache().findFileState( path, true); + if ( finfo.isDirectory()) + fstate.setFileStatus( DirectoryExists); + else + fstate.setFileStatus( FileExists); + fstate.setFilesystemObject( nodeRef); } } @@ -971,7 +985,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa String[] paths = FileName.splitPath(searchPath); - if ( ctx.hasStateTable()) + if ( ctx.hasStateCache()) { // See if the folder to be searched has a file state, we can avoid having to walk the path @@ -988,16 +1002,16 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Create a file state for the folder - searchFolderState = ctx.getStateTable().findFileState( paths[0], true, true); + searchFolderState = ctx.getStateCache().findFileState( paths[0], true); } // Make sure the associated node is set - if ( searchFolderState.hasNodeRef() == false) + if ( searchFolderState.hasFilesystemObject() == false) { // Set the associated node for the folder - searchFolderState.setNodeRef( nodeRef); + searchFolderState.setFilesystemObject( nodeRef); } // Add pseudo files to the folder being searched @@ -1115,16 +1129,16 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Use a cache lookup search context - CacheLookupSearchContext cacheContext = new CacheLookupSearchContext(cifsHelper, results, searchFileSpec, pseudoList, paths[0], ctx.getStateTable()); + CacheLookupSearchContext cacheContext = new CacheLookupSearchContext(cifsHelper, results, searchFileSpec, pseudoList, paths[0], ctx.getStateCache()); searchCtx = cacheContext; // Set the '.' and '..' pseudo file entry details - if ( searchFolderState != null && searchFolderState.hasNodeRef()) + if ( searchFolderState != null && searchFolderState.hasFilesystemObject()) { // Get the '.' pseudo entry file details - FileInfo finfo = cifsHelper.getFileInformation( searchFolderState.getNodeRef()); + FileInfo finfo = cifsHelper.getFileInformation((NodeRef) searchFolderState.getFilesystemObject()); // Blend in any cached timestamps @@ -1166,11 +1180,11 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Get the file state for the parent path, if available - FileState parentState = ctx.getStateTable().findFileState( parentPath); + FileState parentState = ctx.getStateCache().findFileState( parentPath); NodeRef parentNode = null; if ( parentState != null) - parentNode = parentState.getNodeRef(); + parentNode = (NodeRef) parentState.getFilesystemObject(); if ( parentState == null || parentNode == null) parentNode = getNodeForPath( tree, parentPath); @@ -1247,27 +1261,21 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { ContentContext ctx = (ContentContext) tree.getContext(); int status = FileStatus.Unknown; + FileState fstate = null; try { // Check for a cached file state - FileState fstate = null; + if ( ctx.hasStateCache()) + fstate = ctx.getStateCache().findFileState(name, true); - if ( ctx.hasStateTable()) - ctx.getStateTable().findFileState(name); - - if ( fstate != null) + if ( fstate != null && fstate.getFileStatus() != FileUnknown) { - FileStateStatus fsts = fstate.getFileStatus(); + status = fstate.getFileStatus(); + if ( status >= CustomFileStatus) + status = FileNotExist; - if ( fsts == FileStateStatus.FileExists) - status = FileStatus.FileExists; - else if ( fsts == FileStateStatus.FolderExists) - status = FileStatus.DirectoryExists; - else if ( fsts == FileStateStatus.NotExist || fsts == FileStateStatus.Renamed) - status = FileStatus.NotExist; - // DEBUG if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO)) @@ -1286,7 +1294,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Make sure the parent folder has a file state, and the path exists String[] paths = FileName.splitPath( name); - fstate = ctx.getStateTable().findFileState( paths[0]); + fstate = ctx.getStateCache().findFileState( paths[0]); if ( fstate == null) { @@ -1296,14 +1304,14 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Create the file state - fstate = ctx.getStateTable().findFileState( paths[0], true, true); + fstate = ctx.getStateCache().findFileState( paths[0], true); - fstate.setFileStatus( FileStatus.DirectoryExists); + fstate.setFileStatus( DirectoryExists); // Get the node for the folder path beginReadTransaction( sess); - fstate.setNodeRef( getNodeForPath( tree, paths[0])); + fstate.setFilesystemObject( getNodeForPath( tree, paths[0])); // Add pseudo files to the folder @@ -1319,7 +1327,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Make sure the file state has the node ref - if ( fstate.hasNodeRef() == false) + if ( fstate.hasFilesystemObject() == false) { // Create the transaction @@ -1327,7 +1335,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Get the node for the folder path - fstate.setNodeRef( getNodeForPath( tree, paths[0])); + fstate.setFilesystemObject( getNodeForPath( tree, paths[0])); } // Add pseudo files for the parent folder @@ -1378,12 +1386,19 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { status = FileStatus.FileExists; } + + // Update the file state status + + if ( fstate != null) + fstate.setFileStatus( status); } } } catch (FileNotFoundException e) { status = FileStatus.NotExist; + if ( fstate != null) + fstate.setFileStatus( status); } catch (IOException e) { @@ -1398,7 +1413,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Debug if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO)) - logger.debug("File status determined: name=" + name + " status=" + FileStatus.asString(status)); + logger.debug("File status determined: name=" + name + " status=" + fileStatusString(fstate.getFileStatus())); // Return the file/folder status @@ -1436,7 +1451,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Make sure the parent folder has a file state, and the path exists String[] paths = FileName.splitPath( path); - FileState fstate = ctx.getStateTable().findFileState( paths[0]); + FileState fstate = ctx.getStateCache().findFileState( paths[0]); if ( fstate == null) { @@ -1446,9 +1461,9 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Create the file state and add any pseudo files - fstate = ctx.getStateTable().findFileState( paths[0], true, true); + fstate = ctx.getStateCache().findFileState( paths[0], true); - fstate.setFileStatus( FileStatus.DirectoryExists); + fstate.setFileStatus( DirectoryExists); getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]); // Debug @@ -1523,11 +1538,11 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa FileState fstate = null; - if ( ctx.hasStateTable()) + if ( ctx.hasStateCache()) { // Check if there is a file state for the file - fstate = ctx.getStateTable().findFileState( params.getPath()); + fstate = ctx.getStateCache().findFileState( params.getPath()); if ( fstate != null) { @@ -1540,7 +1555,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Create a file state for the path - fstate = ctx.getStateTable().findFileState( params.getPath(), false, true); + fstate = ctx.getStateCache().findFileState( params.getPath(), true); } // Check if the current file open allows the required shared access @@ -1765,15 +1780,15 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Create a file state for the open file - if ( ctx.hasStateTable()) + if ( ctx.hasStateCache()) { if ( fstate == null) - fstate = ctx.getStateTable().findFileState(params.getPath(), params.isDirectory(), true); + fstate = ctx.getStateCache().findFileState(params.getPath(), true); // Update the file state, cache the node fstate.incrementOpenCount(); - fstate.setNodeRef(nodeRef); + fstate.setFilesystemObject(nodeRef); // Store the state with the file @@ -1846,7 +1861,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // If the state table is available then try to find the parent folder node for the new file // to save having to walk the path - if ( ctx.hasStateTable()) + if ( ctx.hasStateCache()) { // See if the parent folder has a file state, we can avoid having to walk the path @@ -1871,8 +1886,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Get the file state for the parent folder parentState = getStateForPath(tree, paths[0]); - if ( parentState == null && ctx.hasStateTable()) - parentState = ctx.getStateTable().findFileState( paths[0], true, true); + if ( parentState == null && ctx.hasStateCache()) + parentState = ctx.getStateCache().findFileState( paths[0], true); } } @@ -1904,9 +1919,9 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Add a file state for the new file/folder - if ( ctx.hasStateTable()) + if ( ctx.hasStateCache()) { - FileState fstate = ctx.getStateTable().findFileState(params.getPath(), false, true); + FileState fstate = ctx.getStateCache().findFileState(params.getPath(), true); if ( fstate != null) { // Save the file sharing mode, needs to be done before the open count is incremented @@ -1916,9 +1931,9 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Indicate that the file is open - fstate.setFileStatus(FileStateStatus.FileExists); + fstate.setFileStatus( FileExists); fstate.incrementOpenCount(); - fstate.setNodeRef(nodeRef); + fstate.setFilesystemObject(nodeRef); // Store the file state with the file @@ -2008,7 +2023,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // If the state table is available then try to find the parent folder node for the new folder // to save having to walk the path - if ( ctx.hasStateTable()) + if ( ctx.hasStateCache()) { // See if the parent folder has a file state, we can avoid having to walk the path @@ -2033,8 +2048,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Get the file state for the parent folder parentState = getStateForPath(tree, paths[0]); - if ( parentState == null && ctx.hasStateTable()) - parentState = ctx.getStateTable().findFileState( paths[0], true, true); + if ( parentState == null && ctx.hasStateCache()) + parentState = ctx.getStateCache().findFileState( paths[0], true); } } @@ -2044,15 +2059,15 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Add a file state for the new folder - if ( ctx.hasStateTable()) + if ( ctx.hasStateCache()) { - FileState fstate = ctx.getStateTable().findFileState( params.getPath(), true, true); + FileState fstate = ctx.getStateCache().findFileState( params.getPath(), true); if ( fstate != null) { // Indicate that the file is open - fstate.setFileStatus(FileStateStatus.FolderExists); - fstate.setNodeRef(nodeRef); + fstate.setFileStatus( DirectoryExists); + fstate.setFilesystemObject(nodeRef); // DEBUG @@ -2131,11 +2146,11 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Remove the file state - if ( ctx.hasStateTable()) + if ( ctx.hasStateCache()) { // Remove the file state - ctx.getStateTable().removeFileState(dir); + ctx.getStateCache().removeFileState(dir); // Update, or create, a parent folder file state @@ -2145,8 +2160,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Get the file state for the parent folder FileState parentState = getStateForPath(tree, paths[0]); - if ( parentState == null && ctx.hasStateTable()) - parentState = ctx.getStateTable().findFileState( paths[0], true, true); + if ( parentState == null && ctx.hasStateCache()) + parentState = ctx.getStateCache().findFileState( paths[0], true); // Update the modification timestamp @@ -2251,32 +2266,32 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa return; } - } - if ( ctx.hasStateTable()) - { - FileState fstate = ctx.getStateTable().findFileState(file.getFullName()); - if ( fstate != null) { - - // If the file open count is now zero then reset the stored sharing mode - - if ( fstate.decrementOpenCount() == 0) - fstate.setSharedAccess( SharingMode.READWRITE + SharingMode.DELETE); - - // Check if there is a cached modification timestamp to be written out - - if ( file.hasDeleteOnClose() == false && fstate.hasModifyDateTime() && fstate.hasNodeRef()) { - - // Update the modification date on the file/folder node - - Date modifyDate = new Date( fstate.getModifyDateTime()); - nodeService.setProperty( fstate.getNodeRef(), ContentModel.PROP_MODIFIED, modifyDate); - - // Debug - - if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE)) - logger.debug("Updated modifcation timestamp, " + file.getFullName() + ", modTime=" + modifyDate); - } + if ( ctx.hasStateCache()) + { + FileState fstate = ctx.getStateCache().findFileState(file.getFullName()); + if ( fstate != null) { + + // If the file open count is now zero then reset the stored sharing mode + + if ( fstate.decrementOpenCount() == 0) + fstate.setSharedAccess( SharingMode.READWRITE + SharingMode.DELETE); + + // Check if there is a cached modification timestamp to be written out + + if ( file.hasDeleteOnClose() == false && fstate.hasModifyDateTime() && fstate.hasFilesystemObject()) { + + // Update the modification date on the file/folder node + + Date modifyDate = new Date( fstate.getModifyDateTime()); + nodeService.setProperty((NodeRef) fstate.getFilesystemObject(), ContentModel.PROP_MODIFIED, modifyDate); + + // Debug + + if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE)) + logger.debug("Updated modifcation timestamp, " + file.getFullName() + ", modTime=" + modifyDate); + } + } } } @@ -2341,28 +2356,28 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Set the file state to indicate a delete on close - if ( ctx.hasStateTable()) + if ( ctx.hasStateCache()) { if ( isVersionable == true) { // Get, or create, the file state - FileState fState = ctx.getStateTable().findFileState(file.getFullName(), false, true); + FileState fState = ctx.getStateCache().findFileState(file.getFullName(), true); // Indicate that the file was deleted via a delete on close request - fState.setFileStatus(FileStateStatus.DeleteOnClose); + fState.setFileStatus( DeleteOnClose); // Make sure the file state is cached for a short while, save the noderef details fState.setExpiryTime(System.currentTimeMillis() + FileState.RenameTimeout); - fState.setNodeRef(nodeRef); + fState.setFilesystemObject(nodeRef); } else { // Remove the file state - ctx.getStateTable().removeFileState( file.getFullName()); + ctx.getStateCache().removeFileState( file.getFullName()); } } } @@ -2444,7 +2459,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Remove the file state - if ( ctx.hasStateTable()) + if ( ctx.hasStateCache()) { // Check if the node is versionable, cache the node details for a short while @@ -2453,17 +2468,17 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Make sure the file state is cached for a short while, a new file may be renamed to the same name // in which case we can connect the file to the previous version history - FileState delState = ctx.getStateTable().findFileState( name, false, true); + FileState delState = ctx.getStateCache().findFileState( name, true); delState.setExpiryTime(System.currentTimeMillis() + FileState.DeleteTimeout); - delState.setFileStatus(FileStateStatus.DeleteOnClose); - delState.setNodeRef( nodeRef); + delState.setFileStatus( DeleteOnClose); + delState.setFilesystemObject( nodeRef); } else { // Remove the file state - ctx.getStateTable().removeFileState( name); + ctx.getStateCache().removeFileState( name); } // Update, or create, a parent folder file state @@ -2474,8 +2489,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Get the file state for the parent folder FileState parentState = getStateForPath(tree, paths[0]); - if ( parentState == null && ctx.hasStateTable()) - parentState = ctx.getStateTable().findFileState( paths[0], true, true); + if ( parentState == null && ctx.hasStateCache()) + parentState = ctx.getStateCache().findFileState( paths[0], true); // Update the modification timestamp @@ -2580,7 +2595,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Get the file state for the old file, if available - FileState oldState = ctx.getStateTable().findFileState( oldName); + FileState oldState = ctx.getStateCache().findFileState( oldName); // Check if we are renaming a folder, or the rename is to a different folder @@ -2594,7 +2609,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa { // Update the file state index to use the new name - ctx.getStateTable().renameFileState(newName, oldState); + ctx.getStateCache().renameFileState(newName, oldState, true); } // Rename or move the file/folder @@ -2616,7 +2631,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Check if the target file already exists int newExists = fileExists( sess, tree, newName); - FileState newState = ctx.getStateTable().findFileState( newName, false, true); + FileState newState = ctx.getStateCache().findFileState( newName, true); NodeRef targetNodeRef = null; @@ -2632,7 +2647,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Check if the target has a renamed or delete-on-close state - if ( newState.getFileStatus() == FileStateStatus.Renamed) { + if ( newState.getFileStatus() == FileRenamed) { // DEBUG @@ -2641,9 +2656,9 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Use the renamed node to clone aspects/state - cloneNodeAspects( name, newState.getNodeRef(), nodeToMoveRef, ctx); + cloneNodeAspects( name, (NodeRef) newState.getFilesystemObject(), nodeToMoveRef, ctx); } - else if ( newState.getFileStatus() == FileStateStatus.DeleteOnClose) { + else if ( newState.getFileStatus() == DeleteOnClose) { // DEBUG @@ -2652,7 +2667,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Restore the deleted node so we can relink the new version to the old history/properties - NodeRef archivedNode = getNodeArchiveService().getArchivedNode( newState.getNodeRef()); + NodeRef archivedNode = getNodeArchiveService().getArchivedNode((NodeRef) newState.getFilesystemObject()); // DEBUG @@ -2672,16 +2687,18 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Check if the deleted file had a linked node, due to a rename - if ( newState.hasLinkNode() && nodeService.exists( newState.getLinkNode())) { + NodeRef linkNode = (NodeRef) newState.findAttribute( AttrLinkNode); + + if ( linkNode != null && nodeService.exists( linkNode)) { // Clone aspects from the linked node onto the restored node - cloneNodeAspects( name, newState.getLinkNode(), targetNodeRef, ctx); + cloneNodeAspects( name, linkNode, targetNodeRef, ctx); // DEBUG if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME)) { - logger.debug(" Moved aspects from linked node " + newState.getLinkNode()); + logger.debug(" Moved aspects from linked node " + linkNode); // Check if the node is a working copy @@ -2730,8 +2747,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Mark the new file as existing - newState.setFileStatus( FileStatus.FileExists); - newState.setNodeRef( nodeToMoveRef); + newState.setFileStatus( FileExists); + newState.setFilesystemObject( nodeToMoveRef); // Make sure the old file state is cached for a short while, the file may not be open so the // file state could be expired @@ -2740,8 +2757,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Indicate that this is a renamed file state, set the node ref of the file that was renamed - oldState.setFileStatus(FileStateStatus.Renamed); - oldState.setNodeRef(nodeToMoveRef); + oldState.setFileStatus( FileRenamed); + oldState.setFilesystemObject(nodeToMoveRef); // DEBUG @@ -2770,8 +2787,8 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Mark the new file as existing - newState.setFileStatus( FileStatus.FileExists); - newState.setNodeRef( targetNodeRef); + newState.setFileStatus( FileExists); + newState.setFilesystemObject( targetNodeRef); // Delete the old file @@ -2784,12 +2801,12 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Indicate that this is a deleted file state, set the node ref of the file that was renamed - oldState.setFileStatus(FileStateStatus.DeleteOnClose); - oldState.setNodeRef(nodeToMoveRef); + oldState.setFileStatus( DeleteOnClose); + oldState.setFilesystemObject(nodeToMoveRef); // Link to the new node, a new file may be renamed into place, we need to transfer aspect/locks - oldState.setLinkNode( targetNodeRef); + oldState.addAttribute( AttrLinkNode, targetNodeRef); // DEBUG @@ -3259,16 +3276,16 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa ContentContext ctx = (ContentContext) tree.getContext(); - if ( ctx.hasStateTable()) + if ( ctx.hasStateCache()) { // Try and get the node ref from an in memory file state - FileState fstate = ctx.getStateTable().findFileState(path); - if ( fstate != null && fstate.hasNodeRef() && fstate.exists() ) + FileState fstate = ctx.getStateCache().findFileState(path); + if ( fstate != null && fstate.hasFilesystemObject() && fstate.exists() ) { // Check that the node exists - if (fileFolderService.exists(fstate.getNodeRef())) + if (fileFolderService.exists((NodeRef) fstate.getFilesystemObject())) { // Bump the file states expiry time @@ -3276,11 +3293,11 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa // Return the cached noderef - return fstate.getNodeRef(); + return (NodeRef) fstate.getFilesystemObject(); } else { - ctx.getStateTable().removeFileState(path); + ctx.getStateCache().removeFileState(path); } } } @@ -3344,11 +3361,11 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa ContentContext ctx = (ContentContext) tree.getContext(); FileState fstate = null; - if ( ctx.hasStateTable()) + if ( ctx.hasStateCache()) { // Get the file state for a file/folder - fstate = ctx.getStateTable().findFileState(path); + fstate = ctx.getStateCache().findFileState(path); } // Return the file state @@ -3548,5 +3565,38 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME)) logger.debug(" Removed versionable aspect from temp file"); } - } + } + + /** + * Return the file state status as a string + * + * @param sts int + * @return String + */ + private final String fileStatusString( int sts) { + String fstatus = "Unknown"; + + switch ( sts) { + case FileUnknown: + fstatus = "Unknown"; + break; + case FileNotExist: + fstatus = "NotExist"; + break; + case FileExists: + fstatus = "FileExists"; + break; + case DirectoryExists: + fstatus = "DirectoryExists"; + break; + case FileRenamed: + fstatus = "FileRenamed"; + break; + case DeleteOnClose: + fstatus = "DeleteOnClose"; + break; + } + + return fstatus; + } } diff --git a/source/java/org/alfresco/filesys/repo/HomeShareMapper.java b/source/java/org/alfresco/filesys/repo/HomeShareMapper.java index b33bc15a79..e5477e4240 100644 --- a/source/java/org/alfresco/filesys/repo/HomeShareMapper.java +++ b/source/java/org/alfresco/filesys/repo/HomeShareMapper.java @@ -389,7 +389,7 @@ public class HomeShareMapper implements ShareMapper, InitializingBean // Create the disk driver and context ContentContext diskCtx = new ContentContext( getHomeFolderName(), "", "", alfClient.getHomeFolder()); - diskCtx.enableStateTable( true, m_driver.getStateReaper()); + diskCtx.enableStateCache( true); // Create a temporary shared device for the users home directory diff --git a/source/java/org/alfresco/filesys/repo/NodeMonitor.java b/source/java/org/alfresco/filesys/repo/NodeMonitor.java index 2930c8ba57..e3329217c9 100644 --- a/source/java/org/alfresco/filesys/repo/NodeMonitor.java +++ b/source/java/org/alfresco/filesys/repo/NodeMonitor.java @@ -22,10 +22,10 @@ package org.alfresco.filesys.repo; import java.io.Serializable; import java.util.Map; -import org.alfresco.filesys.state.FileState; -import org.alfresco.filesys.state.FileStateTable; import org.alfresco.jlan.server.filesys.FileStatus; import org.alfresco.jlan.server.filesys.NotifyChange; +import org.alfresco.jlan.server.filesys.cache.FileState; +import org.alfresco.jlan.server.filesys.cache.FileStateCache; import org.alfresco.jlan.smb.server.notify.NotifyChangeHandler; import org.alfresco.model.ContentModel; import org.alfresco.repo.node.NodeServicePolicies; @@ -88,7 +88,7 @@ public class NodeMonitor extends TransactionListenerAdapter // File state table and change notification handler - private FileStateTable m_stateTable; + private FileStateCache m_stateTable; private NotifyChangeHandler m_changeHandler; // Root node path and store @@ -188,7 +188,7 @@ public class NodeMonitor extends TransactionListenerAdapter // Get the file state table and change notification handler, if enabled - m_stateTable = m_filesysCtx.getStateTable(); + m_stateTable = m_filesysCtx.getStateCache(); m_changeHandler = m_filesysCtx.getChangeHandler(); // Start the event processing thread diff --git a/source/java/org/alfresco/filesys/repo/desk/CheckInOutDesktopAction.java b/source/java/org/alfresco/filesys/repo/desk/CheckInOutDesktopAction.java index ba9149603d..0620eb0369 100644 --- a/source/java/org/alfresco/filesys/repo/desk/CheckInOutDesktopAction.java +++ b/source/java/org/alfresco/filesys/repo/desk/CheckInOutDesktopAction.java @@ -26,11 +26,11 @@ import org.alfresco.filesys.alfresco.DesktopAction; import org.alfresco.filesys.alfresco.DesktopParams; import org.alfresco.filesys.alfresco.DesktopResponse; import org.alfresco.filesys.alfresco.DesktopTarget; -import org.alfresco.filesys.state.FileState; -import org.alfresco.filesys.state.FileStateTable; import org.alfresco.jlan.server.filesys.FileName; import org.alfresco.jlan.server.filesys.FileStatus; import org.alfresco.jlan.server.filesys.NotifyChange; +import org.alfresco.jlan.server.filesys.cache.FileState; +import org.alfresco.jlan.server.filesys.cache.FileStateCache; import org.alfresco.model.ContentModel; import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.repository.NodeRef; @@ -183,12 +183,12 @@ public class CheckInOutDesktopAction extends DesktopAction { // Update cached state for the working copy to indicate the file exists - FileStateTable stateTable = getContext().getStateTable(); - if ( stateTable != null) { + FileStateCache stateCache = getContext().getStateCache(); + if ( stateCache != null) { // Update any cached state for the working copy file - FileState fstate = stateTable.findFileState( fileName); + FileState fstate = stateCache.findFileState( fileName); if ( fstate != null) fstate.setFileStatus( FileStatus.FileExists); } diff --git a/source/java/org/alfresco/filesys/state/FileState.java b/source/java/org/alfresco/filesys/state/FileState.java deleted file mode 100644 index 7901120240..0000000000 --- a/source/java/org/alfresco/filesys/state/FileState.java +++ /dev/null @@ -1,841 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.filesys.state; - -import org.alfresco.jlan.locking.FileLock; -import org.alfresco.jlan.locking.FileLockList; -import org.alfresco.jlan.locking.LockConflictException; -import org.alfresco.jlan.locking.NotLockedException; -import org.alfresco.jlan.server.filesys.ExistingOpLockException; -import org.alfresco.jlan.server.filesys.FileOpenParams; -import org.alfresco.jlan.server.filesys.FileStatus; -import org.alfresco.jlan.server.filesys.pseudo.PseudoFile; -import org.alfresco.jlan.server.filesys.pseudo.PseudoFileList; -import org.alfresco.jlan.server.locking.OpLockDetails; -import org.alfresco.jlan.smb.SharingMode; -import org.alfresco.service.cmr.repository.NodeRef; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * File State Class - * - *

Keeps track of file state across all sessions on the server, to keep track of file sharing modes, - * file locks and also for synchronizing access to files/folders. - * - * @author gkspencer - */ -public class FileState -{ - private static final Log logger = LogFactory.getLog(FileState.class); - - // File state constants - - public final static long NoTimeout = -1L; - public final static long DefTimeout = 2 * 60000L; // 2 minutes - public final static long RenameTimeout = 1 * 60000L; // 1 minute - public final static long DeleteTimeout = 15000L; // 15 seconds - - // File status - - public enum FileStateStatus { NotExist, FileExists, FolderExists, Renamed, DeleteOnClose }; - - // File name/path - - private String m_path; - - // File state timeout, -1 indicates no timeout - - private long m_tmo; - - // File status, indicates if the file/folder exists and if it is a file or folder. - - private FileStateStatus m_fileStatus = FileStateStatus.NotExist; - - // Open file count - - private int m_openCount; - - // Sharing mode and PID of first process to open the file - - private int m_sharedAccess = SharingMode.READWRITE + SharingMode.DELETE; - private int m_pid = -1; - - // File lock list, allocated once there are active locks on this file - - private FileLockList m_lockList; - - // Oplock details - - private OpLockDetails m_oplock; - - // Node for this file - - private NodeRef m_nodeRef; - - // Link to the new file state when a file is renamed - - private FileState m_newNameState; - - // Pseudo file list - - private PseudoFileList m_pseudoFiles; - - // File timestamps updated only whilst file is open - - private long m_accessDate; - private long m_modifyDate; - private long m_changeDate; - - // Keep track of the node we are linked to, when deleted - - private NodeRef m_linkNode; - - /** - * Class constructor - * - * @param fname String - * @param isdir boolean - */ - public FileState(String fname, boolean isdir) - { - - // Normalize the file path - - setPath(fname); - setExpiryTime(System.currentTimeMillis() + DefTimeout); - - // Set the file/folder status - - setFileStatus( isdir ? FileStateStatus.FolderExists : FileStateStatus.FileExists); - } - - /** - * Return the file name/path - * - * @return String - */ - public final String getPath() - { - return m_path; - } - - /** - * Return the file status - * - * @return FileStateStatus - */ - public final FileStateStatus getFileStatus() - { - return m_fileStatus; - } - - /** - * Determine if the file/folder exists - * - * @return boolen - */ - public final boolean exists() - { - if ( m_fileStatus == FileStateStatus.FileExists || - m_fileStatus == FileStateStatus.FolderExists) - return true; - return false; - } - - /** - * Return the directory state - * - * @return boolean - */ - public final boolean isDirectory() - { - return m_fileStatus == FileStateStatus.FolderExists ? true : false; - } - - /** - * Determine if the associated node has been set - * - * @return boolean - */ - public final boolean hasNodeRef() - { - return m_nodeRef != null ? true : false; - } - - /** - * Return the associated node - * - * @return NodeRef - */ - public final NodeRef getNodeRef() - { - return m_nodeRef; - } - - /** - * Return the file open count - * - * @return int - */ - public final int getOpenCount() - { - return m_openCount; - } - - /** - * Return the shared access mode - * - * @return int - */ - public final int getSharedAccess() - { - return m_sharedAccess; - } - - /** - * Return the PID of the first process to open the file, or -1 if the file is not open - * - * @return int - */ - public final int getProcessId() - { - return m_pid; - } - - /** - * Check if there are active locks on this file - * - * @return boolean - */ - public final boolean hasActiveLocks() - { - if (m_lockList != null && m_lockList.numberOfLocks() > 0) - return true; - return false; - } - - /** - * Check if this file state does not expire - * - * @return boolean - */ - public final boolean hasNoTimeout() - { - return m_tmo == NoTimeout ? true : false; - } - - /** - * Check if the file can be opened depending on any current file opens and the sharing mode of - * the first file open - * - * @param params FileOpenParams - * @return boolean - */ - public final boolean allowsOpen(FileOpenParams params) - { - - // If the file is not currently open then allow the file open - - if (getOpenCount() == 0) - return true; - - // Check the shared access mode - - if (getSharedAccess() == SharingMode.READWRITE && params.getSharedAccess() == SharingMode.READWRITE) - return true; - else if ((getSharedAccess() & SharingMode.READ) != 0 && params.isReadOnlyAccess()) - return true; - else if ((getSharedAccess() & SharingMode.WRITE) != 0 && params.isWriteOnlyAccess()) - return true; - - // Sharing violation, do not allow the file open - - return false; - } - - /** - * Increment the file open count - * - * @return int - */ - public final synchronized int incrementOpenCount() - { - return m_openCount++; - } - - /** - * Decrement the file open count - * - * @return int - */ - public final synchronized int decrementOpenCount() - { - - // Debug - - if (m_openCount <= 0) - logger.debug("@@@@@ File close name=" + getPath() + ", count=" + m_openCount + " <>"); - else - m_openCount--; - - // Clear the PID if the file is no longer open - - if ( m_openCount == 0) - m_pid = -1; - - return m_openCount; - } - - /** - * Check if the file state has expired - * - * @param curTime long - * @return boolean - */ - public final boolean hasExpired(long curTime) - { - if (m_tmo == NoTimeout) - return false; - if (curTime > m_tmo) - return true; - return false; - } - - /** - * Return the number of seconds left before the file state expires - * - * @param curTime long - * @return long - */ - public final long getSecondsToExpire(long curTime) - { - if (m_tmo == NoTimeout) - return -1; - return (m_tmo - curTime) / 1000L; - } - - /** - * Determine if the file state has an associated rename state - * - * @return boolean - */ - public final boolean hasRenameState() - { - return m_newNameState != null ? true : false; - } - - /** - * Return the associated rename state - * - * @return FileState - */ - public final FileState getRenameState() - { - return m_newNameState; - } - - /** - * Determine if a folder has pseudo files associated with it - * - * @return boolean - */ - public final boolean hasPseudoFiles() - { - if ( m_pseudoFiles != null) - return m_pseudoFiles.numberOfFiles() > 0; - return false; - } - - /** - * Return the pseudo file list - * - * @return PseudoFileList - */ - public final PseudoFileList getPseudoFileList() - { - return m_pseudoFiles; - } - - /** - * Add a pseudo file to this folder - * - * @param pfile PseudoFile - */ - public final void addPseudoFile(PseudoFile pfile) - { - if ( m_pseudoFiles == null) - m_pseudoFiles = new PseudoFileList(); - m_pseudoFiles.addFile( pfile); - } - - /** - * Set the file status - * - * @param status FileStateStatus - */ - public final void setFileStatus(FileStateStatus status) - { - m_fileStatus = status; - } - - /** - * Set the file status - * - * @param fsts int - */ - public final void setFileStatus(int fsts) - { - if ( fsts == FileStatus.FileExists) - m_fileStatus = FileStateStatus.FileExists; - else if ( fsts == FileStatus.DirectoryExists) - m_fileStatus = FileStateStatus.FolderExists; - else if ( fsts == FileStatus.NotExist) - m_fileStatus = FileStateStatus.NotExist; - } - - /** - * Set the file state expiry time - * - * @param expire long - */ - public final void setExpiryTime(long expire) - { - m_tmo = expire; - } - - /** - * Set the node ref for the file/folder - * - * @param nodeRef NodeRef - */ - public final void setNodeRef(NodeRef nodeRef) - { - m_nodeRef = nodeRef; - } - - /** - * Set the associated file state when a file is renamed, this is the link to the new file state - * - * @param fstate FileState - */ - public final void setRenameState(FileState fstate) - { - m_newNameState = fstate; - } - - /** - * Set the shared access mode, from the first file open - * - * @param mode int - */ - public final void setSharedAccess(int mode) - { - if (getOpenCount() == 0) - m_sharedAccess = mode; - } - - /** - * Set the PID of the process opening the file - * - * @param pid int - */ - public final void setProcessId(int pid) - { - if ( getOpenCount() == 0) - m_pid = pid; - } - - /** - * Set the file path - * - * @param path String - */ - public final void setPath(String path) - { - - // Split the path into directories and file name, only uppercase the directories to - // normalize the path. - - m_path = normalizePath(path); - } - - /** - * Return the count of active locks on this file - * - * @return int - */ - public final int numberOfLocks() - { - if (m_lockList != null) - return m_lockList.numberOfLocks(); - return 0; - } - - /** - * Add a lock to this file - * - * @param lock FileLock - * @exception LockConflictException - */ - public final void addLock(FileLock lock) throws LockConflictException - { - - // Check if the lock list has been allocated - - if (m_lockList == null) - { - - synchronized (this) - { - - // Allocate the lock list, check if the lock list has been allocated elsewhere - // as we may have been waiting for the lock - - if (m_lockList == null) - m_lockList = new FileLockList(); - } - } - - // Add the lock to the list, check if there are any lock conflicts - - synchronized (m_lockList) - { - - // Check if the new lock overlaps with any existing locks - - if (m_lockList.allowsLock(lock)) - { - - // Add the new lock to the list - - m_lockList.addLock(lock); - } - else - throw new LockConflictException(); - } - } - - /** - * Remove a lock on this file - * - * @param lock FileLock - * @exception NotLockedException - */ - public final void removeLock(FileLock lock) throws NotLockedException - { - - // Check if the lock list has been allocated - - if (m_lockList == null) - throw new NotLockedException(); - - // Remove the lock from the active list - - synchronized (m_lockList) - { - - // Remove the lock, check if we found the matching lock - - if (m_lockList.removeLock(lock) == null) - throw new NotLockedException(); - } - } - - /** - * Check if the access date/time has been set - * - * @return boolean - */ - public final boolean hasAccessDateTime() { - return m_accessDate != 0L ? true : false; - } - - /** - * Return the access date/time - * - * @return long - */ - public final long getAccessDateTime() { - return m_accessDate; - } - - /** - * Update the access date/time - */ - public final void updateAccessDateTime() { - m_accessDate = System.currentTimeMillis(); - } - - /** - * Check if the change date/time has been set - * - * @return boolean - */ - public final boolean hasChangeDateTime() { - return m_changeDate != 0L ? true : false; - } - - /** - * Return the change date/time - * - * @return long - */ - public final long getChangeDateTime() { - return m_changeDate; - } - - /** - * Update the change date/time - */ - public final void updateChangeDateTime() { - m_changeDate = System.currentTimeMillis(); - } - - /** - * Check if the modification date/time has been set - * - * @return boolean - */ - public final boolean hasModifyDateTime() { - return m_modifyDate != 0L ? true : false; - } - - /** - * Return the modify date/time - * - * @return long - */ - public final long getModifyDateTime() { - return m_modifyDate; - } - - /** - * Update the modify date/time - */ - public final void updateModifyDateTime() { - m_modifyDate = System.currentTimeMillis(); - m_accessDate = m_modifyDate; - } - - /** - * Update the modify date/time - * - * @param modTime long - */ - public final void updateModifyDateTime( long modTime) { - m_modifyDate = modTime; - } - - /** - * Check if the file is linked to another node - * - * @return boolean - */ - public final boolean hasLinkNode() { - return m_linkNode != null ? true : false; - } - - /** - * Return the node that the file is linked to - * - * @return NodeRef - */ - public final NodeRef getLinkNode() { - return m_linkNode; - } - - /** - * Set the node that this file is linked to - * - * @param node NodeRef - */ - public final void setLinkNode( NodeRef node) { - m_linkNode = node; - } - - /** - * Check if the file is readable for the specified section of the file and process id - * - * @param offset long - * @param len long - * @param pid int - * @return boolean - */ - public final boolean canReadFile(long offset, long len, int pid) - { - - // Check if the lock list is valid - - if (m_lockList == null) - return true; - - // Check if the file section is readable by the specified process - - boolean readOK = false; - - synchronized (m_lockList) - { - - // Check if the file section is readable - - readOK = m_lockList.canReadFile(offset, len, pid); - } - - // Return the read status - - return readOK; - } - - /** - * Check if the file is writeable for the specified section of the file and process id - * - * @param offset long - * @param len long - * @param pid int - * @return boolean - */ - public final boolean canWriteFile(long offset, long len, int pid) - { - - // Check if the lock list is valid - - if (m_lockList == null) - return true; - - // Check if the file section is writeable by the specified process - - boolean writeOK = false; - - synchronized (m_lockList) - { - - // Check if the file section is writeable - - writeOK = m_lockList.canWriteFile(offset, len, pid); - } - - // Return the write status - - return writeOK; - } - - /** - * Check if the file has an active oplock - * - * @return boolean - */ - public final boolean hasOpLock() { - return m_oplock != null ? true : false; - } - - /** - * Return the oplock details - * - * @return OpLockDetails - */ - public final OpLockDetails getOpLock() { - return m_oplock; - } - - /** - * Set the oplock for this file - * - * @param oplock OpLockDetails - * @exception ExistingOpLockException If there is an active oplock on this file - */ - public final synchronized void setOpLock(OpLockDetails oplock) - throws ExistingOpLockException { - - if ( m_oplock == null) - m_oplock = oplock; - else - throw new ExistingOpLockException(); - } - - /** - * Clear the oplock - */ - public final synchronized void clearOpLock() { - m_oplock = null; - } - - /** - * Normalize the path to uppercase the directory names and keep the case of the file name. - * - * @param path String - * @return String - */ - public final static String normalizePath(String path) - { - return path.toUpperCase(); - } - - /** - * Return the file state as a string - * - * @return String - */ - public String toString() - { - StringBuffer str = new StringBuffer(); - - str.append("["); - str.append(getPath()); - str.append(","); - str.append(getFileStatus()); - str.append(":Opn="); - str.append(getOpenCount()); - str.append("/"); - str.append(getProcessId()); - - str.append(",Expire="); - str.append(getSecondsToExpire(System.currentTimeMillis())); - - str.append(",Locks="); - str.append(numberOfLocks()); - - str.append(",Ref="); - if ( hasNodeRef()) - str.append(getNodeRef().getId()); - else - str.append("Null"); - - str.append(",Shr=0x"); - str.append(Integer.toHexString(getSharedAccess())); - - if ( isDirectory()) - { - str.append(",Pseudo="); - if ( hasPseudoFiles()) - str.append(getPseudoFileList().numberOfFiles()); - else - str.append(0); - } - - if ( hasOpLock()) { - str.append(",OpLock="); - str.append(getOpLock()); - } - - str.append("]"); - - return str.toString(); - } -} diff --git a/source/java/org/alfresco/filesys/state/FileStateListener.java b/source/java/org/alfresco/filesys/state/FileStateListener.java deleted file mode 100644 index e65b60710e..0000000000 --- a/source/java/org/alfresco/filesys/state/FileStateListener.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2006-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.filesys.state; - -/** - * File State Listener Interface - * - * @author gkspencer - */ -public interface FileStateListener { - - /** - * File state has expired. The listener can control whether the file state is removed - * from the cache, or not. - * - * @param state FileState - * @return true to remove the file state from the cache, or false to leave the file state in the cache - */ - public boolean fileStateExpired(FileState state); - - /** - * File state cache is closing down, any resources attached to the file state must be released. - * - * @param state FileState - */ - public void fileStateClosed(FileState state); -} diff --git a/source/java/org/alfresco/filesys/state/FileStateLockManager.java b/source/java/org/alfresco/filesys/state/FileStateLockManager.java deleted file mode 100644 index 4ccb052993..0000000000 --- a/source/java/org/alfresco/filesys/state/FileStateLockManager.java +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.filesys.state; - -import java.io.IOException; -import java.util.Enumeration; -import java.util.Hashtable; - -import org.alfresco.jlan.debug.Debug; -import org.alfresco.jlan.locking.FileLock; -import org.alfresco.jlan.locking.LockConflictException; -import org.alfresco.jlan.locking.NotLockedException; -import org.alfresco.jlan.server.SrvSession; -import org.alfresco.jlan.server.filesys.ExistingOpLockException; -import org.alfresco.jlan.server.filesys.NetworkFile; -import org.alfresco.jlan.server.filesys.TreeConnection; -import org.alfresco.jlan.server.filesys.pseudo.MemoryNetworkFile; -import org.alfresco.jlan.server.locking.LockManager; -import org.alfresco.jlan.server.locking.OpLockDetails; -import org.alfresco.jlan.server.locking.OpLockManager; -import org.alfresco.jlan.smb.OpLock; -import org.alfresco.jlan.smb.SMBStatus; -import org.alfresco.jlan.smb.server.SMBSrvPacket; -import org.alfresco.jlan.smb.server.SMBSrvSession; -import org.alfresco.filesys.alfresco.AlfrescoNetworkFile; - -/** - * File State Lock Manager Class - * - *

Implementation of a lock manager that uses the file state cache to track locks on a file. - * - * @author gkspencer - */ -public class FileStateLockManager implements LockManager, OpLockManager, Runnable { - - // Oplock break timeout - - private static final long OpLockBreakTimeout = 5000L; // 5 seconds - - // File state cache used for byte range locks/oplocks - - private FileStateTable m_stateCache; - - // Oplock breaks in progress - - private Hashtable m_oplockQueue; - - // Oplock break timeout thread - - private Thread m_expiryThread; - private boolean m_shutdown; - - /** - * Lock a byte range within a file, or the whole file. - * - * @param sess SrvSession - * @param tree TreeConnection - * @param file NetworkFile - * @param lock FileLock - * @exception LockConflictException - * @exception IOException - */ - public void lockFile(SrvSession sess, TreeConnection tree, NetworkFile file, FileLock lock) - throws LockConflictException, IOException { - - // Get the file state associated with the file - - FileState fstate = null; - - if ( file instanceof AlfrescoNetworkFile) { - AlfrescoNetworkFile alfFile = (AlfrescoNetworkFile) file; - fstate = alfFile.getFileState(); - } - else if ( file instanceof MemoryNetworkFile) { - file.addLock(lock); - return; - } - - if ( fstate == null) - throw new IOException("Open file without state (lock)"); - - // Add the lock to the active lock list for the file, check if the new lock conflicts with - // any existing locks. Add the lock to the file instance so that locks can be removed if the - // file is closed/session abnormally terminates. - - fstate.addLock(lock); - file.addLock(lock); - } - - /** - * Unlock a byte range within a file, or the whole file - * - * @param sess SrvSession - * @param tree TreeConnection - * @param file NetworkFile - * @param lock FileLock - * @exception NotLockedException - * @exception IOException - */ - public void unlockFile(SrvSession sess, TreeConnection tree, NetworkFile file, FileLock lock) - throws NotLockedException, IOException { - - // Get the file state associated with the file - - FileState fstate = null; - - if ( file instanceof AlfrescoNetworkFile) { - AlfrescoNetworkFile alfFile = (AlfrescoNetworkFile) file; - fstate = alfFile.getFileState(); - } - else if ( file instanceof MemoryNetworkFile) { - file.removeLock(lock); - return; - } - - if ( fstate == null) - throw new IOException("Open file without state (unlock)"); - - // Remove the lock from the active lock list for the file, and the file instance - - fstate.removeLock(lock); - file.removeLock(lock); - } - - /** - * Create a lock object, use the standard FileLock object. - * - * @param sess SrvSession - * @param tree TreeConnection - * @param file NetworkFile - * @param offset long - * @param len long - * @param pid int - */ - public FileLock createLockObject(SrvSession sess, TreeConnection tree, NetworkFile file, long offset, long len, int pid) { - - // Create a lock object to represent the file lock - - return new FileLock(offset, len, pid); - } - - /** - * Release all locks that a session has on a file. This method is called to perform cleanup if a file - * is closed that has active locks or if a session abnormally terminates. - * - * @param sess SrvSession - * @param tree TreeConnection - * @param file NetworkFile - */ - public void releaseLocksForFile(SrvSession sess, TreeConnection tree, NetworkFile file) { - - // Check if the file has active locks - - if ( file.hasLocks()) - { - - synchronized ( file) - { - - // Enumerate the locks and remove - - while ( file.numberOfLocks() > 0) - { - // Get the current file lock - - FileLock curLock = file.getLockAt(0); - - // Remove the lock, ignore errors - - try - { - - // Unlock will remove the lock from the global list and the local files list - - unlockFile(sess, tree, file, curLock); - } - catch (Exception ex) - { - } - } - } - } - } - - /** - * Enable oplock support by setting the file state table - * - * @param stateTable FileStateTable - */ - public final void setStateTable(FileStateTable stateTable) { - - m_stateCache = stateTable; - - // Create the oplock break queue - - m_oplockQueue = new Hashtable(); - - // Start the oplock break expiry thread - - m_expiryThread = new Thread(this); - m_expiryThread.setDaemon(true); - m_expiryThread.setName("OpLockExpire"); - m_expiryThread.start(); -} - - /** - * Check if there is an oplock for the specified path, return the oplock type. - * - * @param path String - * @return int - */ - public int hasOpLock(String path) { - - // Check if oplocks/state cache are enabled - - if ( m_stateCache == null) - return OpLock.TypeNone; - - // Get the file state - - FileState fstate = m_stateCache.findFileState(path); - if ( fstate != null && fstate.hasOpLock()) { - - // Return the oplock type - - OpLockDetails oplock = fstate.getOpLock(); - if ( oplock != null) - return oplock.getLockType(); - } - - // No oplock - - return OpLock.TypeNone; - } - - /** - * Return the oplock details for a path, or null if there is no oplock on the path - * - * @param path String - * @return OpLockDetails - */ - public OpLockDetails getOpLockDetails(String path) { - - // Check if oplocks/state cache are enabled - - if ( m_stateCache == null) - return null; - - // Get the file state - - FileState fstate = m_stateCache.findFileState(path); - if ( fstate != null) - return fstate.getOpLock(); - - // No oplock - - return null; - } - - /** - * Grant an oplock, store the oplock details - * - * @param path String - * @param oplock OpLockDetails - * @return boolean - * @exception ExistingOpLockException If the file already has an oplock - */ - public boolean grantOpLock(String path, OpLockDetails oplock) - throws ExistingOpLockException { - - // Check if oplocks/state cache are enabled - - if ( m_stateCache == null) - return false; - - // Get, or create, a file state - - FileState fstate = m_stateCache.findFileState(path, false, true); - - // Check if the file is already in use - - if ( fstate.getOpenCount() != 1) - return false; - - // Set the oplock - - fstate.setOpLock( oplock); - return true; - } - - /** - * Inform the oplock manager that an oplock break is in progress for the specified file/oplock - * - * @param path String - * @param oplock OpLockDetails - */ - public void informOpLockBreakInProgress(String path, OpLockDetails oplock) { - - // Check if oplocks/state cache are enabled - - if ( m_stateCache == null) - return; - - // Add the oplock to the break in progress queue - - synchronized ( m_oplockQueue) { - m_oplockQueue.put( path, oplock); - m_oplockQueue.notify(); - } - } - - /** - * Release an oplock - * - * @param path String - */ - public void releaseOpLock(String path) { - - // Check if oplocks/state cache are enabled - - if ( m_stateCache == null) - return; - - // Get the file state - - FileState fstate = m_stateCache.findFileState(path); - if ( fstate != null) - fstate.clearOpLock(); - - // Remove from the pending oplock break queue - - synchronized ( m_oplockQueue) { - m_oplockQueue.remove( path); - } - } - - /** - * Check for expired oplock break requests - * - * @return int - */ - public int checkExpiredOplockBreaks() { - - // Check if there are ny oplock breaks in progress - - if ( m_oplockQueue.size() == 0) - return 0; - - // Check for oplock break requests that have expired - - int expireCnt = 0; - - long timeNow = System.currentTimeMillis(); - Enumeration opBreakKeys = m_oplockQueue.keys(); - - while ( opBreakKeys.hasMoreElements()) { - - // Check the current oplock break - - String path = opBreakKeys.nextElement(); - OpLockDetails opLock = m_oplockQueue.get( path); - if ( opLock != null) { - - // Check if the oplock break has timed out - - if ( opLock.hasDeferredSession() && (opLock.getOplockBreakTime() + OpLockBreakTimeout) <= timeNow) { - - // Get the deferred request details - - SMBSrvSession sess = opLock.getDeferredSession(); - SMBSrvPacket pkt = opLock.getDeferredPacket(); - - try { - - // Return an error for the deferred file open request - - if ( sess.sendAsyncErrorResponseSMB( pkt, SMBStatus.NTAccessDenied, SMBStatus.NTErr) == true) { - - // DEBUG - - if ( Debug.EnableDbg && sess.hasDebug( SMBSrvSession.DBG_OPLOCK)) - sess.debugPrintln( "Oplock break timeout, oplock=" + opLock); - - // Release the packet back to the pool - - sess.getPacketPool().releasePacket( pkt); - } - else if ( Debug.EnableDbg && sess.hasDebug( SMBSrvSession.DBG_OPLOCK)) - sess.debugPrintln( "Failed to send open reject, oplock break timed out, oplock=" + opLock); - } - catch ( IOException ex) { - - } - - // Remove the oplock break from the queue - - m_oplockQueue.remove( path); - - // Clear the deferred packet details - - opLock.clearDeferredSession(); - - // Mark the oplock has having a failed oplock break - - opLock.setOplockBreakFailed(); - - // Update the expired oplock break count - - expireCnt++; - } - } - } - - // Return the count of expired oplock breaks - - return expireCnt; - } - - /** - * Run the oplock break expiry - */ - public void run() - { - // Loop forever - - m_shutdown = false; - - while ( m_shutdown == false) - { - // Wait for an oplock break or sleep for a while if there are active oplock break requests - - try - { - synchronized ( m_oplockQueue) { - if ( m_oplockQueue.size() == 0) - m_oplockQueue.wait(); - } - - // Oplock break added to the queue, wait a while before checking the queue - - if ( m_oplockQueue.size() > 0) - Thread.sleep( OpLockBreakTimeout); - } - catch (InterruptedException ex) - { - } - - // Check for shutdown - - if ( m_shutdown == true) - return; - - // Check for expired oplock break requests - - checkExpiredOplockBreaks(); - } - } - - /** - * Request the oplock break expiry thread to shutdown - */ - public final void shutdownRequest() { - m_shutdown = true; - - if ( m_expiryThread != null) - { - try { - m_expiryThread.interrupt(); - } - catch (Exception ex) { - } - } - } -} diff --git a/source/java/org/alfresco/filesys/state/FileStateReaper.java b/source/java/org/alfresco/filesys/state/FileStateReaper.java deleted file mode 100644 index ab93503ada..0000000000 --- a/source/java/org/alfresco/filesys/state/FileStateReaper.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . */ - -package org.alfresco.filesys.state; - -import java.util.Enumeration; -import java.util.Hashtable; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * File State Reaper Class - * - *

FileStateTable objects register with the file state reaper to periodically check for expired file states. - * - * @author gkspencer - */ -public class FileStateReaper implements Runnable { - - // Logging - - private static final Log logger = LogFactory.getLog(FileStateReaper.class); - - // Default expire check thread interval - - private static final long DEFAULT_EXPIRECHECK = 15000; - - // Wakeup interval for the expire file state checker thread - - private long m_expireInterval = DEFAULT_EXPIRECHECK; - - // File state checker thread - - private Thread m_thread; - - // Shutdown request flag - - private boolean m_shutdown; - - // List of file state tables to be scanned for expired file states - - private Hashtable m_stateTables; - - /** - * Default constructor - */ - public FileStateReaper() - { - // Create the reaper thread - - m_thread = new Thread(this); - m_thread.setDaemon(true); - m_thread.setName("FileStateReaper"); - m_thread.start(); - - // Create the file state table list - - m_stateTables = new Hashtable(); - } - - /** - * Return the expired file state checker interval, in milliseconds - * - * @return long - */ - public final long getCheckInterval() - { - return m_expireInterval; - } - - /** - * Set the expired file state checker interval, in milliseconds - * - * @param chkIntval long - */ - public final void setCheckInterval(long chkIntval) - { - m_expireInterval = chkIntval; - } - - /** - * Add a file state table to the reaper list - * - * @param filesysName String - * @param stateTable FileStateTable - */ - public final void addStateTable( String filesysName, FileStateTable stateTable) - { - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug( "Added file state table for " + filesysName); - - m_stateTables.put( filesysName, stateTable); - } - - /** - * Remove a state table from the reaper list - * - * @param filesysName String - */ - public final void removeStateTable( String filesysName) - { - m_stateTables.remove( filesysName); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug( "Removed file state table for " + filesysName); - - } - - /** - * Expired file state checker thread - */ - public void run() - { - // Loop forever - - m_shutdown = false; - - while ( m_shutdown == false) - { - - // Sleep for the required interval - - try - { - Thread.sleep(getCheckInterval()); - } - catch (InterruptedException ex) - { - } - - // Check for shutdown - - if ( m_shutdown == true) - { - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("FileStateReaper thread closing"); - - return; - } - - // Check if there are any state tables registered - - if ( m_stateTables != null && m_stateTables.size() > 0) - { - try - { - // Loop through the registered file state tables and remove expired file states - - Enumeration filesysNames = m_stateTables.keys(); - - while ( filesysNames.hasMoreElements()) - { - // Get the current filesystem name and associated state table - - String filesysName = filesysNames.nextElement(); - FileStateTable stateTable = m_stateTables.get( filesysName); - - // Check for expired file states - - int cnt = stateTable.removeExpiredFileStates(); - - // Debug - - if (logger.isDebugEnabled() && cnt > 0) - logger.debug("Expired " + cnt + " file states for " + filesysName + ", cache=" + stateTable.numberOfStates()); - } - } - catch (Exception ex) - { - // Log errors if not shutting down - - if ( m_shutdown == false) - logger.debug(ex); - } - } - } - } - - /** - * Request the file state checker thread to shutdown - */ - public final void shutdownRequest() { - m_shutdown = true; - - if ( m_thread != null) - { - try { - m_thread.interrupt(); - } - catch (Exception ex) { - } - } - } -} diff --git a/source/java/org/alfresco/filesys/state/FileStateTable.java b/source/java/org/alfresco/filesys/state/FileStateTable.java deleted file mode 100644 index 7204c10ef3..0000000000 --- a/source/java/org/alfresco/filesys/state/FileStateTable.java +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.filesys.state; - -import java.util.*; - -import org.apache.commons.logging.*; - -/** - * File State Table Class - * - *

Contains an indexed list of the currently open files/folders. - * - * @author gkspencer - */ -public class FileStateTable -{ - private static final Log logger = LogFactory.getLog(FileStateTable.class); - - // Initial allocation size for the state cache - - private static final int INITIAL_SIZE = 100; - - // File state table, keyed by file path - - private Hashtable m_stateTable; - - // File state expiry time in seconds - - private long m_cacheTimer = 2 * 60000L; // 2 minutes default - - // File state listener, can veto expiring of file states - - private FileStateListener m_stateListener; - - /** - * Class constructor - */ - public FileStateTable() - { - m_stateTable = new Hashtable(INITIAL_SIZE); - - // Start the expired file state checker thread - - } - - /** - * Get the file state cache timer, in milliseconds - * - * @return long - */ - public final long getCacheTimer() - { - return m_cacheTimer; - } - - /** - * Return the number of states in the cache - * - * @return int - */ - public final int numberOfStates() - { - return m_stateTable.size(); - } - - /** - * Set the default file state cache timer, in milliseconds - * - * @param tmo long - */ - public final void setCacheTimer(long tmo) - { - m_cacheTimer = tmo; - } - - /** - * Add a new file state - * - * @param fstate FileState - */ - public final synchronized void addFileState(FileState fstate) - { - - // Check if the file state already exists in the cache - - if (logger.isDebugEnabled() && m_stateTable.get(fstate.getPath()) != null) - logger.debug("***** addFileState() state=" + fstate.toString() + " - ALREADY IN CACHE *****"); - - // DEBUG - - if (logger.isDebugEnabled() && fstate == null) - { - logger.debug("addFileState() NULL FileState"); - return; - } - - // Set the file state timeout and add to the cache - - fstate.setExpiryTime(System.currentTimeMillis() + getCacheTimer()); - m_stateTable.put(fstate.getPath(), fstate); - } - - /** - * Find the file state for the specified path - * - * @param path String - * @return FileState - */ - public final synchronized FileState findFileState(String path) - { - FileState fstate = m_stateTable.get(FileState.normalizePath(path)); - - if ( fstate != null) - fstate.updateAccessDateTime(); - - return fstate; - } - - /** - * Find the file state for the specified path, and optionally create a new file state if not - * found - * - * @param path String - * @param isdir boolean - * @param create boolean - * @return FileState - */ - public final synchronized FileState findFileState(String path, boolean isdir, boolean create) - { - - // Find the required file state, if it exists - - FileState state = m_stateTable.get(FileState.normalizePath(path)); - - // Check if we should create a new file state - - if (state == null && create == true) - { - - // Create a new file state - - state = new FileState(path, isdir); - - // Set the file state timeout and add to the cache - - state.setExpiryTime(System.currentTimeMillis() + getCacheTimer()); - m_stateTable.put(state.getPath(), state); - - // DEBUG - - if ( logger.isDebugEnabled() && state.getPath().length() > 0 && state.getPath().indexOf("\\") == -1) { - logger.debug("*** File state path is not relative - " + state.getPath() + " ***"); - Thread.dumpStack(); - } - } - - // Update the access date/time if valid - - if ( state != null) - state.updateAccessDateTime(); - - // Return the file state - - return state; - } - - /** - * Update the name that a file state is cached under, and the associated file state - * - * @param oldName String - * @param newName String - * @return FileState - */ - public final synchronized FileState updateFileState(String oldName, String newName) - { - // Find the current file state - - FileState state = m_stateTable.remove(FileState.normalizePath(oldName)); - - // Rename the file state and add it back into the cache using the new name - - if (state != null) - { - state.setPath(newName); - addFileState(state); - - // Update the access date/time - - state.updateAccessDateTime(); - } - - // Return the updated file state - - return state; - } - - /** - * Enumerate the file state cache - * - * @return Enumeration - */ - public final Enumeration enumerate() - { - return m_stateTable.keys(); - } - - /** - * Remove the file state for the specified path - * - * @param path String - * @return FileState - */ - public final synchronized FileState removeFileState(String path) - { - - // Remove the file state from the cache - - FileState state = m_stateTable.remove(FileState.normalizePath(path)); - - // Return the removed file state - - return state; - } - - /** - * Rename a file state, remove the existing entry, update the path and add the state back into - * the cache using the new path. - * - * @param newPath String - * @param state FileState - */ - public final synchronized void renameFileState(String newPath, FileState state) - { - - // Remove the existing file state from the cache, using the original name - - m_stateTable.remove(state.getPath()); - - // Update the file state path and add it back to the cache using the new name - - state.setPath(FileState.normalizePath(newPath)); - m_stateTable.put(state.getPath(), state); - - // Updaet the access date/time - - state.updateAccessDateTime(); - } - - /** - * Remove all file states from the cache - */ - public final synchronized void removeAllFileStates() - { - - // Check if there are any items in the cache - - if (m_stateTable == null || m_stateTable.size() == 0) - return; - - // Enumerate the file state cache and remove expired file state objects - - Enumeration enm = m_stateTable.keys(); - - while (enm.hasMoreElements()) - { - - // Get the file state - - FileState state = m_stateTable.get(enm.nextElement()); - - // Check if there is a state listener - - if ( m_stateListener != null) - m_stateListener.fileStateClosed(state); - - // DEBUG - - if (logger.isDebugEnabled()) - logger.debug("++ Closed: " + state.getPath()); - } - - // Remove all the file states - - m_stateTable.clear(); - } - - /** - * Remove expired file states from the cache - * - * @return int - */ - public final int removeExpiredFileStates() - { - - // Check if there are any items in the cache - - if (m_stateTable == null || m_stateTable.size() == 0) - return 0; - - // Enumerate the file state cache and remove expired file state objects - - Enumeration enm = m_stateTable.keys(); - long curTime = System.currentTimeMillis(); - - int expiredCnt = 0; - - while (enm.hasMoreElements()) - { - - // Get the file state - - FileState state = m_stateTable.get(enm.nextElement()); - - if (state != null && state.hasNoTimeout() == false) - { - - synchronized (state) - { - - // Check if the file state has expired and there are no open references to the - // file - - if (state.hasExpired(curTime) && state.getOpenCount() == 0) - { - // Check with the state listener before removing the file state, if enabled - - if ( hasStateListener() == false || m_stateListener.fileStateExpired( state) == true) - { - // Remove the expired file state - - m_stateTable.remove(state.getPath()); - - // DEBUG - - if (logger.isDebugEnabled()) - logger.debug("Expired file state: " + state); - - // Update the expired count - - expiredCnt++; - } - } - } - } - } - - // Return the count of expired file states that were removed - - return expiredCnt; - } - - /** - * Dump the state cache entries to the specified stream - */ - public final void Dump() - { - - // Dump the file state cache entries to the specified stream - - if (m_stateTable.size() > 0) - logger.debug("FileStateCache Entries:"); - - Enumeration enm = m_stateTable.keys(); - long curTime = System.currentTimeMillis(); - - while (enm.hasMoreElements()) - { - String fname = enm.nextElement(); - FileState state = m_stateTable.get(fname); - - logger.debug(" " + fname + "(" + state.getSecondsToExpire(curTime) + ") : " + state); - } - } - - /** - * Add a file state listener - * - * @param l FileStateListener - */ - public final void addStateListener(FileStateListener l) { - m_stateListener = l; - } - - /** - * Remove a file state listener - * - * @param l FileStateListener - */ - public final void removeStateListener(FileStateListener l) { - if ( m_stateListener == l) - m_stateListener = null; - } - - /** - * Check if the file state listener is set - * - * @return boolean - */ - public final boolean hasStateListener() { - return m_stateListener != null ? true : false; - } -} \ No newline at end of file