package cn.reghao.tnb.sb.zk.lock;

import cn.reghao.tnb.sb.zk.redis.RedisManager;

/**
 * Redis 分布式锁
 * TODO 实现公平锁
 *
 * @author reghao
 * @date 2019-12-16 09:36:18
 */
public class RedisLock extends DistributedLock {
    private final String lockLua = "local result = redis.call('setnx', KEYS[1], ARGV[1])\n" +
            "if result == 1 then redis.call('expire', KEYS[1], tonumber(ARGV[2]))\n" +
            "return 1 else return 0 end";
    private final String unlockLua = "if redis.call('get',KEYS[1]) == ARGV[1]\n" +
            "then if redis.call('del',KEYS[1]) then return 1 end\n" +
            "else return 0 end";

    public RedisLock(RedisManager redisManager) {
        super(redisManager.redisCommand(), "UrlSchedulerKeys.spiderLock");
    }

    @Override
    public void lock() {
        setLockValue(Thread.currentThread().getName() + "@" + System.currentTimeMillis());
        String timeout = "10";
        String[] keys = new String[] {lockKey.get()};
        String[] values = new String[] {lockValue.get(), timeout};
        boolean ret = commandOps.eval(lockLua, keys, values);
        while (!ret) {
            System.out.printf("线程 %s 获取 Redis 锁失败，休眠 1s 后再获取...\n", Thread.currentThread().getName());
            try {
                Thread.sleep(1_000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ret = commandOps.eval(lockLua, keys, values);
        }
    }

    @Override
    public void unlock() {
        String[] keys = new String[] {lockKey.get()};
        String[] values = new String[] {lockValue.get()};
        boolean ret = commandOps.eval(unlockLua, keys, values);
        if (!ret) {
            System.out.printf("线程 %s 释放 Redis 锁失败...\n", Thread.currentThread().getName());
        }
    }
}
