From f2bd8c4119f466e6d3f55728d2a50a7077ee1e6b Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Mon, 22 Jul 2019 15:10:18 -0400 Subject: [PATCH] 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 --- .../file/locking/NioFileLocker.java | 85 ++++++++++--------- .../file/locking/NioFileLockerTests.java | 50 ++++++----- 2 files changed, 73 insertions(+), 62 deletions(-) diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/locking/NioFileLocker.java b/spring-integration-file/src/main/java/org/springframework/integration/file/locking/NioFileLocker.java index 78cf260dba..d427ca6919 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/locking/NioFileLocker.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/locking/NioFileLocker.java @@ -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 does not 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 lockCache = new ConcurrentHashMap(); + private final ConcurrentMap lockCache = new ConcurrentHashMap(); - /** - * {@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); + } + } + } diff --git a/spring-integration-file/src/test/java/org/springframework/integration/file/locking/NioFileLockerTests.java b/spring-integration-file/src/test/java/org/springframework/integration/file/locking/NioFileLockerTests.java index 10e4c97f9d..cd9bd4cfa7 100644 --- a/spring-integration-file/src/test/java/org/springframework/integration/file/locking/NioFileLockerTests.java +++ b/spring-integration-file/src/test/java/org/springframework/integration/file/locking/NioFileLockerTests.java @@ -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 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) new ArrayList())); - } + @Test + public void fileNotListedWhenLockedByOtherFilter() throws IOException { + NioFileLocker filter1 = new NioFileLocker(); + FileListFilter 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())); + filter1.unlock(testFile); + } }