001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.kahadb.util; 018 019import java.io.File; 020import java.io.IOException; 021import java.io.RandomAccessFile; 022import java.nio.channels.FileLock; 023import java.nio.channels.OverlappingFileLockException; 024import java.util.Date; 025 026/** 027 * Used to lock a File. 028 * 029 * @author chirino 030 */ 031public class LockFile { 032 033 private static final boolean DISABLE_FILE_LOCK = "true".equals(System.getProperty("java.nio.channels.FileLock.broken", "false")); 034 final private File file; 035 036 private FileLock lock; 037 private RandomAccessFile readFile; 038 private int lockCounter; 039 private final boolean deleteOnUnlock; 040 041 public LockFile(File file, boolean deleteOnUnlock) { 042 this.file = file; 043 this.deleteOnUnlock = deleteOnUnlock; 044 } 045 046 /** 047 * @throws IOException 048 */ 049 synchronized public void lock() throws IOException { 050 if (DISABLE_FILE_LOCK) { 051 return; 052 } 053 054 if( lockCounter>0 ) { 055 return; 056 } 057 058 IOHelper.mkdirs(file.getParentFile()); 059 if (System.getProperty(getVmLockKey()) != null) { 060 throw new IOException("File '" + file + "' could not be locked as lock is already held for this jvm."); 061 } 062 if (lock == null) { 063 readFile = new RandomAccessFile(file, "rw"); 064 IOException reason = null; 065 try { 066 lock = readFile.getChannel().tryLock(0, readFile.getChannel().size(), false); 067 } catch (OverlappingFileLockException e) { 068 reason = IOExceptionSupport.create("File '" + file + "' could not be locked.",e); 069 } catch (IOException ioe) { 070 reason = ioe; 071 } 072 if (lock != null) { 073 lockCounter++; 074 System.setProperty(getVmLockKey(), new Date().toString()); 075 } else { 076 // new read file for next attempt 077 closeReadFile(); 078 if (reason != null) { 079 throw reason; 080 } 081 throw new IOException("File '" + file + "' could not be locked."); 082 } 083 084 } 085 } 086 087 /** 088 */ 089 public void unlock() { 090 if (DISABLE_FILE_LOCK) { 091 return; 092 } 093 094 lockCounter--; 095 if( lockCounter!=0 ) { 096 return; 097 } 098 099 // release the lock.. 100 if (lock != null) { 101 try { 102 lock.release(); 103 System.getProperties().remove(getVmLockKey()); 104 } catch (Throwable ignore) { 105 } 106 lock = null; 107 } 108 closeReadFile(); 109 110 if( deleteOnUnlock ) { 111 file.delete(); 112 } 113 } 114 115 private String getVmLockKey() throws IOException { 116 return getClass().getName() + ".lock." + file.getCanonicalPath(); 117 } 118 119 private void closeReadFile() { 120 // close the file. 121 if (readFile != null) { 122 try { 123 readFile.close(); 124 } catch (Throwable ignore) { 125 } 126 readFile = null; 127 } 128 129 } 130 131}