diff --git a/source/java/org/alfresco/filesys/avm/AVMContext.java b/source/java/org/alfresco/filesys/avm/AVMContext.java
index 33b199e11a..801b6aa46f 100644
--- a/source/java/org/alfresco/filesys/avm/AVMContext.java
+++ b/source/java/org/alfresco/filesys/avm/AVMContext.java
@@ -20,6 +20,8 @@ package org.alfresco.filesys.avm;
import org.alfresco.filesys.server.filesys.DiskDeviceContext;
import org.alfresco.filesys.server.filesys.FileSystem;
import org.alfresco.filesys.server.filesys.SrvDiskInfo;
+import org.alfresco.filesys.server.state.FileStateReaper;
+import org.alfresco.filesys.server.state.FileStateTable;
/**
* AVM Filesystem Context Class
@@ -41,15 +43,21 @@ public class AVMContext extends DiskDeviceContext {
private String m_storePath;
private int m_version = VERSION_HEAD;
+ // File state table and associated file state reaper
+
+ private FileStateTable m_stateTable;
+ private FileStateReaper m_stateReaper;
+
/**
* Class constructor
*
+ * @param filesysName String
* @param storePath String
* @param version int
*/
- public AVMContext( String storePath, int version)
+ public AVMContext( String filesysName, String storePath, int version)
{
- super( storePath + "(" + version + ")");
+ super( filesysName, storePath + "(" + version + ")");
// Set the store root path, remove any trailing slash as relative paths will be appended to this value
@@ -106,8 +114,64 @@ public class AVMContext extends DiskDeviceContext {
*/
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();
}
+
+ /**
+ * 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( getFilesystemName());
+ 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( getFilesystemName(), m_stateTable);
+ }
+
+ // Save the reaper, for deregistering when the filesystem is closed
+
+ m_stateReaper = stateReaper;
+ }
}
diff --git a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java
index 26b6db8f00..77ab5e1187 100644
--- a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java
+++ b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java
@@ -28,6 +28,7 @@ import org.alfresco.config.ConfigElement;
import org.alfresco.filesys.server.SrvSession;
import org.alfresco.filesys.server.core.DeviceContext;
import org.alfresco.filesys.server.core.DeviceContextException;
+import org.alfresco.filesys.server.core.DeviceInterface;
import org.alfresco.filesys.server.filesys.AccessDeniedException;
import org.alfresco.filesys.server.filesys.DirectoryNotEmptyException;
import org.alfresco.filesys.server.filesys.DiskInterface;
@@ -40,6 +41,7 @@ import org.alfresco.filesys.server.filesys.FileStatus;
import org.alfresco.filesys.server.filesys.NetworkFile;
import org.alfresco.filesys.server.filesys.SearchContext;
import org.alfresco.filesys.server.filesys.TreeConnection;
+import org.alfresco.filesys.server.state.FileStateReaper;
import org.alfresco.filesys.util.StringList;
import org.alfresco.filesys.util.WildCard;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
@@ -93,6 +95,10 @@ public class AVMDiskDriver implements DiskInterface {
private ServiceRegistry m_serviceRegistry;
+ // File state reaper
+
+ private FileStateReaper m_stateReaper;
+
/**
* Default constructor
*/
@@ -140,6 +146,16 @@ public class AVMDiskDriver implements DiskInterface {
return m_serviceRegistry;
}
+ /**
+ * Return the file state reaper
+ *
+ * @return FileStateReaper
+ */
+ public final FileStateReaper getStateReaper()
+ {
+ return m_stateReaper;
+ }
+
/**
* Set the AVM service
*
@@ -200,15 +216,27 @@ public class AVMDiskDriver implements DiskInterface {
m_mimetypeService = mimetypeService;
}
+ /**
+ * Set the file state reaper
+ *
+ * @param stateReaper FileStateReaper
+ */
+ public final void setStateReaper(FileStateReaper stateReaper)
+ {
+ m_stateReaper = stateReaper;
+ }
+
/**
* Parse and validate the parameter string and create a device context object for this instance
* of the shared device.
*
+ * @param devIface DeviceInterface
+ * @param name String
* @param cfg ConfigElement
* @return DeviceContext
* @exception DeviceContextException
*/
- public DeviceContext createContext(ConfigElement cfg)
+ public DeviceContext createContext(DeviceInterface devIface, String name, ConfigElement cfg)
throws DeviceContextException
{
// Use the system user as the authenticated context for the filesystem initialization
@@ -315,7 +343,7 @@ public class AVMDiskDriver implements DiskInterface {
// Create the context
- context = new AVMContext(storePath, version);
+ context = new AVMContext( name, storePath, version);
}
catch (Exception ex)
{
@@ -342,6 +370,10 @@ public class AVMDiskDriver implements DiskInterface {
}
}
+ // Enable file state caching
+
+ context.enableStateTable( true, getStateReaper());
+
// Return the context for this shared filesystem
return context;
diff --git a/source/java/org/alfresco/filesys/avm/AVMPath.java b/source/java/org/alfresco/filesys/avm/AVMPath.java
new file mode 100644
index 0000000000..f79e003449
--- /dev/null
+++ b/source/java/org/alfresco/filesys/avm/AVMPath.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2006 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the
+ * License.
+ */
+
+package org.alfresco.filesys.avm;
+
+import org.alfresco.filesys.server.filesys.FileName;
+
+/**
+ * AVM Path Class
+ *
+ *
Parses a share relative path into store, version and remaining path values.
+ *
+ * @author gkspencer
+ */
+public class AVMPath {
+
+ // Constants
+ //
+ // Invalid version id value
+
+ private static final int InvalidVersionId = -2;
+
+ // Version id string for the head version
+
+ private static final String VersionNameHead = "Head";
+
+ // AVM path seperator
+
+ public static final char AVM_SEPERATOR = '/';
+
+ // Store name
+
+ private String m_storeName;
+
+ // Version id
+
+ private int m_version = InvalidVersionId;
+
+ // Remaining path
+
+ private String m_path;
+
+ // AVM style path
+
+ private String m_avmPath;
+
+ /**
+ * Class constructor
+ *
+ * @param shrPath String
+ */
+ public AVMPath(String shrPath)
+ {
+ // Parse the path
+
+ parsePath( shrPath);
+ }
+
+ /**
+ * Return the store name
+ *
+ * @return String
+ */
+ public final String getStoreName()
+ {
+ return m_storeName;
+ }
+
+ /**
+ * Check if the version id was specified in the path
+ *
+ * @return boolean
+ */
+ public final boolean hasVersion()
+ {
+ return m_version != InvalidVersionId ? true : false;
+ }
+
+ /**
+ * Return the version id
+ *
+ * @return int
+ */
+ public final int getVersion()
+ {
+ return m_version;
+ }
+
+ /**
+ * Return the share relative path
+ *
+ * @return String
+ */
+ public final String getRelativePath()
+ {
+ return m_path;
+ }
+
+ /**
+ * Return the AVM style path, in :/ format
+ *
+ * @return String
+ */
+ public final String getAVMPath()
+ {
+ return m_avmPath;
+ }
+
+ /**
+ * Check if the path is valid
+ *
+ * @return boolean
+ */
+ public final boolean isValid()
+ {
+ return m_storeName == null ? false : true;
+ }
+
+ /**
+ * Parse the path
+ *
+ * @param path String
+ */
+ private final void parsePath( String path)
+ {
+ // Split the path
+
+ String[] paths = FileName.splitAllPaths(path);
+
+ if ( paths == null || paths.length == 0)
+ return;
+
+ // Set the store name
+
+ m_storeName = paths[0];
+
+ if ( paths.length > 1)
+ {
+ // Validate the version id
+
+ String verStr = paths[1];
+ if ( verStr.equalsIgnoreCase( VersionNameHead))
+ m_version = -1;
+ else
+ {
+ try
+ {
+ // Parse the version id
+
+ m_version = Integer.parseInt( verStr);
+
+ // Validate the version id
+
+ if ( m_version < 0)
+ {
+ // Invalid version id
+
+ m_storeName = null;
+ return;
+ }
+ }
+ catch ( NumberFormatException ex)
+ {
+ m_storeName = null;
+ return;
+ }
+ }
+
+ // If there additional path elements build the share and AVM relative paths
+
+ if ( paths.length > 2)
+ {
+ // Build the share relative path
+
+ StringBuilder pathStr = new StringBuilder();
+
+ for ( int i = 2; i < paths.length; i++)
+ {
+ pathStr.append( FileName.DOS_SEPERATOR);
+ pathStr.append( paths[i]);
+ }
+
+ m_path = pathStr.toString();
+
+ // Build the AVM path, in :/ format
+
+ pathStr.setLength( 0);
+
+ pathStr.append( m_storeName);
+ pathStr.append( ":");
+ pathStr.append( m_path.replace( FileName.DOS_SEPERATOR, AVM_SEPERATOR));
+
+ m_avmPath = pathStr.toString();
+ }
+ }
+ }
+
+ /**
+ * Return the AVM path details as a string
+ *
+ * @return String
+ */
+ public String toString()
+ {
+ StringBuilder str = new StringBuilder();
+
+ str.append("[");
+ str.append(getStoreName());
+ str.append(",");
+
+ if ( hasVersion())
+ str.append(getVersion());
+ else
+ str.append("NoVersion");
+
+ str.append(",");
+ str.append(getRelativePath());
+ str.append(":");
+ str.append(getAVMPath());
+ str.append("]");
+
+ return str.toString();
+ }
+}
diff --git a/source/java/org/alfresco/filesys/avm/AVMShareMapper.java b/source/java/org/alfresco/filesys/avm/AVMShareMapper.java
index 0f1592b7d0..dca26255f6 100644
--- a/source/java/org/alfresco/filesys/avm/AVMShareMapper.java
+++ b/source/java/org/alfresco/filesys/avm/AVMShareMapper.java
@@ -249,12 +249,9 @@ public class AVMShareMapper implements ShareMapper {
// Create a dynamic share mapped to the AVM store/version
- DiskDeviceContext avmCtx = new AVMContext( storePath, storeVersion);
+ AVMContext avmCtx = new AVMContext( name, storePath, storeVersion);
+ avmCtx.enableStateTable( true, avmDrv.getStateReaper());
- // Default the filesystem to look like an 80Gb sized disk with 90% free space
-
- avmCtx.setDiskInformation(new SrvDiskInfo(2560, 64, 512, 2304));
-
// Create a dynamic shared device for the store version
DiskSharedDevice diskShare = new DiskSharedDevice( name, avmDrv, avmCtx, SharedDevice.Temporary);
diff --git a/source/java/org/alfresco/filesys/ftp/FTPSrvSession.java b/source/java/org/alfresco/filesys/ftp/FTPSrvSession.java
index afd55c32a8..db56f00801 100644
--- a/source/java/org/alfresco/filesys/ftp/FTPSrvSession.java
+++ b/source/java/org/alfresco/filesys/ftp/FTPSrvSession.java
@@ -3352,7 +3352,7 @@ public class FTPSrvSession extends SrvSession implements Runnable
// Create the disk driver and context
DiskInterface diskDrv = getServer().getConfiguration().getDiskInterface();
- DiskDeviceContext diskCtx = new ContentContext("", "", client.getHomeFolder());
+ DiskDeviceContext diskCtx = new ContentContext( client.getUserName(), "", "", client.getHomeFolder());
// Default the filesystem to look like an 80Gb sized disk with 90% free space
diff --git a/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java
index 3effae1145..dd932b0694 100644
--- a/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java
+++ b/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java
@@ -836,7 +836,7 @@ public abstract class CifsAuthenticator
// Create the disk driver and context
DiskInterface diskDrv = m_config.getDiskInterface();
- DiskDeviceContext diskCtx = new ContentContext("", "", client.getHomeFolder());
+ DiskDeviceContext diskCtx = new ContentContext(client.getUserName(), "", "", client.getHomeFolder());
// Default the filesystem to look like an 80Gb sized disk with 90% free space
diff --git a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java
index 73e78464c0..0bb0ce20a7 100644
--- a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java
+++ b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java
@@ -69,13 +69,13 @@ import org.alfresco.filesys.server.core.SharedDeviceList;
import org.alfresco.filesys.server.filesys.DefaultShareMapper;
import org.alfresco.filesys.server.filesys.DiskInterface;
import org.alfresco.filesys.server.filesys.DiskSharedDevice;
-import org.alfresco.filesys.server.filesys.HomeShareMapper;
import org.alfresco.filesys.smb.ServerType;
import org.alfresco.filesys.smb.TcpipSMB;
import org.alfresco.filesys.smb.server.repo.ContentContext;
import org.alfresco.filesys.smb.server.repo.DesktopAction;
import org.alfresco.filesys.smb.server.repo.DesktopActionException;
import org.alfresco.filesys.smb.server.repo.DesktopActionTable;
+import org.alfresco.filesys.smb.server.repo.HomeShareMapper;
import org.alfresco.filesys.util.IPAddress;
import org.alfresco.filesys.util.StringList;
import org.alfresco.filesys.util.X64;
@@ -1692,11 +1692,16 @@ public class ServerConfiguration extends AbstractLifecycleBean
// the new filesystem
DiskInterface filesysDriver = this.avmDiskInterface;
- AVMContext filesysContext = (AVMContext) filesysDriver.createContext(elem);
+ AVMContext filesysContext = (AVMContext) filesysDriver.createContext( filesysDriver, filesysName, elem);
+ filesysContext.setFilesystemName(filesysName);
// Create the shared filesystem
filesys = new DiskSharedDevice(filesysName, filesysDriver, filesysContext);
+
+ // Start the filesystem
+
+ filesysContext.startFilesystem(filesys);
}
else
{
@@ -1704,7 +1709,7 @@ public class ServerConfiguration extends AbstractLifecycleBean
// the new filesystem
DiskInterface filesysDriver = this.diskInterface;
- ContentContext filesysContext = (ContentContext) filesysDriver.createContext(elem);
+ ContentContext filesysContext = (ContentContext) filesysDriver.createContext( filesysDriver, filesysName, elem);
// Check if an access control list has been specified
@@ -1804,7 +1809,7 @@ public class ServerConfiguration extends AbstractLifecycleBean
{
// Create the new share for the store
- AVMContext avmContext = new AVMContext( storeName + ":/", AVMContext.VERSION_HEAD);
+ AVMContext avmContext = new AVMContext( storeName, storeName + ":/", AVMContext.VERSION_HEAD);
// Create the shared filesystem
diff --git a/source/java/org/alfresco/filesys/server/core/DeviceContext.java b/source/java/org/alfresco/filesys/server/core/DeviceContext.java
index 422eeb826d..5d379b9743 100644
--- a/source/java/org/alfresco/filesys/server/core/DeviceContext.java
+++ b/source/java/org/alfresco/filesys/server/core/DeviceContext.java
@@ -29,14 +29,17 @@ public class DeviceContext
private String m_devName;
+ // Filesystem name
+
+ private String m_filesysName;
+
// Flag to indicate if the device is available. Unavailable devices will not be listed by the
- // various
- // protocol servers.
+ // various protocol servers.
private boolean m_available = true;
/**
- * DeviceContext constructor.
+ * Default constructor
*/
public DeviceContext()
{
@@ -44,23 +47,37 @@ public class DeviceContext
}
/**
- * DeviceContext constructor.
+ * Class constructor
+ *
+ * @param filesysName String
+ * @param devName String
*/
- public DeviceContext(String devName)
+ public DeviceContext(String filesysName, String devName)
{
- m_devName = devName;
+ m_filesysName = filesysName;
+ m_devName = devName;
}
/**
* Return the device name.
*
- * @return java.lang.String
+ * @return String
*/
public final String getDeviceName()
{
return m_devName;
}
+ /**
+ * Return the filesystem name
+ *
+ * @return String
+ */
+ public final String getFilesystemName()
+ {
+ return m_filesysName;
+ }
+
/**
* Determine if the filesystem is available
*
@@ -84,13 +101,23 @@ public class DeviceContext
/**
* Set the device name.
*
- * @param name java.lang.String
+ * @param name String
*/
public final void setDeviceName(String name)
{
m_devName = name;
}
+ /**
+ * Set the filesystem name
+ *
+ * @param filesysName String
+ */
+ public final void setFilesystemName( String filesysName)
+ {
+ m_filesysName = filesysName;
+ }
+
/**
* Close the device context, free any resources allocated by the context
*/
@@ -108,6 +135,8 @@ public class DeviceContext
StringBuffer str = new StringBuffer();
str.append("[");
+ str.append(getFilesystemName());
+ str.append(",");
str.append(getDeviceName());
str.append("]");
diff --git a/source/java/org/alfresco/filesys/server/core/DeviceInterface.java b/source/java/org/alfresco/filesys/server/core/DeviceInterface.java
index 54af951dc2..47462000b1 100644
--- a/source/java/org/alfresco/filesys/server/core/DeviceInterface.java
+++ b/source/java/org/alfresco/filesys/server/core/DeviceInterface.java
@@ -32,11 +32,14 @@ public interface DeviceInterface
* of the shared device. The same DeviceInterface implementation may be used for multiple
* shares.
*
+ * @param devIface DeviceInterface
+ * @param name String
* @param args ConfigElement
* @return DeviceContext
* @exception DeviceContextException
*/
- public DeviceContext createContext(ConfigElement args) throws DeviceContextException;
+ public DeviceContext createContext(DeviceInterface devIface, String name, ConfigElement args)
+ throws DeviceContextException;
/**
* Connection opened to this disk device
diff --git a/source/java/org/alfresco/filesys/server/core/SharedDevice.java b/source/java/org/alfresco/filesys/server/core/SharedDevice.java
index 61df75a120..203fb51bfc 100644
--- a/source/java/org/alfresco/filesys/server/core/SharedDevice.java
+++ b/source/java/org/alfresco/filesys/server/core/SharedDevice.java
@@ -383,7 +383,7 @@ public class SharedDevice implements Comparable
*/
public DeviceContext createContext(String[] args)
{
- return new DeviceContext(args[0]);
+ return new DeviceContext("", args[0]);
}
/**
diff --git a/source/java/org/alfresco/filesys/server/filesys/DiskDeviceContext.java b/source/java/org/alfresco/filesys/server/filesys/DiskDeviceContext.java
index a4a108db7b..369f4fc4fe 100644
--- a/source/java/org/alfresco/filesys/server/filesys/DiskDeviceContext.java
+++ b/source/java/org/alfresco/filesys/server/filesys/DiskDeviceContext.java
@@ -59,11 +59,12 @@ public class DiskDeviceContext extends DeviceContext
/**
* Class constructor
*
+ * @param filesysName String
* @param devName String
*/
- public DiskDeviceContext(String devName)
+ public DiskDeviceContext(String filesysName, String devName)
{
- super(devName);
+ super(filesysName, devName);
}
/**
diff --git a/source/java/org/alfresco/filesys/smb/server/repo/FileState.java b/source/java/org/alfresco/filesys/server/state/FileState.java
similarity index 95%
rename from source/java/org/alfresco/filesys/smb/server/repo/FileState.java
rename to source/java/org/alfresco/filesys/server/state/FileState.java
index dc87680438..1ebc55434b 100644
--- a/source/java/org/alfresco/filesys/smb/server/repo/FileState.java
+++ b/source/java/org/alfresco/filesys/server/state/FileState.java
@@ -14,7 +14,7 @@
* language governing permissions and limitations under the
* License.
*/
-package org.alfresco.filesys.smb.server.repo;
+package org.alfresco.filesys.server.state;
import org.alfresco.filesys.locking.FileLock;
import org.alfresco.filesys.locking.FileLockList;
diff --git a/source/java/org/alfresco/filesys/server/state/FileStateReaper.java b/source/java/org/alfresco/filesys/server/state/FileStateReaper.java
new file mode 100644
index 0000000000..ce11004379
--- /dev/null
+++ b/source/java/org/alfresco/filesys/server/state/FileStateReaper.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2006 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the
+ * License.
+ */
+
+package org.alfresco.filesys.server.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/smb/server/repo/FileStateTable.java b/source/java/org/alfresco/filesys/server/state/FileStateTable.java
similarity index 72%
rename from source/java/org/alfresco/filesys/smb/server/repo/FileStateTable.java
rename to source/java/org/alfresco/filesys/server/state/FileStateTable.java
index 2eb2797979..e52593591c 100644
--- a/source/java/org/alfresco/filesys/smb/server/repo/FileStateTable.java
+++ b/source/java/org/alfresco/filesys/server/state/FileStateTable.java
@@ -14,19 +14,20 @@
* language governing permissions and limitations under the
* License.
*/
-package org.alfresco.filesys.smb.server.repo;
+package org.alfresco.filesys.server.state;
import java.util.*;
-import java.io.*;
import org.apache.commons.logging.*;
/**
* File State Table Class
- *
- * Contains an indexed list of the currently open files/folders.
+ *
+ *
Contains an indexed list of the currently open files/folders.
+ *
+ * @author gkspencer
*/
-public class FileStateTable implements Runnable
+public class FileStateTable
{
private static final Log logger = LogFactory.getLog(FileStateTable.class);
@@ -34,30 +35,14 @@ public class FileStateTable implements Runnable
private static final int INITIAL_SIZE = 100;
- // Default expire check thread interval
-
- private static final long DEFAULT_EXPIRECHECK = 15000;
-
// File state table, keyed by file path
private Hashtable m_stateTable;
- // Wakeup interval for the expire file state checker thread
-
- private long m_expireInterval = DEFAULT_EXPIRECHECK;
-
// File state expiry time in seconds
private long m_cacheTimer = 2 * 60000L; // 2 minutes default
- // File state checker thread
-
- private Thread m_thread;
-
- // Shutdown request flag
-
- private boolean m_shutdown;
-
/**
* Class constructor
*/
@@ -67,20 +52,6 @@ public class FileStateTable implements Runnable
// Start the expired file state checker thread
- m_thread = new Thread(this);
- m_thread.setDaemon(true);
- m_thread.setName("FileStateExpire");
- m_thread.start();
- }
-
- /**
- * Return the expired file state checker interval, in milliseconds
- *
- * @return long
- */
- public final long getCheckInterval()
- {
- return m_expireInterval;
}
/**
@@ -113,16 +84,6 @@ public class FileStateTable implements Runnable
m_cacheTimer = tmo;
}
- /**
- * Set the expired file state checker interval, in milliseconds
- *
- * @param chkIntval long
- */
- public final void setCheckInterval(long chkIntval)
- {
- m_expireInterval = chkIntval;
- }
-
/**
* Add a new file state
*
@@ -351,7 +312,7 @@ public class FileStateTable implements Runnable
// DEBUG
if (logger.isDebugEnabled())
- logger.debug("++ Expired file state: " + state);
+ logger.debug("Expired file state: " + state);
// Update the expired count
@@ -366,79 +327,6 @@ public class FileStateTable implements Runnable
return expiredCnt;
}
- /**
- * 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("FileStateExpire thread closing");
-
- return;
- }
-
- try
- {
-
- // Check for expired file states
-
- int cnt = removeExpiredFileStates();
-
- // Debug
-
- if (logger.isDebugEnabled() && cnt > 0)
- {
- logger.debug("++ Expired " + cnt + " file states, cache=" + m_stateTable.size());
- Dump();
- }
- }
- catch (Exception ex)
- {
- 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) {
- }
- }
- }
-
/**
* Dump the state cache entries to the specified stream
*/
@@ -448,7 +336,7 @@ public class FileStateTable implements Runnable
// Dump the file state cache entries to the specified stream
if (m_stateTable.size() > 0)
- logger.debug("++ FileStateCache Entries:");
+ logger.debug("FileStateCache Entries:");
Enumeration enm = m_stateTable.keys();
long curTime = System.currentTimeMillis();
@@ -458,7 +346,7 @@ public class FileStateTable implements Runnable
String fname = (String) enm.nextElement();
FileState state = m_stateTable.get(fname);
- logger.debug(" ++ " + fname + "(" + state.getSecondsToExpire(curTime) + ") : " + state);
+ logger.debug(" " + fname + "(" + state.getSecondsToExpire(curTime) + ") : " + state);
}
}
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/filesys/smb/server/repo/ContentContext.java b/source/java/org/alfresco/filesys/smb/server/repo/ContentContext.java
index 211bcd684b..ac6b372855 100644
--- a/source/java/org/alfresco/filesys/smb/server/repo/ContentContext.java
+++ b/source/java/org/alfresco/filesys/smb/server/repo/ContentContext.java
@@ -19,6 +19,8 @@ package org.alfresco.filesys.smb.server.repo;
import java.util.Enumeration;
import org.alfresco.filesys.server.filesys.*;
+import org.alfresco.filesys.server.state.FileStateReaper;
+import org.alfresco.filesys.server.state.FileStateTable;
import org.alfresco.filesys.smb.server.repo.pseudo.ContentPseudoFileImpl;
import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFileInterface;
import org.alfresco.service.cmr.repository.*;
@@ -41,9 +43,10 @@ public class ContentContext extends DiskDeviceContext
private NodeRef m_rootNodeRef;
- // File state table
+ // 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
@@ -65,13 +68,14 @@ public class ContentContext extends DiskDeviceContext
/**
* Class constructor
*
+ *@param filesysName String
* @param storeName String
* @param rootPath String
* @param rootNodeRef NodeRef
*/
- public ContentContext(String storeName, String rootPath, NodeRef rootNodeRef)
+ public ContentContext(String filesysName, String storeName, String rootPath, NodeRef rootNodeRef)
{
- super(rootNodeRef.toString());
+ super(filesysName, rootNodeRef.toString());
m_storeName = storeName;
m_rootPath = rootPath;
@@ -147,13 +151,31 @@ public class ContentContext extends DiskDeviceContext
* Enable/disable the file state table
*
* @param ena boolean
+ * @param stateReaper FileStateReaper
*/
- public final void enableStateTable(boolean ena)
+ public final void enableStateTable(boolean ena, FileStateReaper stateReaper)
{
if ( ena == false)
+ {
+ // Remove the state table from the reaper
+
+ stateReaper.removeStateTable( getFilesystemName());
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( getFilesystemName(), m_stateTable);
+ }
+
+ // Save the reaper, for deregistering when the filesystem is closed
+
+ m_stateReaper = stateReaper;
}
/**
@@ -354,14 +376,10 @@ public class ContentContext extends DiskDeviceContext
*/
public void CloseContext() {
- // Check if file states are enabled
+ // Deregister the file state table from the reaper
- if ( hasStateTable())
- {
- // Shutdown the file state checker thread
-
- getStateTable().shutdownRequest();
- }
+ if ( m_stateTable != null)
+ enableStateTable( false, m_stateReaper);
// Call the base class
diff --git a/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java
index 7ce6b8705f..983cba5a49 100644
--- a/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java
+++ b/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java
@@ -28,6 +28,7 @@ import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.filesys.server.SrvSession;
import org.alfresco.filesys.server.core.DeviceContext;
import org.alfresco.filesys.server.core.DeviceContextException;
+import org.alfresco.filesys.server.core.DeviceInterface;
import org.alfresco.filesys.server.filesys.AccessDeniedException;
import org.alfresco.filesys.server.filesys.AccessMode;
import org.alfresco.filesys.server.filesys.DiskInterface;
@@ -44,11 +45,13 @@ import org.alfresco.filesys.server.filesys.NetworkFile;
import org.alfresco.filesys.server.filesys.SearchContext;
import org.alfresco.filesys.server.filesys.SrvDiskInfo;
import org.alfresco.filesys.server.filesys.TreeConnection;
+import org.alfresco.filesys.server.state.FileState;
+import org.alfresco.filesys.server.state.FileStateReaper;
+import org.alfresco.filesys.server.state.FileState.FileStateStatus;
import org.alfresco.filesys.smb.SMBException;
import org.alfresco.filesys.smb.SMBStatus;
import org.alfresco.filesys.smb.SharingMode;
import org.alfresco.filesys.smb.server.SMBSrvSession;
-import org.alfresco.filesys.smb.server.repo.FileState.FileStateStatus;
import org.alfresco.filesys.smb.server.repo.pseudo.MemoryNetworkFile;
import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFile;
import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFileInterface;
@@ -113,6 +116,10 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
private ServiceRegistry serviceRegistry;
+ // File state reaper
+
+ private FileStateReaper m_stateReaper;
+
/**
* Class constructor
*
@@ -202,6 +209,16 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
return this.serviceRegistry;
}
+ /**
+ * Return the file state reaper
+ *
+ * @return FileStateReaper
+ */
+ public final FileStateReaper getStateReaper()
+ {
+ return m_stateReaper;
+ }
+
/**
* @param contentService the content service
*/
@@ -282,16 +299,28 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
this.authService = authService;
}
+ /**
+ * Set the file state reaper
+ *
+ * @param stateReaper FileStateReaper
+ */
+ public final void setStateReaper(FileStateReaper stateReaper)
+ {
+ m_stateReaper = stateReaper;
+ }
+
/**
* Parse and validate the parameter string and create a device context object for this instance
* of the shared device. The same DeviceInterface implementation may be used for multiple
* shares.
*
+ * @param devIface DeviceInterface
+ * @param name String
* @param args ConfigElement
* @return DeviceContext
* @exception DeviceContextException
*/
- public DeviceContext createContext(ConfigElement cfg) throws DeviceContextException
+ public DeviceContext createContext(DeviceInterface devIface, String name, ConfigElement cfg) throws DeviceContextException
{
// Use the system user as the authenticated context for the filesystem initialization
@@ -389,7 +418,7 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
// Create the context
- context = new ContentContext(storeValue, rootPath, rootNodeRef);
+ context = new ContentContext(name, storeValue, rootPath, rootNodeRef);
// Default the filesystem to look like an 80Gb sized disk with 90% free space
@@ -497,6 +526,10 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
logger.info("Locked files will be marked as offline");
}
+ // Enable file state caching
+
+ context.enableStateTable( true, getStateReaper());
+
// Return the context for this shared filesystem
return context;
diff --git a/source/java/org/alfresco/filesys/server/filesys/HomeShareMapper.java b/source/java/org/alfresco/filesys/smb/server/repo/HomeShareMapper.java
similarity index 92%
rename from source/java/org/alfresco/filesys/server/filesys/HomeShareMapper.java
rename to source/java/org/alfresco/filesys/smb/server/repo/HomeShareMapper.java
index 4e1289d3c4..58209e07eb 100644
--- a/source/java/org/alfresco/filesys/server/filesys/HomeShareMapper.java
+++ b/source/java/org/alfresco/filesys/smb/server/repo/HomeShareMapper.java
@@ -15,7 +15,7 @@
* License.
*/
-package org.alfresco.filesys.server.filesys;
+package org.alfresco.filesys.smb.server.repo;
import java.util.Enumeration;
@@ -29,7 +29,9 @@ import org.alfresco.filesys.server.core.ShareMapper;
import org.alfresco.filesys.server.core.ShareType;
import org.alfresco.filesys.server.core.SharedDevice;
import org.alfresco.filesys.server.core.SharedDeviceList;
+import org.alfresco.filesys.server.filesys.DiskSharedDevice;
import org.alfresco.filesys.smb.server.repo.ContentContext;
+import org.alfresco.filesys.smb.server.repo.ContentDiskDriver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -317,13 +319,11 @@ public class HomeShareMapper implements ShareMapper
{
// Create the disk driver and context
- DiskInterface diskDrv = m_config.getDiskInterface();
- DiskDeviceContext diskCtx = new ContentContext("", "", client.getHomeFolder());
-
- // Default the filesystem to look like an 80Gb sized disk with 90% free space
-
- diskCtx.setDiskInformation(new SrvDiskInfo(2560, 64, 512, 2304));
+ ContentDiskDriver diskDrv = ( ContentDiskDriver) m_config.getDiskInterface();
+ ContentContext diskCtx = new ContentContext( getHomeFolderName(), "", "", client.getHomeFolder());
+ diskCtx.enableStateTable( true, diskDrv.getStateReaper());
+
// Create a temporary shared device for the users home directory
return new DiskSharedDevice(getHomeFolderName(), diskDrv, diskCtx, SharedDevice.Temporary);
diff --git a/source/java/org/alfresco/filesys/smb/server/repo/pseudo/ContentPseudoFileImpl.java b/source/java/org/alfresco/filesys/smb/server/repo/pseudo/ContentPseudoFileImpl.java
index ab38534a88..e2e6f8c4da 100644
--- a/source/java/org/alfresco/filesys/smb/server/repo/pseudo/ContentPseudoFileImpl.java
+++ b/source/java/org/alfresco/filesys/smb/server/repo/pseudo/ContentPseudoFileImpl.java
@@ -21,11 +21,11 @@ import java.util.Enumeration;
import org.alfresco.filesys.server.SrvSession;
import org.alfresco.filesys.server.filesys.FileName;
import org.alfresco.filesys.server.filesys.TreeConnection;
+import org.alfresco.filesys.server.state.FileState;
import org.alfresco.filesys.smb.server.SMBSrvSession;
import org.alfresco.filesys.smb.server.repo.ContentContext;
import org.alfresco.filesys.smb.server.repo.DesktopAction;
import org.alfresco.filesys.smb.server.repo.DesktopActionTable;
-import org.alfresco.filesys.smb.server.repo.FileState;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;