com.griddynamics.jagger.coordinator.zookeeper.DefaultZNodeLock.java Source code

Java tutorial

Introduction

Here is the source code for com.griddynamics.jagger.coordinator.zookeeper.DefaultZNodeLock.java

Source

/*
 * Copyright (c) 2010-2012 Grid Dynamics Consulting Services, Inc, All Rights Reserved
 * http://www.griddynamics.com
 *
 * This library is free software; you can redistribute it and/or modify it under the terms of
 * the GNU Lesser General Public License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.griddynamics.jagger.coordinator.zookeeper;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;

import java.util.List;
import java.util.concurrent.CountDownLatch;

import static com.griddynamics.jagger.coordinator.zookeeper.Zoo.znode;

/**
 * Lock implementation as described at {@see http://zookeeper.apache.org/doc/r3.1.2/recipes.html#sc_recipes_Locks}.
 * <span color="#ff0000">In progress. May cause a deadlocks!</span>
 */
public class DefaultZNodeLock implements ZNodeLock {
    private final ZNode node;

    private final String lockPath;

    private ZNode lockNode;

    public DefaultZNodeLock(ZNode node) {
        this(node, "lock");
    }

    public DefaultZNodeLock(ZNode node, String lockPath) {
        this.node = node;
        this.lockPath = lockPath;
    }

    private ZNode lockDir() {
        return node.child(lockPath);
    }

    @Override
    public void makeLockable() {
        node.createChild(znode().withPath(lockPath));
    }

    @Override
    public boolean isLockable() {
        return node.hasChild(lockPath);
    }

    @Override
    public void lock() {
        while (true) {
            ZNode node = lockDir().createChild(znode().ephemeralSequential());

            final String currentNodeName = node.getShortPath();
            int currentFlag = Integer.valueOf(currentNodeName);

            final List<ZNode> children = lockDir().children();
            int lowestNodeVal = Integer.MAX_VALUE;
            int nextNodeFlag = -1;
            String nextNodePath = null;

            for (ZNode child : children) {
                String childPath = child.getShortPath();
                int childFlag = Integer.valueOf(childPath);

                if (childFlag < lowestNodeVal) {
                    lowestNodeVal = childFlag;
                }

                if (childFlag < currentFlag && childFlag > nextNodeFlag) {
                    nextNodeFlag = childFlag;
                    nextNodePath = childPath;
                }
            }

            if (currentFlag == lowestNodeVal) {
                lockNode = node;
                break;
            }

            final CountDownLatch signal = new CountDownLatch(1);
            boolean hasChild = lockDir().hasChild(nextNodePath, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    signal.countDown();
                }
            });

            if (hasChild) {
                lockNode = node;

                try {
                    signal.await();
                    break;
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

            node.remove();
        }
    }

    @Override
    public void unlock() {
        if (lockNode == null) {
            return;
        }

        lockNode.remove();

    }
}