53
53
import java .util .Map ;
54
54
import java .util .Map .Entry ;
55
55
import java .util .concurrent .atomic .AtomicBoolean ;
56
- import java .util .concurrent .locks .ReadWriteLock ;
57
- import java .util .concurrent .locks .ReentrantReadWriteLock ;
56
+ import java .util .concurrent .locks .StampedLock ;
58
57
import javax .annotation .Nullable ;
59
58
60
59
import static com .google .common .base .Preconditions .checkNotNull ;
@@ -77,8 +76,8 @@ public class PlatformManager {
77
76
private final AtomicBoolean initialized = new AtomicBoolean ();
78
77
private final AtomicBoolean configured = new AtomicBoolean ();
79
78
80
- private final ReadWriteLock platformsLock = new ReentrantReadWriteLock ();
81
- private final ReadWriteLock preferencesLock = new ReentrantReadWriteLock ();
79
+ private final StampedLock platformsLock = new StampedLock ();
80
+ private final StampedLock preferencesLock = new StampedLock ();
82
81
83
82
/**
84
83
* Create a new platform manager.
@@ -106,11 +105,11 @@ public void register(Platform platform) {
106
105
107
106
// Just add the platform to the list of platforms: we'll pick favorites
108
107
// once all the platforms have been loaded
109
- platformsLock .writeLock (). lock ();
108
+ long stamp = platformsLock .writeLock ();
110
109
try {
111
110
platforms .add (platform );
112
111
} finally {
113
- platformsLock .writeLock (). unlock ( );
112
+ platformsLock .unlockWrite ( stamp );
114
113
}
115
114
116
115
// Make sure that versions are in sync
@@ -137,40 +136,40 @@ public boolean unregister(Platform platform) {
137
136
checkNotNull (platform );
138
137
139
138
boolean removed ;
140
- platformsLock .writeLock (). lock ();
139
+ long platformsStamp = platformsLock .writeLock ();
141
140
142
141
try {
143
142
removed = platforms .remove (platform );
143
+ } finally {
144
+ platformsLock .unlockWrite (platformsStamp );
145
+ }
144
146
145
- if (removed ) {
146
- LOGGER .info ("Unregistering " + platform .getClass ().getCanonicalName () + " from WorldEdit" );
147
+ if (removed ) {
148
+ LOGGER .info ("Unregistering " + platform .getClass ().getCanonicalName () + " from WorldEdit" );
147
149
148
- boolean choosePreferred = false ;
150
+ boolean choosePreferred = false ;
149
151
150
- preferencesLock .writeLock (). lock ();
152
+ long preferencesStamp = preferencesLock .writeLock ();
151
153
152
- try {
153
- // Check whether this platform was chosen to be the preferred one
154
- // for any capability and be sure to remove it
155
- Iterator <Entry <Capability , Platform >> it = preferences .entrySet ().iterator ();
156
- while (it .hasNext ()) {
157
- Entry <Capability , Platform > entry = it .next ();
158
- if (entry .getValue ().equals (platform )) {
159
- entry .getKey ().uninitialize (this , entry .getValue ());
160
- it .remove ();
161
- choosePreferred = true ; // Have to choose new favorites
162
- }
154
+ try {
155
+ // Check whether this platform was chosen to be the preferred one
156
+ // for any capability and be sure to remove it
157
+ Iterator <Entry <Capability , Platform >> it = preferences .entrySet ().iterator ();
158
+ while (it .hasNext ()) {
159
+ Entry <Capability , Platform > entry = it .next ();
160
+ if (entry .getValue ().equals (platform )) {
161
+ entry .getKey ().uninitialize (this , entry .getValue ());
162
+ it .remove ();
163
+ choosePreferred = true ; // Have to choose new favorites
163
164
}
164
- } finally {
165
- preferencesLock .writeLock ().unlock ();
166
165
}
166
+ } finally {
167
+ preferencesLock .unlockWrite (preferencesStamp );
168
+ }
167
169
168
- if (choosePreferred ) {
169
- choosePreferred ();
170
- }
170
+ if (choosePreferred ) {
171
+ choosePreferred ();
171
172
}
172
- } finally {
173
- platformsLock .writeLock ().unlock ();
174
173
}
175
174
176
175
return removed ;
@@ -184,24 +183,33 @@ public boolean unregister(Platform platform) {
184
183
* @throws NoCapablePlatformException thrown if no platform is capable
185
184
*/
186
185
public Platform queryCapability (Capability capability ) throws NoCapablePlatformException {
187
- preferencesLock .readLock ().lock ();
186
+ checkNotNull (capability );
187
+
188
+ long stamp = preferencesLock .tryOptimisticRead ();
189
+ Platform platform = preferences .get (capability );
190
+ boolean hasNoPreferences = platform == null && preferences .isEmpty ();
191
+
192
+ if (!preferencesLock .validate (stamp )) {
193
+ stamp = preferencesLock .readLock ();
194
+ try {
195
+ platform = preferences .get (capability );
196
+ hasNoPreferences = platform == null && preferences .isEmpty ();
197
+ } finally {
198
+ preferencesLock .unlockRead (stamp );
199
+ }
200
+ }
188
201
189
- try {
190
- Platform platform = preferences .get (checkNotNull (capability ));
191
- if (platform != null ) {
192
- return platform ;
193
- } else {
194
- if (preferences .isEmpty ()) {
195
- // Not all platforms registered, this is being called too early!
196
- throw new NoCapablePlatformException (
197
- "Not all platforms have been registered yet!"
198
- + " Please wait until WorldEdit is initialized."
199
- );
200
- }
201
- throw new NoCapablePlatformException ("No platform was found supporting " + capability .name ());
202
+ if (platform != null ) {
203
+ return platform ;
204
+ } else {
205
+ if (hasNoPreferences ) {
206
+ // Not all platforms registered, this is being called too early!
207
+ throw new NoCapablePlatformException (
208
+ "Not all platforms have been registered yet!"
209
+ + " Please wait until WorldEdit is initialized."
210
+ );
202
211
}
203
- } finally {
204
- preferencesLock .readLock ().unlock ();
212
+ throw new NoCapablePlatformException ("No platform was found supporting " + capability .name ());
205
213
}
206
214
}
207
215
@@ -212,31 +220,37 @@ private void choosePreferred() {
212
220
for (Capability capability : Capability .values ()) {
213
221
Platform preferred = findMostPreferred (capability );
214
222
if (preferred != null ) {
215
- preferencesLock .writeLock ().lock ();
223
+ Platform oldPreferred ;
224
+ long stamp = preferencesLock .writeLock ();
216
225
try {
217
- Platform oldPreferred = preferences .put (capability , preferred );
218
- // only (re)initialize if it changed
219
- if (preferred != oldPreferred ) {
220
- // uninitialize if needed
221
- if (oldPreferred != null ) {
222
- capability .uninitialize (this , oldPreferred );
223
- }
224
- capability .initialize (this , preferred );
225
- }
226
+ oldPreferred = preferences .put (capability , preferred );
226
227
} finally {
227
- preferencesLock .writeLock ().unlock ();
228
+ preferencesLock .unlockWrite (stamp );
229
+ }
230
+ // only (re)initialize if it changed
231
+ if (preferred != oldPreferred ) {
232
+ // uninitialize if needed
233
+ if (oldPreferred != null ) {
234
+ capability .uninitialize (this , oldPreferred );
235
+ }
236
+ capability .initialize (this , preferred );
228
237
}
229
238
}
230
239
}
231
240
232
- preferencesLock .readLock ().lock ();
233
- try {
234
- // Fire configuration event
235
- if (preferences .containsKey (Capability .CONFIGURATION ) && configured .compareAndSet (false , true )) {
236
- worldEdit .getEventBus ().post (new ConfigurationLoadEvent (queryCapability (Capability .CONFIGURATION ).getConfiguration ()));
241
+ long stamp = preferencesLock .tryOptimisticRead ();
242
+ boolean hasConfiguration = preferences .containsKey (Capability .CONFIGURATION );
243
+ if (!preferencesLock .validate (stamp )) {
244
+ stamp = preferencesLock .readLock ();
245
+ try {
246
+ hasConfiguration = preferences .containsKey (Capability .CONFIGURATION );
247
+ } finally {
248
+ preferencesLock .unlockRead (stamp );
237
249
}
238
- } finally {
239
- preferencesLock .readLock ().unlock ();
250
+ }
251
+ // Fire configuration event
252
+ if (hasConfiguration && configured .compareAndSet (false , true )) {
253
+ worldEdit .getEventBus ().post (new ConfigurationLoadEvent (queryCapability (Capability .CONFIGURATION ).getConfiguration ()));
240
254
}
241
255
}
242
256
@@ -270,12 +284,18 @@ private void choosePreferred() {
270
284
* @return a list of platforms
271
285
*/
272
286
public List <Platform > getPlatforms () {
273
- platformsLock .readLock ().lock ();
274
- try {
275
- return new ArrayList <>(platforms );
276
- } finally {
277
- platformsLock .readLock ().unlock ();
287
+ long stamp = platformsLock .tryOptimisticRead ();
288
+ List <Platform > platformsCopy = new ArrayList <>(platforms );
289
+ if (!platformsLock .validate (stamp )) {
290
+ stamp = platformsLock .readLock ();
291
+ try {
292
+ platformsCopy = new ArrayList <>(platforms );
293
+ } finally {
294
+ platformsLock .unlockRead (stamp );
295
+ }
278
296
}
297
+
298
+ return platformsCopy ;
279
299
}
280
300
281
301
/**
0 commit comments