mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 02:41:13 +08:00
FIX: Clobbering plugin files on startup is problematic
On startup, (including when starting a rails console) we manipule a collection of plugin files. Writing these files is done in multiple observable steps, which presents opportunities for race conditions and causes temporary corruption. This commit uses the write, fsync and rename trick to atomically overwrite these files instead, but reads them first to avoid unnecessary writes. c457d3bf was a previous attempt to fix the same problem.
This commit is contained in:
@ -45,6 +45,39 @@ module Discourse
|
||||
logs.join("\n".freeze)
|
||||
end
|
||||
|
||||
def self.atomic_write_file(destination, contents)
|
||||
begin
|
||||
return if File.read(destination) == contents
|
||||
rescue Errno::ENOENT
|
||||
end
|
||||
|
||||
FileUtils.mkdir_p(File.join(Rails.root, 'tmp'))
|
||||
temp_destination = File.join(Rails.root, 'tmp', SecureRandom.hex)
|
||||
|
||||
File.open(temp_destination, "w") do |fd|
|
||||
fd.write(contents)
|
||||
fd.fsync()
|
||||
end
|
||||
|
||||
File.rename(temp_destination, destination)
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def self.atomic_ln_s(source, destination)
|
||||
begin
|
||||
return if File.readlink(destination) == source
|
||||
rescue Errno::ENOENT, Errno::EINVAL
|
||||
end
|
||||
|
||||
FileUtils.mkdir_p(File.join(Rails.root, 'tmp'))
|
||||
temp_destination = File.join(Rails.root, 'tmp', SecureRandom.hex)
|
||||
execute_command('ln', '-s', source, temp_destination)
|
||||
File.rename(temp_destination, destination)
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
class CommandRunner
|
||||
|
Reference in New Issue
Block a user