thread_safe 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +13 -5
- data/ext/org/jruby/ext/thread_safe/JRubyCacheBackendLibrary.java +7 -1
- data/ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMap.java +3 -0
- data/ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMapV8.java +18 -6
- data/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/ConcurrentHashMapV8.java +18 -6
- data/lib/thread_safe/cache.rb +6 -0
- data/lib/thread_safe/version.rb +19 -1
- data/test/test_cache.rb +11 -1
- data/thread_safe.gemspec +1 -1
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: becd0122b50b5237811fa86271f7d33724680011
|
4
|
+
data.tar.gz: 3111e146b92de7b07e7b052b3dd126aaad1aca2c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae11d6069603a1f4a6ae9ce62347629b22b2841c4008f248fd05b5c5fc2449913fbc0554919f4615e0abd55fdb903a42eee1520fbc723e17618e7b6419933559
|
7
|
+
data.tar.gz: 8c80390a923556d2627d89af464e51ddae6ac9b5c44a485c6c6c0ad804b01aeed631680a7ab23c63e46293d8649978eceb5dd40cc6218d1f101597baf50b6ee1
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -28,14 +28,22 @@ sh = ThreadSafe::Hash.new # supports standard Hash.new forms
|
|
28
28
|
```
|
29
29
|
|
30
30
|
`ThreadSafe::Cache` also exists, as a hash-like object, and should have
|
31
|
-
much better performance characteristics under concurrency than
|
31
|
+
much better performance characteristics esp. under high concurrency than
|
32
32
|
`ThreadSafe::Hash`. However, `ThreadSafe::Cache` is not strictly semantically
|
33
|
-
equivalent to ruby Hash -- for instance, it does not
|
34
|
-
insertion time as Hash
|
35
|
-
recommend you consider `ThreadSafe::Cache` instead of
|
36
|
-
concurrency-safe hash needs.
|
33
|
+
equivalent to a ruby `Hash` -- for instance, it does not necessarily retain
|
34
|
+
ordering by insertion time as `Hash` does. For most uses it should do fine
|
35
|
+
though, and we recommend you consider `ThreadSafe::Cache` instead of
|
36
|
+
`ThreadSafe::Hash` for your concurrency-safe hash needs. It understands some
|
37
|
+
options when created (depending on your ruby platform) that control some of the
|
38
|
+
internals - when unsure just leave them out:
|
37
39
|
|
38
40
|
|
41
|
+
```ruby
|
42
|
+
require 'thread_safe'
|
43
|
+
|
44
|
+
cache = ThreadSafe::Cache.new
|
45
|
+
```
|
46
|
+
|
39
47
|
## Contributing
|
40
48
|
|
41
49
|
1. Fork it
|
@@ -178,11 +178,17 @@ public class JRubyCacheBackendLibrary implements Library {
|
|
178
178
|
return getRuntime().newBoolean(map.replace(key, oldValue, newValue));
|
179
179
|
}
|
180
180
|
|
181
|
-
@JRubyMethod(name =
|
181
|
+
@JRubyMethod(name = "key?", required = 1)
|
182
182
|
public RubyBoolean has_key_p(IRubyObject key) {
|
183
183
|
return map.containsKey(key) ? getRuntime().getTrue() : getRuntime().getFalse();
|
184
184
|
}
|
185
185
|
|
186
|
+
@JRubyMethod
|
187
|
+
public IRubyObject key(IRubyObject value) {
|
188
|
+
final IRubyObject key = map.findKey(value);
|
189
|
+
return key == null ? getRuntime().getNil() : key;
|
190
|
+
}
|
191
|
+
|
186
192
|
@JRubyMethod
|
187
193
|
public IRubyObject replace_if_exists(IRubyObject key, IRubyObject value) {
|
188
194
|
IRubyObject result = map.replace(key, value);
|
@@ -2430,8 +2430,8 @@ public class ConcurrentHashMapV8<K, V>
|
|
2430
2430
|
@SuppressWarnings("serial") static class Traverser<K,V,R> {
|
2431
2431
|
final ConcurrentHashMapV8<K, V> map;
|
2432
2432
|
Node next; // the next entry to use
|
2433
|
-
|
2434
|
-
|
2433
|
+
K nextKey; // cached key field of next
|
2434
|
+
V nextVal; // cached val field of next
|
2435
2435
|
Node[] tab; // current table; updated if resized
|
2436
2436
|
int index; // index of bin to use next
|
2437
2437
|
int baseIndex; // current index of initial table
|
@@ -2461,9 +2461,9 @@ public class ConcurrentHashMapV8<K, V>
|
|
2461
2461
|
* Advances next; returns nextVal or null if terminated.
|
2462
2462
|
* See above for explanation.
|
2463
2463
|
*/
|
2464
|
-
final
|
2464
|
+
final V advance() {
|
2465
2465
|
Node e = next;
|
2466
|
-
|
2466
|
+
V ev = null;
|
2467
2467
|
outer: do {
|
2468
2468
|
if (e != null) // advance past used/skipped node
|
2469
2469
|
e = e.next;
|
@@ -2489,8 +2489,8 @@ public class ConcurrentHashMapV8<K, V>
|
|
2489
2489
|
} // visit upper slots if present
|
2490
2490
|
index = (i += baseSize) < n ? i : (baseIndex = b + 1);
|
2491
2491
|
}
|
2492
|
-
nextKey = e.key;
|
2493
|
-
} while ((ev = e.val) == null); // skip deleted or special nodes
|
2492
|
+
nextKey = (K) e.key;
|
2493
|
+
} while ((ev = (V) e.val) == null); // skip deleted or special nodes
|
2494
2494
|
next = e;
|
2495
2495
|
return nextVal = ev;
|
2496
2496
|
}
|
@@ -2730,6 +2730,18 @@ public class ConcurrentHashMapV8<K, V>
|
|
2730
2730
|
return false;
|
2731
2731
|
}
|
2732
2732
|
|
2733
|
+
public K findKey(Object value) {
|
2734
|
+
if (value == null)
|
2735
|
+
throw new NullPointerException();
|
2736
|
+
Object v;
|
2737
|
+
Traverser<K,V,Object> it = new Traverser<K,V,Object>(this);
|
2738
|
+
while ((v = it.advance()) != null) {
|
2739
|
+
if (v == value || value.equals(v))
|
2740
|
+
return it.nextKey;
|
2741
|
+
}
|
2742
|
+
return null;
|
2743
|
+
}
|
2744
|
+
|
2733
2745
|
/**
|
2734
2746
|
* Legacy method testing if some key maps into the specified value
|
2735
2747
|
* in this table. This method is identical in functionality to
|
@@ -2422,8 +2422,8 @@ public class ConcurrentHashMapV8<K, V>
|
|
2422
2422
|
@SuppressWarnings("serial") static class Traverser<K,V,R> {
|
2423
2423
|
final ConcurrentHashMapV8<K, V> map;
|
2424
2424
|
Node next; // the next entry to use
|
2425
|
-
|
2426
|
-
|
2425
|
+
K nextKey; // cached key field of next
|
2426
|
+
V nextVal; // cached val field of next
|
2427
2427
|
AtomicReferenceArray<Node> tab; // current table; updated if resized
|
2428
2428
|
int index; // index of bin to use next
|
2429
2429
|
int baseIndex; // current index of initial table
|
@@ -2453,9 +2453,9 @@ public class ConcurrentHashMapV8<K, V>
|
|
2453
2453
|
* Advances next; returns nextVal or null if terminated.
|
2454
2454
|
* See above for explanation.
|
2455
2455
|
*/
|
2456
|
-
final
|
2456
|
+
final V advance() {
|
2457
2457
|
Node e = next;
|
2458
|
-
|
2458
|
+
V ev = null;
|
2459
2459
|
outer: do {
|
2460
2460
|
if (e != null) // advance past used/skipped node
|
2461
2461
|
e = e.next;
|
@@ -2481,8 +2481,8 @@ public class ConcurrentHashMapV8<K, V>
|
|
2481
2481
|
} // visit upper slots if present
|
2482
2482
|
index = (i += baseSize) < n ? i : (baseIndex = b + 1);
|
2483
2483
|
}
|
2484
|
-
nextKey = e.key;
|
2485
|
-
} while ((ev = e.val) == null); // skip deleted or special nodes
|
2484
|
+
nextKey = (K) e.key;
|
2485
|
+
} while ((ev = (V) e.val) == null); // skip deleted or special nodes
|
2486
2486
|
next = e;
|
2487
2487
|
return nextVal = ev;
|
2488
2488
|
}
|
@@ -2722,6 +2722,18 @@ public class ConcurrentHashMapV8<K, V>
|
|
2722
2722
|
return false;
|
2723
2723
|
}
|
2724
2724
|
|
2725
|
+
public K findKey(Object value) {
|
2726
|
+
if (value == null)
|
2727
|
+
throw new NullPointerException();
|
2728
|
+
Object v;
|
2729
|
+
Traverser<K,V,Object> it = new Traverser<K,V,Object>(this);
|
2730
|
+
while ((v = it.advance()) != null) {
|
2731
|
+
if (v == value || value.equals(v))
|
2732
|
+
return it.nextKey;
|
2733
|
+
}
|
2734
|
+
return null;
|
2735
|
+
}
|
2736
|
+
|
2725
2737
|
/**
|
2726
2738
|
* Legacy method testing if some key maps into the specified value
|
2727
2739
|
* in this table. This method is identical in functionality to
|
data/lib/thread_safe/cache.rb
CHANGED
@@ -95,6 +95,12 @@ module ThreadSafe
|
|
95
95
|
each_pair {|k, v| yield v}
|
96
96
|
end unless method_defined?(:each_value)
|
97
97
|
|
98
|
+
def key(value)
|
99
|
+
each_pair {|k, v| return k if v == value}
|
100
|
+
nil
|
101
|
+
end unless method_defined?(:key)
|
102
|
+
alias_method :index, :key if RUBY_VERSION < '1.9'
|
103
|
+
|
98
104
|
def empty?
|
99
105
|
each_pair {|k, v| return false}
|
100
106
|
true
|
data/lib/thread_safe/version.rb
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
module ThreadSafe
|
2
|
+
VERSION = "0.3.1"
|
3
|
+
end
|
4
|
+
|
5
|
+
# NOTE: <= 0.2.0 used Threadsafe::VERSION
|
6
|
+
# @private
|
1
7
|
module Threadsafe
|
2
|
-
|
8
|
+
|
9
|
+
# @private
|
10
|
+
def self.const_missing(name)
|
11
|
+
name = name.to_sym
|
12
|
+
if ThreadSafe.const_defined?(name)
|
13
|
+
warn "[DEPRECATION] `Threadsafe::#{name}' is deprecated, use `ThreadSafe::#{name}' instead."
|
14
|
+
ThreadSafe.const_get(name)
|
15
|
+
else
|
16
|
+
warn "[DEPRECATION] the `Threadsafe' module is deprecated, please use `ThreadSafe` instead."
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
3
21
|
end
|
data/test/test_cache.rb
CHANGED
@@ -371,6 +371,16 @@ class TestCache < Test::Unit::TestCase
|
|
371
371
|
end
|
372
372
|
|
373
373
|
def test_key
|
374
|
+
with_or_without_default_proc do
|
375
|
+
assert_equal nil, @cache.key(1)
|
376
|
+
@cache[:a] = 1
|
377
|
+
assert_equal :a, @cache.key(1)
|
378
|
+
assert_equal nil, @cache.key(0)
|
379
|
+
assert_equal :a, @cache.index(1) if RUBY_VERSION =~ /1\.8/
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
def test_key?
|
374
384
|
with_or_without_default_proc do
|
375
385
|
assert_equal false, @cache.key?(:a)
|
376
386
|
@cache[:a] = 1
|
@@ -378,7 +388,7 @@ class TestCache < Test::Unit::TestCase
|
|
378
388
|
end
|
379
389
|
end
|
380
390
|
|
381
|
-
def test_value
|
391
|
+
def test_value?
|
382
392
|
with_or_without_default_proc do
|
383
393
|
assert_equal false, @cache.value?(1)
|
384
394
|
@cache[:a] = 1
|
data/thread_safe.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
17
|
gem.name = "thread_safe"
|
18
18
|
gem.require_paths = ["lib"]
|
19
|
-
gem.version =
|
19
|
+
gem.version = ThreadSafe::VERSION
|
20
20
|
gem.license = "Apache-2.0"
|
21
21
|
|
22
22
|
gem.add_dependency 'atomic', ['>= 1.1.7', '< 2']
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thread_safe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles Oliver Nutter
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-03-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: atomic
|
@@ -115,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
115
|
version: '0'
|
116
116
|
requirements: []
|
117
117
|
rubyforge_project:
|
118
|
-
rubygems_version: 2.2.
|
118
|
+
rubygems_version: 2.2.2
|
119
119
|
signing_key:
|
120
120
|
specification_version: 4
|
121
121
|
summary: A collection of data structures and utilities to make thread-safe programming
|
@@ -128,4 +128,3 @@ test_files:
|
|
128
128
|
- test/test_hash.rb
|
129
129
|
- test/test_helper.rb
|
130
130
|
- test/test_synchronized_delegator.rb
|
131
|
-
has_rdoc:
|