thread_safe 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|