/* $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); } }