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