Maintenance: Fix unhandled race condidtions in file locking of the web socket server.
This commit is contained in:
parent
2d31b6ced4
commit
770c1271a5
1 changed files with 54 additions and 78 deletions
|
@ -70,11 +70,7 @@ class Sessions::Store::File
|
||||||
|
|
||||||
def set(client_id, data)
|
def set(client_id, data)
|
||||||
path = "#{@path}/#{client_id}"
|
path = "#{@path}/#{client_id}"
|
||||||
File.open("#{path}/session", 'wb') do |file|
|
write_with_lock("#{path}/session", data.to_json)
|
||||||
file.flock(File::LOCK_EX)
|
|
||||||
file.write data.to_json
|
|
||||||
file.flock(File::LOCK_UN)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(client_id)
|
def get(client_id)
|
||||||
|
@ -85,15 +81,10 @@ class Sessions::Store::File
|
||||||
return if !check_session_file_for_client(client_id, session_dir, session_file)
|
return if !check_session_file_for_client(client_id, session_dir, session_file)
|
||||||
|
|
||||||
begin
|
begin
|
||||||
File.open(session_file, 'rb') do |file|
|
data_json = JSON.parse(read_with_lock(session_file))
|
||||||
file.flock(File::LOCK_SH)
|
if data_json
|
||||||
all = file.read
|
data = Sessions.symbolize_keys(data_json)
|
||||||
file.flock(File::LOCK_UN)
|
data[:user] = data_json['user'] # for compat. reasons
|
||||||
data_json = JSON.parse(all)
|
|
||||||
if data_json
|
|
||||||
data = Sessions.symbolize_keys(data_json)
|
|
||||||
data[:user] = data_json['user'] # for compat. reasons
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
rescue => e
|
rescue => e
|
||||||
Sessions.log('error', e.inspect)
|
Sessions.log('error', e.inspect)
|
||||||
|
@ -109,12 +100,7 @@ class Sessions::Store::File
|
||||||
return false if !location
|
return false if !location
|
||||||
|
|
||||||
begin
|
begin
|
||||||
File.open(location, 'wb') do |file|
|
write_with_lock(location, data.to_json)
|
||||||
file.flock(File::LOCK_EX)
|
|
||||||
file.write data.to_json
|
|
||||||
file.flock(File::LOCK_UN)
|
|
||||||
file.close
|
|
||||||
end
|
|
||||||
rescue => e
|
rescue => e
|
||||||
Sessions.log('error', e.inspect)
|
Sessions.log('error', e.inspect)
|
||||||
Sessions.log('error', "error in writing message file '#{location}'")
|
Sessions.log('error', "error in writing message file '#{location}'")
|
||||||
|
@ -156,11 +142,7 @@ class Sessions::Store::File
|
||||||
FileUtils.mkpath path
|
FileUtils.mkpath path
|
||||||
|
|
||||||
file_path = "#{path}/#{Time.now.utc.to_f}-#{rand(99_999)}"
|
file_path = "#{path}/#{Time.now.utc.to_f}-#{rand(99_999)}"
|
||||||
File.open(file_path, 'wb') do |file|
|
write_with_lock(file_path, data.to_json)
|
||||||
file.flock(File::LOCK_EX)
|
|
||||||
file.write data.to_json
|
|
||||||
file.flock(File::LOCK_UN)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def each_spool()
|
def each_spool()
|
||||||
|
@ -178,13 +160,8 @@ class Sessions::Store::File
|
||||||
filename = "#{path}/#{entry}"
|
filename = "#{path}/#{entry}"
|
||||||
next if !File.exist?(filename)
|
next if !File.exist?(filename)
|
||||||
|
|
||||||
File.open(filename, 'rb') do |file|
|
message = read_with_lock(filename)
|
||||||
file.flock(File::LOCK_SH)
|
yield message, entry
|
||||||
message = file.read
|
|
||||||
file.flock(File::LOCK_UN)
|
|
||||||
|
|
||||||
yield message, entry
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -209,18 +186,14 @@ class Sessions::Store::File
|
||||||
nodes = []
|
nodes = []
|
||||||
files = Dir.glob(path)
|
files = Dir.glob(path)
|
||||||
files.each do |filename|
|
files.each do |filename|
|
||||||
File.open(filename, 'rb') do |file|
|
begin
|
||||||
file.flock(File::LOCK_SH)
|
content = read_with_lock(filename)
|
||||||
content = file.read
|
data = JSON.parse(content)
|
||||||
file.flock(File::LOCK_UN)
|
nodes.push data
|
||||||
begin
|
rescue => e
|
||||||
data = JSON.parse(content)
|
Rails.logger.error "can't parse status file #{filename}, #{e.inspect}"
|
||||||
nodes.push data
|
# to_delete.push "#{path}/#{entry}"
|
||||||
rescue => e
|
# next
|
||||||
Rails.logger.error "can't parse status file #{filename}, #{e.inspect}"
|
|
||||||
# to_delete.push "#{path}/#{entry}"
|
|
||||||
# next
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
nodes
|
nodes
|
||||||
|
@ -236,9 +209,7 @@ class Sessions::Store::File
|
||||||
content = data.to_json
|
content = data.to_json
|
||||||
|
|
||||||
# store session data in session file
|
# store session data in session file
|
||||||
File.open(status_file, 'wb') do |file|
|
write_with_lock(status_file, content)
|
||||||
file.write content
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def each_node_session()
|
def each_node_session()
|
||||||
|
@ -247,22 +218,18 @@ class Sessions::Store::File
|
||||||
|
|
||||||
files = Dir.glob(path)
|
files = Dir.glob(path)
|
||||||
files.each do |filename|
|
files.each do |filename|
|
||||||
File.open(filename, 'rb') do |file|
|
begin
|
||||||
file.flock(File::LOCK_SH)
|
content = read_with_lock(filename)
|
||||||
content = file.read
|
next if content.blank?
|
||||||
file.flock(File::LOCK_UN)
|
|
||||||
begin
|
|
||||||
next if content.blank?
|
|
||||||
|
|
||||||
data = JSON.parse(content)
|
data = JSON.parse(content)
|
||||||
next if data.blank?
|
next if data.blank?
|
||||||
|
|
||||||
yield data
|
yield data
|
||||||
rescue => e
|
rescue => e
|
||||||
Rails.logger.error "can't parse session file #{filename}, #{e.inspect}"
|
Rails.logger.error "can't parse session file #{filename}, #{e.inspect}"
|
||||||
# to_delete.push "#{path}/#{entry}"
|
# to_delete.push "#{path}/#{entry}"
|
||||||
# next
|
# next
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -276,9 +243,7 @@ class Sessions::Store::File
|
||||||
content = data.to_json
|
content = data.to_json
|
||||||
|
|
||||||
# store session data in session file
|
# store session data in session file
|
||||||
File.open(status_file, 'wb') do |file|
|
write_with_lock(status_file, content)
|
||||||
file.write content
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def each_session_by_node(node_id)
|
def each_session_by_node(node_id)
|
||||||
|
@ -287,28 +252,39 @@ class Sessions::Store::File
|
||||||
|
|
||||||
files = Dir.glob(path)
|
files = Dir.glob(path)
|
||||||
files.each do |filename|
|
files.each do |filename|
|
||||||
File.open(filename, 'rb') do |file|
|
begin
|
||||||
file.flock(File::LOCK_SH)
|
content = read_with_lock(filename)
|
||||||
content = file.read
|
next if content.blank?
|
||||||
file.flock(File::LOCK_UN)
|
|
||||||
begin
|
|
||||||
next if content.blank?
|
|
||||||
|
|
||||||
data = JSON.parse(content)
|
data = JSON.parse(content)
|
||||||
next if data.blank?
|
next if data.blank?
|
||||||
|
|
||||||
yield data
|
yield data
|
||||||
rescue => e
|
rescue => e
|
||||||
Rails.logger.error "can't parse session file #{filename}, #{e.inspect}"
|
Rails.logger.error "can't parse session file #{filename}, #{e.inspect}"
|
||||||
# to_delete.push "#{path}/#{entry}"
|
# to_delete.push "#{path}/#{entry}"
|
||||||
# next
|
# next
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def write_with_lock(filename, data)
|
||||||
|
File.open(filename, 'ab') do |file|
|
||||||
|
file.flock(File::LOCK_EX)
|
||||||
|
file.truncate 0 # Truncate only after locking to avoid empty state
|
||||||
|
file.write data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_with_lock(filename)
|
||||||
|
File.open(filename, 'rb') do |file|
|
||||||
|
file.flock(File::LOCK_SH)
|
||||||
|
return file.read
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def queue_file_read(path, filename)
|
def queue_file_read(path, filename)
|
||||||
location = "#{path}#{filename}"
|
location = "#{path}#{filename}"
|
||||||
message = ''
|
message = ''
|
||||||
|
|
Loading…
Reference in a new issue