diff --git a/ruby/ext/google/protobuf_c/protobuf.c b/ruby/ext/google/protobuf_c/protobuf.c index 6c94a648f867..4dd1a0c81acb 100644 --- a/ruby/ext/google/protobuf_c/protobuf.c +++ b/ruby/ext/google/protobuf_c/protobuf.c @@ -272,6 +272,8 @@ static void ObjectCache_Init(VALUE protobuf) { weak_obj_cache = rb_class_new_instance(0, NULL, cache_class); rb_const_set(protobuf, rb_intern("OBJECT_CACHE"), weak_obj_cache); + rb_const_set(protobuf, rb_intern("SIZEOF_LONG"), INT2NUM(SIZEOF_LONG)); + rb_const_set(protobuf, rb_intern("SIZEOF_VALUE"), INT2NUM(SIZEOF_VALUE)); } VALUE ObjectCache_TryAdd(const void *key, VALUE val) { diff --git a/ruby/tests/BUILD.bazel b/ruby/tests/BUILD.bazel index 9ec6634f2279..c072cc713647 100644 --- a/ruby/tests/BUILD.bazel +++ b/ruby/tests/BUILD.bazel @@ -76,6 +76,16 @@ ruby_test( ], ) +ruby_test( + name = "object_cache_test", + srcs = ["object_cache_test.rb"], + deps = [ + "//ruby:protobuf", + "//ruby:test_ruby_protos", + "@protobuf_bundle//:test-unit", + ], +) + ruby_test( name = "repeated_field_test", srcs = ["repeated_field_test.rb"], diff --git a/ruby/tests/object_cache_test.rb b/ruby/tests/object_cache_test.rb new file mode 100644 index 000000000000..bdfc3655eecc --- /dev/null +++ b/ruby/tests/object_cache_test.rb @@ -0,0 +1,41 @@ +require 'google/protobuf' +require 'test/unit' + +class ObjectCacheTest < Test::Unit::TestCase + def test_correct_implementation_for_platform + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0') and Google::Protobuf::SIZEOF_LONG >= Google::Protobuf::SIZEOF_VALUE + assert_instance_of Google::Protobuf::ObjectCache, Google::Protobuf::OBJECT_CACHE + else + assert_instance_of Google::Protobuf::LegacyObjectCache, Google::Protobuf::OBJECT_CACHE + end + end + + def test_try_add_returns_existing_value + cache = Google::Protobuf::OBJECT_CACHE.class.new + key = 0xdeadbeefdeadbeef + first_value = 42 + second_value = 43 + assert_same first_value, cache.try_add(key, first_value) + assert_same first_value, cache.get(key) + assert_same first_value, cache.try_add(key, second_value) + assert_same first_value, cache.get(key) + end + + def test_multithreaded_access + cache = Google::Protobuf::OBJECT_CACHE.class.new + key = 0xdeadbeefdeadbeef + threads = [] + + 100.times do |i| + threads[i] = Thread.new { + Thread.current["result"] = cache.try_add(key, i) + } + end + + results = {} + + threads.each_with_index {|t, i | t.join; results[i] = t["result"] } + assert_equal 100, results.size + assert_equal 1, results.values.uniq.size + end +end \ No newline at end of file