@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"); 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() .id("anotherProcess").executable(SrcdepsCoreUtils.getCurrentJavaExecutable()) .arguments( "-cp", classPath, PathLockerProcess.class.getName(), dirToLock.toString(), srcVersion.toString(), keepRunnigFile.toString(), lockSuccessFile.toString() ) .workingDirectory(lockerDirectory) .output(LineConsumer::dummy).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; } }); 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("org.srcdeps.example", dirToLock, srcVersion)) { Assert.fail(String.format("The current thread and process should not be able to lock [%s]", dirToLock)); } catch (CannotAcquireLockException e) { } finally { Files.deleteIfExists(keepRunnigFile); future.get(5, TimeUnit.SECONDS); } try (PathLock lock1 = pathLocker.lockDirectory("org.srcdeps.example", dirToLock, srcVersion)) { Assert.assertTrue(lock1 != null); } }
public PathLock lockDirectory(String requestId, Path path, M pathMetadata) throws IOException, CannotAcquireLockException { SrcdepsCoreUtils.ensureDirectoryExists(path); final LockMetadataPair<M> newPair = new LockMetadataPair<M>(new ReentrantLock(), pathMetadata); final LockMetadataPair<M> oldPair = locks.putIfAbsent(path, newPair); final LockMetadataPair<M> mdPair = oldPair == null ? newPair : oldPair; synchronized (mdPair) { final ReentrantLock lock = mdPair.getLock(); final M oldMd = mdPair.getMetadata(); if (oldMd.equals(pathMetadata)) { lock.lock(); log.debug("srcdeps[{}]: Locked on thread level [{}]", requestId, path); return lockInFilesystem(requestId, path, lock); } else { if (lock.tryLock()) { log.debug("srcdeps[{}]: Locked on thread level [{}]", requestId, path); mdPair.setMetadata(pathMetadata); return lockInFilesystem(requestId, path, lock); } else { throw new CannotAcquireLockException( String.format("Path [%s] is locked by another thread for [%s]", path, oldPair)); } } } }
PathLocker { public PathLock lockDirectory(String requestId, Path path, M pathMetadata) throws IOException, CannotAcquireLockException { SrcdepsCoreUtils.ensureDirectoryExists(path); final LockMetadataPair<M> newPair = new LockMetadataPair<M>(new ReentrantLock(), pathMetadata); final LockMetadataPair<M> oldPair = locks.putIfAbsent(path, newPair); final LockMetadataPair<M> mdPair = oldPair == null ? newPair : oldPair; synchronized (mdPair) { final ReentrantLock lock = mdPair.getLock(); final M oldMd = mdPair.getMetadata(); if (oldMd.equals(pathMetadata)) { lock.lock(); log.debug("srcdeps[{}]: Locked on thread level [{}]", requestId, path); return lockInFilesystem(requestId, path, lock); } else { if (lock.tryLock()) { log.debug("srcdeps[{}]: Locked on thread level [{}]", requestId, path); mdPair.setMetadata(pathMetadata); return lockInFilesystem(requestId, path, lock); } else { throw new CannotAcquireLockException( String.format("Path [%s] is locked by another thread for [%s]", path, oldPair)); } } } } }
PathLocker { public PathLock lockDirectory(String requestId, Path path, M pathMetadata) throws IOException, CannotAcquireLockException { SrcdepsCoreUtils.ensureDirectoryExists(path); final LockMetadataPair<M> newPair = new LockMetadataPair<M>(new ReentrantLock(), pathMetadata); final LockMetadataPair<M> oldPair = locks.putIfAbsent(path, newPair); final LockMetadataPair<M> mdPair = oldPair == null ? newPair : oldPair; synchronized (mdPair) { final ReentrantLock lock = mdPair.getLock(); final M oldMd = mdPair.getMetadata(); if (oldMd.equals(pathMetadata)) { lock.lock(); log.debug("srcdeps[{}]: Locked on thread level [{}]", requestId, path); return lockInFilesystem(requestId, path, lock); } else { if (lock.tryLock()) { log.debug("srcdeps[{}]: Locked on thread level [{}]", requestId, path); mdPair.setMetadata(pathMetadata); return lockInFilesystem(requestId, path, lock); } else { throw new CannotAcquireLockException( String.format("Path [%s] is locked by another thread for [%s]", path, oldPair)); } } } }  }
PathLocker { public PathLock lockDirectory(String requestId, Path path, M pathMetadata) throws IOException, CannotAcquireLockException { SrcdepsCoreUtils.ensureDirectoryExists(path); final LockMetadataPair<M> newPair = new LockMetadataPair<M>(new ReentrantLock(), pathMetadata); final LockMetadataPair<M> oldPair = locks.putIfAbsent(path, newPair); final LockMetadataPair<M> mdPair = oldPair == null ? newPair : oldPair; synchronized (mdPair) { final ReentrantLock lock = mdPair.getLock(); final M oldMd = mdPair.getMetadata(); if (oldMd.equals(pathMetadata)) { lock.lock(); log.debug("srcdeps[{}]: Locked on thread level [{}]", requestId, path); return lockInFilesystem(requestId, path, lock); } else { if (lock.tryLock()) { log.debug("srcdeps[{}]: Locked on thread level [{}]", requestId, path); mdPair.setMetadata(pathMetadata); return lockInFilesystem(requestId, path, lock); } else { throw new CannotAcquireLockException( String.format("Path [%s] is locked by another thread for [%s]", path, oldPair)); } } } }  PathLock lockDirectory(String requestId, Path path, M pathMetadata); }
PathLocker { public PathLock lockDirectory(String requestId, Path path, M pathMetadata) throws IOException, CannotAcquireLockException { SrcdepsCoreUtils.ensureDirectoryExists(path); final LockMetadataPair<M> newPair = new LockMetadataPair<M>(new ReentrantLock(), pathMetadata); final LockMetadataPair<M> oldPair = locks.putIfAbsent(path, newPair); final LockMetadataPair<M> mdPair = oldPair == null ? newPair : oldPair; synchronized (mdPair) { final ReentrantLock lock = mdPair.getLock(); final M oldMd = mdPair.getMetadata(); if (oldMd.equals(pathMetadata)) { lock.lock(); log.debug("srcdeps[{}]: Locked on thread level [{}]", requestId, path); return lockInFilesystem(requestId, path, lock); } else { if (lock.tryLock()) { log.debug("srcdeps[{}]: Locked on thread level [{}]", requestId, path); mdPair.setMetadata(pathMetadata); return lockInFilesystem(requestId, path, lock); } else { throw new CannotAcquireLockException( String.format("Path [%s] is locked by another thread for [%s]", path, oldPair)); } } } }  PathLock lockDirectory(String requestId, Path path, M pathMetadata);  }