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 com.google.common.annotations.Beta;
11 import com.google.common.base.Verify;
12 import java.util.concurrent.CountDownLatch;
13 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
14 import java.util.concurrent.locks.StampedLock;
17 * A lock implementation which allows users to perform optimistic reads and validate them in a fashion similar
18 * to {@link StampedLock}. In case a read is contented with a write, the read side will throw
19 * an {@link InversibleLockException}, which the caller can catch and use to wait for the write to resolve.
21 * @author Robert Varga
24 public final class InversibleLock {
25 private static final AtomicReferenceFieldUpdater<InversibleLock, CountDownLatch> LATCH_UPDATER =
26 AtomicReferenceFieldUpdater.newUpdater(InversibleLock.class, CountDownLatch.class, "latch");
28 private final StampedLock lock = new StampedLock();
29 private volatile CountDownLatch latch;
32 * Return a stamp for read validation.
34 * @return A stamp, which can be used with {@link #validate(long)}.
35 * @throws InversibleLockException if this lock is currently write-locked
37 public long optimisticRead() {
39 final long stamp = lock.tryOptimisticRead();
44 // Write-locked. Read the corresponding latch and if present report an exception, which will propagate
45 // and force release of locks.
46 final CountDownLatch local = latch;
48 throw new InversibleLockException(local);
51 // No latch present: retry optimistic lock
55 public boolean validate(final long stamp) {
56 return lock.validate(stamp);
59 public long writeLock() {
60 final CountDownLatch local = new CountDownLatch(1);
61 final boolean taken = LATCH_UPDATER.compareAndSet(this, null, local);
64 return lock.writeLock();
67 public void unlockWrite(final long stamp) {
68 final CountDownLatch local = LATCH_UPDATER.getAndSet(this, null);
69 Verify.verifyNotNull(local);
70 lock.unlockWrite(stamp);