@VisibleForTesting
    static File doUnpackNar(final File nar, final File baseWorkingDirectory, Runnable extractCallback)
            throws IOException {
        File parentDirectory = new File(baseWorkingDirectory, nar.getName() + "-unpacked");
        if (!parentDirectory.exists()) {
            if (parentDirectory.mkdirs()) {
                log.info("Created directory {}", parentDirectory);
            } else if (!parentDirectory.exists()) {
                throw new IOException("Cannot create " + parentDirectory);
            }
        }
        String md5Sum = Base64.getUrlEncoder().withoutPadding().encodeToString(calculateMd5sum(nar));
        // ensure that one process can extract the files
        File lockFile = new File(parentDirectory, "." + md5Sum + ".lock");
        // prevent OverlappingFileLockException by ensuring that one thread tries to create a lock in this JVM
        Object localLock = CURRENT_JVM_FILE_LOCKS.computeIfAbsent(lockFile.getAbsolutePath(), key -> new Object());
        synchronized (localLock) {
            // create file lock that ensures that other processes
            // using the same lock file don't execute concurrently
            try (FileChannel channel = new RandomAccessFile(lockFile, "rw").getChannel();
                 FileLock lock = channel.lock()) {
                File narWorkingDirectory = new File(parentDirectory, md5Sum);
                if (narWorkingDirectory.mkdir()) {
                    try {
                        log.info("Extracting {} to {}", nar, narWorkingDirectory);
                        if (extractCallback != null) {
                            extractCallback.run();
                        }
                        unpack(nar, narWorkingDirectory);
                    } catch (IOException e) {
                        log.error("There was a problem extracting the nar file. Deleting {} to clean up state.",
                                narWorkingDirectory, e);
                        FileUtils.deleteFile(narWorkingDirectory, true);
                        throw e;
                    }
                }
                return narWorkingDirectory;
            }
        }
    }
@Test
    void shouldExtractFilesOnceInSameProcess() throws InterruptedException {
        int threads = 20;
        CountDownLatch countDownLatch = new CountDownLatch(threads);
        AtomicInteger exceptionCounter = new AtomicInteger();
        AtomicInteger extractCounter = new AtomicInteger();
        for (int i = 0; i < threads; i++) {
            new Thread(() -> {
                try {
                    NarUnpacker.doUnpackNar(sampleZipFile, extractDirectory, extractCounter::incrementAndGet);
                } catch (Exception e) {
                    log.error("Unpacking failed", e);
                    exceptionCounter.incrementAndGet();
                } finally {
                    countDownLatch.countDown();
                }
            }).start();
        }
        assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
        assertEquals(exceptionCounter.get(), 0);
        assertEquals(extractCounter.get(), 1);
    }