This type has always been internal-only, but moving it to a module named `Internal` will make this clearer. PiperOrigin-RevId: 606649281pull/15812/head
parent
3ab1276bbb
commit
f824f6d0d7
6 changed files with 117 additions and 115 deletions
@ -0,0 +1,99 @@ |
||||
# Protocol Buffers - Google's data interchange format |
||||
# Copyright 2023 Google Inc. All rights reserved. |
||||
# |
||||
# Use of this source code is governed by a BSD-style |
||||
# license that can be found in the LICENSE file or at |
||||
# https://developers.google.com/open-source/licenses/bsd |
||||
|
||||
module Google |
||||
module Protobuf |
||||
module Internal |
||||
# A pointer -> Ruby Object cache that keeps references to Ruby wrapper |
||||
# objects. This allows us to look up any Ruby wrapper object by the address |
||||
# of the object it is wrapping. That way we can avoid ever creating two |
||||
# different wrapper objects for the same C object, which saves memory and |
||||
# preserves object identity. |
||||
# |
||||
# We use WeakMap for the cache. If sizeof(long) > sizeof(VALUE), we also |
||||
# need a secondary Hash to store WeakMap keys, because our pointer keys may |
||||
# need to be stored as Bignum instead of Fixnum. Since WeakMap is weak for |
||||
# both keys and values, a Bignum key will cause the WeakMap entry to be |
||||
# collected immediately unless there is another reference to the Bignum. |
||||
# This happens on 64-bit Windows, on which pointers are 64 bits but longs |
||||
# are 32 bits. In this case, we enable the secondary Hash to hold the keys |
||||
# and prevent them from being collected. |
||||
class ObjectCache |
||||
def initialize |
||||
@map = ObjectSpace::WeakMap.new |
||||
@mutex = Mutex.new |
||||
end |
||||
|
||||
def get(key) |
||||
@map[key] |
||||
end |
||||
|
||||
def try_add(key, value) |
||||
@map[key] || @mutex.synchronize do |
||||
@map[key] ||= value |
||||
end |
||||
end |
||||
end |
||||
|
||||
class LegacyObjectCache |
||||
def initialize |
||||
@secondary_map = {} |
||||
@map = ObjectSpace::WeakMap.new |
||||
@mutex = Mutex.new |
||||
end |
||||
|
||||
def get(key) |
||||
value = if secondary_key = @secondary_map[key] |
||||
@map[secondary_key] |
||||
else |
||||
@mutex.synchronize do |
||||
@map[(@secondary_map[key] ||= Object.new)] |
||||
end |
||||
end |
||||
|
||||
# GC if we could remove at least 2000 entries or 20% of the table size |
||||
# (whichever is greater). Since the cost of the GC pass is O(N), we |
||||
# want to make sure that we condition this on overall table size, to |
||||
# avoid O(N^2) CPU costs. |
||||
cutoff = (@secondary_map.size * 0.2).ceil |
||||
cutoff = 2_000 if cutoff < 2_000 |
||||
if (@secondary_map.size - @map.size) > cutoff |
||||
purge |
||||
end |
||||
|
||||
value |
||||
end |
||||
|
||||
def try_add(key, value) |
||||
if secondary_key = @secondary_map[key] |
||||
if old_value = @map[secondary_key] |
||||
return old_value |
||||
end |
||||
end |
||||
|
||||
@mutex.synchronize do |
||||
secondary_key ||= (@secondary_map[key] ||= Object.new) |
||||
@map[secondary_key] ||= value |
||||
end |
||||
end |
||||
|
||||
private |
||||
|
||||
def purge |
||||
@mutex.synchronize do |
||||
@secondary_map.each do |key, secondary_key| |
||||
unless @map.key?(secondary_key) |
||||
@secondary_map.delete(key) |
||||
end |
||||
end |
||||
end |
||||
nil |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,97 +0,0 @@ |
||||
# Protocol Buffers - Google's data interchange format |
||||
# Copyright 2023 Google Inc. All rights reserved. |
||||
# |
||||
# Use of this source code is governed by a BSD-style |
||||
# license that can be found in the LICENSE file or at |
||||
# https://developers.google.com/open-source/licenses/bsd |
||||
|
||||
module Google |
||||
module Protobuf |
||||
# A pointer -> Ruby Object cache that keeps references to Ruby wrapper |
||||
# objects. This allows us to look up any Ruby wrapper object by the address |
||||
# of the object it is wrapping. That way we can avoid ever creating two |
||||
# different wrapper objects for the same C object, which saves memory and |
||||
# preserves object identity. |
||||
# |
||||
# We use WeakMap for the cache. If sizeof(long) > sizeof(VALUE), we also |
||||
# need a secondary Hash to store WeakMap keys, because our pointer keys may |
||||
# need to be stored as Bignum instead of Fixnum. Since WeakMap is weak for |
||||
# both keys and values, a Bignum key will cause the WeakMap entry to be |
||||
# collected immediately unless there is another reference to the Bignum. |
||||
# This happens on 64-bit Windows, on which pointers are 64 bits but longs |
||||
# are 32 bits. In this case, we enable the secondary Hash to hold the keys |
||||
# and prevent them from being collected. |
||||
class ObjectCache |
||||
def initialize |
||||
@map = ObjectSpace::WeakMap.new |
||||
@mutex = Mutex.new |
||||
end |
||||
|
||||
def get(key) |
||||
@map[key] |
||||
end |
||||
|
||||
def try_add(key, value) |
||||
@map[key] || @mutex.synchronize do |
||||
@map[key] ||= value |
||||
end |
||||
end |
||||
end |
||||
|
||||
class LegacyObjectCache |
||||
def initialize |
||||
@secondary_map = {} |
||||
@map = ObjectSpace::WeakMap.new |
||||
@mutex = Mutex.new |
||||
end |
||||
|
||||
def get(key) |
||||
value = if secondary_key = @secondary_map[key] |
||||
@map[secondary_key] |
||||
else |
||||
@mutex.synchronize do |
||||
@map[(@secondary_map[key] ||= Object.new)] |
||||
end |
||||
end |
||||
|
||||
# GC if we could remove at least 2000 entries or 20% of the table size |
||||
# (whichever is greater). Since the cost of the GC pass is O(N), we |
||||
# want to make sure that we condition this on overall table size, to |
||||
# avoid O(N^2) CPU costs. |
||||
cutoff = (@secondary_map.size * 0.2).ceil |
||||
cutoff = 2_000 if cutoff < 2_000 |
||||
if (@secondary_map.size - @map.size) > cutoff |
||||
purge |
||||
end |
||||
|
||||
value |
||||
end |
||||
|
||||
def try_add(key, value) |
||||
if secondary_key = @secondary_map[key] |
||||
if old_value = @map[secondary_key] |
||||
return old_value |
||||
end |
||||
end |
||||
|
||||
@mutex.synchronize do |
||||
secondary_key ||= (@secondary_map[key] ||= Object.new) |
||||
@map[secondary_key] ||= value |
||||
end |
||||
end |
||||
|
||||
private |
||||
|
||||
def purge |
||||
@mutex.synchronize do |
||||
@secondary_map.each do |key, secondary_key| |
||||
unless @map.key?(secondary_key) |
||||
@secondary_map.delete(key) |
||||
end |
||||
end |
||||
end |
||||
nil |
||||
end |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue