ruby-changes:65397
From: Jeremy <ko1@a...>
Date: Sat, 6 Mar 2021 00:18:46 +0900 (JST)
Subject: [ruby-changes:65397] 14e1739ff3 (master): [ruby/irb] Make save-history extension safe for concurrent use
https://git.ruby-lang.org/ruby.git/commit/?id=14e1739ff3 From 14e1739ff3ec81c9ea87a8aba03393f0bf0433a7 Mon Sep 17 00:00:00 2001 From: Jeremy Evans <code@j...> Date: Tue, 2 Mar 2021 12:17:23 -0800 Subject: [ruby/irb] Make save-history extension safe for concurrent use This makes the save-history extension check for modifications to the history file before saving it. If the history file was modified after the history was loaded and before it was saved, append only the new history lines to the history file. This can result in more lines in the history file than SAVE_HISTORY allows. However, that will be fixed the next time irb is run and the history is saved. Fixes [Bug #13654] https://github.com/ruby/irb/commit/041ef53845 --- lib/irb/ext/save-history.rb | 20 +++++++++++++++----- test/irb/test_history.rb | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/lib/irb/ext/save-history.rb b/lib/irb/ext/save-history.rb index ac358c8..7acaebe 100644 --- a/lib/irb/ext/save-history.rb +++ b/lib/irb/ext/save-history.rb @@ -81,6 +81,8 @@ module IRB https://github.com/ruby/ruby/blob/trunk/lib/irb/ext/save-history.rb#L81 end } end + @loaded_history_lines = history.size + @loaded_history_mtime = File.mtime(history_file) end end @@ -105,12 +107,20 @@ module IRB https://github.com/ruby/ruby/blob/trunk/lib/irb/ext/save-history.rb#L107 raise end - open(history_file, "w:#{IRB.conf[:LC_MESSAGES].encoding}", 0600) do |f| + if File.exist?(history_file) && @loaded_history_mtime && + File.mtime(history_file) != @loaded_history_mtime + history = history[@loaded_history_lines..-1] + append_history = true + end + + open(history_file, "#{append_history ? 'a' : 'w'}:#{IRB.conf[:LC_MESSAGES].encoding}", 0600) do |f| hist = history.map{ |l| l.split("\n").join("\\\n") } - begin - hist = hist.last(num) if hist.size > num and num > 0 - rescue RangeError # bignum too big to convert into `long' - # Do nothing because the bignum should be treated as inifinity + unless append_history + begin + hist = hist.last(num) if hist.size > num and num > 0 + rescue RangeError # bignum too big to convert into `long' + # Do nothing because the bignum should be treated as inifinity + end end f.puts(hist) end diff --git a/test/irb/test_history.rb b/test/irb/test_history.rb index 392a6af..aad8952 100644 --- a/test/irb/test_history.rb +++ b/test/irb/test_history.rb @@ -127,6 +127,37 @@ module TestIRB https://github.com/ruby/ruby/blob/trunk/test/irb/test_history.rb#L127 INPUT end + def test_history_concurrent_use + omit "Skip Editline" if /EditLine/n.match(Readline::VERSION) + IRB.conf[:SAVE_HISTORY] = 1 + assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT) do |history_file| + exit + 5 + exit + EXPECTED_HISTORY + 1 + 2 + 3 + 4 + INITIAL_HISTORY + 5 + exit + INPUT + assert_history(<<~EXPECTED_HISTORY2, <<~INITIAL_HISTORY2, <<~INPUT2) + exit + EXPECTED_HISTORY2 + 1 + 2 + 3 + 4 + INITIAL_HISTORY2 + 5 + exit + INPUT2 + File.utime(File.atime(history_file), File.mtime(history_file) + 2, history_file) + end + end + private def assert_history(expected_history, initial_irb_history, input) @@ -143,6 +174,11 @@ module TestIRB https://github.com/ruby/ruby/blob/trunk/test/irb/test_history.rb#L174 io = TestInputMethod.new io.class::HISTORY.clear io.load_history + if block_given? + history = io.class::HISTORY.dup + yield IRB.rc_file("_history") + io.class::HISTORY.replace(history) + end io.class::HISTORY.concat(input.split) io.save_history -- cgit v1.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/