Skip to content
This repository was archived by the owner on Mar 15, 2022. It is now read-only.

Commit 029c1e1

Browse files
author
Brian Durand
committed
change gem name; refactor pure ruby weak reference implementation
1 parent 4246c6e commit 029c1e1

36 files changed

+319
-272
lines changed

README.rdoc

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
This library provides object references for Ruby as well as some common utilities for working with references. Object references are used to point to other objects and come in three distinct flavors that interact differently with the garbage collector.
22

3-
* References::StrongReference - This is a plain old pointer to another object.
4-
* References::WeakReference - This is a pointer to another object, but it is not seen by the garbage collector and the memory used by the object can be reclaimed at any time.
5-
* References::SoftReference - This is similar to a weak reference, but the garbage collector is not as eager to reclaim the referenced object.
3+
* Ref::StrongReference - This is a plain old pointer to another object.
4+
* Ref::WeakReference - This is a pointer to another object, but it is not seen by the garbage collector and the memory used by the object can be reclaimed at any time.
5+
* Ref::SoftReference - This is similar to a weak reference, but the garbage collector is not as eager to reclaim the referenced object.
66

7-
All of these classes extend from a common References::Reference class and have a common interface.
7+
All of these classes extend from a common Ref::Reference class and have a common interface.
88

99
Weak and soft references are useful when you have instantiated objects that you may want to use again but can recreate if necessary. Since the garbage collector determines when to reclaim the memory used by the objects, you don't need to worry about bloating the Ruby heap.
1010

11-
== Example Usage
11+
= Example Usage
1212

13-
ref = References::WeakReference.new("hello")
13+
ref = Ref::WeakReference.new("hello")
1414
ref.object # should be "hello"
1515
ObjectSpace.garbage_collect
1616
ref.object # should be nil (assuming the garbage collector reclaimed the reference)
1717

18-
== Goodies
18+
= Goodies
1919

2020
This library also includes tools for some common uses of weak and soft references.
2121

22-
* References::WeakKeyMap - A map of keys to values where the keys are weak references
23-
* References::WeakValueMap - A map of keys to values where the values are weak references
24-
* References::SoftKeyMap - A map of keys to values where the keys are soft references
25-
* References::SoftValueMap - A map of keys to values where the values are soft references
26-
* References::ReferenceQueue - A thread safe implementation of a queue that will add references to itself as their objects are garbage collected.
22+
* Ref::WeakKeyMap - A map of keys to values where the keys are weak references
23+
* Ref::WeakValueMap - A map of keys to values where the values are weak references
24+
* Ref::SoftKeyMap - A map of keys to values where the keys are soft references
25+
* Ref::SoftValueMap - A map of keys to values where the values are soft references
26+
* Ref::ReferenceQueue - A thread safe implementation of a queue that will add references to itself as their objects are garbage collected.
2727

28-
== Problems with WeakRef
28+
= Problems with WeakRef
2929

3030
Ruby does come with the WeakRef class in the standard library. However, there are issues with this class across several different Ruby runtimes. This gem provides a common interface to weak references that works across MRI, Ruby Enterprise Edition, YARV, Jruby, Rubinius, and IronRuby.
3131

Rakefile

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ require 'rake'
22
require 'rake/rdoctask'
33
require 'rake/testtask'
44
require 'rake/gempackagetask'
5-
require File.expand_path('../lib/references', __FILE__)
5+
require File.expand_path('../lib/ref', __FILE__)
66

77
desc 'Default: run unit tests.'
88
task :default => :test
@@ -20,12 +20,12 @@ end
2020
desc 'Generate documentation.'
2121
Rake::RDocTask.new(:rdoc) do |rdoc|
2222
rdoc.rdoc_dir = 'rdoc'
23-
rdoc.options << '--title' << 'References' << '--line-numbers' << '--inline-source' << '--main' << 'README.rdoc'
23+
rdoc.options << '--title' << 'Ref' << '--line-numbers' << '--inline-source' << '--main' << 'README.rdoc'
2424
rdoc.rdoc_files.include('README.rdoc')
2525
rdoc.rdoc_files.include('lib/**/*.rb')
2626
end
2727

28-
spec = eval(File.read(File.expand_path('../references.gemspec', __FILE__)))
28+
spec = eval(File.read(File.expand_path('../ref.gemspec', __FILE__)))
2929

3030
Rake::GemPackageTask.new(spec) do |p|
3131
p.gem_spec = spec
@@ -45,11 +45,11 @@ namespace :java do
4545
base_dir = File.dirname(__FILE__)
4646
tmp_dir = File.join(base_dir, "tmp")
4747
classes_dir = File.join(tmp_dir, "classes")
48-
jar_dir = File.join(base_dir, "lib", "org", "jruby", "ext", "references")
48+
jar_dir = File.join(base_dir, "lib", "org", "jruby", "ext", "ref")
4949
FileUtils.rm_rf(classes_dir)
5050
ext_dir = File.join(base_dir, "ext", "java")
5151
source_files = FileList["#{base_dir}/**/*.java"]
52-
jar_file = File.join(jar_dir, 'reference.jar')
52+
jar_file = File.join(jar_dir, 'references.jar')
5353
# Only build if any of the source files have changed
5454
up_to_date = File.exist?(jar_file) && source_files.all?{|f| File.mtime(f) <= File.mtime(jar_file)}
5555
unless up_to_date
@@ -71,9 +71,12 @@ namespace :test do
7171
task :weak_reference do
7272
puts "Testing performance of weak references..."
7373
t = Time.now
74-
100000.times do
75-
References::WeakReference.new(Object.new)
74+
Process.fork do
75+
100000.times do
76+
Ref::WeakReference.new(Object.new)
77+
end
7678
end
79+
Process.wait
7780
puts "Creating 100,000 weak references took #{Time.now - t} seconds"
7881
end
7982

@@ -82,8 +85,10 @@ namespace :test do
8285
puts "Testing performance of soft references..."
8386
t = Time.now
8487
100000.times do |i|
85-
References::SoftReference.new(Object.new)
88+
Ref::SoftReference.new(Object.new)
8689
end
90+
GC.start
91+
GC.start
8792
puts "Creating 100,000 soft references took #{Time.now - t} seconds"
8893
end
8994
end

ext/java/org/jruby/ext/references/ReferenceService.java renamed to ext/java/org/jruby/ext/ref/ReferencesService.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.jruby.ext.references;
1+
package org.jruby.ext.ref;
22

33
import java.io.IOException;
44
import org.jruby.Ruby;
@@ -12,15 +12,15 @@
1212
*
1313
* @author Brian Durand
1414
*/
15-
public class ReferenceService implements BasicLibraryService {
15+
public class ReferencesService implements BasicLibraryService {
1616
public boolean basicLoad(Ruby runtime) throws IOException {
17-
RubyModule referencesModule = runtime.getModule("References");
18-
RubyClass referenceClass = referencesModule.getClass("Reference");
17+
RubyModule refModule = runtime.getModule("Ref");
18+
RubyClass referenceClass = refModule.getClass("Reference");
1919

20-
RubyClass rubyWeakReferenceClass = runtime.defineClassUnder("WeakReference", referenceClass, RubyWeakReference.ALLOCATOR, referencesModule);
20+
RubyClass rubyWeakReferenceClass = runtime.defineClassUnder("WeakReference", referenceClass, RubyWeakReference.ALLOCATOR, refModule);
2121
rubyWeakReferenceClass.defineAnnotatedMethods(RubyWeakReference.class);
2222

23-
RubyClass rubySoftReferenceClass = runtime.defineClassUnder("SoftReference", referenceClass, RubySoftReference.ALLOCATOR, referencesModule);
23+
RubyClass rubySoftReferenceClass = runtime.defineClassUnder("SoftReference", referenceClass, RubySoftReference.ALLOCATOR, refModule);
2424
rubySoftReferenceClass.defineAnnotatedMethods(RubySoftReference.class);
2525

2626
return true;

ext/java/org/jruby/ext/references/RubySoftReference.java renamed to ext/java/org/jruby/ext/ref/RubySoftReference.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.jruby.ext.references;
1+
package org.jruby.ext.ref;
22

33
import java.lang.ref.SoftReference;
44
import org.jruby.Ruby;

ext/java/org/jruby/ext/references/RubyWeakReference.java renamed to ext/java/org/jruby/ext/ref/RubyWeakReference.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.jruby.ext.references;
1+
package org.jruby.ext.ref;
22

33
import java.lang.ref.WeakReference;
44
import org.jruby.Ruby;

lib/org/jruby/ext/ref/references.jar

4.5 KB
Binary file not shown.
-4.59 KB
Binary file not shown.
Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,39 @@
1-
require 'monitor'
2-
3-
module References
4-
autoload :AbstractReferenceValueMap, File.join(File.dirname(__FILE__), "references", "abstract_reference_value_map.rb")
5-
autoload :AbstractReferenceKeyMap, File.join(File.dirname(__FILE__), "references", "abstract_reference_key_map.rb")
6-
autoload :Mock, File.join(File.dirname(__FILE__), "references", "mock.rb")
7-
autoload :Reference, File.join(File.dirname(__FILE__), "references", "reference.rb")
8-
autoload :ReferenceQueue, File.join(File.dirname(__FILE__), "references", "reference_queue.rb")
9-
autoload :SoftKeyMap, File.join(File.dirname(__FILE__), "references", "soft_key_map.rb")
10-
autoload :SoftValueMap, File.join(File.dirname(__FILE__), "references", "soft_value_map.rb")
11-
autoload :StrongReference, File.join(File.dirname(__FILE__), "references", "strong_reference.rb")
12-
autoload :WeakKeyMap, File.join(File.dirname(__FILE__), "references", "weak_key_map.rb")
13-
autoload :WeakValueMap, File.join(File.dirname(__FILE__), "references", "weak_value_map.rb")
1+
module Ref
2+
autoload :AbstractReferenceValueMap, File.join(File.dirname(__FILE__), "ref", "abstract_reference_value_map.rb")
3+
autoload :AbstractReferenceKeyMap, File.join(File.dirname(__FILE__), "ref", "abstract_reference_key_map.rb")
4+
autoload :Mock, File.join(File.dirname(__FILE__), "ref", "mock.rb")
5+
autoload :Reference, File.join(File.dirname(__FILE__), "ref", "reference.rb")
6+
autoload :ReferenceQueue, File.join(File.dirname(__FILE__), "ref", "reference_queue.rb")
7+
autoload :SafeMonitor, File.join(File.dirname(__FILE__), "ref", "safe_monitor.rb")
8+
autoload :SoftKeyMap, File.join(File.dirname(__FILE__), "ref", "soft_key_map.rb")
9+
autoload :SoftValueMap, File.join(File.dirname(__FILE__), "ref", "soft_value_map.rb")
10+
autoload :StrongReference, File.join(File.dirname(__FILE__), "ref", "strong_reference.rb")
11+
autoload :WeakKeyMap, File.join(File.dirname(__FILE__), "ref", "weak_key_map.rb")
12+
autoload :WeakValueMap, File.join(File.dirname(__FILE__), "ref", "weak_value_map.rb")
1413

1514
# Set the best implementation for weak references based on the runtime.
1615
if defined?(RUBY_PLATFORM) && RUBY_PLATFORM == 'java'
1716
# Use native Java references
1817
begin
1918
$LOAD_PATH.unshift(File.dirname(__FILE__))
20-
require 'org/jruby/ext/references/reference'
19+
require 'org/jruby/ext/ref/references'
2120
ensure
2221
$LOAD_PATH.shift if $LOAD_PATH.first == File.dirname(__FILE__)
2322
end
2423
else
25-
autoload :SoftReference, File.join(File.dirname(__FILE__), "references", "soft_reference.rb")
24+
autoload :SoftReference, File.join(File.dirname(__FILE__), "ref", "soft_reference.rb")
2625
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ironruby'
2726
# IronRuby has it's own implementation of weak references.
28-
autoload :WeakReference, File.join(File.dirname(__FILE__), "references", "weak_reference", "iron_ruby.rb")
27+
autoload :WeakReference, File.join(File.dirname(__FILE__), "ref", "weak_reference", "iron_ruby.rb")
2928
elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
3029
# If using Rubinius set the implementation to use WeakRef since it is very efficient.
31-
autoload :WeakReference, File.join(File.dirname(__FILE__), "references", "weak_reference", "weak_ref.rb")
30+
autoload :WeakReference, File.join(File.dirname(__FILE__), "ref", "weak_reference", "weak_ref.rb")
3231
elsif defined?(ObjectSpace._id2ref)
3332
# If ObjectSpace can lookup objects from their object_id, then use the pure ruby implementation.
34-
autoload :WeakReference, File.join(File.dirname(__FILE__), "references", "weak_reference", "pure_ruby.rb")
33+
autoload :WeakReference, File.join(File.dirname(__FILE__), "ref", "weak_reference", "pure_ruby.rb")
3534
else
3635
# Otherwise, wrap the standard library WeakRef class
37-
autoload :WeakReference, File.join(File.dirname(__FILE__), "references", "weak_reference", "weak_ref.rb")
36+
autoload :WeakReference, File.join(File.dirname(__FILE__), "ref", "weak_reference", "weak_ref.rb")
3837
end
3938
end
4039
end

lib/references/abstract_reference_key_map.rb renamed to lib/ref/abstract_reference_key_map.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module References
1+
module Ref
22
# Abstract base class for WeakKeyMap and SoftKeyMap.
33
#
44
# The classes behave similar to Hashes, but the keys in the map are not strong references
@@ -21,8 +21,8 @@ def reference_class #:nodoc:
2121
def initialize
2222
@values = {}
2323
@references_to_keys_map = {}
24+
@lock = SafeMonitor.new
2425
@reference_cleanup = lambda{|object_id| remove_reference_to(object_id)}
25-
@monitor = Monitor.new
2626
end
2727

2828
# Get a value from the map by key. If the value has been reclaimed by the garbage
@@ -35,7 +35,7 @@ def [](key)
3535
# Add a key/value to the map.
3636
def []=(key, value)
3737
ObjectSpace.define_finalizer(key, @reference_cleanup)
38-
@monitor.synchronize do
38+
@lock.synchronize do
3939
@references_to_keys_map[key.__id__] = self.class.reference_class.new(key)
4040
@values[key.__id__] = value
4141
end
@@ -75,7 +75,7 @@ def each
7575

7676
# Clear the map of all key/value pairs.
7777
def clear
78-
@monitor.synchronize do
78+
@lock.synchronize do
7979
@values.clear
8080
@references_to_keys_map.clear
8181
end
@@ -108,8 +108,10 @@ def ref_key (key)
108108
end
109109

110110
def remove_reference_to(object_id)
111-
@references_to_keys_map.delete(object_id)
112-
@values.delete(object_id)
111+
@lock.synchronize do
112+
@references_to_keys_map.delete(object_id)
113+
@values.delete(object_id)
114+
end
113115
end
114116
end
115117
end

lib/references/abstract_reference_value_map.rb renamed to lib/ref/abstract_reference_value_map.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module References
1+
module Ref
22
# Abstract base class for WeakValueMap and SoftValueMap.
33
#
44
# The classes behave similar to Hashes, but the values in the map are not strong references
@@ -21,8 +21,8 @@ def reference_class #:nodoc:
2121
def initialize
2222
@references = {}
2323
@references_to_keys_map = {}
24+
@lock = SafeMonitor.new
2425
@reference_cleanup = lambda{|object_id| remove_reference_to(object_id)}
25-
@monitor = Monitor.new
2626
end
2727

2828
# Get a value from the map by key. If the value has been reclaimed by the garbage
@@ -37,7 +37,7 @@ def [](key)
3737
def []=(key, value)
3838
ObjectSpace.define_finalizer(value, @reference_cleanup)
3939
key = key.dup if key.is_a?(String)
40-
@monitor.synchronize do
40+
@lock.synchronize do
4141
@references[key] = self.class.reference_class.new(value)
4242
keys_for_id = @references_to_keys_map[value.__id__]
4343
unless keys_for_id
@@ -89,7 +89,7 @@ def each
8989

9090
# Clear the map of all key/value pairs.
9191
def clear
92-
@monitor.synchronize do
92+
@lock.synchronize do
9393
@references.clear
9494
@references_to_keys_map.clear
9595
end
@@ -113,7 +113,7 @@ def inspect
113113
private
114114

115115
def remove_reference_to(object_id)
116-
@monitor.synchronize do
116+
@lock.synchronize do
117117
keys = @references_to_keys_map[object_id]
118118
if keys
119119
keys.each do |key|

0 commit comments

Comments
 (0)