📄 nativefslockfactory.java
字号:
package org.apache.lucene.store;/** * 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. */import java.nio.channels.FileChannel;import java.nio.channels.FileLock;import java.io.File;import java.io.RandomAccessFile;import java.io.IOException;import java.util.HashSet;import java.util.Random;/** * <p>Implements {@link LockFactory} using native OS file * locks. Note that because this LockFactory relies on * java.nio.* APIs for locking, any problems with those APIs * will cause locking to fail. Specifically, on certain NFS * environments the java.nio.* locks will fail (the lock can * incorrectly be double acquired) whereas {@link * SimpleFSLockFactory} worked perfectly in those same * environments. For NFS based access to an index, it's * recommended that you try {@link SimpleFSLockFactory} * first and work around the one limitation that a lock file * could be left when the JVM exits abnormally.</p> * * <p>The primary benefit of {@link NativeFSLockFactory} is * that lock files will be properly removed (by the OS) if * the JVM has an abnormal exit.</p> * * <p>Note that, unlike {@link SimpleFSLockFactory}, the existence of * leftover lock files in the filesystem on exiting the JVM * is fine because the OS will free the locks held against * these files even though the files still remain.</p> * * <p>If you suspect that this or any other LockFactory is * not working properly in your environment, you can easily * test it by using {@link VerifyingLockFactory}, {@link * LockVerifyServer} and {@link LockStressTest}.</p> * * @see LockFactory */public class NativeFSLockFactory extends LockFactory { /** * Directory specified by <code>org.apache.lucene.lockDir</code> * system property. If that is not set, then <code>java.io.tmpdir</code> * system property is used. */ private File lockDir; // Simple test to verify locking system is "working". On // NFS, if it's misconfigured, you can hit long (35 // second) timeouts which cause Lock.obtain to take far // too long (it assumes the obtain() call takes zero // time). Since it's a configuration problem, we test up // front once on creating the LockFactory: private void acquireTestLock() throws IOException { String randomLockName = "lucene-" + Long.toString(new Random().nextInt(), Character.MAX_RADIX) + "-test.lock"; Lock l = makeLock(randomLockName); try { l.obtain(); } catch (IOException e) { IOException e2 = new IOException("Failed to acquire random test lock; please verify filesystem for lock directory '" + lockDir + "' supports locking"); e2.initCause(e); throw e2; } l.release(); } /** * Create a NativeFSLockFactory instance, with null (unset) * lock directory. This is package-private and is only * used by FSDirectory when creating this LockFactory via * the System property * org.apache.lucene.store.FSDirectoryLockFactoryClass. */ NativeFSLockFactory() throws IOException { this((File) null); } /** * Create a NativeFSLockFactory instance, storing lock * files into the specified lockDirName: * * @param lockDirName where lock files are created. */ public NativeFSLockFactory(String lockDirName) throws IOException { this(new File(lockDirName)); } /** * Create a NativeFSLockFactory instance, storing lock * files into the specified lockDir: * * @param lockDir where lock files are created. */ public NativeFSLockFactory(File lockDir) throws IOException { setLockDir(lockDir); } /** * Set the lock directory. This is package-private and is * only used externally by FSDirectory when creating this * LockFactory via the System property * org.apache.lucene.store.FSDirectoryLockFactoryClass. */ void setLockDir(File lockDir) throws IOException { this.lockDir = lockDir; if (lockDir != null) { // Ensure that lockDir exists and is a directory. if (!lockDir.exists()) { if (!lockDir.mkdirs()) throw new IOException("Cannot create directory: " + lockDir.getAbsolutePath()); } else if (!lockDir.isDirectory()) { throw new IOException("Found regular file where directory expected: " + lockDir.getAbsolutePath()); } acquireTestLock(); } } public synchronized Lock makeLock(String lockName) { if (lockPrefix != null) lockName = lockPrefix + "-n-" + lockName; return new NativeFSLock(lockDir, lockName); } public void clearLock(String lockName) throws IOException { // Note that this isn't strictly required anymore // because the existence of these files does not mean // they are locked, but, still do this in case people // really want to see the files go away: if (lockDir.exists()) { if (lockPrefix != null) { lockName = lockPrefix + "-n-" + lockName; } File lockFile = new File(lockDir, lockName); if (lockFile.exists() && !lockFile.delete()) { throw new IOException("Cannot delete " + lockFile); } } }};class NativeFSLock extends Lock { private RandomAccessFile f; private FileChannel channel; private FileLock lock; private File path; private File lockDir; /* * The javadocs for FileChannel state that you should have * a single instance of a FileChannel (per JVM) for all * locking against a given file. To ensure this, we have * a single (static) HashSet that contains the file paths * of all currently locked locks. This protects against * possible cases where different Directory instances in * one JVM (each with their own NativeFSLockFactory * instance) have set the same lock dir and lock prefix. */ private static HashSet LOCK_HELD = new HashSet(); public NativeFSLock(File lockDir, String lockFileName) { this.lockDir = lockDir; path = new File(lockDir, lockFileName); } public synchronized boolean obtain() throws IOException { if (isLocked()) { // Our instance is already locked: return false; } // Ensure that lockDir exists and is a directory. if (!lockDir.exists()) { if (!lockDir.mkdirs()) throw new IOException("Cannot create directory: " + lockDir.getAbsolutePath()); } else if (!lockDir.isDirectory()) { throw new IOException("Found regular file where directory expected: " + lockDir.getAbsolutePath()); } String canonicalPath = path.getCanonicalPath(); boolean markedHeld = false; try { // Make sure nobody else in-process has this lock held // already, and, mark it held if not: synchronized(LOCK_HELD) { if (LOCK_HELD.contains(canonicalPath)) { // Someone else in this JVM already has the lock: return false; } else { // This "reserves" the fact that we are the one // thread trying to obtain this lock, so we own // the only instance of a channel against this // file: LOCK_HELD.add(canonicalPath); markedHeld = true; } } try { f = new RandomAccessFile(path, "rw"); } catch (IOException e) { // On Windows, we can get intermittant "Access // Denied" here. So, we treat this as failure to // acquire the lock, but, store the reason in case // there is in fact a real error case. failureReason = e; f = null; } if (f != null) { try { channel = f.getChannel(); try { lock = channel.tryLock(); } catch (IOException e) { // At least on OS X, we will sometimes get an // intermittant "Permission Denied" IOException, // which seems to simply mean "you failed to get // the lock". But other IOExceptions could be // "permanent" (eg, locking is not supported via // the filesystem). So, we record the failure // reason here; the timeout obtain (usually the // one calling us) will use this as "root cause" // if it fails to get the lock. failureReason = e; } finally { if (lock == null) { try { channel.close(); } finally { channel = null; } } } } finally { if (channel == null) { try { f.close(); } finally { f = null; } } } } } finally { if (markedHeld && !isLocked()) { synchronized(LOCK_HELD) { if (LOCK_HELD.contains(canonicalPath)) { LOCK_HELD.remove(canonicalPath); } } } } return isLocked(); } public synchronized void release() throws IOException { if (isLocked()) { try { lock.release(); } finally { lock = null; try { channel.close(); } finally { channel = null; try { f.close(); } finally { f = null; synchronized(LOCK_HELD) { LOCK_HELD.remove(path.getCanonicalPath()); } } } } if (!path.delete()) throw new LockReleaseFailedException("failed to delete " + path); } } public synchronized boolean isLocked() { return lock != null; } public String toString() { return "NativeFSLock@" + path; } public void finalize() throws Throwable { try { if (isLocked()) { release(); } } finally { super.finalize(); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -