From 0c59526fa269b1e2954ef46851656968745cc6b2 Mon Sep 17 00:00:00 2001 From: Brad Bicknell Date: Thu, 7 Sep 2017 11:45:04 -0700 Subject: [PATCH] Fix Relationship.instances cache. (#1) Taken from: https://github.com/randym/axlsx/pull/477 --- lib/axlsx/package.rb | 8 ++++++-- lib/axlsx/rels/relationship.rb | 18 +++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/axlsx/package.rb b/lib/axlsx/package.rb index 8a4f29dc..2581abed 100644 --- a/lib/axlsx/package.rb +++ b/lib/axlsx/package.rb @@ -100,11 +100,13 @@ def workbook=(workbook) DataTypeValidator.validate :Package_workbook, Workbook, # File.open('example_streamed.xlsx', 'w') { |f| f.write(s.read) } def serialize(output, confirm_valid=false) return false unless !confirm_valid || self.validate.empty? - Relationship.clear_cached_instances + Relationship.initialize_cached_instances Zip::OutputStream.open(output) do |zip| write_parts(zip) end true + ensure + Relationship.clear_cached_instances end @@ -113,11 +115,13 @@ def serialize(output, confirm_valid=false) # @return [StringIO|Boolean] False if confirm_valid and validation errors exist. rewound string IO if not. def to_stream(confirm_valid=false) return false unless !confirm_valid || self.validate.empty? - Relationship.clear_cached_instances + Relationship.initialize_cached_instances zip = write_parts(Zip::OutputStream.new(StringIO.new, true)) stream = zip.close_buffer stream.rewind stream + ensure + Relationship.clear_cached_instances end # Encrypt the package into a CFB using the password provided diff --git a/lib/axlsx/rels/relationship.rb b/lib/axlsx/rels/relationship.rb index 99dad367..222432c5 100644 --- a/lib/axlsx/rels/relationship.rb +++ b/lib/axlsx/rels/relationship.rb @@ -8,10 +8,10 @@ class << self # Keeps track of all instances of this class. # @return [Array] def instances - @instances ||= [] + Thread.current[:axlsx_relationship_cached_instances] ||= [] end - - # Clear cached instances. + + # Initialize cached instances. # # This should be called before serializing a package (see {Package#serialize} and # {Package#to_stream}) to make sure that serialization is idempotent (i.e. @@ -20,8 +20,16 @@ def instances # # Also, calling this avoids memory leaks (cached instances lingering around # forever). + def initialize_cached_instances + Thread.current[:axlsx_relationship_cached_instances] = [] + end + + # Clear cached instances. + # + # This should be called after serializing a package (see {Package#serialize} and + # {Package#to_stream}) to free the memory allocated for cache. def clear_cached_instances - @instances = [] + Thread.current[:axlsx_relationship_cached_instances] = nil end # Generate and return a unique id (eg. `rId123`) Used for setting {#Id}. @@ -30,7 +38,7 @@ def clear_cached_instances # {clear_cached_instances} will automatically reset the generated ids, too. # @return [String] def next_free_id - "rId#{@instances.size + 1}" + "rId#{instances.size + 1}" end end