Skip to content

Commit aa74981

Browse files
committed
Prevent OptionsCache from leaking memory
1 parent 2087a95 commit aa74981

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

Rakefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Bundler::GemHelper.install_tasks
33

44
require 'rspec/core/rake_task'
55
RSpec::Core::RakeTask.new(:base_spec) do |task|
6-
task.pattern = 'spec/multi_json_spec.rb'
6+
task.pattern = 'spec/multi_json_spec.rb,spec/options_cache_spec.rb'
77
end
88

99
namespace :adapters do

lib/multi_json/options_cache.rb

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,21 @@ def reset
99

1010
def fetch(type, key)
1111
cache = instance_variable_get("@#{type}_cache")
12-
cache.key?(key) ? cache[key] : cache[key] = yield
12+
cache.key?(key) ? cache[key] : write(cache, key, &Proc.new)
13+
end
14+
15+
private
16+
17+
# Normally MultiJson is used with a few option sets for both dump/load
18+
# methods. When options are generated dynamically though, every call would
19+
# cause a cache miss and the cache would grow indefinitely. To prevent
20+
# this, we just reset the cache every time the number of keys outgrows
21+
# 1000.
22+
MAX_CACHE_SIZE = 1000
23+
24+
def write(cache, key)
25+
cache.clear if cache.length >= MAX_CACHE_SIZE
26+
cache[key] = yield
1327
end
1428
end
1529
end

spec/options_cache_spec.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
require "spec_helper"
2+
3+
describe MultiJson::OptionsCache do
4+
before { described_class.reset }
5+
6+
it "doesn't leak memory" do
7+
described_class::MAX_CACHE_SIZE.succ.times do |i|
8+
described_class.fetch(:dump, :key => i) do
9+
{ :foo => i }
10+
end
11+
12+
described_class.fetch(:load, :key => i) do
13+
{ :foo => i }
14+
end
15+
end
16+
17+
expect(described_class.instance_variable_get(:@dump_cache).length).to eq(1)
18+
expect(described_class.instance_variable_get(:@load_cache).length).to eq(1)
19+
end
20+
end

0 commit comments

Comments
 (0)