PERF: Memoize core svgs in memory to avoid expensive XML parsing.
The XML parsing of SVGs is done whenever the cache expires or on the first load after a reboot. In one of our production instance, parsing ranges from 30ms to 70ms which is not ideal. Instead, we've decided to make a small memory trade off here by memoizing the core SVGs once on boot to avoid parsing of the SVG files during the duration of a request. The memozied hash will take up 57440 bytes or 0.05744 megabytes in size.
This commit is contained in:
parent
ab8949d13a
commit
0700e9382d
|
@ -914,9 +914,9 @@ module Discourse
|
||||||
|
|
||||||
schema_cache = ActiveRecord::Base.connection.schema_cache
|
schema_cache = ActiveRecord::Base.connection.schema_cache
|
||||||
|
|
||||||
# load up schema cache for all multisite assuming all dbs have
|
|
||||||
# an identical schema
|
|
||||||
RailsMultisite::ConnectionManagement.safe_each_connection do
|
RailsMultisite::ConnectionManagement.safe_each_connection do
|
||||||
|
# load up schema cache for all multisite assuming all dbs have
|
||||||
|
# an identical schema
|
||||||
dup_cache = schema_cache.dup
|
dup_cache = schema_cache.dup
|
||||||
# this line is not really needed, but just in case the
|
# this line is not really needed, but just in case the
|
||||||
# underlying implementation changes lets give it a shot
|
# underlying implementation changes lets give it a shot
|
||||||
|
@ -948,6 +948,9 @@ module Discourse
|
||||||
},
|
},
|
||||||
Thread.new {
|
Thread.new {
|
||||||
LetterAvatar.image_magick_version
|
LetterAvatar.image_magick_version
|
||||||
|
},
|
||||||
|
Thread.new {
|
||||||
|
SvgSprite.core_svgs
|
||||||
}
|
}
|
||||||
].each(&:join)
|
].each(&:join)
|
||||||
ensure
|
ensure
|
||||||
|
|
|
@ -225,19 +225,21 @@ module SvgSprite
|
||||||
get_set_cache("custom_svg_sprites_#{Theme.transform_ids(theme_ids).join(',')}") do
|
get_set_cache("custom_svg_sprites_#{Theme.transform_ids(theme_ids).join(',')}") do
|
||||||
custom_sprite_paths = Dir.glob("#{Rails.root}/plugins/*/svg-icons/*.svg")
|
custom_sprite_paths = Dir.glob("#{Rails.root}/plugins/*/svg-icons/*.svg")
|
||||||
|
|
||||||
ThemeField.where(type_id: ThemeField.types[:theme_upload_var], name: THEME_SPRITE_VAR_NAME, theme_id: Theme.transform_ids(theme_ids))
|
if theme_ids.present?
|
||||||
.pluck(:upload_id).each do |upload_id|
|
ThemeField.where(type_id: ThemeField.types[:theme_upload_var], name: THEME_SPRITE_VAR_NAME, theme_id: Theme.transform_ids(theme_ids))
|
||||||
|
.pluck(:upload_id).each do |upload_id|
|
||||||
|
|
||||||
upload = Upload.find(upload_id) rescue nil
|
upload = Upload.find(upload_id) rescue nil
|
||||||
|
|
||||||
if Discourse.store.external?
|
if Discourse.store.external?
|
||||||
external_copy = Discourse.store.download(upload) rescue nil
|
external_copy = Discourse.store.download(upload) rescue nil
|
||||||
original_path = external_copy.try(:path)
|
original_path = external_copy.try(:path)
|
||||||
else
|
else
|
||||||
original_path = Discourse.store.path_for(upload)
|
original_path = Discourse.store.path_for(upload)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_sprite_paths << original_path if original_path.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
custom_sprite_paths << original_path if original_path.present?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
custom_sprite_paths
|
custom_sprite_paths
|
||||||
|
@ -275,7 +277,33 @@ module SvgSprite
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.sprite_sources(theme_ids)
|
def self.sprite_sources(theme_ids)
|
||||||
CORE_SVG_SPRITES | custom_svg_sprites(theme_ids)
|
sources = CORE_SVG_SPRITES
|
||||||
|
|
||||||
|
if theme_ids.present?
|
||||||
|
sources = sources + custom_svg_sprites(theme_ids)
|
||||||
|
end
|
||||||
|
|
||||||
|
sources
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.core_svgs
|
||||||
|
@core_svgs ||= begin
|
||||||
|
symbols = {}
|
||||||
|
|
||||||
|
CORE_SVG_SPRITES.each do |filename|
|
||||||
|
svg_filename = "#{File.basename(filename, ".svg")}"
|
||||||
|
|
||||||
|
Nokogiri::XML(File.open(filename)) do |config|
|
||||||
|
config.options = Nokogiri::XML::ParseOptions::NOBLANKS
|
||||||
|
end.css('symbol').each do |sym|
|
||||||
|
icon_id = prepare_symbol(sym, svg_filename)
|
||||||
|
sym.attributes['id'].value = icon_id
|
||||||
|
symbols[icon_id] = sym.to_xml
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
symbols
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.bundle(theme_ids = [])
|
def self.bundle(theme_ids = [])
|
||||||
|
@ -288,19 +316,28 @@ License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL
|
||||||
<svg xmlns='http://www.w3.org/2000/svg' style='display: none;'>
|
<svg xmlns='http://www.w3.org/2000/svg' style='display: none;'>
|
||||||
""".dup
|
""".dup
|
||||||
|
|
||||||
sprite_sources(theme_ids).each do |fname|
|
core_svgs.each do |icon_id, sym|
|
||||||
svg_file = Nokogiri::XML(File.open(fname)) do |config|
|
if icons.include?(icon_id)
|
||||||
config.options = Nokogiri::XML::ParseOptions::NOBLANKS
|
svg_subset << sym
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
svg_filename = "#{File.basename(fname, ".svg")}"
|
if theme_ids.present?
|
||||||
|
custom_svg_sprites(theme_ids).each do |fname|
|
||||||
|
svg_file = Nokogiri::XML(File.open(fname)) do |config|
|
||||||
|
config.options = Nokogiri::XML::ParseOptions::NOBLANKS
|
||||||
|
end
|
||||||
|
|
||||||
svg_file.css('symbol').each do |sym|
|
svg_filename = "#{File.basename(fname, ".svg")}"
|
||||||
icon_id = prepare_symbol(sym, svg_filename)
|
|
||||||
if icons.include? icon_id
|
svg_file.css("symbol").each do |sym|
|
||||||
sym.attributes['id'].value = icon_id
|
icon_id = prepare_symbol(sym, svg_filename)
|
||||||
sym.css('title').each(&:remove)
|
|
||||||
svg_subset << sym.to_xml
|
if icons.include? icon_id
|
||||||
|
sym.attributes['id'].value = icon_id
|
||||||
|
sym.css('title').each(&:remove)
|
||||||
|
svg_subset << sym.to_xml
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -405,6 +442,8 @@ License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.theme_icons(theme_ids)
|
def self.theme_icons(theme_ids)
|
||||||
|
return [] if theme_ids.blank?
|
||||||
|
|
||||||
theme_icon_settings = []
|
theme_icon_settings = []
|
||||||
|
|
||||||
# Need to load full records for default values
|
# Need to load full records for default values
|
||||||
|
@ -422,6 +461,8 @@ License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.custom_icons(theme_ids)
|
def self.custom_icons(theme_ids)
|
||||||
|
return [] if theme_ids.blank?
|
||||||
|
|
||||||
# Automatically register icons in sprites added via themes or plugins
|
# Automatically register icons in sprites added via themes or plugins
|
||||||
icons = []
|
icons = []
|
||||||
custom_svg_sprites(theme_ids).each do |fname|
|
custom_svg_sprites(theme_ids).each do |fname|
|
||||||
|
|
Loading…
Reference in New Issue