Class FileLockManagerTest

java.lang.Object
ubic.gemma.core.util.locking.FileLockManagerTest

public class FileLockManagerTest extends Object
  • Constructor Details

    • FileLockManagerTest

      public FileLockManagerTest()
  • Method Details

    • tearDown

      @AfterEach public void tearDown() throws IOException
      Throws:
      IOException
    • testMappingSurvivesTheFirstAcquirersKeyBeingCollected

      @Test public void testMappingSurvivesTheFirstAcquirersKeyBeingCollected() throws Exception
      The path→lock mapping must survive as long as any holder does — regardless of WHICH Path instance each caller used and of what the garbage collector decides.

      The JVM's file-lock table is global, so two ReadWriteFileLock instances for one file throw OverlappingFileLockException the moment both lock. The manager once kept the mapping in a WeakHashMap, where the entry was reachable only through the FIRST acquirer's key object: a cache probe would create the entry and close, a later caller would hold the lock through an equal-but-distinct Path, GC would evict the entry mid-hold, and the next probe would mint a second instance against the held file — observed as every /data/raw request 500ing instantly while a disconnected caller's build still held the exclusive lock (2026-08-19). The System.gc() calls below made that reproduce; with a strong map they must be irrelevant.

      Throws:
      Exception
    • testSharedLockOnAMissingDirectoryCreatesNothing

      @Test public void testSharedLockOnAMissingDirectoryCreatesNothing() throws IOException
      🛑 A shared lock is often taken only to ask "does this file exist?", and it must not answer by creating the directory the file would have lived in.

      Gemma 1.0's QC page probes all nine metadata types for every dataset regardless of platform. Each probe took a shared lock, whose lock file needed a parent, so the parent chain was created -- leaving ~15,000 empty MultiQCReports/ directories in the production metadata tree, one per microarray dataset that can never have an RNA-Seq report.

      Throws:
      IOException
    • testExclusiveLockStillCreatesItsDirectoryChain

      @Test public void testExclusiveLockStillCreatesItsDirectoryChain() throws IOException
      The counterpart: an exclusive acquirer still gets its directory chain. copyMetadataFileInternal takes the lock BEFORE creating the parent directories, so removing this would break every metadata write.
      Throws:
      IOException
    • testSharedLockIsARealFileLockOnceTheDirectoryExists

      @Test public void testSharedLockIsARealFileLockOnceTheDirectoryExists() throws IOException
      Once the directory exists a writer can be mid-copy into it, so the real file lock comes back and reader/writer coordination is what it always was. Degrading is only for the case where the file cannot possibly exist.
      Throws:
      IOException
    • testDegradedSharedLockCanStillBeUpgraded

      @Test public void testDegradedSharedLockCanStillBeUpgraded() throws IOException
      A degraded shared lock upgrades into a real one: toExclusive() re-acquires from scratch, which is how a probe that decides to write still coordinates properly.
      Throws:
      IOException
    • testSharedLockUnderAReadOnlyDirectoryDoesNotThrow

      @Test @EnabledOnOs({LINUX,MAC}) public void testSharedLockUnderAReadOnlyDirectoryDoesNotThrow() throws IOException
      A read-only directory is a read-only directory, not an error. Reading a tree another deployment owns -- Gemma 1.0's metadata tree, mounted into the 2.0 container -- must not require write access to it.
      Throws:
      IOException
    • testGetLockInfo

      @Test @EnabledOnOs(LINUX) public void testGetLockInfo() throws IOException
      Throws:
      IOException
    • testReentrant

      @Test public void testReentrant() throws IOException
      Throws:
      IOException
    • testToShared

      @Test public void testToShared() throws IOException
      Throws:
      IOException
    • testToExclusive

      @Test public void testToExclusive() throws IOException
      Throws:
      IOException
    • testSteal

      @Test public void testSteal() throws IOException
      Throws:
      IOException
    • testStealWithPath

      @Test public void testStealWithPath() throws IOException
      Throws:
      IOException
    • testConcurrent

      @Test public void testConcurrent() throws IOException, InterruptedException
      Throws:
      IOException
      InterruptedException
    • testTwoManagers

      @Test public void testTwoManagers() throws IOException
      Throws:
      IOException