All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.qcloud.cos.internal.FileLocks Maven / Gradle / Ivy

The newest version!
package com.qcloud.cos.internal;

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.Map;
import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.qcloud.cos.exception.FileLockException;
import com.qcloud.cos.utils.IOUtils;

/**
 * An internal utility used to provide both inter and intra JVM file locking.
 * This works well as long as this class is loaded with the same class loader in
 * a JVM. Otherwise, intra-JVM file locking is not guaranteed.
 * 

* Per javadoc of {@link FileLock}, "File locks are held on behalf of the entire * Java virtual machine. They are not suitable for controlling access to a file * by multiple threads within the same virtual machine." *

* Hence the need for this utility class. */ public enum FileLocks { ; // External file lock doesn't seem to work correctly on Windows, // so disabling for now (Ref: TT0047889941) private static final boolean EXTERNAL_LOCK = false; private static final Logger log = LoggerFactory.getLogger(FileLocks.class); private static final Map lockedFiles = new TreeMap(); /** * Acquires an exclusive lock on the specified file, creating the file as * necessary. Caller of this method is responsible to call the * {@link #unlock(File)} method to prevent release leakage. * * @return true if the locking is successful; false otherwise. * * @throws FileLockException if we failed to lock the file */ public static boolean lock(File file) { synchronized(lockedFiles) { if (lockedFiles.containsKey(file)) return false; // already locked } FileLock lock = null; RandomAccessFile raf = null; try { // Note if the file does not already exist then an attempt will be // made to create it because of the use of "rw". raf = new RandomAccessFile(file, "rw"); FileChannel channel = raf.getChannel(); if (EXTERNAL_LOCK) lock = channel.lock(); } catch (Exception e) { IOUtils.closeQuietly(raf, log); throw new FileLockException(e); } final boolean locked; synchronized(lockedFiles) { RandomAccessFile prev = lockedFiles.put(file, raf); if (prev == null) { locked = true; } else { // race condition: some other thread got locked it before this locked = false; lockedFiles.put(file, prev); // put it back } } if (locked) { if (log.isDebugEnabled()) log.debug("Locked file " + file + " with " + lock); } else { IOUtils.closeQuietly(raf, log); } return locked; } /** * Returns true if the specified file is currently locked; false otherwise. */ public static boolean isFileLocked(File file) { synchronized(lockedFiles) { return lockedFiles.containsKey(file); } } /** * Unlocks a file previously locked via {@link #lock(File)}. * * @return true if the unlock is successful; false otherwise. Successful * unlock means we have found and attempted to close the locking * file channel, but ignoring the fact that the close operation may * have actually failed. */ public static boolean unlock(File file) { synchronized(lockedFiles) { final RandomAccessFile raf = lockedFiles.get(file); if (raf == null) return false; else { // Must close out the channel before removing it from the map; // or else risk giving a false negative (of no lock but in fact // the file is still locked by the file system.) IOUtils.closeQuietly(raf, log); lockedFiles.remove(file); } } if (log.isDebugEnabled()) log.debug("Unlocked file " + file); return true; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy