[drakma-devel] [patch] timeouts, take two

Stanislaw Halik sthalik at test123.ltd.pl
Thu Aug 27 04:07:12 UTC 2009


Hey Edi,

I made a new patch that uses TRIVIAL-TIMEOUT instead of usocket
WAIT-FOR-INPUT. Results are great, it yields no slowdown at all when
downloading a 10MB zero-filled file.

Patch follows. I can't attach files due to posting to Gmane through
tin(1) so it's included in the message body. If it gets mangled in the
transmission, it's alternatively available at
http://tehran.lain.pl/stuff/20090827-drakma-timeout-gray-stream-take2.diff

diff -rN -u old-drakma/drakma.asd new-drakma/drakma.asd
--- old-drakma/drakma.asd	2009-08-27 05:59:20.000000000 +0200
+++ new-drakma/drakma.asd	2009-08-27 05:59:20.000000000 +0200
@@ -53,10 +53,13 @@
                (:file "util")
                (:file "read")
                (:file "cookies")
+               #-lispworks (:file "timeouts")
                (:file "request"))
   :depends-on (:puri
                :cl-base64
                :chunga
                :flexi-streams
+               #-lispworks #:trivial-timeout
+               #-lispworks #:trivial-gray-streams
                #-:lispworks :usocket
                #-(or :lispworks :allegro) :cl+ssl))
diff -rN -u old-drakma/request.lisp new-drakma/request.lisp
--- old-drakma/request.lisp	2009-08-27 05:59:20.000000000 +0200
+++ new-drakma/request.lisp	2009-08-27 05:59:20.000000000 +0200
@@ -200,9 +200,11 @@
                               force-binary
                               want-stream
                               stream
-                              #+:lispworks (connection-timeout 20)
-                              #+:lispworks (read-timeout 20)
-                              #+(and :lispworks (not :lw-does-not-have-write-timeout))
+                              (connection-timeout 20)
+                              (read-timeout 20)
+                              #+(or (not :lispworks)
+                                    (and :lispworks
+                                         (not :lw-does-not-have-write-timeout)))
                               (write-timeout 20 write-timeout-provided-p)
                               #+openmcl
                               deadline)
@@ -385,6 +387,7 @@
 time units.  If the server fails to respond until that time, a
 COMMUNICATION-DEADLINE-EXPIRED condition is signalled.  DEADLINE is
 only available on CCL 1.2 and later."
+  #-lispworks (declare (ignore write-timeout-provided-p))
   (unless (member protocol '(:http/1.0 :http/1.1) :test #'eq)
     (parameter-error "Don't know how to handle protocol ~S." protocol))
   (setq uri (cond ((uri-p uri) (copy-uri uri))
@@ -450,12 +453,16 @@
                                                           :write-timeout write-timeout
                                                           :errorp t)
                                     #-:lispworks
-                                    (usocket:socket-stream
-                                     (usocket:socket-connect host port
-                                                             :element-type 'octet
-                                                             #+openmcl #+openmcl
-                                                             :deadline deadline
-                                                             :nodelay t))))
+                                    (let ((sock (trivial-timeout:with-timeout (connection-timeout)
+                                                  (usocket:socket-connect host port
+                                                                          :element-type 'octet
+                                                                          #+openmcl #+openmcl
+                                                                          :deadline deadline
+                                                                          :nodelay t))))
+                                      (if (or read-timeout write-timeout)
+                                          (usocket-timeout:timeout-stream-for-socket
+                                           sock :read-timeout read-timeout :write-timeout write-timeout)
+                                          (usocket:socket-stream sock)))))
               #+openmcl
               (when deadline
                 ;; it is correct to set the deadline here even though
diff -rN -u old-drakma/timeouts.lisp new-drakma/timeouts.lisp
--- old-drakma/timeouts.lisp	1970-01-01 01:00:00.000000000 +0100
+++ new-drakma/timeouts.lisp	2009-08-27 05:59:20.000000000 +0200
@@ -0,0 +1,62 @@
+(defpackage #:usocket-timeout
+    (:use #:cl #:usocket #:trivial-timeout #:trivial-gray-streams)
+  (:shadowing-import-from #:trivial-timeout #:timeout-error)
+  (:export #:timeout-stream-for-socket))
+
+(in-package #:usocket-timeout)
+
+
+(defclass timeout-mixin ()
+  ((socket-of     :initarg :socket
+                  :reader socket-of)))
+
+(defclass timeout-input-stream (trivial-gray-stream-mixin
+                                fundamental-binary-input-stream
+                                timeout-mixin)
+  ((read-timeout  :initform nil
+                  :initarg :read-timeout
+                  :reader read-timeout-of)))
+
+(defmethod stream-read-sequence ((stream timeout-input-stream)
+                                 sequence start end &key)
+  (with-timeout ((read-timeout-of stream))
+    (read-sequence sequence (socket-of stream) :start start :end end)))
+
+(defmethod stream-read-byte ((stream timeout-input-stream))
+  (with-timeout ((read-timeout-of stream))
+    (read-byte (socket-of stream))))
+
+
+(defclass timeout-output-stream (trivial-gray-stream-mixin
+                                 fundamental-binary-output-stream
+                                 timeout-mixin)
+  ((write-timeout :initform nil
+                  :initarg :write-timeout
+                  :reader write-timeout-of)))
+
+(defmethod stream-finish-output ((stream timeout-output-stream))
+  (finish-output (socket-of stream)))
+
+(defmethod stream-write-sequence ((stream timeout-output-stream)
+                                  sequence start end &key)
+  (with-timeout ((write-timeout-of stream))
+    (write-sequence sequence (socket-of stream)
+                    :start (or start 0)
+                    :end end)))
+
+(defmethod stream-write-byte ((stream timeout-output-stream) integer)
+  (with-timeout ((write-timeout-of stream))
+    (write-byte integer (socket-of stream))))
+
+
+(defclass usocket-timeout-stream (timeout-input-stream timeout-output-stream)
+  ())
+
+(defun timeout-stream-for-socket (socket &key timeout
+                                  (read-timeout timeout)
+                                  (write-timeout timeout))
+  (make-instance 'usocket-timeout-stream
+                 :socket (socket-stream socket)
+                 :read-timeout read-timeout
+                 :write-timeout write-timeout))
+





More information about the Drakma-devel mailing list