about summary refs log tree commit homepage
path: root/lib/mogilefs/http_file.rb
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2011-12-07 02:03:05 +0000
committerEric Wong <normalperson@yhbt.net>2011-12-07 02:29:23 +0000
commit0bbbd8cfa2df665bc22a47831adf91668e391e3e (patch)
tree08b1c1e8cfabaca403ae34bc2b68e4d8510d0610 /lib/mogilefs/http_file.rb
parentda58f47f541cff65e814a614ecff722ba2a35bf8 (diff)
downloadmogilefs-client-0bbbd8cfa2df665bc22a47831adf91668e391e3e.tar.gz
TCP keepalives are inexpensive, so we can use them to monitor
whether or not our connection is still alive while uploading.

Remote servers make take an unpredictable amount of time to
actually write out the data we've uploaded (and empty socket
buffers to receive more), so it is extremely difficult to
calculate an effective timeout for select() or poll().
Diffstat (limited to 'lib/mogilefs/http_file.rb')
-rw-r--r--lib/mogilefs/http_file.rb26
1 files changed, 25 insertions, 1 deletions
diff --git a/lib/mogilefs/http_file.rb b/lib/mogilefs/http_file.rb
index b8bfd48..0d6faf5 100644
--- a/lib/mogilefs/http_file.rb
+++ b/lib/mogilefs/http_file.rb
@@ -1,5 +1,6 @@
 # -*- encoding: binary -*-
 # here are internal implementation details, do not use them in your code
+require 'socket'
 require 'stringio'
 require 'uri'
 require 'digest/md5'
@@ -106,7 +107,7 @@ class MogileFS::HTTPFile < StringIO
   # returns file size if the socket finished writing
   def upload(devid, uri) # :nodoc:
     sock = MogileFS::Socket.tcp(uri.host, uri.port)
-    sock.setsockopt(Socket::IPPROTO_TCP, Socket::SO_KEEPALIVE, 1)
+    set_socket_options(sock)
     file_size = length
 
     if @streaming_io
@@ -192,4 +193,27 @@ class MogileFS::HTTPFile < StringIO
     commit
     super
   end
+
+  # :stopdoc:
+  # aggressive keepalive settings on Linux + Ruby 1.9.2+
+  TCP_KEEPALIVE = {
+    :TCP_KEEPIDLE => 60, # seconds time before keepalive packet is sent
+    :TCP_KEEPINTVL => 5,
+    :TCP_KEEPCNT => 2,  # number of retries
+  }
+
+  req_consts = TCP_KEEPALIVE.keys
+  if (Socket.constants & req_consts).size == req_consts.size
+    def set_socket_options(sock)
+      sock.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, 1)
+      TCP_KEEPALIVE.each do |k,v|
+        sock.setsockopt(:IPPROTO_TCP, k, v)
+      end
+    end
+  else
+    def set_socket_options(sock)
+      sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1)
+    end
+  end
+  # :startdoc:
 end