All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.bdeploy.bhive.op.LockDirectoryOperation Maven / Gradle / Ivy

Go to download

Public API including dependencies, ready to be used for integrations and plugins.

There is a newer version: 7.3.6
Show newest version
package io.bdeploy.bhive.op;

import static io.bdeploy.common.util.RuntimeAssert.assertNotNull;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.bdeploy.bhive.BHive;
import io.bdeploy.common.util.StringHelper;
import io.bdeploy.common.util.Threads;

/**
 * Lock a directory. The operations waits for an already existing lock to disappear before proceeding (max 1000 seconds, ~16
 * minutes). This means only a single lock can exist (intra- and inter-VM).
 *
 * @see ReleaseDirectoryLockOperation
 * @see AwaitDirectoryLockOperation
 */
public class LockDirectoryOperation extends BHive.Operation {

    private static final Logger log = LoggerFactory.getLogger(LockDirectoryOperation.class);

    static final String LOCK_FILE = ".lock";

    private Path directory;

    @Override
    public Void call() throws Exception {
        assertNotNull(directory, "No directory to lock.");

        Path lockFile = directory.resolve(LOCK_FILE);

        String content = "";
        if (getLockContentSupplier() != null) {
            content = getLockContentSupplier().get();
        }

        boolean infoWritten = false;
        for (int i = 0; i < 100_000; ++i) {
            try {
                Files.write(lockFile, Collections.singletonList(content), StandardOpenOption.CREATE_NEW, StandardOpenOption.SYNC)
                        .toFile().deleteOnExit();
                return null;
            } catch (IOException e) {
                // validate to find stale lock files
                if (!isLockFileValid(lockFile, getLockContentValidator())) {
                    continue;
                }
                // inform the user that we're about to wait...
                if (!infoWritten) {
                    log.info("Waiting for {}", directory);
                    infoWritten = true;
                }
                // delay a little...
                if (!Threads.sleep(10)) {
                    break;
                }
            } catch (Exception e) {
                throw new IllegalStateException("Cannot lock root", e);
            }
        }
        throw new IllegalStateException("Retries exceeded or interrupted while waiting to lock " + lockFile
                + ". Please check manually if another process is still running and delete the lock file manually.");
    }

    /**
     * Sets the directory that should be locked.
     */
    public LockDirectoryOperation setDirectory(Path directory) {
        this.directory = directory;
        return this;
    }

    /** Validates whether or not the given lock file is still valid */
    static boolean isLockFileValid(Path lockFile, Predicate lockContentValidator) {
        // No content validator. Assuming the lock is still valid
        if (lockContentValidator == null) {
            return true;
        }

        // Read the lock file to check if the content is still valid
        try {
            List lines = Files.readAllLines(lockFile);
            if (!lines.isEmpty() && !StringHelper.isNullOrEmpty(lines.get(0)) && !lockContentValidator.test(lines.get(0))) {
                log.warn("Stale lock file detected, forcefully resolving...");
                Files.delete(lockFile);
                return false;
            }
            return true;
        } catch (NoSuchFileException | FileNotFoundException fne) {
            return false;
        } catch (IOException ve) {
            log.warn("Cannot validate lock file, assuming it is valid: {}: {}", lockFile, ve.toString());
            return true;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy