blob: 0ec7b7c6f8c9f563a8dc0cf3daa864e4f68a0bcc [file] [log] [blame]
/* $Id: LockManager.java 988245 2010-08-23 18:39:35Z kwright $ */
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.apache.manifoldcf.core.lockmanager;
import org.apache.manifoldcf.core.interfaces.*;
import org.apache.manifoldcf.core.system.Logging;
import org.apache.manifoldcf.core.system.ManifoldCF;
import java.util.*;
import java.io.*;
/** The lock manager manages locks across all threads and JVMs and cluster members. There should be no more than ONE
* instance of this class per thread!!! The factory should enforce this.
*/
public class LockManager implements ILockManager
{
public static final String _rcsid = "@(#)$Id: LockManager.java 988245 2010-08-23 18:39:35Z kwright $";
/** Backing lock manager */
protected final ILockManager lockManager;
public LockManager()
throws ManifoldCFException
{
File synchDirectory = FileLockManager.getSynchDirectoryProperty();
if (synchDirectory != null)
lockManager = new FileLockManager(synchDirectory);
else
lockManager = new BaseLockManager();
}
/** Register a service and begin service activity.
* This atomic operation creates a permanent registration entry for a service.
* If the permanent registration entry already exists, this method will not create it or
* treat it as an error. This operation also enters the "active" zone for the service. The "active" zone will remain in force until it is
* canceled, or until the process is interrupted. Ideally, the corresponding endServiceActivity method will be
* called when the service shuts down. Some ILockManager implementations require that this take place for
* proper management.
* If the transient registration already exists, it is treated as an error and an exception will be thrown.
* If registration will succeed, then this method may call an appropriate IServiceCleanup method to clean up either the
* current service, or all services on the cluster.
*@param serviceType is the type of service.
*@param serviceName is the name of the service to register. If null is passed, a transient unique service name will be
* created, and will be returned to the caller.
*@param cleanup is called to clean up either the current service, or all services of this type, if no other active service exists.
* May be null. Local service cleanup is never called if the serviceName argument is null.
*@return the actual service name.
*/
@Override
public String registerServiceBeginServiceActivity(String serviceType, String serviceName,
IServiceCleanup cleanup)
throws ManifoldCFException
{
return lockManager.registerServiceBeginServiceActivity(serviceType, serviceName, cleanup);
}
/** Register a service and begin service activity.
* This atomic operation creates a permanent registration entry for a service.
* If the permanent registration entry already exists, this method will not create it or
* treat it as an error. This operation also enters the "active" zone for the service. The "active" zone will remain in force until it is
* canceled, or until the process is interrupted. Ideally, the corresponding endServiceActivity method will be
* called when the service shuts down. Some ILockManager implementations require that this take place for
* proper management.
* If the transient registration already exists, it is treated as an error and an exception will be thrown.
* If registration will succeed, then this method may call an appropriate IServiceCleanup method to clean up either the
* current service, or all services on the cluster.
*@param serviceType is the type of service.
*@param serviceName is the name of the service to register. If null is passed, a transient unique service name will be
* created, and will be returned to the caller.
*@param initialData is the initial service data for this service.
*@param cleanup is called to clean up either the current service, or all services of this type, if no other active service exists.
* May be null. Local service cleanup is never called if the serviceName argument is null.
*@return the actual service name.
*/
@Override
public String registerServiceBeginServiceActivity(String serviceType, String serviceName,
byte[] initialData, IServiceCleanup cleanup)
throws ManifoldCFException
{
return lockManager.registerServiceBeginServiceActivity(serviceType, serviceName, initialData, cleanup);
}
/** Set service data for a service.
*@param serviceType is the type of service.
*@param serviceName is the name of the service.
*@param serviceData is the data to update to (may be null).
* This updates the service's transient data (or deletes it). If the service is not active, an exception is thrown.
*/
@Override
public void updateServiceData(String serviceType, String serviceName, byte[] serviceData)
throws ManifoldCFException
{
lockManager.updateServiceData(serviceType, serviceName, serviceData);
}
/** Retrieve service data for a service.
*@param serviceType is the type of service.
*@param serviceName is the name of the service.
*@return the service's transient data.
*/
@Override
public byte[] retrieveServiceData(String serviceType, String serviceName)
throws ManifoldCFException
{
return lockManager.retrieveServiceData(serviceType, serviceName);
}
/** Scan service data for a service type. Only active service data will be considered.
*@param serviceType is the type of service.
*@param dataAcceptor is the object that will be notified of each item of data for each service name found.
*/
@Override
public void scanServiceData(String serviceType, IServiceDataAcceptor dataAcceptor)
throws ManifoldCFException
{
lockManager.scanServiceData(serviceType, dataAcceptor);
}
/** Clean up any inactive services found.
* Calling this method will invoke cleanup of one inactive service at a time.
* If there are no inactive services around, then false will be returned.
* Note that this method will block whatever service it finds from starting up
* for the time the cleanup is proceeding. At the end of the cleanup, if
* successful, the service will be atomically unregistered.
*@param serviceType is the service type.
*@param cleanup is the object to call to clean up an inactive service.
*@return true if there were no cleanup operations necessary.
*/
@Override
public boolean cleanupInactiveService(String serviceType, IServiceCleanup cleanup)
throws ManifoldCFException
{
return lockManager.cleanupInactiveService(serviceType, cleanup);
}
/** Count all active services of a given type.
*@param serviceType is the service type.
*@return the count.
*/
@Override
public int countActiveServices(String serviceType)
throws ManifoldCFException
{
return lockManager.countActiveServices(serviceType);
}
/** End service activity.
* This operation exits the "active" zone for the service. This must take place using the same ILockManager
* object that was used to registerServiceBeginServiceActivity() - which implies that it is the same thread.
*@param serviceType is the type of service.
*@param serviceName is the name of the service to exit.
*/
@Override
public void endServiceActivity(String serviceType, String serviceName)
throws ManifoldCFException
{
lockManager.endServiceActivity(serviceType, serviceName);
}
/** Check whether a service is active or not.
* This operation returns true if the specified service is considered active at the moment. Once a service
* is not active anymore, it can only return to activity by calling beginServiceActivity() once more.
*@param serviceType is the type of service.
*@param serviceName is the name of the service to check on.
*@return true if the service is considered active.
*/
@Override
public boolean checkServiceActive(String serviceType, String serviceName)
throws ManifoldCFException
{
return lockManager.checkServiceActive(serviceType, serviceName);
}
/** Get the current shared configuration. This configuration is available in common among all nodes,
* and thus must not be accessed through here for the purpose of finding configuration data that is specific to any one
* specific node.
*@param configurationData is the globally-shared configuration information.
*/
@Override
public ManifoldCFConfiguration getSharedConfiguration()
throws ManifoldCFException
{
return lockManager.getSharedConfiguration();
}
/** Raise a flag. Use this method to assert a condition, or send a global signal. The flag will be reset when the
* entire system is restarted.
*@param flagName is the name of the flag to set.
*/
@Override
public void setGlobalFlag(String flagName)
throws ManifoldCFException
{
lockManager.setGlobalFlag(flagName);
}
/** Clear a flag. Use this method to clear a condition, or retract a global signal.
*@param flagName is the name of the flag to clear.
*/
@Override
public void clearGlobalFlag(String flagName)
throws ManifoldCFException
{
lockManager.clearGlobalFlag(flagName);
}
/** Check the condition of a specified flag.
*@param flagName is the name of the flag to check.
*@return true if the flag is set, false otherwise.
*/
@Override
public boolean checkGlobalFlag(String flagName)
throws ManifoldCFException
{
return lockManager.checkGlobalFlag(flagName);
}
/** Read data from a shared data resource. Use this method to read any existing data, or get a null back if there is no such resource.
* Note well that this is not necessarily an atomic operation, and it must thus be protected by a lock.
*@param resourceName is the global name of the resource.
*@return a byte array containing the data, or null.
*/
@Override
public byte[] readData(String resourceName)
throws ManifoldCFException
{
return lockManager.readData(resourceName);
}
/** Write data to a shared data resource. Use this method to write a body of data into a shared resource.
* Note well that this is not necessarily an atomic operation, and it must thus be protected by a lock.
*@param resourceName is the global name of the resource.
*@param data is the byte array containing the data. Pass null if you want to delete the resource completely.
*/
@Override
public void writeData(String resourceName, byte[] data)
throws ManifoldCFException
{
lockManager.writeData(resourceName,data);
}
/** Wait for a time before retrying a lock.
*/
@Override
public void timedWait(int time)
throws ManifoldCFException
{
lockManager.timedWait(time);
}
/** Enter a non-exclusive write-locked area (blocking out all readers, but letting in other "writers").
* This kind of lock is designed to be used in conjunction with read locks. It is used typically in
* a situation where the read lock represents a query and the non-exclusive write lock represents a modification
* to an individual item that might affect the query, but where multiple modifications do not individually
* interfere with one another (use of another, standard, write lock per item can guarantee this).
*/
@Override
public void enterNonExWriteLock(String lockKey)
throws ManifoldCFException
{
lockManager.enterNonExWriteLock(lockKey);
}
@Override
public void enterNonExWriteLockNoWait(String lockKey)
throws ManifoldCFException, LockException
{
lockManager.enterNonExWriteLockNoWait(lockKey);
}
/** Leave a non-exclusive write lock.
*/
@Override
public void leaveNonExWriteLock(String lockKey)
throws ManifoldCFException
{
lockManager.leaveNonExWriteLock(lockKey);
}
/** Enter a write locked area (i.e., block out both readers and other writers)
* NOTE: Can't enter until all readers have left.
*/
@Override
public void enterWriteLock(String lockKey)
throws ManifoldCFException
{
lockManager.enterWriteLock(lockKey);
}
@Override
public void enterWriteLockNoWait(String lockKey)
throws ManifoldCFException, LockException
{
lockManager.enterWriteLockNoWait(lockKey);
}
@Override
public void leaveWriteLock(String lockKey)
throws ManifoldCFException
{
lockManager.leaveWriteLock(lockKey);
}
/** Enter a read-only locked area (i.e., block ONLY if there's a writer)
*/
@Override
public void enterReadLock(String lockKey)
throws ManifoldCFException
{
lockManager.enterReadLock(lockKey);
}
@Override
public void enterReadLockNoWait(String lockKey)
throws ManifoldCFException, LockException
{
lockManager.enterReadLockNoWait(lockKey);
}
@Override
public void leaveReadLock(String lockKey)
throws ManifoldCFException
{
lockManager.leaveReadLock(lockKey);
}
@Override
public void clearLocks()
throws ManifoldCFException
{
lockManager.clearLocks();
}
/** Enter multiple locks
*/
@Override
public void enterLocks(String[] readLocks, String[] nonExWriteLocks, String[] writeLocks)
throws ManifoldCFException
{
lockManager.enterLocks(readLocks, nonExWriteLocks, writeLocks);
}
@Override
public void enterLocksNoWait(String[] readLocks, String[] nonExWriteLocks, String[] writeLocks)
throws ManifoldCFException, LockException
{
lockManager.enterLocksNoWait(readLocks, nonExWriteLocks, writeLocks);
}
/** Leave multiple locks
*/
@Override
public void leaveLocks(String[] readLocks, String[] writeNonExLocks, String[] writeLocks)
throws ManifoldCFException
{
lockManager.leaveLocks(readLocks, writeNonExLocks, writeLocks);
}
/** Enter a named, read critical section (NOT a lock). Critical sections never cross JVM boundaries.
* Critical section names do not collide with lock names; they have a distinct namespace.
*@param sectionKey is the name of the section to enter. Only one thread can be in any given named
* section at a time.
*/
@Override
public void enterReadCriticalSection(String sectionKey)
throws ManifoldCFException
{
lockManager.enterReadCriticalSection(sectionKey);
}
/** Leave a named, read critical section (NOT a lock). Critical sections never cross JVM boundaries.
* Critical section names do not collide with lock names; they have a distinct namespace.
*@param sectionKey is the name of the section to leave. Only one thread can be in any given named
* section at a time.
*/
@Override
public void leaveReadCriticalSection(String sectionKey)
throws ManifoldCFException
{
lockManager.leaveReadCriticalSection(sectionKey);
}
/** Enter a named, non-exclusive write critical section (NOT a lock). Critical sections never cross JVM boundaries.
* Critical section names do not collide with lock names; they have a distinct namespace.
*@param sectionKey is the name of the section to enter. Only one thread can be in any given named
* section at a time.
*/
@Override
public void enterNonExWriteCriticalSection(String sectionKey)
throws ManifoldCFException
{
lockManager.enterNonExWriteCriticalSection(sectionKey);
}
/** Leave a named, non-exclusive write critical section (NOT a lock). Critical sections never cross JVM boundaries.
* Critical section names do not collide with lock names; they have a distinct namespace.
*@param sectionKey is the name of the section to leave. Only one thread can be in any given named
* section at a time.
*/
@Override
public void leaveNonExWriteCriticalSection(String sectionKey)
throws ManifoldCFException
{
lockManager.leaveNonExWriteCriticalSection(sectionKey);
}
/** Enter a named, exclusive critical section (NOT a lock). Critical sections never cross JVM boundaries.
* Critical section names should be distinct from all lock names.
*@param sectionKey is the name of the section to enter. Only one thread can be in any given named
* section at a time.
*/
@Override
public void enterWriteCriticalSection(String sectionKey)
throws ManifoldCFException
{
lockManager.enterWriteCriticalSection(sectionKey);
}
/** Leave a named, exclusive critical section (NOT a lock). Critical sections never cross JVM boundaries.
* Critical section names should be distinct from all lock names.
*@param sectionKey is the name of the section to leave. Only one thread can be in any given named
* section at a time.
*/
@Override
public void leaveWriteCriticalSection(String sectionKey)
throws ManifoldCFException
{
lockManager.leaveWriteCriticalSection(sectionKey);
}
/** Enter multiple critical sections simultaneously.
*@param readSectionKeys is an array of read section descriptors, or null if there are no read sections desired.
*@param nonExSectionKeys is an array of non-ex write section descriptors, or null if none desired.
*@param writeSectionKeys is an array of write section descriptors, or null if there are none desired.
*/
@Override
public void enterCriticalSections(String[] readSectionKeys, String[] nonExSectionKeys, String[] writeSectionKeys)
throws ManifoldCFException
{
lockManager.enterCriticalSections(readSectionKeys, nonExSectionKeys, writeSectionKeys);
}
/** Leave multiple critical sections simultaneously.
*@param readSectionKeys is an array of read section descriptors, or null if there are no read sections desired.
*@param nonExSectionKeys is an array of non-ex write section descriptors, or null if none desired.
*@param writeSectionKeys is an array of write section descriptors, or null if there are none desired.
*/
@Override
public void leaveCriticalSections(String[] readSectionKeys, String[] nonExSectionKeys, String[] writeSectionKeys)
throws ManifoldCFException
{
lockManager.leaveCriticalSections(readSectionKeys, nonExSectionKeys, writeSectionKeys);
}
}