package com.sleepycat.je.log; public class FileManager { private RandomAccessFile lockFile; private FileChannel channel; private FileLock envLock; private FileLock exclLock; /** * Lock the environment. Return true if the lock was acquired. If exclusive * is false, then this implements a single writer, multiple reader lock. If * exclusive is true, then implement an exclusive lock. * There is a lock file and there are two regions of the lock file: byte 0, * and byte 1. Byte 0 is the exclusive writer process area of the lock file. * If an environment is opened for write, then it attempts to take an * exclusive write lock on byte 0. Byte 1 is the shared reader process area * of the lock file. If an environment is opened for read-only, then it * attempts to take a shared lock on byte 1. This is how we implement single * writer, multi reader semantics. * The cleaner, each time it is invoked, attempts to take an exclusive lock * on byte 1. The owning process already either has an exclusive lock on * byte 0, or a shared lock on byte 1. This will necessarily conflict with * any shared locks on byte 1, even if it's in the same process and there * are no other holders of that shared lock. So if there is only one * read-only process, it will have byte 1 for shared access, and the cleaner * can not run in it because it will attempt to get an exclusive lock on * byte 1 (which is already locked for shared access by itself). If a write * process comes along and tries to run the cleaner, it will attempt to get * an exclusive lock on byte 1. If there are no other reader processes (with * shared locks on byte 1), and no other writers (which are running cleaners * on with exclusive locks on byte 1), then the cleaner will run. */ public boolean lockEnvironment( boolean readOnly, boolean exclusive) throws DatabaseException { try { if (checkEnvHomePermissions(readOnly)) { return true; } if (lockFile == null) { lockFile=new RandomAccessFile(new File(dbEnvHome,"je" + LOCK_SUFFIX),"rw"); } channel=lockFile.getChannel(); boolean throwIt=false; try { if (exclusive) { exclLock=channel.tryLock(1,2,false); if (exclLock == null) { return false; } return true; } else { if (readOnly) { envLock=channel.tryLock(1,2,true); } else { envLock=channel.tryLock(0,1,false); } if (envLock == null) { throwIt=true; } } } catch ( OverlappingFileLockException e) { throwIt=true; } if (throwIt) { throw new LogException("A je" + LOCK_SUFFIX + "file exists in "+ dbEnvHome+ " The environment can not be locked for "+ (readOnly ? "shared" : "single writer")+ " access."); } } catch ( IOException IOE) { throw new LogException(IOE.toString()); } return true; } public void releaseExclusiveLock() throws DatabaseException { try { if (exclLock != null) { exclLock.release(); } } catch ( IOException IOE) { throw new DatabaseException(IOE); } } protected void hook467( boolean readOnly) throws DatabaseException { lockEnvironment(readOnly,false); original(readOnly); } /** * Clear the file lock. */ public void close() throws IOException, DatabaseException { if (envLock != null) { envLock.release(); } if (exclLock != null) { exclLock.release(); } if (channel != null) { channel.close(); } if (lockFile != null) { lockFile.close(); } original(); } }