diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/BasicJarHandler.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/BasicJarHandler.java index 4411fb843fab..4ca0ea81c215 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/BasicJarHandler.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/BasicJarHandler.java @@ -109,15 +109,16 @@ public class BasicJarHandler extends ZipHandlerBase { private ScheduledFuture myInvalidationRequest; void attach() throws IOException { + synchronized (ourOpenFileLimitGuard) { + ourOpenFileLimitGuard.remove(BasicJarHandler.this); + } + myLock.lock(); ScheduledFuture invalidationRequest = myInvalidationRequest; if (invalidationRequest != null) { invalidationRequest.cancel(false); myInvalidationRequest = null; - synchronized (ourOpenFileLimitGuard) { - ourOpenFileLimitGuard.remove(BasicJarHandler.this); - } } if (myFile == null) { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/JarFileSystemTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/JarFileSystemTest.java index 8d2db314be51..141bd0cfad67 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/JarFileSystemTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/JarFileSystemTest.java @@ -23,6 +23,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.util.io.IoTestUtil; import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.impl.jar.BasicJarHandler; import com.intellij.openapi.vfs.impl.jar.JarFileSystemImpl; import com.intellij.openapi.vfs.impl.jar.JarHandler; import com.intellij.openapi.vfs.newvfs.ArchiveFileSystem; @@ -40,7 +41,11 @@ import org.junit.Test; import java.io.*; import java.lang.reflect.Field; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.List; +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Future; import java.util.jar.JarFile; import java.util.stream.Stream; @@ -131,6 +136,45 @@ public class JarFileSystemTest extends BareTestFixtureTestCase { assertEquals("some text", VfsUtilCore.loadText(newEntry)); } + @Test + public void testBasicJarHandlerConcurrency() throws Exception { + int number = 40; + List handlers = new ArrayList<>(); + for(int i = 0; i < number; ++i) { + File jar = IoTestUtil.createTestJar(tempDir.newFile("test" + i + ".jar")); + handlers.add(new BasicJarHandler(jar.getPath())); + } + + int N = Math.max(2, Runtime.getRuntime().availableProcessors()); + for(int iteration = 0 ; iteration < 200; ++iteration) { + if (iteration % 10 == 0) System.out.println(iteration); + List futuresToWait = new ArrayList<>(); + CountDownLatch sameStartCondition = new CountDownLatch(N); + + for(int i = 0; i < N; ++i) { + futuresToWait.add(ApplicationManager.getApplication().executeOnPooledThread(() -> { + try { + sameStartCondition.countDown(); + sameStartCondition.await(); + Random random = new Random(); + for (int j = 0; j < 1000; ++j) { + BasicJarHandler handler = handlers.get(random.nextInt(handlers.size())); + + int op = random.nextInt(2); + if (op == 0) assertNotNull(handler.getAttributes(JarFile.MANIFEST_NAME)); + else if (op == 1) assertNotNull(handler.contentsToByteArray(JarFile.MANIFEST_NAME)); + } + } + catch (Throwable ignore) { + ignore.printStackTrace(); + } + })); + } + + for(Future future:futuresToWait) future.get(); + } + } + @Test public void testJarHandlerDoNotCreateCopyWhenListingArchive() throws Exception { File jar = IoTestUtil.createTestJar(tempDir.newFile("test.jar"));