Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save casperlehmann/e442ecc4186f325c1b5ac5eca7894213 to your computer and use it in GitHub Desktop.

Select an option

Save casperlehmann/e442ecc4186f325c1b5ac5eca7894213 to your computer and use it in GitHub Desktop.
ruby-twin-keys-cache.rb
#!/usr/bin/env ruby
def mutate_hash_key_and_return_cache
key1 = { k: 1 }
key2 = { k: 2 }
puts "key hash: #{key1.hash} obj_id: #{key1.object_id}" # key hash: 2866644869520814412 obj_id: 60
puts "val hash: #{key2.hash} obj_id: #{key2.object_id}" # val hash: -3505864355511529673 obj_id: 80
cache = { key1 => "x", key2 => "y" }
key2[:k] = 1 # The two keys in the cache now have the same value.
puts cache # {{:k=>1}=>"x", {:k=>1}=>"y"}
puts "--------------------------------"
# Returning cache object. Original references to objects key1 and key2 will now go out of scope.
# References still exist in the cache object. But you won't be able to access them without iterating through the
# cache, since this is the only way to get the key with the correct object id.
#
# Note: The hash values of the keys are identical.
# But each object id remain unique (and unchanging), even as the values are updated.
# Now, will these object ids when the process is reforked? Will new objects be created from scratch, and will these
# previously distinct objects share the same identity?
# If so, then we might have lost object permanence, since previously distinct cache keys are now one, and can only
# point to one of the two cache values
cache
end
def print_cache_details(cache)
cache.each_pair do |key, val|
puts "Cache object ID: #{cache.object_id}. Contents:"
puts "key: %s val: %s" % [key, val]
puts "key hash: #{key.hash} obj_id: #{key.object_id}"
puts "val hash: #{val.hash} obj_id: #{val.object_id}"
end
puts "--------------------------------"
end
def monitor_cache_periodically(cache)
loop do
threads = 10.times.map do
Thread.new do
10_000.times { "string" * 1000 }
end
end
threads.each(&:join)
puts "Start garbage collection manually"
GC.start
print_cache_details(cache)
begin
puts "ObjectSpace._id2ref(60): #{ObjectSpace._id2ref(60)} ObjectSpace._id2ref(80): #{ObjectSpace._id2ref(80)}"
rescue RangeError
puts "A key has been garbage collected"
end
sleep 30
end
end
cache = mutate_hash_key_and_return_cache
monitor_cache_periodically(cache)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment