Introduce a separate cache for the regexp definitions not to expire them with results
Closed this issue · 0 comments
mensfeld commented
While using the DeviceDetector gem I've noticed, that the same cache is being used to store the final detection results as well as to tackle the internal caching.
This approach causes a YAML reload of regexps when enough browsers are being recognized.
Here's an example of how to reproduce that:
require 'device_detector'
DeviceDetector.configure do |config|
config.max_cache_keys = 10
end
module Bench
def self.call
t = Time.now.to_f
r = yield
p (Time.now.to_f-t)*1000
r
end
end
20.times do
Bench.call { DeviceDetector.new(Time.now.to_f.to_s).full_version }
end
the result is:
16.92676544189453
0.14138221740722656
0.1392364501953125
0.1327991485595703
0.13113021850585938
28.29146385192871
0.7753372192382812
0.11897087097167969
0.11181831359863281
45.581817626953125
1.2042522430419922
1.0809898376464844
1.1005401611328125
17.076730728149414
0.12612342834472656
0.11444091796875
0.10657310485839844
27.06766128540039
0.13065338134765625
0.1087188720703125
So we see spikes in the time needed due to reloading of yaml definitions.
After applying the following patch:
module Patches
module DeviceDetectorParser
CACHE = ::DeviceDetector::MemoryCache.new({})
private_constant :CACHE
def regexes_for(file_paths)
CACHE.get_or_set(filepaths) do
super
end
end
end
end
DeviceDetector::Parser.prepend(Patches::DeviceDetectorParser)
the results are always consistent as only the "public" results are being purged while keeping the regexp definitions intact in the cache.
require 'device_detector'
DeviceDetector.configure do |config|
config.max_cache_keys = 10
end
module Patches
module DeviceDetectorParser
CACHE = ::DeviceDetector::MemoryCache.new({})
private_constant :CACHE
def regexes_for(file_paths)
CACHE.get_or_set(filepaths) do
super
end
end
end
end
DeviceDetector::Parser.prepend(Patches::DeviceDetectorParser)
module Bench
def self.call
t = Time.now.to_f
r = yield
p (Time.now.to_f-t)*1000
r
end
end
20.times do
Bench.call { DeviceDetector.new(Time.now.to_f.to_s).full_version }
end
Result:
19.721269607543945
1.1222362518310547
0.8854866027832031
0.1773834228515625
0.1361370086669922
0.1354217529296875
0.1327991485595703
0.13184547424316406
0.1277923583984375
0.13184547424316406
0.12993812561035156
0.1289844512939453
0.13017654418945312
0.13184547424316406
0.12826919555664062
0.13208389282226562
0.13065338134765625
0.12731552124023438
0.12969970703125
0.13637542724609375
if that approach is ok, I can make a PR.