Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Detect timeouts which halt in-progress socket operations [fixes #146]

  • Loading branch information...
commit 371adde995946d82f9e2f836d1c2e8b297f9d7ea 1 parent 525ca92
@mperham authored
Showing with 37 additions and 6 deletions.
  1. +1 −0  History.md
  2. +14 −5 lib/dalli/server.rb
  3. +22 −1 test/test_failover.rb
View
1  History.md
@@ -8,6 +8,7 @@ Dalli Changelog
- DalliStore#fetch called the block if the cached value == false [#205]
- DalliStore should have accessible options [#195]
- Add silence and mute support for DalliStore [#207]
+- Tracked down and fixed socket corruption due to Timeout [#146]
2.0.3
=======
View
19 lib/dalli/server.rb
@@ -41,6 +41,7 @@ def initialize(attribs, options = {})
# Chokepoint method for instrumentation
def request(op, *args)
+ check_for_inprogress
raise Dalli::NetworkError, "#{hostname}:#{port} is down: #{@error} #{@msg}" unless alive?
begin
send(op, *args)
@@ -80,6 +81,7 @@ def close
return unless @sock
@sock.close rescue nil
@sock = nil
+ @inprogress = false
end
def lock!
@@ -92,6 +94,10 @@ def unlock!
private
+ def check_for_inprogress
+ failure! if @inprogress
+ end
+
def failure!
Dalli.logger.info { "#{hostname}:#{port} failed (count: #{@fail_count})" }
@@ -368,19 +374,23 @@ def multi_response
def write(bytes)
begin
- @sock.write(bytes)
+ @inprogress = true
+ result = @sock.write(bytes)
+ @inprogress = false
+ result
rescue SystemCallError, Timeout::Error
failure!
- retry
end
end
def read(count)
begin
- @sock.readfull(count)
+ @inprogress = true
+ data = @sock.readfull(count)
+ @inprogress = false
+ data
rescue SystemCallError, Timeout::Error, EOFError
failure!
- retry
end
end
@@ -397,7 +407,6 @@ def connect
rescue SystemCallError, Timeout::Error, EOFError, SocketError
# SocketError = DNS resolution failure
failure!
- retry
end
end
View
23 test/test_failover.rb
@@ -1,6 +1,27 @@
require 'helper'
-describe 'FailOver' do
+describe 'failover' do
+
+ describe 'timeouts' do
+ should 'not lead to corrupt sockets' do
+ memcached(29125) do
+ dc = Dalli::Client.new ['localhost:29125']
+ begin
+ Timeout.timeout 0.01 do
+ 1_000.times do
+ dc.set("test_123", {:test => "123"})
+ end
+ flunk("Did not timeout")
+ end
+ rescue Timeout::Error => e
+ end
+
+ assert_equal({:test => '123'}, dc.get("test_123"))
+ end
+ end
+ end
+
+
context 'assuming some bad servers' do
should 'silently reconnect if server hiccups' do
Please sign in to comment.
Something went wrong with that request. Please try again.