BUG-7033: Add batchHint flag to RaftActor#persistData
[controller.git] / opendaylight / md-sal / cds-access-client / src / main / java / org / opendaylight / controller / cluster / access / client / InversibleLock.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.access.client;
9
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;
15
16 /**
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.
20  *
21  * @author Robert Varga
22  */
23 @Beta
24 public final class InversibleLock {
25     private static final AtomicReferenceFieldUpdater<InversibleLock, CountDownLatch> LATCH_UPDATER =
26             AtomicReferenceFieldUpdater.newUpdater(InversibleLock.class, CountDownLatch.class, "latch");
27
28     private final StampedLock lock = new StampedLock();
29     private volatile CountDownLatch latch;
30
31     /**
32      * Return a stamp for read validation.
33      *
34      * @return A stamp, which can be used with {@link #validate(long)}.
35      * @throws InversibleLockException if this lock is currently write-locked
36      */
37     public long optimisticRead() {
38         while (true) {
39             final long stamp = lock.tryOptimisticRead();
40             if (stamp != 0) {
41                 return stamp;
42             }
43
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;
47             if (local != null) {
48                 throw new InversibleLockException(latch);
49             }
50
51             // No latch present: retry optimistic lock
52         }
53     }
54
55     public boolean validate(final long stamp) {
56         return lock.validate(stamp);
57     }
58
59     public long writeLock() {
60         final CountDownLatch local = new CountDownLatch(1);
61         final boolean taken = LATCH_UPDATER.compareAndSet(this, null, local);
62         Verify.verify(taken);
63
64         return lock.writeLock();
65     }
66
67     public void unlockWrite(final long stamp) {
68         final CountDownLatch local = LATCH_UPDATER.getAndSet(this, null);
69         Verify.verifyNotNull(local);
70         lock.unlockWrite(stamp);
71         local.countDown();
72     }
73
74 }