2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.cluster.access.client;
10 import static com.google.common.base.Verify.verify;
11 import static com.google.common.base.Verify.verifyNotNull;
13 import java.lang.invoke.MethodHandles;
14 import java.lang.invoke.VarHandle;
15 import java.util.concurrent.CountDownLatch;
16 import java.util.concurrent.locks.StampedLock;
19 * A lock implementation which allows users to perform optimistic reads and validate them in a fashion similar
20 * to {@link StampedLock}. In case a read is contented with a write, the read side will throw
21 * an {@link InversibleLockException}, which the caller can catch and use to wait for the write to resolve.
23 public final class InversibleLock {
24 private static final VarHandle LATCH;
28 LATCH = MethodHandles.lookup().findVarHandle(InversibleLock.class, "latch", CountDownLatch.class);
29 } catch (NoSuchFieldException | IllegalAccessException e) {
30 throw new ExceptionInInitializerError(e);
34 private final StampedLock lock = new StampedLock();
36 private volatile CountDownLatch latch;
39 * Return a stamp for read validation.
41 * @return A stamp, which can be used with {@link #validate(long)}.
42 * @throws InversibleLockException if this lock is currently write-locked
44 public long optimisticRead() {
46 final long stamp = lock.tryOptimisticRead();
51 // Write-locked. Read the corresponding latch and if present report an exception, which will propagate
52 // and force release of locks.
53 final var local = latch;
55 throw new InversibleLockException(local);
58 // No latch present: retry optimistic lock
62 public boolean validate(final long stamp) {
63 return lock.validate(stamp);
66 public long writeLock() {
67 verify(LATCH.compareAndSet(this, null, new CountDownLatch(1)));
68 return lock.writeLock();
71 public void unlockWrite(final long stamp) {
72 final CountDownLatch local = (CountDownLatch) LATCH.getAndSet(this, null);
74 lock.unlockWrite(stamp);