# HG changeset patch # User Dmitry Neverov # Date 1375344368 -14400 # Node ID cea0fb35f941e04215e9a915991edec4c0d04a5f # Parent a6c708e5bb1051b710aa861653b2ab04b8d4551b# Parent 7a4ecffe34a938abe547ef09584e560d3deedf80 Merge branch Gaya-8.0.x diff -r a6c708e5bb10 -r cea0fb35f941 .hgignore --- a/.hgignore Wed Jul 24 17:19:53 2013 +0200 +++ b/.hgignore Thu Aug 01 12:06:08 2013 +0400 @@ -5,4 +5,5 @@ mercurial.properties syntax: glob .idea/workspace.xml -out \ No newline at end of file +out +.DS_Store \ No newline at end of file diff -r a6c708e5bb10 -r cea0fb35f941 build/ant.build.xml --- a/build/ant.build.xml Wed Jul 24 17:19:53 2013 +0200 +++ b/build/ant.build.xml Thu Aug 01 12:06:08 2013 +0400 @@ -1,23 +1,30 @@ - - + + + - - - - + + + + + + + + + - + + + - - + diff -r a6c708e5bb10 -r cea0fb35f941 mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgFileUtil.java --- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgFileUtil.java Wed Jul 24 17:19:53 2013 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgFileUtil.java Thu Aug 01 12:06:08 2013 +0400 @@ -8,12 +8,15 @@ import java.io.File; import java.io.FileFilter; import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; /** * @author dmitry.neverov */ public final class HgFileUtil { + private final static ConcurrentMap myTmpDirLocks = new ConcurrentHashMap(); private final static String TEMP_DIR_PREFIX = "hg"; private HgFileUtil() { @@ -28,13 +31,30 @@ File parentDir = new File(FileUtil.getTempDirectory()); int suffix = 0; File dir; - do { + while (true) { suffix++; - dir = new File(parentDir, TEMP_DIR_PREFIX + suffix); - } while (dir.exists() || !dir.createNewFile()); - dir.delete(); - dir.mkdir(); - return dir; + String tmpDirName = TEMP_DIR_PREFIX + suffix; + dir = new File(parentDir, tmpDirName); + if (dir.exists()) + continue; + + synchronized (getTmpDirLock(tmpDirName)) { + if (!dir.createNewFile()) + continue; + if (!dir.delete()) + continue; + if (!dir.mkdir()) + continue; + } + return dir; + } + } + + + private static Object getTmpDirLock(@NotNull String tmpDirName) { + Object tmpDirLock = new Object(); + Object existingLock = myTmpDirLocks.putIfAbsent(tmpDirName, tmpDirLock); + return existingLock != null ? existingLock : tmpDirLock; } diff -r a6c708e5bb10 -r cea0fb35f941 mercurial-tests/mercurial-tests.iml --- a/mercurial-tests/mercurial-tests.iml Wed Jul 24 17:19:53 2013 +0200 +++ b/mercurial-tests/mercurial-tests.iml Thu Aug 01 12:06:08 2013 +0400 @@ -21,6 +21,7 @@ + diff -r a6c708e5bb10 -r cea0fb35f941 mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgFileUtilTest.java --- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgFileUtilTest.java Wed Jul 24 17:19:53 2013 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgFileUtilTest.java Thu Aug 01 12:06:08 2013 +0400 @@ -1,11 +1,18 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; +import jetbrains.buildServer.util.TestFor; import org.testng.annotations.Test; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertFalse; @Test @@ -17,4 +24,37 @@ assertFalse(tmpDir1.getCanonicalPath().equals(tmpDir2.getCanonicalPath())); } + + @TestFor(issues = "TW-30589") + @Test(invocationCount = 10) + public void createTempFile_should_always_return_unique_dir() throws Exception { + final CountDownLatch allThreadsInitialized = new CountDownLatch(1); + final Set tmpFiles = new HashSet(); + Runnable createTmpFile = new Runnable() { + public void run() { + try { + allThreadsInitialized.await(); + tmpFiles.add(HgFileUtil.createTempDir()); + } catch (Exception e) { + //ignore + } + } + }; + + List threads = new ArrayList(); + for (int i = 0; i < 50; i++) { + Thread t = new Thread(createTmpFile); + t.start(); + threads.add(t); + } + + allThreadsInitialized.countDown(); + + for (Thread t : threads) { + t.join(); + } + + assertEquals("Race condition in createTempDir", threads.size(), tmpFiles.size()); + } + } diff -r a6c708e5bb10 -r cea0fb35f941 mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Util.java --- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Util.java Wed Jul 24 17:19:53 2013 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Util.java Thu Aug 01 12:06:08 2013 +0400 @@ -2,6 +2,7 @@ import jetbrains.buildServer.TempFiles; import jetbrains.buildServer.util.FileUtil; +import com.intellij.openapi.util.SystemInfo; import jetbrains.buildServer.vcs.CheckoutRules; import jetbrains.buildServer.vcs.VcsException; import jetbrains.buildServer.vcs.VcsRoot; @@ -22,11 +23,11 @@ public static String getHgPath() throws IOException { String providedHg = System.getenv(Constants.HG_PATH_ENV); - if (providedHg != null) { + if (providedHg != null) return providedHg; - } else { + if (SystemInfo.isWindows) return new File("mercurial-tests/testData/bin/hg.exe").getAbsolutePath(); - } + return "hg"; //assume it is somethere in the $PATH } diff -r a6c708e5bb10 -r cea0fb35f941 teamcity-plugin.xml --- a/teamcity-plugin.xml Wed Jul 24 17:19:53 2013 +0200 +++ b/teamcity-plugin.xml Thu Aug 01 12:06:08 2013 +0400 @@ -4,7 +4,7 @@ mercurial VCS Support: Mercurial - @Plugin_Version@ + @version@ JetBrains, s.r.o. http://www.jetbrains.com