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

ai.grakn.engine.lock.JedisLock Maven / Gradle / Ivy

There is a newer version: 1.4.3
Show newest version
/*
 * Grakn - A Distributed Semantic Database
 * Copyright (C) 2016-2018 Grakn Labs Limited
 *
 * Grakn is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Grakn is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Grakn. If not, see .
 */

package ai.grakn.engine.lock;

import com.google.common.base.Preconditions;
import redis.clients.jedis.Jedis;
import redis.clients.util.Pool;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Wrapper for Jedis lock
 *
 * @author Domenico Corapi
 */
public class JedisLock implements Lock {

    private static final long TIMEOUT_MS = 10_000L;
    private final String lockName;
    // Name of the lock
    private String internalLockName;

    // Lock expiration in miliseconds.
    private int expireMsecs = 60_000;

    private boolean locked = false;
    private Pool jedis;
    private Lock lock = new ReentrantLock();

    public JedisLock(Pool jedis, String internalLockName) {
        Preconditions.checkNotNull(jedis,"JedisPool used in lock cannot be null");
        Preconditions.checkArgument(internalLockName != null && !internalLockName.isEmpty(),"Lock name not valid");
        this.jedis = jedis;
        this.lockName = internalLockName;
        this.internalLockName = "lock:" + internalLockName;
    }

    @Override
    public void lock() {
        try {
            lockInterruptibly();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        try(Jedis r = jedis.getResource()) {
            acquire(r, TIMEOUT_MS);
        }
    }

    @Override
    public boolean tryLock() {
        try(Jedis r = jedis.getResource()) {
            return tryOnce(r);
        }
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        Preconditions.checkNotNull(unit);
        long timeout = unit.convert(time, TimeUnit.MILLISECONDS);
        try(Jedis r = jedis.getResource()) {
            return acquire(r, timeout);
        }
    }

    @Override
    public void unlock() {
        try(Jedis r = jedis.getResource()) {
            release(r);
        }
    }

    @Override
    public Condition newCondition() {
        // TODO
        throw new RuntimeException("Not implemented");
    }

    private boolean acquire(Jedis jedis, long timeout) throws InterruptedException {
            while (timeout >= 0) {
                lock.lock();
                try{
                    if (tryOnce(jedis)) {
                        return true;
                    }
                } finally {
                    lock.unlock();
                }
                timeout -= 100;
                Thread.sleep(100);
            }
            return false;
    }

    private boolean tryOnce(Jedis jedis) {
        long expires = System.currentTimeMillis() + expireMsecs + 1;
        String expiresStr = String.valueOf(expires);

        lock.lock();
        try{
            if (jedis.setnx(internalLockName, expiresStr) == 1) {
                // lock acquired
                locked = true;
                return true;
            }
        } finally {
            lock.unlock();
        }

        String currentValueStr = jedis.get(internalLockName);
        if (currentValueStr != null && Long.parseLong(currentValueStr) < System
                .currentTimeMillis()) {
            // lock is expired
            lock.lock();
            try{
                String oldValueStr = jedis.getSet(internalLockName, expiresStr);
                if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
                    // lock acquired
                    locked = true;
                    return true;
                }
            } finally {
                lock.unlock();
            }
        }
        return false;
    }

    private  void release(Jedis jedis) {
        lock.lock();
        try {
            if (locked) {
                jedis.del(internalLockName);
                locked = false;
            }
        } finally {
            lock.unlock();
        }
    }

    public String getLockName() {
        return lockName;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy