Curator源码笔记学习2 Curator DistributedAtomicInteger

DistributedAtomicInteger 提供分布式的计数器

使用方法


object AtomicInt extends App {

  val PATH = "/atomicInt"

  curatorContext { client =>
    val atomicInt = new DistributedAtomicInteger(client,
      PATH, new RetryNTimes(3, 1000))

    val res = atomicInt.add(8)
    println(s"Result: ${res.preValue()} ${res.postValue()}")
  }
}

原理解析


DistributedAtomicInteger 整体来说不难。
其内部只有一个成员变量

private final DistributedAtomicValue value;

其实它的所有操作其实都是调用的DistributedAtomicValue的方法。

值的修改


DistributedAtomicInteger 的 add、subtract、decrement、increment 其实都是调用的 DistributedAtomicInteger 的 worker方法,而在worker里面核心又是调用的 DistributedAtomicValue 的 trySet方法

private AtomicValue<Integer> worker(final Integer addAmount) throws Exception {
        Preconditions.checkNotNull(addAmount, "addAmount cannot be null");

        MakeValue makeValue = new MakeValue() {
            @Override
            public byte[] makeFrom(byte[] previous) {
                int previousValue = (previous != null) ? bytesToValue(previous) : 0;
                int newValue = previousValue + addAmount;
                return valueToBytes(newValue);
            }
        };

        AtomicValue<byte[]> result = value.trySet(makeValue);
        return new AtomicInteger(result);
}

MakeValue 告诉了 DistributedAtomicValue 如何将原来的值变成现在要设置的值,这里实现了加法

DistributedAtomicValue.trySet


 public AtomicValue<byte[]> trySet(final byte[] newValue) throws Exception {
        MutableAtomicValue<byte[]> result = new MutableAtomicValue<byte[]>(null, null, false);

        MakeValue makeValue = new MakeValue() {
            @Override
            public byte[] makeFrom(byte[] previous) {
                return newValue;
            }
        };
        tryOptimistic(result, makeValue);
        if (!result.succeeded() && (mutex != null)) {
            tryWithMutex(result, makeValue);
        }

        return result;
    }
  • 首先,试图通过乐观锁设置值(通过版本号)
  • 然后,如果通过乐观锁设置失败了,且提供了锁,则再次尝试通过在乐观锁的基础上再加一个悲观锁(代码里面将这种锁成为promoted lock)更新值
  • Result 描述了操作是否成功,上次的值和新的值,以及AtomicStats
  • AtomicStats 包含了乐观锁的尝试次数,使用时间;提升锁(promoted lock)的尝试次数,使用时间

DistributedAtomicValue.tryOptimistic(乐观锁修改)


private void tryOptimistic(MutableAtomicValue<byte[]> result, MakeValue makeValue) throws Exception {
    long startMs = System.currentTimeMillis();
    int retryCount = 0;

    boolean done = false;
    while (!done) {
        result.stats.incrementOptimisticTries();
        // 尝试修改一次
        // tryOnce用的是version保证的原子性
        if (tryOnce(result, makeValue)) {
            result.succeeded = true;
            done = true;
        } else {
        	// 判断是否需要重试
            if (!retryPolicy.allowRetry(retryCount++, System.currentTimeMillis() - startMs, RetryLoop.getDefaultRetrySleeper())) {
                done = true;
            }
        }
    }

    result.stats.setOptimisticTimeMs(System.currentTimeMillis() - startMs);
}

逻辑很简单,主要是调用的tryOnce进行的值的修改

DistributedAtomicValue.tryWithMutex(加锁修改)


private void tryWithMutex(MutableAtomicValue<byte[]> result, MakeValue makeValue) throws Exception {
    long startMs = System.currentTimeMillis();
    int retryCount = 0;
    
    // 相对于tryOptimistic多了一个获取锁的操作
    if (mutex.acquire(promotedToLock.getMaxLockTime(), promotedToLock.getMaxLockTimeUnit())) {
        try {
            boolean done = false;
            while (!done) {
                result.stats.incrementPromotedTries();
                if (tryOnce(result, makeValue)) {
                    result.succeeded = true;
                    done = true;
                } else {
                    if (!promotedToLock.getRetryPolicy().allowRetry(retryCount++, System.currentTimeMillis() - startMs, RetryLoop.getDefaultRetrySleeper())) {
                        done = true;
                    }
                }
            }
        } finally {
            mutex.release();
        }
    }

    result.stats.setPromotedTimeMs(System.currentTimeMillis() - startMs);
}

DistributedAtomicValue.tryOnce(真正的值的修改)


private boolean tryOnce(MutableAtomicValue<byte[]> result, MakeValue makeValue) throws Exception {
    Stat stat = new Stat();
    // 将当前值和节点信息获取到result和stat中,并获取是否需要创建节点
    boolean createIt = getCurrentValue(result, stat);

    boolean success = false;
    try {
        // 通过旧值,获得新值
        byte[] newValue = makeValue.makeFrom(result.preValue);
        if (createIt) {
            // 节点不存在,则创建并初始化值
            client.create().creatingParentContainersIfNeeded().forPath(path, newValue);
        } else {
            // 节点存在,通过版本修改值
            client.setData().withVersion(stat.getVersion()).forPath(path, newValue);
        }
        result.postValue = Arrays.copyOf(newValue, newValue.length);
        success = true;
    } catch (KeeperException.NodeExistsException e) {
        // 捕获异常并忽略,让外面的方法根据重试策略重试
    } catch (KeeperException.BadVersionException e) {
        // 捕获异常并忽略,让外面的方法根据重试策略重试
    } catch (KeeperException.NoNodeException e) {
        // 捕获异常并忽略,让外面的方法根据重试策略重试
    }

    return success;
}

值的获取


值的获取没有什么特别的,仅仅就是通过getData获取而已

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值