Clear lock cache in NioFileLocker (#2998)

Fixes https://github.com/spring-projects/spring-integration/issues/2980
# Conflicts:
#	spring-integration-file/src/test/java/org/springframework/integration/file/locking/NioFileLockerTests.java

# Conflicts:
#	spring-integration-file/src/main/java/org/springframework/integration/file/locking/NioFileLocker.java
#	spring-integration-file/src/test/java/org/springframework/integration/file/locking/NioFileLockerTests.java
This commit is contained in:
Gary Russell
2019-07-22 15:10:18 -04:00
committed by Artem Bilan
parent 9d4aa8b378
commit f2bd8c4119
2 changed files with 73 additions and 62 deletions

View File

@@ -16,15 +16,15 @@
package org.springframework.integration.file.locking;
import org.springframework.messaging.MessagingException;
import org.springframework.integration.file.FileReadingMessageSource;
import java.io.File;
import java.io.IOException;
import java.nio.channels.FileLock;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.springframework.integration.file.FileReadingMessageSource;
import org.springframework.messaging.MessagingException;
/**
* File locking strategy that uses java.nio. The locks taken by FileChannel are shared with all the threads in a single
* JVM, so this locking strategy <b>does not</b> prevent files being picked up multiple times within the same JVM.
@@ -39,45 +39,46 @@ import java.util.concurrent.ConcurrentMap;
*/
public class NioFileLocker extends AbstractFileLockerFilter {
private final ConcurrentMap<File, FileLock> lockCache = new ConcurrentHashMap<File, FileLock>();
private final ConcurrentMap<File, FileLock> lockCache = new ConcurrentHashMap<File, FileLock>();
/**
* {@inheritDoc}
*/
public boolean lock(File fileToLock) {
FileLock lock = this.lockCache.get(fileToLock);
if (lock == null) {
FileLock newLock = null;
try {
newLock = FileChannelCache.tryLockFor(fileToLock);
}
catch (IOException e) {
throw new MessagingException("Failed to lock file: "
+ fileToLock, e);
}
if (newLock != null) {
FileLock original = this.lockCache.putIfAbsent(fileToLock, newLock);
lock = original != null ? original : newLock;
}
}
return lock != null;
}
public boolean isLockable(File file) {
return this.lockCache.containsKey(file) || !FileChannelCache.isLocked(file);
}
public void unlock(File fileToUnlock) {
FileLock fileLock = this.lockCache.get(fileToUnlock);
try {
if (fileLock != null) {
fileLock.release();
}
FileChannelCache.closeChannelFor(fileToUnlock);
}
catch (IOException e) {
throw new MessagingException("Failed to unlock file: "
+ fileToUnlock, e);
}
/**
* {@inheritDoc}
*/
public boolean lock(File fileToLock) {
FileLock lock = this.lockCache.get(fileToLock);
if (lock == null) {
FileLock newLock;
try {
newLock = FileChannelCache.tryLockFor(fileToLock);
}
catch (IOException e) {
throw new MessagingException("Failed to lock file: "
+ fileToLock, e);
}
if (newLock != null) {
FileLock original = this.lockCache.putIfAbsent(fileToLock, newLock);
lock = original != null ? original : newLock;
}
}
return lock != null;
}
public boolean isLockable(File file) {
return this.lockCache.containsKey(file) || !FileChannelCache.isLocked(file);
}
@Override
public void unlock(File fileToUnlock) {
FileLock fileLock = this.lockCache.remove(fileToUnlock);
try {
if (fileLock != null) {
fileLock.release();
}
FileChannelCache.closeChannelFor(fileToUnlock);
}
catch (IOException e) {
throw new MessagingException("Failed to unlock file: " + fileToUnlock, e);
}
}
}

View File

@@ -18,20 +18,24 @@ package org.springframework.integration.file.locking;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.integration.file.filters.FileListFilter;
import org.springframework.integration.test.util.TestUtils;
/**
* @author Iwein Fuld
* @author Gary Russell
*/
public class NioFileLockerTests {
@@ -46,25 +50,31 @@ public class NioFileLockerTests {
}
};
@Test
public void fileListedByFirstFilter() throws IOException {
NioFileLocker filter = new NioFileLocker();
File testFile = new File(workdir, "test0");
testFile.createNewFile();
assertThat(filter.filterFiles(workdir.listFiles()).get(0), is(testFile));
filter.lock(testFile);
assertThat(filter.filterFiles(workdir.listFiles()).get(0), is(testFile));
}
@Test
public void fileListedByFirstFilter() throws Exception {
NioFileLocker filter = new NioFileLocker();
File testFile = new File(workdir, "test0");
testFile.createNewFile();
assertThat(filter.filterFiles(workdir.listFiles()).get(0), is(testFile));
filter.lock(testFile);
assertThat(filter.filterFiles(workdir.listFiles()).get(0), is(testFile));
filter.unlock(testFile);
Field channelCache = FileChannelCache.class.getDeclaredField("channelCache");
channelCache.setAccessible(true);
assertTrue(((Map<?, ?>) channelCache.get(null)).isEmpty());
assertTrue(TestUtils.getPropertyValue(filter, "lockCache", Map.class).isEmpty());
}
@Test
public void fileNotListedWhenLockedByOtherFilter() throws IOException {
NioFileLocker filter1 = new NioFileLocker();
FileListFilter<File> filter2 = new NioFileLocker();
File testFile = new File(workdir, "test1");
testFile.createNewFile();
assertThat(filter1.filterFiles(workdir.listFiles()).get(0), is(testFile));
filter1.lock(testFile);
assertThat(filter2.filterFiles(workdir.listFiles()), is((List<File>) new ArrayList<File>()));
}
@Test
public void fileNotListedWhenLockedByOtherFilter() throws IOException {
NioFileLocker filter1 = new NioFileLocker();
FileListFilter<File> filter2 = new NioFileLocker();
File testFile = new File(workdir, "test1");
testFile.createNewFile();
assertThat(filter1.filterFiles(workdir.listFiles()).get(0), is(testFile));
filter1.lock(testFile);
assertThat(filter2.filterFiles(workdir.listFiles()), is(new ArrayList<File>()));
filter1.unlock(testFile);
}
}