Repository navigation
Make FakeValuesService thread safe - #770
Conversation
Codecov Report
📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more @@ Coverage Diff @@
## main #770 +/- ##
============================================
- Coverage 92.54% 92.27% -0.28%
- Complexity 2654 2662 +8
============================================
Files 286 287 +1
Lines 5274 5309 +35
Branches 553 552 -1
============================================
+ Hits 4881 4899 +18
- Misses 252 269 +17
Partials 141 141
... and 1 file with indirect coverage changes 📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
|
that's still a tricky part to create a 100% reproducible test for failing non thread safe FakeValuesService... |
|
Would this be something @rwong-gw could maybe help validate? |
|
For the past couple days, I have been using CI to run my Gatling tests every half hour with this version, and everything looks good, with no hanging or deadlocks. One suggestion: |
|
makes sense, added implementation |
| private static final Logger LOG = Logger.getLogger("faker"); | ||
|
|
||
| private final Map<SingletonLocale, FakeValuesInterface> fakeValuesInterfaceMap = new IdentityHashMap<>(); | ||
| private final StampedLockMap<SingletonLocale, FakeValuesInterface> fakeValuesInterfaceMap = new StampedLockMap<>(IdentityHashMap::new); |
There was a problem hiding this comment.
As we don't use any StampedLockMap specific functions, isn't it better to keep type unchanged (as Map) ?
There was a problem hiding this comment.
yes, for some of them it makes sense, for some not since there is updateNestedValue method specific for StampedLockMap
| } finally { | ||
| lock.unlockRead(stamp); | ||
| } | ||
| } |
There was a problem hiding this comment.
Why don't you reuse doROOperation function here? Looks like a duplicate of code...
There was a problem hiding this comment.
in fact it was kind of test version...
As measurement shows here it's that rare case when code duplication wins. With doROOperation it becomes 10% slower.... The reason is that it requires Supplier object which is generated during runtime. Without this method and this object generation there is no need for that extra object.
|
Funny thing is that I finally adapted the test from #759 attached by @rwong-gw At the same time another option I had in mind was CopyOnWriteMaps ( So I replaced it with @kingthorin so at least one test is added |
| } | ||
|
|
||
| @Override | ||
| public V put(K key, V value) { |
There was a problem hiding this comment.
I think this function should be synchronized otherwise it might produce incorrect result, don't you think?
For example 2 threads will access this function at the same time, one of the pair of key-value will be lost...
There was a problem hiding this comment.
No, that's the main idea of COW approach: it is lock free.
Ok let's consider the case when 2 threads accessing this map.
Yes, in worst case one of the value will be lost. However it is ok.
We use this as a cache. It means that the lost value will be recalculated and put into map next time.
So there is no issue.
| } | ||
|
|
||
| @Override | ||
| public V remove(Object key) { |
There was a problem hiding this comment.
The same, don't you think that all the modification functions should be synchronized ?
There was a problem hiding this comment.
see the answer above
| } | ||
|
|
||
| @Override | ||
| public void putAll(Map<? extends K, ? extends V> m) { |
There was a problem hiding this comment.
see the answer above
| } | ||
|
|
||
| @Override | ||
| public void clear() { |
There was a problem hiding this comment.
see the answer above
| Map<K, V> newMap = mapSupplier.get(); | ||
| newMap.putAll(map); | ||
| final V result = newMap.remove(key); | ||
| map = newMap; |
There was a problem hiding this comment.
Isn't it better to keep the internal map as unmodifiable? Just for safety.
Like:
map = Collections.unmodifiableMap(newMap);
@snuyanzin I'll give it a try. |
2883fcd to
9616a24
Compare
06743ef to
03675f4
Compare
|
merging since it contains a test provided at #759 |


The PR assumes that most of the time there is no writes to the maps and only reads.
In this case there could be used optimistic locks most of the time and cheapStampedLock'sbased on measurements there is overhead only about 10% for some of methods, for others there is no noticeable differencee.g.
Datafaker_KotlinFakerBenchmark.kotlinFakerTestbefore PR
after (10% slower)
DatafakerSimpleMethods.firstnamebefore
after (about 10% slower)
DatafakerSimpleMethods.fullnamebefore
after (about 10% slower)
UPD: a new approach passing added test is with
COWMap