Example #1
0
  /**
   * Makes sure that multiple threads of the same Java process cannot lock the same directory at
   * once.
   *
   * @throws Exception
   */
  @Test
  public void multipleThreadsOfCurrentJvmSameVersion() throws Exception {

    final PathLocker<SrcVersion> pathLocker = new PathLocker<>();

    final Path dir1 = lockerDirectory.resolve(UUID.randomUUID().toString());
    final SrcVersion srcVersion = SrcVersion.parse("1.2.3-SRC-revision-deadbeef");

    Future<PathLock> concurrLockFuture = null;
    try (PathLock lock1 = pathLocker.lockDirectory(dir1, srcVersion)) {
      /* locked for the current thread */

      /* now try to lock from another thread which should fail with a TimeoutException
       * because we have locked above */
      try {
        concurrLockFuture = lockConcurrently(pathLocker, dir1, srcVersion);
        concurrLockFuture.get(1, TimeUnit.SECONDS);
        Assert.fail("TimeoutException expected");
      } catch (InterruptedException e) {
        throw e;
      } catch (ExecutionException e) {
        throw e;
      } catch (TimeoutException e) {
        /* expected */
      }
    }

    /* unlocked again - the above attempt to lock from a concurrent thread must succeed now */
    PathLock lock2 = concurrLockFuture.get(1, TimeUnit.SECONDS);
    Assert.assertNotNull(lock2);
  }
Example #2
0
  @Test
  public void multipleThreadsOfCurrentJvmDistinctVersion() throws Exception {

    final PathLocker<SrcVersion> pathLocker = new PathLocker<>();

    final Path dir1 = lockerDirectory.resolve(UUID.randomUUID().toString());
    final SrcVersion srcVersion1 = SrcVersion.parse("1.2.3-SRC-revision-deadbeef");
    final SrcVersion srcVersion2 = SrcVersion.parse("2.3.4-SRC-revision-coffeebabe");

    Future<PathLock> concurrLockFuture = null;
    try (PathLock lock1 = pathLocker.lockDirectory(dir1, srcVersion1)) {
      /* locked for the current thread */

      /*
       * now try to lock for a distinct version from another thread which should fail with a
       * CannotAcquireLockException because we have locked the path above
       */
      try {
        concurrLockFuture = lockConcurrently(pathLocker, dir1, srcVersion2);
        concurrLockFuture.get(1, TimeUnit.SECONDS);
        Assert.fail("CannotAcquireLockException expected");
      } catch (InterruptedException e) {
        throw e;
      } catch (ExecutionException e) {
        Assert.assertTrue(
            "Should throw CannotAcquireLockException",
            CannotAcquireLockException.class.equals(e.getCause().getClass()));
      } catch (TimeoutException e) {
        throw e;
      }
    }

    /* the above concurrent attempt should still fail, even if lock1 has been released in between */
    try {
      concurrLockFuture.get(1, TimeUnit.SECONDS);

      Assert.fail("CannotAcquireLockException expected");
    } catch (ExecutionException e) {
      Assert.assertTrue(
          "Should throw CannotAcquireLockException",
          CannotAcquireLockException.class.equals(e.getCause().getClass()));
    }

    /* but a fresh attempt must succeed */
    try {
      Future<PathLock> concurrLockFuture2 = lockConcurrently(pathLocker, dir1, srcVersion2);
      Assert.assertNotNull(concurrLockFuture2.get(1, TimeUnit.SECONDS));
    } catch (InterruptedException e) {
      throw e;
    } catch (ExecutionException e) {
      throw e;
    } catch (TimeoutException e) {
      throw e;
    }
  }
Example #3
0
  /**
   * First spawns another process that locks some test directory and then makes sure that the
   * present process'es {@link PathLocker} cannot lock the same directory at the same time.
   *
   * @throws Exception
   */
  @Test
  public void anotherProcess() throws Exception {

    final Path keepRunnigFile =
        targetDirectory.resolve("PathLockerProcess-keep-running-" + UUID.randomUUID().toString());
    Files.write(
        keepRunnigFile, "PathLockerProcess will run till this file exists".getBytes("utf-8"));

    final Path dirToLock = lockerDirectory.resolve(UUID.randomUUID().toString());
    final SrcVersion srcVersion = SrcVersion.parse("1.2.3-SRC-revision-deadbeef");
    final Path lockSuccessFile = dirToLock.resolve("lock-success.txt");

    /* lock dirToLock from another process running on the same machine */
    final String slfApiJar = getJarPath(org.slf4j.LoggerFactory.class);
    final String slfSimpleJar = getJarPath(org.slf4j.impl.StaticLoggerBinder.class);
    final String classPath =
        targetDirectory.resolve("classes").toString()
            + File.pathSeparator
            + targetDirectory.resolve("test-classes").toString()
            + File.pathSeparator
            + slfApiJar
            + File.pathSeparator
            + slfSimpleJar;
    final ShellCommand command =
        ShellCommand.builder()
            .executable(SrcdepsCoreUtils.getCurrentJavaExecutable())
            .arguments(
                "-cp",
                classPath,
                PathLockerProcess.class.getName(),
                dirToLock.toString(),
                srcVersion.toString(),
                keepRunnigFile.toString(),
                lockSuccessFile.toString())
            .workingDirectory(lockerDirectory)
            .build();
    final ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<Boolean> future =
        executor.submit(
            new Callable<Boolean>() {
              @Override
              public Boolean call() throws Exception {
                Shell.execute(command).assertSuccess();
                return true;
              }
            });

    /* with some delay, the dirToLock eventually gets locked by PathLockerProcess */
    final PathLocker<SrcVersion> pathLocker = new PathLocker<>();
    final long timeoutSeconds = 5;
    final long lockDeadline = System.currentTimeMillis() + (timeoutSeconds * 1000);
    while (Files.notExists(lockSuccessFile) && System.currentTimeMillis() <= lockDeadline) {
      log.debug(pid + " Lock success file not there yet {}", lockSuccessFile);
      Thread.sleep(10);
    }

    Assert.assertTrue(
        String.format(
            "PathLockerProcess has not locked [%s] within [%d] seconds", dirToLock, timeoutSeconds),
        Files.exists(lockSuccessFile));

    log.debug(pid + " Lock success file exists {}", lockSuccessFile);

    try (PathLock lock1 = pathLocker.lockDirectory(dirToLock, srcVersion)) {
      /* locked for the current thread */
      Assert.fail(
          String.format(
              "The current thread and process should not be able to lock [%s]", dirToLock));
    } catch (CannotAcquireLockException e) {
      /* expected */
    } finally {
      /* Signal to PathLockerProcess that it should exit */
      Files.deleteIfExists(keepRunnigFile);

      /* Ensure the PathLockerProcess exited cleanly */
      future.get(5, TimeUnit.SECONDS);
    }

    /* PathLockerProcess must have unlocked at this point
     * and we must succeed in locking from here now */
    try (PathLock lock1 = pathLocker.lockDirectory(dirToLock, srcVersion)) {
      Assert.assertTrue(lock1 != null);
    }
  }