1 package com.atlassian.plugin.manager.store;
2
3 import com.atlassian.annotations.Internal;
4 import com.atlassian.plugin.manager.PluginPersistentState;
5 import com.atlassian.plugin.manager.PluginPersistentStateStore;
6 import com.atlassian.util.concurrent.ManagedLock;
7 import com.atlassian.util.concurrent.ManagedLocks;
8 import com.atlassian.util.concurrent.Supplier;
9 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory;
11
12 import java.util.concurrent.TimeUnit;
13 import java.util.concurrent.atomic.AtomicInteger;
14 import java.util.concurrent.locks.Condition;
15 import java.util.concurrent.locks.Lock;
16 import java.util.concurrent.locks.ReadWriteLock;
17 import java.util.concurrent.locks.ReentrantLock;
18 import java.util.concurrent.locks.ReentrantReadWriteLock;
19
20 import static com.atlassian.plugin.util.EnumUtils.enumValueFromProperty;
21 import static com.google.common.base.Preconditions.checkNotNull;
22
23
24
25
26
27
28
29
30
31 public class SynchronizedPluginPersistentStateStore implements PluginPersistentStateStore {
32 private static final Logger log = LoggerFactory.getLogger(SynchronizedPluginPersistentStateStore.class);
33
34 @Internal
35 public enum LockMode {
36 UNLOCKED {
37 @Override
38 ReadWriteLock getReadWriteLock() {
39 return new CommonReadWriteLock(new NoOpLock());
40 }
41 },
42 SIMPLE {
43 @Override
44 ReadWriteLock getReadWriteLock() {
45 return new CommonReadWriteLock(new ReentrantLock());
46 }
47
48 },
49 FAIRSIMPLE {
50 @Override
51 ReadWriteLock getReadWriteLock() {
52 return new CommonReadWriteLock(new ReentrantLock(true));
53 }
54 },
55 READWRITE {
56 @Override
57 ReadWriteLock getReadWriteLock() {
58 return new ReentrantReadWriteLock();
59 }
60 },
61 FAIRREADWRITE {
62 @Override
63 ReadWriteLock getReadWriteLock() {
64 return new ReentrantReadWriteLock(true);
65 }
66 };
67
68 private static final String PROPERTY_NAME = SynchronizedPluginPersistentStateStore.class.getName() + ".lockMode";
69
70 static LockMode current() {
71 return enumValueFromProperty(PROPERTY_NAME, LockMode.values(), LockMode.READWRITE);
72 }
73
74 abstract ReadWriteLock getReadWriteLock();
75
76 }
77
78 @Internal
79 public static String getLockModeProperty() {
80 return LockMode.PROPERTY_NAME;
81 }
82
83 private final PluginPersistentStateStore delegate;
84 private final ManagedLock.ReadWrite lock;
85 private final AtomicInteger loadConcurrency = new AtomicInteger(0);
86 private final AtomicInteger saveConcurrency = new AtomicInteger(0);
87
88 public SynchronizedPluginPersistentStateStore(final PluginPersistentStateStore delegate) {
89 this(delegate, LockMode.current().getReadWriteLock());
90 }
91
92 public SynchronizedPluginPersistentStateStore(final PluginPersistentStateStore delegate, final ReadWriteLock lock) {
93 this.delegate = checkNotNull(delegate);
94 this.lock = ManagedLocks.manageReadWrite(checkNotNull(lock));
95 }
96
97 @Override
98 public void save(final PluginPersistentState state) {
99 final int writes = saveConcurrency.incrementAndGet();
100 log.debug("save concurrency {}", writes);
101 lock.write().withLock(new Runnable() {
102 @Override
103 public void run() {
104 delegate.save(state);
105 }
106 });
107 saveConcurrency.decrementAndGet();
108 }
109
110 @Override
111 public PluginPersistentState load() {
112 final int reads = loadConcurrency.incrementAndGet();
113 log.debug("load concurrency {}", reads);
114 final PluginPersistentState pluginPersistentState = lock.read().withLock(new Supplier<PluginPersistentState>() {
115 @Override
116 public PluginPersistentState get() {
117 return delegate.load();
118 }
119 });
120 loadConcurrency.decrementAndGet();
121 return pluginPersistentState;
122 }
123
124 static class NoOpLock implements Lock {
125 @Override
126 public void lock() {
127 }
128
129 @Override
130 public void lockInterruptibly() {
131 }
132
133 @Override
134 public boolean tryLock() {
135 return true;
136 }
137
138 @Override
139 public boolean tryLock(final long time, final TimeUnit unit) {
140 return true;
141 }
142
143 @Override
144 public void unlock() {
145 }
146
147 @Override
148 public Condition newCondition() {
149 throw new UnsupportedOperationException("Not implemented");
150 }
151 }
152
153 static class CommonReadWriteLock implements ReadWriteLock {
154 private final Lock lock;
155
156 public CommonReadWriteLock(final Lock lock) {
157 this.lock = lock;
158 }
159
160 @Override
161 public Lock readLock() {
162 return lock;
163 }
164
165 @Override
166 public Lock writeLock() {
167 return lock;
168 }
169 }
170 }