From swm at itasoftware.com Tue Jun 1 13:23:32 2010 From: swm at itasoftware.com (Scott McKay) Date: Tue, 1 Jun 2010 09:23:32 -0400 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> Message-ID: <29EE915A-E7BB-4A7B-9932-DB2D35FF51EE@itasoftware.com> I'll address all these issues, then send the next set of changes back according to the referenced file. BTW, I chose not to use a generic function for the thread creation function and the too-many-threads handler for what I have to assume is the same reason that the various logger functions are also done as slots: so that you aren't forced to subclass just to provide a couple of functions. If this were Java, I'd say subclassing is the right approach, but since it's Lisp, I think supplying a function is better. After all, that's what first-class functions are for! :-) Thanks! On May 30, 2010, at 5:56 AM, Hans H?bner wrote: > Hi Scott, > > first off, thank you for taking the time to improve Hunchentoot and > for sending a proposed patch. Please have a look at > http://weitz.de/patches.html before submitting your next patch for > review. In particular, it makes reviews much easier if there is > documentation about what the patch means to do. > > On Thu, May 27, 2010 at 16:57, Scott McKay wrote: >> A few notes: >> - The function conditionalized out with #+++potentially-faster-way >> is meant to be a hint as to how we might refuse the connection >> without invoking the overhead of accepting the over-the-limit >> connection. It might be slightly faster, but I don't know if >> I like the idea of constantly closing and reopening the listener. > > I don't like the idea, as it opens up a race condition which will > result in connections being rejected under high load. > >> - 'handle-incoming-connection' on 'one-thread-per-connection-taskmaster' >> should really try to generate an HTTP 503 error, instead of just >> closing the connection. I tried several things to make this happen, >> but nothing seemed to work properly. It seems a shame to have to >> open the client connection, suck in the whole request, etc etc, >> just to do this. Is there a better way? Is there some sort of >> "connection refused" we can do at the socket level? > > I don't see a need to read the request in order to reply with a 503 > error. If the server can't dispatch the request because a resource > limit has been hit, there is nothing wrong with just sending a 503 > reply without looking at the request at all. Berkeley sockets do not > provide a means to reject individual pending connections. > > Further comments inline: > >> >> --Scott >> >> >> Modified: trunk/qres/lisp/libs/hunchentoot/packages.lisp >> ============================================================================== >> --- trunk/qres/lisp/libs/hunchentoot/packages.lisp (original) >> +++ trunk/qres/lisp/libs/hunchentoot/packages.lisp Thu May 27 10:31:21 2010 >> @@ -192,7 +192,6 @@ >> "MIME-TYPE" >> "NEXT-SESSION-ID" >> "NO-CACHE" >> - "ONE-THREAD-PER-CONNECTION-TASKMASTER" >> "PARAMETER" >> "PARAMETER-ERROR" >> "POST-PARAMETER" >> @@ -250,7 +249,6 @@ >> "SET-COOKIE" >> "SET-COOKIE*" >> "SHUTDOWN" >> - "SINGLE-THREADED-TASKMASTER" >> #-:hunchentoot-no-ssl "SSL-ACCEPTOR" >> "SSL-P" >> "START" >> @@ -259,7 +257,12 @@ >> "STOP" >> "TASKMASTER" >> "TASKMASTER-ACCEPTOR" >> - "URL-DECODE" >> + "SINGLE-THREADED-TASKMASTER" >> + "ONE-THREAD-PER-CONNECTION-TASKMASTER" >> + "POOLED-THREAD-PER-CONNECTION-TASKMASTER" >> + "INCREMENT-TASKMASTER-THREAD-COUNT" >> + "DECREMENT-TASKMASTER-THREAD-COUNT" >> + "URL-DECODE" >> "URL-ENCODE" >> "USER-AGENT")) >> >> Modified: trunk/qres/lisp/libs/hunchentoot/acceptor.lisp >> ============================================================================== >> --- trunk/qres/lisp/libs/hunchentoot/acceptor.lisp (original) >> +++ trunk/qres/lisp/libs/hunchentoot/acceptor.lisp Thu May 27 10:31:21 2010 >> @@ -86,7 +86,7 @@ >> reason to change this to NIL.") >> (input-chunking-p :initarg :input-chunking-p >> :accessor acceptor-input-chunking-p >> - :documentation "A generalized boolean denoting >> + :documentation "A generalized boolean denoting >> whether the acceptor may use chunked encoding for input, i.e. when >> accepting request bodies from the client. The default is T and >> there's usually no reason to change this to NIL.") >> @@ -117,8 +117,7 @@ >> process different from the one where START was called.") >> #-:lispworks >> (listen-socket :accessor acceptor-listen-socket >> - :documentation "The socket listening for incoming >> -connections.") >> + :documentation "The socket listening for incoming connections.") >> (acceptor-shutdown-p :initform nil >> :accessor acceptor-shutdown-p >> :documentation "A flag that makes the acceptor >> @@ -349,9 +348,12 @@ >> ;; the default is to always answer "no" >> nil) >> >> -;; usocket implementation >> + >> +;;; usocket implementation >> >> #-:lispworks >> +(progn > > What is this progn needed for? > >> + >> (defmethod start-listening ((acceptor acceptor)) >> (setf (acceptor-listen-socket acceptor) >> (usocket:socket-listen (or (acceptor-address acceptor) >> @@ -361,26 +363,61 @@ >> :element-type '(unsigned-byte 8))) >> (values)) >> >> -#-:lispworks >> (defmethod accept-connections ((acceptor acceptor)) >> (usocket:with-server-socket (listener (acceptor-listen-socket acceptor)) >> (loop >> - (when (acceptor-shutdown-p acceptor) >> - (return)) >> - (when (usocket:wait-for-input listener :timeout +new-connection-wait-time+) >> - (handler-case >> - (when-let (client-connection (usocket:socket-accept listener)) >> - (set-timeouts client-connection >> - (acceptor-read-timeout acceptor) >> - (acceptor-write-timeout acceptor)) >> - (handle-incoming-connection (acceptor-taskmaster acceptor) >> - client-connection)) >> - ;; ignore condition >> - (usocket:connection-aborted-error ())))))) >> + (when (acceptor-shutdown-p acceptor) >> + (return)) >> + (when (usocket:wait-for-input listener :timeout +new-connection-wait-time+) >> + (handler-case >> + (let ((taskmaster (acceptor-taskmaster acceptor))) >> + (when-let (client-connection (usocket:socket-accept listener)) >> + (set-timeouts client-connection >> + (acceptor-read-timeout acceptor) >> + (acceptor-write-timeout acceptor)) >> + ;; This will bail if the taskmaster has reached its thread limit >> + (handle-incoming-connection taskmaster client-connection))) >> + ;; Ignore the error >> + (usocket:connection-aborted-error ())))))) >> + >> +#+++potentially-faster-way >> +(defmethod accept-connections ((acceptor acceptor)) >> + (loop >> + (usocket:with-server-socket (listener (acceptor-listen-socket acceptor)) >> + (loop named waiter doing >> + (when (acceptor-shutdown-p acceptor) >> + (return-from accept-connections)) >> + (when (usocket:wait-for-input listener :timeout +new-connection-wait-time+) >> + (handler-case >> + (let ((taskmaster (acceptor-taskmaster acceptor))) >> + ;; Optimization to avoid creating the client connection: >> + ;; if the taskmaster has reached its thread limit, just close >> + ;; and reopen the listener socket, and don't even call 'accept' >> + (when (and (taskmaster-max-threads taskmaster) >> + (> (taskmaster-thread-count taskmaster) (taskmaster-max-threads taskmaster))) >> + (when-let (handler (taskmaster-too-many-threads-handler taskmaster)) >> + (funcall handler taskmaster listener)) >> + (usocket:socket-close listener) ;close the listener >> + (setq listener nil) >> + (start-listening acceptor) ;and start up a new one >> + (return-from waiter)) >> + (when-let (client-connection (usocket:socket-accept listener)) >> + (set-timeouts client-connection >> + (acceptor-read-timeout acceptor) >> + (acceptor-write-timeout acceptor)) >> + ;; This will bail if the taskmaster has reached its thread limit >> + (handle-incoming-connection taskmaster client-connection))) >> + ;; Ignore the error >> + (usocket:connection-aborted-error ()))))))) >> + >> +) ;#-:lispworks >> >> -;; LispWorks implementation >> + >> +;;; LispWorks implementation >> >> #+:lispworks >> +(progn >> + > > Don't use progn here. Conditionalize the individual top-level forms. > Otherwise, automatic reindentation will screw up the source file. > >> (defmethod start-listening ((acceptor acceptor)) >> (multiple-value-bind (listener-process startup-condition) >> (comm:start-up-server :service (acceptor-port acceptor) >> @@ -398,8 +435,8 @@ >> ;; is made >> :function (lambda (handle) >> (unless (acceptor-shutdown-p acceptor) >> - (handle-incoming-connection >> - (acceptor-taskmaster acceptor) handle))) >> + (let ((taskmaster (acceptor-taskmaster acceptor))) >> + (handle-incoming-connection taskmaster client-connection)))) >> ;; wait until the acceptor was successfully started >> ;; or an error condition is returned >> :wait t) >> @@ -409,11 +446,13 @@ >> (setf (acceptor-process acceptor) listener-process) >> (values))) >> >> -#+:lispworks >> (defmethod accept-connections ((acceptor acceptor)) >> (mp:process-unstop (acceptor-process acceptor)) >> nil) >> >> +) ;#+:lispworks >> + >> + >> (defun list-request-dispatcher (request) >> "The default request dispatcher which selects a request handler >> based on a list of individual request dispatchers all of which can >> >> Modified: trunk/qres/lisp/libs/hunchentoot/taskmaster.lisp >> ============================================================================== >> --- trunk/qres/lisp/libs/hunchentoot/taskmaster.lisp (original) >> +++ trunk/qres/lisp/libs/hunchentoot/taskmaster.lisp Thu May 27 10:31:21 2010 >> @@ -62,6 +62,21 @@ >> might terminate all threads that are currently associated with it. >> This function is called by the acceptor's STOP method.")) >> >> +;; Default method >> +(defmethod taskmaster-max-threads ((taskmaster taskmaster)) >> + nil) >> + >> +;; Default method >> +(defmethod taskmaster-thread-count ((taskmaster taskmaster)) >> + 0) >> + >> +(defmethod increment-taskmaster-thread-count ((taskmaster taskmaster)) >> + nil) >> + >> +(defmethod decrement-taskmaster-thread-count ((taskmaster taskmaster)) >> + nil) >> + >> + >> (defclass single-threaded-taskmaster (taskmaster) >> () >> (:documentation "A taskmaster that runs synchronously in the thread >> @@ -80,25 +95,95 @@ >> ;; in a single-threaded environment we just call PROCESS-CONNECTION >> (process-connection (taskmaster-acceptor taskmaster) socket)) >> >> + >> (defclass one-thread-per-connection-taskmaster (taskmaster) >> (#-:lispworks >> - (acceptor-process :accessor acceptor-process >> - :documentation "A process that accepts incoming >> -connections and hands them off to new processes for request >> -handling.")) >> + (acceptor-process >> + :accessor acceptor-process >> + :documentation >> + "A process that accepts incoming connections and hands them off to new processes >> + for request handling.") >> + (create-thread-function >> + :initarg :create-thread-function >> + :initform 'create-taskmaster-thread >> + :accessor taskmaster-create-thread-function >> + :documentation >> + "Function called to create the handler thread; >> + takes two arguments, the taskmaster and the socket") >> + ;; Support for bounding the number of threads we'll create >> + (max-threads >> + :type (or integer null) >> + :initarg :max-threads >> + :initform nil >> + :accessor taskmaster-max-threads) >> + (thread-count >> + :type integer >> + :initform 0 >> + :accessor taskmaster-thread-count) >> + (thread-count-lock >> + :initform (bt:make-lock "taskmaster-thread-count") >> + :accessor taskmaster-thread-count-lock) >> + (worker-thread-name-format >> + :type (or string null) >> + :initarg :worker-thread-name-format >> + :initform "hunchentoot-worker-~A" >> + :accessor taskmaster-worker-thread-name-format) >> + (too-many-threads-handler >> + :initarg :too-many-threads-handler >> + :initform nil >> + :accessor taskmaster-too-many-threads-handler >> + :documentation >> + "Function called with two arguments, the taskmaster and the socket, >> + when too many threads reached, just prior to closing the connection")) >> + (:default-initargs >> + :too-many-threads-handler 'log-too-many-threads) >> (:documentation "A taskmaster that starts one thread for listening >> -to incoming requests and one thread for each incoming connection. >> +to incoming requests and one new thread for each incoming connection. >> +If 'max-threads' is supplied, the number of threads is limited to that. > > Why did you chose to implement create-threads-function and > too-many-threads-handler as slots rather than generic functions? The > latter seems much more natural to me. > >> >> This is the default taskmaster implementation for multi-threaded Lisp >> implementations.")) >> >> -;; usocket implementation >> +(defmethod increment-taskmaster-thread-count ((taskmaster one-thread-per-connection-taskmaster)) >> + (when (taskmaster-max-threads taskmaster) >> + (bt:with-lock-held ((taskmaster-thread-count-lock taskmaster)) >> + (incf (taskmaster-thread-count taskmaster))))) >> + >> +(defmethod decrement-taskmaster-thread-count ((taskmaster one-thread-per-connection-taskmaster)) >> + (when (taskmaster-max-threads taskmaster) >> + (bt:with-lock-held ((taskmaster-thread-count-lock taskmaster)) >> + (decf (taskmaster-thread-count taskmaster))))) >> + >> +(defun log-too-many-threads (taskmaster socket) >> + (declare (ignore socket)) >> + (let* ((acceptor (taskmaster-acceptor taskmaster)) >> + (logger (and acceptor (acceptor-message-logger acceptor)))) >> + (when logger >> + (funcall logger :warning "Can't handle a new connection, too many threads already")))) >> + >> + >> +;;--- If thread creation is too slow, it would be worth finishing this >> +;;--- For now, it's just a synonym for 'one-thread-per-connection-taskmaster' >> +(defclass pooled-thread-per-connection-taskmaster (one-thread-per-connection-taskmaster) >> + ((create-thread-function >> + :initarg :create-thread-function >> + :initform 'create-taskmaster-thread >> + :accessor taskmaster-create-thread-function >> + :documentation >> + "Function called to create the handler thread")) >> + (:documentation "A taskmaster that starts one thread for listening >> +to incoming requests and then uses a thread pool for each incoming connection. >> +If 'max-threads' is supplied, the number of threads is limited to that.")) >> + >> + >> +;;; usocket implementation >> >> #-:lispworks >> +(progn >> + > > Another top-level progn that should go. > >> (defmethod shutdown ((taskmaster taskmaster)) >> taskmaster) >> >> -#-:lispworks >> (defmethod shutdown ((taskmaster one-thread-per-connection-taskmaster)) >> ;; just wait until the acceptor process has finished, then return >> (loop >> @@ -107,16 +192,39 @@ >> (sleep 1)) >> taskmaster) >> >> -#-:lispworks >> (defmethod execute-acceptor ((taskmaster one-thread-per-connection-taskmaster)) >> (setf (acceptor-process taskmaster) >> - (bt:make-thread (lambda () >> - (accept-connections (taskmaster-acceptor taskmaster))) >> - :name (format nil "Hunchentoot listener \(~A:~A)" >> - (or (acceptor-address (taskmaster-acceptor taskmaster)) "*") >> - (acceptor-port (taskmaster-acceptor taskmaster)))))) >> + (bt:make-thread >> + (lambda () >> + (accept-connections (taskmaster-acceptor taskmaster))) >> + :name (format nil "hunchentoot-listener-~A:~A" >> + (or (acceptor-address (taskmaster-acceptor taskmaster)) "*") >> + (acceptor-port (taskmaster-acceptor taskmaster)))))) >> + >> +(defmethod handle-incoming-connection ((taskmaster one-thread-per-connection-taskmaster) socket) >> + ;; Only take lock if necessary >> + (if (taskmaster-max-threads taskmaster) >> + (if (< (taskmaster-thread-count taskmaster) (taskmaster-max-threads taskmaster)) >> + (progn >> + (increment-taskmaster-thread-count taskmaster) >> + (funcall (taskmaster-create-thread-function taskmaster) taskmaster socket)) >> + (progn >> + (when-let (handler (taskmaster-too-many-threads-handler taskmaster)) >> + (funcall handler taskmaster socket)) >> + ;; Just close the socket, which will effectively abort the request >> + ;;--- It sure would be nice to be able to generate an HTTP 503 error, >> + ;;--- but I just can't seem to get that to work properly >> + (usocket:socket-close socket))) > > Please do not use (if .. (progn ..) (progn ..)). Use cond instead or > refactor. In this case, I'd think that the maintenance of the thread > count could be moved into the generic function that creates the > thread, once the callback slot has been replaced by a gf. > >> + (funcall (taskmaster-create-thread-function taskmaster) taskmaster socket))) >> + >> +(defun create-taskmaster-thread (taskmaster socket) >> + (bt:make-thread >> + (lambda () >> + (multiple-value-prog1 >> + (process-connection (taskmaster-acceptor taskmaster) socket) >> + (decrement-taskmaster-thread-count taskmaster))) >> + :name (format nil (taskmaster-worker-thread-name-format taskmaster) (client-as-string socket)))) >> >> -#-:lispworks >> (defun client-as-string (socket) >> "A helper function which returns the client's address and port as a >> string and tries to act robustly in the presence of network problems." >> @@ -127,15 +235,14 @@ >> (usocket:vector-quad-to-dotted-quad address) >> port)))) >> >> -#-:lispworks >> -(defmethod handle-incoming-connection ((taskmaster one-thread-per-connection-taskmaster) socket) >> - (bt:make-thread (lambda () >> - (process-connection (taskmaster-acceptor taskmaster) socket)) >> - :name (format nil "Hunchentoot worker \(client: ~A)" (client-as-string socket)))) >> +) ;#-:lispworks >> + >> >> -;; LispWorks implementation >> +;;; LispWorks implementation >> >> #+:lispworks >> +(progn >> + > > Another top-level progn (not going to point at those if there are any > more, please let them all go). > >> (defmethod shutdown ((taskmaster taskmaster)) >> (when-let (process (acceptor-process (taskmaster-acceptor taskmaster))) >> ;; kill the main acceptor process, see LW documentation for >> @@ -143,20 +250,38 @@ >> (mp:process-kill process)) >> taskmaster) >> >> -#+:lispworks >> (defmethod execute-acceptor ((taskmaster one-thread-per-connection-taskmaster)) >> (accept-connections (taskmaster-acceptor taskmaster))) >> >> -#+:lispworks >> -(defmethod handle-incoming-connection ((taskmaster one-thread-per-connection-taskmaster) handle) >> +(defmethod handle-incoming-connection ((taskmaster one-thread-per-connection-taskmaster) socket) >> (incf *worker-counter*) >> ;; check if we need to perform a global GC >> (when (and *cleanup-interval* >> (zerop (mod *worker-counter* *cleanup-interval*))) >> (when *cleanup-function* >> (funcall *cleanup-function*))) >> - (mp:process-run-function (format nil "Hunchentoot worker \(client: ~{~A:~A~})" >> - (multiple-value-list >> - (get-peer-address-and-port handle))) >> - nil #'process-connection >> - (taskmaster-acceptor taskmaster) handle)) >> + (if (taskmaster-max-threads taskmaster) >> + (if (< (taskmaster-thread-count taskmaster) (taskmaster-max-threads taskmaster)) >> + (progn >> + (increment-taskmaster-thread-count taskmaster) >> + (funcall (taskmaster-create-thread-function taskmaster) taskmaster socket)) >> + ;; With any luck, we never get this far if we've exceeded the thread count >> + ;; "Good" implementations of 'accept-connections' won't even accept connection requests >> + (progn >> + (when-let (handler (taskmaster-too-many-threads-handler taskmaster)) >> + (funcall handler taskmaster socket)) >> + (usocket:socket-close socket))) >> + (funcall (taskmaster-create-thread-function taskmaster) taskmaster socket))) > > Another (if ... (progn ..)) that should be improved. > >> + >> +(defun create-taskmaster-thread (taskmaster socket) >> + (flet ((process (taskmaster sock) >> + (multiple-value-prog1 >> + (process-connection (taskmaster-acceptor taskmaster) socket) >> + (decrement-taskmaster-thread-count taskmaster)))) >> + (mp:process-run-function (format nil "hunchentoot-worker-{~A:~A~})" >> + (multiple-value-list >> + (get-peer-address-and-port socket))) >> + nil #'process taskmaster socket))) >> + >> +) ;#+:lispworks >> + >> >> >> _______________________________________________ >> tbnl-devel site list >> tbnl-devel at common-lisp.net >> http://common-lisp.net/mailman/listinfo/tbnl-devel >> > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel From hans.huebner at gmail.com Tue Jun 1 13:28:59 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Tue, 1 Jun 2010 15:28:59 +0200 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: <29EE915A-E7BB-4A7B-9932-DB2D35FF51EE@itasoftware.com> References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <29EE915A-E7BB-4A7B-9932-DB2D35FF51EE@itasoftware.com> Message-ID: Scott, as we have chosen to implement Hunchentoot as object oriented program, using generic functions is the proper way to extend the functionality. I do agree that this is not the only way how to structure Lisp programs and it may also not be the best way according to taste and preference. Please use generic functions in order not to make the next guy wonder why part of Hunchentoot is this way, and part of it is another. Thanks. -Hans On Tue, Jun 1, 2010 at 15:23, Scott McKay wrote: > I'll address all these issues, then send the next set > of changes back according to the referenced file. > > BTW, I chose not to use a generic function for the thread > creation function and the too-many-threads handler for what > I have to assume is the same reason that the various logger > functions are also done as slots: so that you aren't forced > to subclass just to provide a couple of functions. ?If this > were Java, I'd say subclassing is the right approach, but > since it's Lisp, I think supplying a function is better. > After all, that's what first-class functions are for! ?:-) > > Thanks! > > > On May 30, 2010, at 5:56 AM, Hans H?bner wrote: > >> Hi Scott, >> >> first off, thank you for taking the time to improve Hunchentoot and >> for sending a proposed patch. ?Please have a look at >> http://weitz.de/patches.html before submitting your next patch for >> review. ?In particular, it makes reviews much easier if there is >> documentation about what the patch means to do. >> >> On Thu, May 27, 2010 at 16:57, Scott McKay wrote: >>> A few notes: >>> ?- The function conditionalized out with #+++potentially-faster-way >>> ? is meant to be a hint as to how we might refuse the connection >>> ? without invoking the overhead of accepting the over-the-limit >>> ? connection. ?It might be slightly faster, but I don't know if >>> ? I like the idea of constantly closing and reopening the listener. >> >> I don't like the idea, as it opens up a race condition which will >> result in connections being rejected under high load. >> >>> ?- 'handle-incoming-connection' on 'one-thread-per-connection-taskmaster' >>> ? ?should really try to generate an HTTP 503 error, instead of just >>> ? ?closing the connection. ?I tried several things to make this happen, >>> ? ?but nothing seemed to work properly. ?It seems a shame to have to >>> ? ?open the client connection, suck in the whole request, etc etc, >>> ? ?just to do this. ?Is there a better way? ?Is there some sort of >>> ? ?"connection refused" we can do at the socket level? >> >> I don't see a need to read the request in order to reply with a 503 >> error. ?If the server can't dispatch the request because a resource >> limit has been hit, there is nothing wrong with just sending a 503 >> reply without looking at the request at all. ?Berkeley sockets do not >> provide a means to reject individual pending connections. >> >> Further comments inline: >> >>> >>> --Scott >>> >>> >>> Modified: trunk/qres/lisp/libs/hunchentoot/packages.lisp >>> ============================================================================== >>> --- trunk/qres/lisp/libs/hunchentoot/packages.lisp ? ? ?(original) >>> +++ trunk/qres/lisp/libs/hunchentoot/packages.lisp ? ? ?Thu May 27 10:31:21 2010 >>> @@ -192,7 +192,6 @@ >>> ? ? ? ? ? "MIME-TYPE" >>> ? ? ? ? ? "NEXT-SESSION-ID" >>> ? ? ? ? ? "NO-CACHE" >>> - ? ? ? ? ? "ONE-THREAD-PER-CONNECTION-TASKMASTER" >>> ? ? ? ? ? "PARAMETER" >>> ? ? ? ? ? "PARAMETER-ERROR" >>> ? ? ? ? ? "POST-PARAMETER" >>> @@ -250,7 +249,6 @@ >>> ? ? ? ? ? "SET-COOKIE" >>> ? ? ? ? ? "SET-COOKIE*" >>> ? ? ? ? ? "SHUTDOWN" >>> - ? ? ? ? ? "SINGLE-THREADED-TASKMASTER" >>> ? ? ? ? ? #-:hunchentoot-no-ssl "SSL-ACCEPTOR" >>> ? ? ? ? ? "SSL-P" >>> ? ? ? ? ? "START" >>> @@ -259,7 +257,12 @@ >>> ? ? ? ? ? "STOP" >>> ? ? ? ? ? "TASKMASTER" >>> ? ? ? ? ? "TASKMASTER-ACCEPTOR" >>> - ? ? ? ? ? "URL-DECODE" >>> + ? ? ? ? ? "SINGLE-THREADED-TASKMASTER" >>> + ? ? ? ? ? "ONE-THREAD-PER-CONNECTION-TASKMASTER" >>> + ? ? ? ? ? "POOLED-THREAD-PER-CONNECTION-TASKMASTER" >>> + ? ? ? ? ? "INCREMENT-TASKMASTER-THREAD-COUNT" >>> + ? ? ? ? ?"DECREMENT-TASKMASTER-THREAD-COUNT" >>> + ? ? ? ? ?"URL-DECODE" >>> ? ? ? ? ? "URL-ENCODE" >>> ? ? ? ? ? "USER-AGENT")) >>> >>> Modified: trunk/qres/lisp/libs/hunchentoot/acceptor.lisp >>> ============================================================================== >>> --- trunk/qres/lisp/libs/hunchentoot/acceptor.lisp ? ? ?(original) >>> +++ trunk/qres/lisp/libs/hunchentoot/acceptor.lisp ? ? ?Thu May 27 10:31:21 2010 >>> @@ -86,7 +86,7 @@ >>> reason to change this to NIL.") >>> ? (input-chunking-p :initarg :input-chunking-p >>> ? ? ? ? ? ? ? ? ? ? :accessor acceptor-input-chunking-p >>> - ? ? ? ? ? ? ? ? ? ? ?:documentation "A generalized boolean denoting >>> + ? ? ? ? ? ? ? ? ? ?:documentation "A generalized boolean denoting >>> whether the acceptor may use chunked encoding for input, i.e. when >>> accepting request bodies from the client. ?The default is T and >>> there's usually no reason to change this to NIL.") >>> @@ -117,8 +117,7 @@ >>> process different from the one where START was called.") >>> ? #-:lispworks >>> ? (listen-socket :accessor acceptor-listen-socket >>> - ? ? ? ? ? ? ? ? ?:documentation "The socket listening for incoming >>> -connections.") >>> + ? ? ? ? ? ? ? ? ?:documentation "The socket listening for incoming connections.") >>> ? (acceptor-shutdown-p :initform nil >>> ? ? ? ? ? ? ? ? ? ? ? ?:accessor acceptor-shutdown-p >>> ? ? ? ? ? ? ? ? ? ? ? ?:documentation "A flag that makes the acceptor >>> @@ -349,9 +348,12 @@ >>> ?;; the default is to always answer "no" >>> ?nil) >>> >>> -;; usocket implementation >>> + >>> +;;; usocket implementation >>> >>> #-:lispworks >>> +(progn >> >> What is this progn needed for? >> >>> + >>> (defmethod start-listening ((acceptor acceptor)) >>> ?(setf (acceptor-listen-socket acceptor) >>> ? ? ? ?(usocket:socket-listen (or (acceptor-address acceptor) >>> @@ -361,26 +363,61 @@ >>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? :element-type '(unsigned-byte 8))) >>> ?(values)) >>> >>> -#-:lispworks >>> (defmethod accept-connections ((acceptor acceptor)) >>> ?(usocket:with-server-socket (listener (acceptor-listen-socket acceptor)) >>> ? ?(loop >>> - ? ? (when (acceptor-shutdown-p acceptor) >>> - ? ? ? (return)) >>> - ? ? (when (usocket:wait-for-input listener :timeout +new-connection-wait-time+) >>> - ? ? ? (handler-case >>> - ? ? ? ? ? (when-let (client-connection (usocket:socket-accept listener)) >>> - ? ? ? ? ? ? (set-timeouts client-connection >>> - ? ? ? ? ? ? ? ? ? ? ? ? ? (acceptor-read-timeout acceptor) >>> - ? ? ? ? ? ? ? ? ? ? ? ? ? (acceptor-write-timeout acceptor)) >>> - ? ? ? ? ? ? (handle-incoming-connection (acceptor-taskmaster acceptor) >>> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? client-connection)) >>> - ? ? ? ? ;; ignore condition >>> - ? ? ? ? (usocket:connection-aborted-error ())))))) >>> + ? ? ?(when (acceptor-shutdown-p acceptor) >>> + ? ? ? (return)) >>> + ? ? ?(when (usocket:wait-for-input listener :timeout +new-connection-wait-time+) >>> + ? ? ? (handler-case >>> + ? ? ? ? ? (let ((taskmaster (acceptor-taskmaster acceptor))) >>> + ? ? ? ? ? ? (when-let (client-connection (usocket:socket-accept listener)) >>> + ? ? ? ? ? ? ? (set-timeouts client-connection >>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? (acceptor-read-timeout acceptor) >>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? (acceptor-write-timeout acceptor)) >>> + ? ? ? ? ? ? ? ;; This will bail if the taskmaster has reached its thread limit >>> + ? ? ? ? ? ? ? (handle-incoming-connection taskmaster client-connection))) >>> + ? ? ? ? ;; Ignore the error >>> + ? ? ? ? (usocket:connection-aborted-error ())))))) >>> + >>> +#+++potentially-faster-way >>> +(defmethod accept-connections ((acceptor acceptor)) >>> + ?(loop >>> + ? ?(usocket:with-server-socket (listener (acceptor-listen-socket acceptor)) >>> + ? ? ?(loop named waiter doing >>> + ? ? ? (when (acceptor-shutdown-p acceptor) >>> + ? ? ? ? (return-from accept-connections)) >>> + ? ? ? (when (usocket:wait-for-input listener :timeout +new-connection-wait-time+) >>> + ? ? ? ? (handler-case >>> + ? ? ? ? ? ? (let ((taskmaster (acceptor-taskmaster acceptor))) >>> + ? ? ? ? ? ? ? ;; Optimization to avoid creating the client connection: >>> + ? ? ? ? ? ? ? ;; if the taskmaster has reached its thread limit, just close >>> + ? ? ? ? ? ? ? ;; and reopen the listener socket, and don't even call 'accept' >>> + ? ? ? ? ? ? ? (when (and (taskmaster-max-threads taskmaster) >>> + ? ? ? ? ? ? ? ? ? ? ? ? ?(> (taskmaster-thread-count taskmaster) (taskmaster-max-threads taskmaster))) >>> + ? ? ? ? ? ? ? ? (when-let (handler (taskmaster-too-many-threads-handler taskmaster)) >>> + ? ? ? ? ? ? ? ? ? (funcall handler taskmaster listener)) >>> + ? ? ? ? ? ? ? ? (usocket:socket-close listener) ? ? ? ;close the listener >>> + ? ? ? ? ? ? ? ? (setq listener nil) >>> + ? ? ? ? ? ? ? ? (start-listening acceptor) ? ? ? ? ? ?;and start up a new one >>> + ? ? ? ? ? ? ? ? (return-from waiter)) >>> + ? ? ? ? ? ? ? (when-let (client-connection (usocket:socket-accept listener)) >>> + ? ? ? ? ? ? ? ? (set-timeouts client-connection >>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (acceptor-read-timeout acceptor) >>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (acceptor-write-timeout acceptor)) >>> + ? ? ? ? ? ? ? ? ;; This will bail if the taskmaster has reached its thread limit >>> + ? ? ? ? ? ? ? ? (handle-incoming-connection taskmaster client-connection))) >>> + ? ? ? ? ? ;; Ignore the error >>> + ? ? ? ? ? (usocket:connection-aborted-error ()))))))) >>> + >>> +) ? ? ?;#-:lispworks >>> >>> -;; LispWorks implementation >>> + >>> +;;; LispWorks implementation >>> >>> #+:lispworks >>> +(progn >>> + >> >> Don't use progn here. ?Conditionalize the individual top-level forms. >> Otherwise, automatic reindentation will screw up the source file. >> >>> (defmethod start-listening ((acceptor acceptor)) >>> ?(multiple-value-bind (listener-process startup-condition) >>> ? ? ?(comm:start-up-server :service (acceptor-port acceptor) >>> @@ -398,8 +435,8 @@ >>> ? ? ? ? ? ? ? ? ? ? ? ? ? ?;; is made >>> ? ? ? ? ? ? ? ? ? ? ? ? ? ?:function (lambda (handle) >>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(unless (acceptor-shutdown-p acceptor) >>> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(handle-incoming-connection >>> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (acceptor-taskmaster acceptor) handle))) >>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(let ((taskmaster (acceptor-taskmaster acceptor))) >>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (handle-incoming-connection taskmaster client-connection)))) >>> ? ? ? ? ? ? ? ? ? ? ? ? ? ?;; wait until the acceptor was successfully started >>> ? ? ? ? ? ? ? ? ? ? ? ? ? ?;; or an error condition is returned >>> ? ? ? ? ? ? ? ? ? ? ? ? ? ?:wait t) >>> @@ -409,11 +446,13 @@ >>> ? ?(setf (acceptor-process acceptor) listener-process) >>> ? ?(values))) >>> >>> -#+:lispworks >>> (defmethod accept-connections ((acceptor acceptor)) >>> ?(mp:process-unstop (acceptor-process acceptor)) >>> ?nil) >>> >>> +) ? ? ?;#+:lispworks >>> + >>> + >>> (defun list-request-dispatcher (request) >>> ?"The default request dispatcher which selects a request handler >>> based on a list of individual request dispatchers all of which can >>> >>> Modified: trunk/qres/lisp/libs/hunchentoot/taskmaster.lisp >>> ============================================================================== >>> --- trunk/qres/lisp/libs/hunchentoot/taskmaster.lisp ? ?(original) >>> +++ trunk/qres/lisp/libs/hunchentoot/taskmaster.lisp ? ?Thu May 27 10:31:21 2010 >>> @@ -62,6 +62,21 @@ >>> might terminate all threads that are currently associated with it. >>> This function is called by the acceptor's STOP method.")) >>> >>> +;; Default method >>> +(defmethod taskmaster-max-threads ((taskmaster taskmaster)) >>> + ?nil) >>> + >>> +;; Default method >>> +(defmethod taskmaster-thread-count ((taskmaster taskmaster)) >>> + ?0) >>> + >>> +(defmethod increment-taskmaster-thread-count ((taskmaster taskmaster)) >>> + ?nil) >>> + >>> +(defmethod decrement-taskmaster-thread-count ((taskmaster taskmaster)) >>> + ?nil) >>> + >>> + >>> (defclass single-threaded-taskmaster (taskmaster) >>> ?() >>> ?(:documentation "A taskmaster that runs synchronously in the thread >>> @@ -80,25 +95,95 @@ >>> ?;; in a single-threaded environment we just call PROCESS-CONNECTION >>> ?(process-connection (taskmaster-acceptor taskmaster) socket)) >>> >>> + >>> (defclass one-thread-per-connection-taskmaster (taskmaster) >>> ?(#-:lispworks >>> - ? (acceptor-process :accessor acceptor-process >>> - ? ? ? ? ? ? ? ? ? ? :documentation "A process that accepts incoming >>> -connections and hands them off to new processes for request >>> -handling.")) >>> + ? (acceptor-process >>> + ? ?:accessor acceptor-process >>> + ? ?:documentation >>> + ? ?"A process that accepts incoming connections and hands them off to new processes >>> + ? ? for request handling.") >>> + ? (create-thread-function >>> + ? ?:initarg :create-thread-function >>> + ? ?:initform 'create-taskmaster-thread >>> + ? ?:accessor taskmaster-create-thread-function >>> + ? ?:documentation >>> + ? ?"Function called to create the handler thread; >>> + ? ? takes two arguments, the taskmaster and the socket") >>> + ? ;; Support for bounding the number of threads we'll create >>> + ? (max-threads >>> + ? ?:type (or integer null) >>> + ? ?:initarg :max-threads >>> + ? ?:initform nil >>> + ? ?:accessor taskmaster-max-threads) >>> + ? (thread-count >>> + ? ?:type integer >>> + ? ?:initform 0 >>> + ? ?:accessor taskmaster-thread-count) >>> + ? (thread-count-lock >>> + ? ?:initform (bt:make-lock "taskmaster-thread-count") >>> + ? ?:accessor taskmaster-thread-count-lock) >>> + ? (worker-thread-name-format >>> + ? ?:type (or string null) >>> + ? ?:initarg :worker-thread-name-format >>> + ? ?:initform "hunchentoot-worker-~A" >>> + ? ?:accessor taskmaster-worker-thread-name-format) >>> + ? (too-many-threads-handler >>> + ? ?:initarg :too-many-threads-handler >>> + ? ?:initform nil >>> + ? ?:accessor taskmaster-too-many-threads-handler >>> + ? ?:documentation >>> + ? ?"Function called with two arguments, the taskmaster and the socket, >>> + ? ? when too many threads reached, just prior to closing the connection")) >>> + ?(:default-initargs >>> + ? :too-many-threads-handler 'log-too-many-threads) >>> ?(:documentation "A taskmaster that starts one thread for listening >>> -to incoming requests and one thread for each incoming connection. >>> +to incoming requests and one new thread for each incoming connection. >>> +If 'max-threads' is supplied, the number of threads is limited to that. >> >> Why did you chose to implement create-threads-function and >> too-many-threads-handler as slots rather than generic functions? ?The >> latter seems much more natural to me. >> >>> >>> This is the default taskmaster implementation for multi-threaded Lisp >>> implementations.")) >>> >>> -;; usocket implementation >>> +(defmethod increment-taskmaster-thread-count ((taskmaster one-thread-per-connection-taskmaster)) >>> + ?(when (taskmaster-max-threads taskmaster) >>> + ? ?(bt:with-lock-held ((taskmaster-thread-count-lock taskmaster)) >>> + ? ? ?(incf (taskmaster-thread-count taskmaster))))) >>> + >>> +(defmethod decrement-taskmaster-thread-count ((taskmaster one-thread-per-connection-taskmaster)) >>> + ?(when (taskmaster-max-threads taskmaster) >>> + ? ?(bt:with-lock-held ((taskmaster-thread-count-lock taskmaster)) >>> + ? ? ?(decf (taskmaster-thread-count taskmaster))))) >>> + >>> +(defun log-too-many-threads (taskmaster socket) >>> + ?(declare (ignore socket)) >>> + ?(let* ((acceptor (taskmaster-acceptor taskmaster)) >>> + ? ? ? ?(logger ? (and acceptor (acceptor-message-logger acceptor)))) >>> + ? ?(when logger >>> + ? ? ?(funcall logger :warning "Can't handle a new connection, too many threads already")))) >>> + >>> + >>> +;;--- If thread creation is too slow, it would be worth finishing this >>> +;;--- For now, it's just a synonym for 'one-thread-per-connection-taskmaster' >>> +(defclass pooled-thread-per-connection-taskmaster (one-thread-per-connection-taskmaster) >>> + ?((create-thread-function >>> + ? ?:initarg :create-thread-function >>> + ? ?:initform 'create-taskmaster-thread >>> + ? ?:accessor taskmaster-create-thread-function >>> + ? ?:documentation >>> + ? ?"Function called to create the handler thread")) >>> + ?(:documentation "A taskmaster that starts one thread for listening >>> +to incoming requests and then uses a thread pool for each incoming connection. >>> +If 'max-threads' is supplied, the number of threads is limited to that.")) >>> + >>> + >>> +;;; usocket implementation >>> >>> #-:lispworks >>> +(progn >>> + >> >> Another top-level progn that should go. >> >>> (defmethod shutdown ((taskmaster taskmaster)) >>> ?taskmaster) >>> >>> -#-:lispworks >>> (defmethod shutdown ((taskmaster one-thread-per-connection-taskmaster)) >>> ?;; just wait until the acceptor process has finished, then return >>> ?(loop >>> @@ -107,16 +192,39 @@ >>> ? (sleep 1)) >>> ?taskmaster) >>> >>> -#-:lispworks >>> (defmethod execute-acceptor ((taskmaster one-thread-per-connection-taskmaster)) >>> ?(setf (acceptor-process taskmaster) >>> - ? ? ? ?(bt:make-thread (lambda () >>> - ? ? ? ? ? ? ? ? ? ? ? ? ?(accept-connections (taskmaster-acceptor taskmaster))) >>> - ? ? ? ? ? ? ? ? ? ? ? ?:name (format nil "Hunchentoot listener \(~A:~A)" >>> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(or (acceptor-address (taskmaster-acceptor taskmaster)) "*") >>> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(acceptor-port (taskmaster-acceptor taskmaster)))))) >>> + ? ? ? ?(bt:make-thread >>> + ? ? ? ?(lambda () >>> + ? ? ? ? ?(accept-connections (taskmaster-acceptor taskmaster))) >>> + ? ? ? ?:name (format nil "hunchentoot-listener-~A:~A" >>> + ? ? ? ? ? ? ? ? ? ? ?(or (acceptor-address (taskmaster-acceptor taskmaster)) "*") >>> + ? ? ? ? ? ? ? ? ? ? ?(acceptor-port (taskmaster-acceptor taskmaster)))))) >>> + >>> +(defmethod handle-incoming-connection ((taskmaster one-thread-per-connection-taskmaster) socket) >>> + ?;; Only take lock if necessary >>> + ?(if (taskmaster-max-threads taskmaster) >>> + ? ?(if (< (taskmaster-thread-count taskmaster) (taskmaster-max-threads taskmaster)) >>> + ? ? ?(progn >>> + ? ? ? (increment-taskmaster-thread-count taskmaster) >>> + ? ? ? (funcall (taskmaster-create-thread-function taskmaster) taskmaster socket)) >>> + ? ? ?(progn >>> + ? ? ? (when-let (handler (taskmaster-too-many-threads-handler taskmaster)) >>> + ? ? ? ? (funcall handler taskmaster socket)) >>> + ? ? ? ;; Just close the socket, which will effectively abort the request >>> + ? ? ? ;;--- It sure would be nice to be able to generate an HTTP 503 error, >>> + ? ? ? ;;--- but I just can't seem to get that to work properly >>> + ? ? ? (usocket:socket-close socket))) >> >> Please do not use (if .. (progn ..) (progn ..)). ?Use cond instead or >> refactor. ?In this case, I'd think that the maintenance of the thread >> count could be moved into the generic function that creates the >> thread, once the callback slot has been replaced by a gf. >> >>> + ? ?(funcall (taskmaster-create-thread-function taskmaster) taskmaster socket))) >>> + >>> +(defun create-taskmaster-thread (taskmaster socket) >>> + ?(bt:make-thread >>> + ? (lambda () >>> + ? ? (multiple-value-prog1 >>> + ? ? ? ?(process-connection (taskmaster-acceptor taskmaster) socket) >>> + ? ? ? (decrement-taskmaster-thread-count taskmaster))) >>> + ? :name (format nil (taskmaster-worker-thread-name-format taskmaster) (client-as-string socket)))) >>> >>> -#-:lispworks >>> (defun client-as-string (socket) >>> ?"A helper function which returns the client's address and port as a >>> string and tries to act robustly in the presence of network problems." >>> @@ -127,15 +235,14 @@ >>> ? ? ? ? ? ? ?(usocket:vector-quad-to-dotted-quad address) >>> ? ? ? ? ? ? ?port)))) >>> >>> -#-:lispworks >>> -(defmethod handle-incoming-connection ((taskmaster one-thread-per-connection-taskmaster) socket) >>> - ?(bt:make-thread (lambda () >>> - ? ? ? ? ? ? ? ? ? ?(process-connection (taskmaster-acceptor taskmaster) socket)) >>> - ? ? ? ? ? ? ? ? ?:name (format nil "Hunchentoot worker \(client: ~A)" (client-as-string socket)))) >>> +) ? ? ?;#-:lispworks >>> + >>> >>> -;; LispWorks implementation >>> +;;; LispWorks implementation >>> >>> #+:lispworks >>> +(progn >>> + >> >> Another top-level progn (not going to point at those if there are any >> more, please let them all go). >> >>> (defmethod shutdown ((taskmaster taskmaster)) >>> ?(when-let (process (acceptor-process (taskmaster-acceptor taskmaster))) >>> ? ?;; kill the main acceptor process, see LW documentation for >>> @@ -143,20 +250,38 @@ >>> ? ?(mp:process-kill process)) >>> ?taskmaster) >>> >>> -#+:lispworks >>> (defmethod execute-acceptor ((taskmaster one-thread-per-connection-taskmaster)) >>> ?(accept-connections (taskmaster-acceptor taskmaster))) >>> >>> -#+:lispworks >>> -(defmethod handle-incoming-connection ((taskmaster one-thread-per-connection-taskmaster) handle) >>> +(defmethod handle-incoming-connection ((taskmaster one-thread-per-connection-taskmaster) socket) >>> ?(incf *worker-counter*) >>> ?;; check if we need to perform a global GC >>> ?(when (and *cleanup-interval* >>> ? ? ? ? ? ? (zerop (mod *worker-counter* *cleanup-interval*))) >>> ? ?(when *cleanup-function* >>> ? ? ?(funcall *cleanup-function*))) >>> - ?(mp:process-run-function (format nil "Hunchentoot worker \(client: ~{~A:~A~})" >>> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (multiple-value-list >>> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(get-peer-address-and-port handle))) >>> - ? ? ? ? ? ? ? ? ? ? ? ? ? nil #'process-connection >>> - ? ? ? ? ? ? ? ? ? ? ? ? ? (taskmaster-acceptor taskmaster) handle)) >>> + ?(if (taskmaster-max-threads taskmaster) >>> + ? ?(if (< (taskmaster-thread-count taskmaster) (taskmaster-max-threads taskmaster)) >>> + ? ? ?(progn >>> + ? ? ? (increment-taskmaster-thread-count taskmaster) >>> + ? ? ? (funcall (taskmaster-create-thread-function taskmaster) taskmaster socket)) >>> + ? ? ?;; With any luck, we never get this far if we've exceeded the thread count >>> + ? ? ?;; "Good" implementations of 'accept-connections' won't even accept connection requests >>> + ? ? ?(progn >>> + ? ? ? (when-let (handler (taskmaster-too-many-threads-handler taskmaster)) >>> + ? ? ? ? (funcall handler taskmaster socket)) >>> + ? ? ? (usocket:socket-close socket))) >>> + ? ?(funcall (taskmaster-create-thread-function taskmaster) taskmaster socket))) >> >> Another (if ... (progn ..)) that should be improved. >> >>> + >>> +(defun create-taskmaster-thread (taskmaster socket) >>> + ?(flet ((process (taskmaster sock) >>> + ? ? ? ? ?(multiple-value-prog1 >>> + ? ? ? ? ? ? ?(process-connection (taskmaster-acceptor taskmaster) socket) >>> + ? ? ? ? ? ?(decrement-taskmaster-thread-count taskmaster)))) >>> + ? ?(mp:process-run-function (format nil "hunchentoot-worker-{~A:~A~})" >>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(multiple-value-list >>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (get-peer-address-and-port socket))) >>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?nil #'process taskmaster socket))) >>> + >>> +) ? ? ?;#+:lispworks >>> + >>> >>> >>> _______________________________________________ >>> tbnl-devel site list >>> tbnl-devel at common-lisp.net >>> http://common-lisp.net/mailman/listinfo/tbnl-devel >>> >> >> _______________________________________________ >> tbnl-devel site list >> tbnl-devel at common-lisp.net >> http://common-lisp.net/mailman/listinfo/tbnl-devel > > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel > From swm at itasoftware.com Tue Jun 1 14:15:49 2010 From: swm at itasoftware.com (Scott McKay) Date: Tue, 1 Jun 2010 10:15:49 -0400 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <29EE915A-E7BB-4A7B-9932-DB2D35FF51EE@itasoftware.com> Message-ID: <4FF5568F-6CDE-40C6-A6E6-410B0F19B6E8@itasoftware.com> On Jun 1, 2010, at 9:28 AM, Hans H?bner wrote: > Scott, > > as we have chosen to implement Hunchentoot as object oriented program, > using generic functions is the proper way to extend the functionality. > I do agree that this is not the only way how to structure Lisp > programs and it may also not be the best way according to taste and > preference. Please use generic functions in order not to make the > next guy wonder why part of Hunchentoot is this way, and part of it is > another. > Well, hang on... that's one of the reasons I *didn't* use generic functions. Take a look at 'access-logger' and 'message-logger' in the 'acceptor' class; this is exactly the model I followed. If I do the new feature using generic functions, I will be doing exactly what you are warning about: making the next guy wonder why one part is one way and another part is another way. From hans.huebner at gmail.com Tue Jun 1 14:24:41 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Tue, 1 Jun 2010 16:24:41 +0200 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: <4FF5568F-6CDE-40C6-A6E6-410B0F19B6E8@itasoftware.com> References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <29EE915A-E7BB-4A7B-9932-DB2D35FF51EE@itasoftware.com> <4FF5568F-6CDE-40C6-A6E6-410B0F19B6E8@itasoftware.com> Message-ID: On Tue, Jun 1, 2010 at 16:15, Scott McKay wrote: > Well, hang on... that's one of the reasons I *didn't* > use generic functions. ?Take a look at 'access-logger' > and 'message-logger' in the 'acceptor' class; this is > exactly the model I followed. ?If I do the new feature > using generic functions, I will be doing exactly what > you are warning about: making the next guy wonder why > one part is one way and another part is another way. That's what you get for growing software: There is always something left over from the first iterations. I have a patch pending that will make the logging functions into generic functions and remove the slots containing the functions. Please help us move there :) Thanks, Hans From swm at itasoftware.com Tue Jun 1 14:42:07 2010 From: swm at itasoftware.com (Scott McKay) Date: Tue, 1 Jun 2010 10:42:07 -0400 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <29EE915A-E7BB-4A7B-9932-DB2D35FF51EE@itasoftware.com> <4FF5568F-6CDE-40C6-A6E6-410B0F19B6E8@itasoftware.com> Message-ID: <0398D637-2BE5-4E7F-896A-60778DD9C911@itasoftware.com> On Jun 1, 2010, at 10:24 AM, Hans H?bner wrote: > On Tue, Jun 1, 2010 at 16:15, Scott McKay wrote: >> Well, hang on... that's one of the reasons I *didn't* >> use generic functions. Take a look at 'access-logger' >> and 'message-logger' in the 'acceptor' class; this is >> exactly the model I followed. If I do the new feature >> using generic functions, I will be doing exactly what >> you are warning about: making the next guy wonder why >> one part is one way and another part is another way. > > That's what you get for growing software: There is always something > left over from the first iterations. I have a patch pending that will > make the logging functions into generic functions and remove the slots > containing the functions. Please help us move there :) > Ha ha ha ha! OK, I accept your appeal for help. :-) I'll get something back to you in the next day or so. Thanks! --Scott From dlw at itasoftware.com Tue Jun 1 15:04:28 2010 From: dlw at itasoftware.com (Daniel Weinreb) Date: Tue, 01 Jun 2010 11:04:28 -0400 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> Message-ID: <4C05217C.4040406@itasoftware.com> Hans, Hans H?bner wrote: > Hi Scott, > > first off, thank you for taking the time to improve Hunchentoot and > for sending a proposed patch. Please have a look at > http://weitz.de/patches.html before submitting your next patch for > review. In particular, it makes reviews much easier if there is > documentation about what the patch means to do. > > On Thu, May 27, 2010 at 16:57, Scott McKay wrote: > >> A few notes: >> - The function conditionalized out with #+++potentially-faster-way >> is meant to be a hint as to how we might refuse the connection >> without invoking the overhead of accepting the over-the-limit >> connection. It might be slightly faster, but I don't know if >> I like the idea of constantly closing and reopening the listener. >> > > I don't like the idea, as it opens up a race condition which will > result in connections being rejected under high load. > I don't understand what race condition you mean. Would you please explain? About rejecting connections: We understand that this behavior would not always be desirable, and I assumed that Scott means it as an option rather than the only possible behavior. This behavior can be useful in a cluster of servers, in which you'd like to tell the load balancer that it should choose another server. Thank you! -- Dan -------------- next part -------------- An HTML attachment was scrubbed... URL: From hans.huebner at gmail.com Wed Jun 2 06:25:21 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Wed, 2 Jun 2010 08:25:21 +0200 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: <4C05217C.4040406@itasoftware.com> References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> Message-ID: On Tue, Jun 1, 2010 at 17:04, Daniel Weinreb wrote: > I don't understand what race condition you mean. > Would you please explain? Rereading the patch, I withdraw my concern. The closing and opening of the socket happens when there is a problem anyway, so it is not too bad if one connection more or less gets dropped. But I think I have trouble understanding what the code really wants to do, a comment describing the intended behavior would be helpful. > About rejecting connections: We understand that > this behavior would not always be desirable, > and I assumed that Scott means it as an option > rather than the only possible behavior. This > behavior can be useful in a cluster of servers, > in which you'd like to tell the load balancer > that it should choose another server. There should be two configurable modes as to how Hunchentoot handles an incoming connection when no handler thread is available: One would set up things so that the connection is accepted, but a 503 error is sent out right away. The other would suspend accepting connections until a thread is available. The latter mode would make new clients hang (and, if the listener queue runs full, be rejected) until resources are available again. Applications that use a load balancer with multiple backends would use the first mode in order to always get quick responses. Applications that consist of only one server would use the second mode with a suitable backlog configuration so that load peaks can (sometimes) be handled without rejecting client connections. -Hans From swm at itasoftware.com Thu Jun 3 19:12:50 2010 From: swm at itasoftware.com (Scott McKay) Date: Thu, 3 Jun 2010 15:12:50 -0400 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> Message-ID: <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> On Jun 2, 2010, at 2:25 AM, Hans H?bner wrote: > On Tue, Jun 1, 2010 at 17:04, Daniel Weinreb wrote: >> I don't understand what race condition you mean. >> Would you please explain? > > Rereading the patch, I withdraw my concern. The closing and opening > of the socket happens when there is a problem anyway, so it is not too > bad if one connection more or less gets dropped. But I think I have > trouble understanding what the code really wants to do, a comment > describing the intended behavior would be helpful. > >> About rejecting connections: We understand that >> this behavior would not always be desirable, >> and I assumed that Scott means it as an option >> rather than the only possible behavior. This >> behavior can be useful in a cluster of servers, >> in which you'd like to tell the load balancer >> that it should choose another server. > > There should be two configurable modes as to how Hunchentoot handles > an incoming connection when no handler thread is available: One would > set up things so that the connection is accepted, but a 503 error is > sent out right away. The other would suspend accepting connections > until a thread is available. The latter mode would make new clients > hang (and, if the listener queue runs full, be rejected) until > resources are available again. > The latter is a nice idea, but I have no good idea how to implement it portably, given the very limited thread model provided by Bordeaux Threads. > Applications that use a load balancer with multiple backends would use > the first mode in order to always get quick responses. Applications > that consist of only one server would use the second mode with a > suitable backlog configuration so that load peaks can (sometimes) be > handled without rejecting client connections. > > -Hans > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel From hans.huebner at gmail.com Thu Jun 3 19:32:12 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Thu, 3 Jun 2010 21:32:12 +0200 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> Message-ID: On Thu, Jun 3, 2010 at 21:12, Scott McKay wrote: > On Jun 2, 2010, at 2:25 AM, Hans H?bner wrote: >> There should be two configurable modes as to how Hunchentoot handles >> an incoming connection when no handler thread is available: ?One would >> set up things so that the connection is accepted, but a 503 error is >> sent out right away. ?The other would suspend accepting connections >> until a thread is available. ?The latter mode would make new clients >> hang (and, if the listener queue runs full, be rejected) until >> resources are available again. >> > > The latter is a nice idea, but I have no good idea how to > implement it portably, given the very limited thread model > provided by Bordeaux Threads. One possible approach would be: When the acceptor detects that there is a resource shortage, it waits on a synchronization variable until a thread in the pool is freed instead of looping to the next accept. The wait should be periodically interrupted to check for server shutdown. I believe that this should be relatively straightforward, although it may need some refactoring in the ACCEPT-CONNECTIONS generic function. Maybe it makes sense to add a new generic function ACCEPT-NEXT-CONNECTION that could have an :AROUND method for your pooled acceptor class which would wait for a thread to be available before calling the next method. What do you mean by the limited thread model of BT, how does it hurt? -Hans From swm at itasoftware.com Thu Jun 3 19:52:34 2010 From: swm at itasoftware.com (Scott McKay) Date: Thu, 3 Jun 2010 15:52:34 -0400 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> Message-ID: <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> On Jun 3, 2010, at 3:32 PM, Hans H?bner wrote: > On Thu, Jun 3, 2010 at 21:12, Scott McKay wrote: >> On Jun 2, 2010, at 2:25 AM, Hans H?bner wrote: > >>> There should be two configurable modes as to how Hunchentoot handles >>> an incoming connection when no handler thread is available: One would >>> set up things so that the connection is accepted, but a 503 error is >>> sent out right away. The other would suspend accepting connections >>> until a thread is available. The latter mode would make new clients >>> hang (and, if the listener queue runs full, be rejected) until >>> resources are available again. >>> >> >> The latter is a nice idea, but I have no good idea how to >> implement it portably, given the very limited thread model >> provided by Bordeaux Threads. > > One possible approach would be: When the acceptor detects that there > is a resource shortage, it waits on a synchronization variable until a > thread in the pool is freed instead of looping to the next accept. > The wait should be periodically interrupted to check for server > shutdown. I believe that this should be relatively straightforward, > although it may need some refactoring in the ACCEPT-CONNECTIONS > generic function. Maybe it makes sense to add a new generic function > ACCEPT-NEXT-CONNECTION that could have an :AROUND method for your > pooled acceptor class which would wait for a thread to be available > before calling the next method. > By the way, this is seeming rather beyond the scope of the original patch. I'll spend another day on this, but I really can't justify spending too much longer on it -- even though it's fun. > What do you mean by the limited thread model of BT, how does it hurt? > My mistake! There is 'condition-wait' and 'condition-notify'. From hans.huebner at gmail.com Thu Jun 3 20:28:28 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Thu, 3 Jun 2010 22:28:28 +0200 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> Message-ID: On Thu, Jun 3, 2010 at 21:52, Scott McKay wrote: > On Jun 3, 2010, at 3:32 PM, Hans H?bner wrote: >> One possible approach would be: ?When the acceptor detects that there >> is a resource shortage, it waits on a synchronization variable until a >> thread in the pool is freed instead of looping to the next accept. >> The wait should be periodically interrupted to check for server >> shutdown. ?I believe that this should be relatively straightforward, >> although it may need some refactoring in the ACCEPT-CONNECTIONS >> generic function. ?Maybe it makes sense to add a new generic function >> ACCEPT-NEXT-CONNECTION that could have an :AROUND method for your >> pooled acceptor class which would wait for a thread to be available >> before calling the next method. >> > > By the way, this is seeming rather beyond the scope of the > original patch. ?I'll spend another day on this, but I really > can't justify spending too much longer on it -- even though > it's fun. I understand - Thanks for taking some extra time! It'd be very nice if the thread pooling mechanism became generally useful and not require a lot of documentation describing its limitations. Cheers, Hans From swm at itasoftware.com Thu Jun 3 20:58:51 2010 From: swm at itasoftware.com (Scott McKay) Date: Thu, 3 Jun 2010 16:58:51 -0400 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> Message-ID: <7521D77A-B539-4C80-BB7F-35388EA63176@itasoftware.com> On Jun 3, 2010, at 4:28 PM, Hans H?bner wrote: > On Thu, Jun 3, 2010 at 21:52, Scott McKay wrote: > >> On Jun 3, 2010, at 3:32 PM, Hans H?bner wrote: > >>> One possible approach would be: When the acceptor detects that there >>> is a resource shortage, it waits on a synchronization variable until a >>> thread in the pool is freed instead of looping to the next accept. >>> The wait should be periodically interrupted to check for server >>> shutdown. I believe that this should be relatively straightforward, >>> although it may need some refactoring in the ACCEPT-CONNECTIONS >>> generic function. Maybe it makes sense to add a new generic function >>> ACCEPT-NEXT-CONNECTION that could have an :AROUND method for your >>> pooled acceptor class which would wait for a thread to be available >>> before calling the next method. >>> >> >> By the way, this is seeming rather beyond the scope of the >> original patch. I'll spend another day on this, but I really >> can't justify spending too much longer on it -- even though >> it's fun. > > I understand - Thanks for taking some extra time! It'd be very nice > if the thread pooling mechanism became generally useful and not > require a lot of documentation describing its limitations. > Yep, I'm working on this now. It doesn't look like I'll need to do any refactoring, but I'm not sure how to get 'condition-wait' to let itself be interrupted to poll for server shutdowns... From hans.huebner at gmail.com Thu Jun 3 21:47:40 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Thu, 3 Jun 2010 23:47:40 +0200 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: <7521D77A-B539-4C80-BB7F-35388EA63176@itasoftware.com> References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> <7521D77A-B539-4C80-BB7F-35388EA63176@itasoftware.com> Message-ID: On Thu, Jun 3, 2010 at 22:58, Scott McKay wrote: > Yep, I'm working on this now. ?It doesn't look like I'll > need to do any refactoring, but I'm not sure how to get > 'condition-wait' to let itself be interrupted to poll for > server shutdowns... It could be that you need to use condition-notify for that. -Hans From patrick.may at mac.com Fri Jun 4 01:53:36 2010 From: patrick.may at mac.com (Patrick May) Date: Thu, 03 Jun 2010 21:53:36 -0400 Subject: [hunchentoot-devel] caching and create-folder-dispatcher-and-handler Message-ID: <8D502099-089C-4F58-A217-9E0BBAF6547D@mac.com> Is it possible to set max-age or no-cache with create-folder-dispatcher-and-handler? I have some audio files that change infrequently and one of my clients is caching them and not catching the changes. Thanks, Patrick -------------- next part -------------- A non-text attachment was scrubbed... Name: smime.p7s Type: application/pkcs7-signature Size: 2421 bytes Desc: not available URL: From swm at itasoftware.com Fri Jun 4 15:08:36 2010 From: swm at itasoftware.com (Scott McKay) Date: Fri, 4 Jun 2010 11:08:36 -0400 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> Message-ID: <586901B0-D79A-4AE5-908F-4FFEE9E3AF38@itasoftware.com> On Jun 3, 2010, at 4:28 PM, Hans H?bner wrote: > On Thu, Jun 3, 2010 at 21:52, Scott McKay wrote: > >> On Jun 3, 2010, at 3:32 PM, Hans H?bner wrote: > >>> One possible approach would be: When the acceptor detects that there >>> is a resource shortage, it waits on a synchronization variable until a >>> thread in the pool is freed instead of looping to the next accept. >>> The wait should be periodically interrupted to check for server >>> shutdown. I believe that this should be relatively straightforward, >>> although it may need some refactoring in the ACCEPT-CONNECTIONS >>> generic function. Maybe it makes sense to add a new generic function >>> ACCEPT-NEXT-CONNECTION that could have an :AROUND method for your >>> pooled acceptor class which would wait for a thread to be available >>> before calling the next method. >>> >> >> By the way, this is seeming rather beyond the scope of the >> original patch. I'll spend another day on this, but I really >> can't justify spending too much longer on it -- even though >> it's fun. > > I understand - Thanks for taking some extra time! It'd be very nice > if the thread pooling mechanism became generally useful and not > require a lot of documentation describing its limitations. > OK, I seem to have something useful working. Note that the pooled-thread taskmaster is still a stub, for two reasons: 1. Thread creation is actually pretty damned fast (on Linux, anyway -- around 200 microseconds on my box), and it's not clear that it's worth it. 2. This *is* where Bordeaux Threads falls down, maybe because not all Lisp implementations support it. "Restarting" an existing thread seems not to be a supported operation, so we'd need some complex -- and potentially fragile and error-prone -- protocol for doing "restartable" threads. The other stuff now works, and there's a test suite for it all in QRes (sadly, not in H'toot itself). From hans.huebner at gmail.com Fri Jun 4 20:29:26 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Fri, 4 Jun 2010 22:29:26 +0200 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: <586901B0-D79A-4AE5-908F-4FFEE9E3AF38@itasoftware.com> References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> <586901B0-D79A-4AE5-908F-4FFEE9E3AF38@itasoftware.com> Message-ID: On Fri, Jun 4, 2010 at 17:08, Scott McKay wrote: > OK, I seem to have something useful working. ?Note that the pooled-thread > taskmaster is still a stub, for two reasons: > ?1. Thread creation is actually pretty damned fast (on Linux, anyway -- > ? ?around 200 microseconds on my box), and it's not clear that it's worth it. > ?2. This *is* where Bordeaux Threads falls down, maybe because not all Lisp > ? ?implementations support it. ?"Restarting" an existing thread seems not > ? ?to be a supported operation, so we'd need some complex -- and potentially > ? ?fragile and error-prone -- protocol for doing "restartable" threads. I'd say that the idea of a thread pool can be abandoned if it is not useful, and it seems that it would not be useful. Let's not put in stubs. -Hans From hans.huebner at gmail.com Sat Jun 5 08:26:41 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Sat, 5 Jun 2010 10:26:41 +0200 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> <586901B0-D79A-4AE5-908F-4FFEE9E3AF38@itasoftware.com> Message-ID: Scott, just as a clarification: I think that if thread pools are not useful (which seems to be the case), we should not have stubs in there for them. I do think that your change, which allows limiting the number of client threads that Hunchentoot has active at any one time, should have the two discussed modes when the limit has been reached: The default mode would be to pause accepting requests or, once the queue runs full, to reject them. The alternative mode would be to accept all new connections but reply with a 503. I don't know what the state of your patch is now, but I guess that the above is what you have implemented. This is just to verify that we're on the same page. Thanks! Hans From swm at itasoftware.com Sat Jun 5 13:01:04 2010 From: swm at itasoftware.com (Scott McKay) Date: Sat, 5 Jun 2010 09:01:04 -0400 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> <586901B0-D79A-4AE5-908F-4FFEE9E3AF38@itasoftware.com> Message-ID: <18913F0E-C4B7-4044-8D02-45BCBBA0CDDE@itasoftware.com> On Jun 5, 2010, at 4:26 AM, Hans H?bner wrote: > Scott, > > just as a clarification: I think that if thread pools are not useful > (which seems to be the case), we should not have stubs in there for > them. I do think that your change, which allows limiting the number > of client threads that Hunchentoot has active at any one time, should > have the two discussed modes when the limit has been reached: The > default mode would be to pause accepting requests or, once the queue > runs full, to reject them. The alternative mode would be to accept > all new connections but reply with a 503. > > I don't know what the state of your patch is now, but I guess that the > above is what you have implemented. This is just to verify that we're > on the same page. > Yes, the above is what I have implemented. I'll remove the "pooled thread" stub on Monday (too busy this weekend). Right now, the default for 'one-thread-per-request-taskmaster' (or whatever it's called) is what it used to be: just keep accepting connections. If you'd like me to change that to "accept N connections and spin off a thread; queue up a few more connections; then issue HTTP 503", that would suit me just fine. It seems like a good, default behavior. The one question I have is, what should N be and what should the increment be beyond which we reject? I'm thinking something like allow 8 threads, and 2-4 on the queue, but I'll go with whatever you think is reasonable. From hans.huebner at gmail.com Sat Jun 5 13:29:44 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Sat, 5 Jun 2010 15:29:44 +0200 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: <18913F0E-C4B7-4044-8D02-45BCBBA0CDDE@itasoftware.com> References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> <586901B0-D79A-4AE5-908F-4FFEE9E3AF38@itasoftware.com> <18913F0E-C4B7-4044-8D02-45BCBBA0CDDE@itasoftware.com> Message-ID: On Sat, Jun 5, 2010 at 15:01, Scott McKay wrote: > Right now, the default for 'one-thread-per-request-taskmaster' > (or whatever it's called) is what it used to be: just keep > accepting connections. ?If you'd like me to change that to > "accept N connections and spin off a thread; queue up a few > more connections; then issue HTTP 503", that would suit me > just fine. ?It seems like a good, default behavior. ?The one > question I have is, what should N be and what should the > increment be beyond which we reject? ?I'm thinking something > like allow 8 threads, and 2-4 on the queue, but I'll go with > whatever you think is reasonable. The default limit for threads needs to be much larger than 8 as - correct me if I'm wrong - there is one thread per connection, not per request. This means that the number of threads allowed is basically identical to the number of simultaneous clients. Lets set the default limit to 100 so that Hunchentoot is not the first thing one needs to tune when coping with larger loads. The listener queue length should not be too short (something like 30-50) so that load transients can be handled. Enjoy your weekend, Hans From gordon at itasoftware.com Sat Jun 5 14:43:17 2010 From: gordon at itasoftware.com (Gordon Sims) Date: Sat, 05 Jun 2010 10:43:17 -0400 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> <586901B0-D79A-4AE5-908F-4FFEE9E3AF38@itasoftware.com> <18913F0E-C4B7-4044-8D02-45BCBBA0CDDE@itasoftware.com> Message-ID: <4C0A6285.5020007@itasoftware.com> On 06/05/2010 09:29 AM, Hans H?bner wrote: > Lets set the default > limit to 100 so that Hunchentoot is not the first thing one needs to > tune when coping with larger loads. The listener queue length should > not be too short (something like 30-50) so that load transients can be > handled. Hans is correct that it should higher. Just for comparison, Tomcat's defaults are about double: 200 threads (maxThreads) and 100 queue size (acceptCount). http://tomcat.apache.org/tomcat-6.0-doc/config/http.html -Gordon From reddaly at gmail.com Sat Jun 5 18:57:45 2010 From: reddaly at gmail.com (Red Daly) Date: Sat, 5 Jun 2010 11:57:45 -0700 Subject: [hunchentoot-devel] Charset assumptions, in particular in POST bodies Message-ID: About 6 months ago I got some strange encoding errors with a Hunchentoot web server. There are a few of places in Hunchentoot where the +latin-1+ character encoding is used as the external format regardless of headers received from the client: - GET-POST-DATA returns a +latin-1+ externally encoded stream no matter what when the WANT-STREAM parameter is true. - PARSE-MULTIPART-FORM-DATA creates a +latin-1+ stream from the CONTENT-STREAM of the request. (relevant RFC: 2388) - MAYBE-READ-POST-PARAMETERS uses +latin-1+ to process "application/x-www-form-urlencoded" content-type POST bodies In addition, RECOMPUTE-REQUEST-PARAMETERS seems to interpret both the message body and the query string according to a charset in the request header. I thought that Content-Type was only supposed to affect the message body, not the headers (which are assumed to be in ASCII). Then shouldn't the URL and query string always be read as ASCII? RFC2047 discusses non-ascii headers for MIME, but I don't know if that is relevant except for parsing multipart forms. I'm not thoroughly versed in the HTTP protocol, but it seems that these are bugs in Hunchentoot. I have a half-completed patch but I want to get some more opinions before I go any further. There may also be other lurking encoding issues in Hunchentoot, or I may be entirely mistaken. Proposed solution: - GET-POST-DATA, PARSE-MULTIPART-FORM-DATA, and MAYBE-READ-POST-PARAMETERS should respect the Content-Type header in the request and use that to define the external-format of the stream used to parse - RECOMPUTE-REQUEST-PARAMETERS should only use the Content-Type external format to parse the post parameters - PARSE-MULTIPART-FORM-DATA may need additional review to be in accordance with RFC2047 and RFC2388 Feedback, please. Thanks, Red From hans.huebner at gmail.com Sat Jun 5 22:28:16 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Sun, 6 Jun 2010 00:28:16 +0200 Subject: [hunchentoot-devel] Charset assumptions, in particular in POST bodies In-Reply-To: References: Message-ID: Red, I'd suggest that you make yourself thoroughly familiar with the relevant RFCs and supply a patch once you are sure that Hunchentoot is buggy. I know that there are some places in Hunchentoot that assume Latin 1 encoding, but I also faintly remember that I have checked RFC conformance in some of these cases years ago. Additionally, before changing Hunchentoot, it'd be very nice to have a case that exposes non-conformant behavior. I'm not saying that Hunchentoot is bug free, but clients are generally buggy as well and we don't want to cater for buggy clients in general. -Hans On Sat, Jun 5, 2010 at 20:57, Red Daly wrote: > About 6 months ago I got some strange encoding errors with a > Hunchentoot web server. ?There are a few of places in Hunchentoot > where the +latin-1+ character encoding is used as the external format > regardless of headers received from the client: > > - GET-POST-DATA returns a +latin-1+ externally encoded stream no > matter what when the WANT-STREAM parameter is true. > - PARSE-MULTIPART-FORM-DATA creates a +latin-1+ stream from the > CONTENT-STREAM of the request. ?(relevant RFC: 2388) > - MAYBE-READ-POST-PARAMETERS uses +latin-1+ to process > "application/x-www-form-urlencoded" content-type POST bodies > > In addition, RECOMPUTE-REQUEST-PARAMETERS seems to interpret both the > message body and the query string according to a charset in the > request header. ?I thought that Content-Type was only supposed to > affect the message body, not the headers (which are assumed to be in > ASCII). ?Then shouldn't the URL and query string always be read as > ASCII? ?RFC2047 discusses non-ascii headers for MIME, but I don't know > if that is relevant except for parsing multipart forms. > > I'm not thoroughly versed in the HTTP protocol, but it seems that > these are bugs in Hunchentoot. ?I have a half-completed patch but I > want to get some more opinions before I go any further. ?There may > also be other lurking encoding issues in Hunchentoot, or I may be > entirely mistaken. > > Proposed solution: > - GET-POST-DATA, PARSE-MULTIPART-FORM-DATA, and > MAYBE-READ-POST-PARAMETERS should respect the Content-Type header in > the request and use that to define the external-format of the stream > used to parse > - RECOMPUTE-REQUEST-PARAMETERS should only use the Content-Type > external format to parse the post parameters > - PARSE-MULTIPART-FORM-DATA may need additional review to be in > accordance with RFC2047 and RFC2388 > > Feedback, please. > > Thanks, > Red > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel > From dochang at gmail.com Sun Jun 6 19:37:55 2010 From: dochang at gmail.com (Desmond O. Chang) Date: Mon, 7 Jun 2010 03:37:55 +0800 Subject: [hunchentoot-devel] maybe bug + patch In-Reply-To: References: <87r5vhfd2y.fsf@gmail.com> Message-ID: Hi Edi, I have this problem too. Richard's patch works for me on SBCL. But I repatch his patch to fix the default value of ACCEPTOR-SHUTDOWN-P to T, because every acceptor should be closed when it is created. See attachment please. Thanks, Des. On Wed, Aug 12, 2009 at 11:25 PM, Edi Weitz wrote: > Hi Richard, > > Thanks for the patch. ?I'm currently on vacation, so I won't be able > to look into this until the end of the month, but can you confirm that > with this change you can stop and start the same acceptor several > times without problems? ?Which Lisp implementation did you test this > on? ?(I'm asking because Hans and I briefly looked at this a couple of > weeks ago and we thought it wasn't totally trivial.) > > Thanks, > Edi. > > > On Wed, Aug 12, 2009 at 2:09 PM, Richard KLINDA wrote: >> Hello, I may have found a bug. >> >> After stopping an acceptor with STOP, one can't start it again with >> START, because the START method doesn't reset the value of >> acceptor-shutdown-p to NIL, so the listener returns/quits instantly. ?See the >> attached trivial patch, that fixes the issue for me, but maybe I'm just >> missing something here. >> >> >> >> -- >> Richard >> >> _______________________________________________ >> tbnl-devel site list >> tbnl-devel at common-lisp.net >> http://common-lisp.net/mailman/listinfo/tbnl-devel >> > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel > -------------- next part -------------- A non-text attachment was scrubbed... Name: hunchentoot.diff Type: text/x-diff Size: 1001 bytes Desc: not available URL: From dlw at itasoftware.com Mon Jun 7 13:29:32 2010 From: dlw at itasoftware.com (Daniel Weinreb) Date: Mon, 07 Jun 2010 09:29:32 -0400 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> <586901B0-D79A-4AE5-908F-4FFEE9E3AF38@itasoftware.com> Message-ID: <4C0CF43C.4020600@itasoftware.com> Hans H?bner wrote: > > > I'd say that the idea of a thread pool can be abandoned if it is not > useful, and it seems that it would not be useful. And don't forget to put in comments or other documentation explaining why this decision was made, so that future developers (a) won't spend time putting it in (or asking why it's not in), and (b) will understand why that decision was made, in case things change (e.g. thread creation turns out to be expensive under some new, unforseen circumstance). -- Dan -------------- next part -------------- An HTML attachment was scrubbed... URL: From swm at itasoftware.com Mon Jun 7 19:14:51 2010 From: swm at itasoftware.com (Scott McKay) Date: Mon, 7 Jun 2010 15:14:51 -0400 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> <586901B0-D79A-4AE5-908F-4FFEE9E3AF38@itasoftware.com> <18913F0E-C4B7-4044-8D02-45BCBBA0CDDE@itasoftware.com> Message-ID: Hans, I've attached a file with the diffs against (what I believe is) the latest version of Hunchentoot. This does what we discussed. -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: htoot-diffs.text URL: -------------- next part -------------- On Jun 5, 2010, at 9:29 AM, Hans H?bner wrote: > On Sat, Jun 5, 2010 at 15:01, Scott McKay wrote: >> Right now, the default for 'one-thread-per-request-taskmaster' >> (or whatever it's called) is what it used to be: just keep >> accepting connections. If you'd like me to change that to >> "accept N connections and spin off a thread; queue up a few >> more connections; then issue HTTP 503", that would suit me >> just fine. It seems like a good, default behavior. The one >> question I have is, what should N be and what should the >> increment be beyond which we reject? I'm thinking something >> like allow 8 threads, and 2-4 on the queue, but I'll go with >> whatever you think is reasonable. > > The default limit for threads needs to be much larger than 8 as - > correct me if I'm wrong - there is one thread per connection, not per > request. This means that the number of threads allowed is basically > identical to the number of simultaneous clients. Lets set the default > limit to 100 so that Hunchentoot is not the first thing one needs to > tune when coping with larger loads. The listener queue length should > not be too short (something like 30-50) so that load transients can be > handled. > > Enjoy your weekend, > Hans > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel From hans.huebner at gmail.com Mon Jun 7 19:33:35 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Mon, 7 Jun 2010 21:33:35 +0200 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> <586901B0-D79A-4AE5-908F-4FFEE9E3AF38@itasoftware.com> <18913F0E-C4B7-4044-8D02-45BCBBA0CDDE@itasoftware.com> Message-ID: Scott, thank you for the patch. May I ask you to add a documentation update? Thanks, Hans On Mon, Jun 7, 2010 at 21:14, Scott McKay wrote: > Hans, I've attached a file with the diffs against > (what I believe is) the latest version of Hunchentoot. > This does what we discussed. > > > > > > > On Jun 5, 2010, at 9:29 AM, Hans H?bner wrote: > >> On Sat, Jun 5, 2010 at 15:01, Scott McKay wrote: >>> Right now, the default for 'one-thread-per-request-taskmaster' >>> (or whatever it's called) is what it used to be: just keep >>> accepting connections. ?If you'd like me to change that to >>> "accept N connections and spin off a thread; queue up a few >>> more connections; then issue HTTP 503", that would suit me >>> just fine. ?It seems like a good, default behavior. ?The one >>> question I have is, what should N be and what should the >>> increment be beyond which we reject? ?I'm thinking something >>> like allow 8 threads, and 2-4 on the queue, but I'll go with >>> whatever you think is reasonable. >> >> The default limit for threads needs to be much larger than 8 as - >> correct me if I'm wrong - there is one thread per connection, not per >> request. ? This means that the number of threads allowed is basically >> identical to the number of simultaneous clients. ?Lets set the default >> limit to 100 so that Hunchentoot is not the first thing one needs to >> tune when coping with larger loads. ?The listener queue length should >> not be too short (something like 30-50) so that load transients can be >> handled. >> >> Enjoy your weekend, >> Hans >> >> _______________________________________________ >> tbnl-devel site list >> tbnl-devel at common-lisp.net >> http://common-lisp.net/mailman/listinfo/tbnl-devel > > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel > From swm at itasoftware.com Mon Jun 7 19:38:43 2010 From: swm at itasoftware.com (Scott McKay) Date: Mon, 7 Jun 2010 15:38:43 -0400 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> <586901B0-D79A-4AE5-908F-4FFEE9E3AF38@itasoftware.com> <18913F0E-C4B7-4044-8D02-45BCBBA0CDDE@itasoftware.com> Message-ID: In the file index.xml, I presume? Sure, no problem. Just don't ask me to document all the stuff that was already in the code, but not yet documented! :-) On Jun 7, 2010, at 3:33 PM, Hans H?bner wrote: > Scott, > > thank you for the patch. May I ask you to add a documentation update? > > Thanks, > Hans > > On Mon, Jun 7, 2010 at 21:14, Scott McKay wrote: >> Hans, I've attached a file with the diffs against >> (what I believe is) the latest version of Hunchentoot. >> This does what we discussed. >> >> >> >> >> >> >> On Jun 5, 2010, at 9:29 AM, Hans H?bner wrote: >> >>> On Sat, Jun 5, 2010 at 15:01, Scott McKay wrote: >>>> Right now, the default for 'one-thread-per-request-taskmaster' >>>> (or whatever it's called) is what it used to be: just keep >>>> accepting connections. If you'd like me to change that to >>>> "accept N connections and spin off a thread; queue up a few >>>> more connections; then issue HTTP 503", that would suit me >>>> just fine. It seems like a good, default behavior. The one >>>> question I have is, what should N be and what should the >>>> increment be beyond which we reject? I'm thinking something >>>> like allow 8 threads, and 2-4 on the queue, but I'll go with >>>> whatever you think is reasonable. >>> >>> The default limit for threads needs to be much larger than 8 as - >>> correct me if I'm wrong - there is one thread per connection, not per >>> request. This means that the number of threads allowed is basically >>> identical to the number of simultaneous clients. Lets set the default >>> limit to 100 so that Hunchentoot is not the first thing one needs to >>> tune when coping with larger loads. The listener queue length should >>> not be too short (something like 30-50) so that load transients can be >>> handled. >>> >>> Enjoy your weekend, >>> Hans >>> >>> _______________________________________________ >>> tbnl-devel site list >>> tbnl-devel at common-lisp.net >>> http://common-lisp.net/mailman/listinfo/tbnl-devel >> >> >> _______________________________________________ >> tbnl-devel site list >> tbnl-devel at common-lisp.net >> http://common-lisp.net/mailman/listinfo/tbnl-devel >> > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel From hans.huebner at gmail.com Mon Jun 7 19:42:41 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Mon, 7 Jun 2010 21:42:41 +0200 Subject: [hunchentoot-devel] 'max-threads' behavior for Hunchentoot In-Reply-To: References: <96F4A9B1-5603-4DE1-9144-415C9251DAA5@itasoftware.com> <4C05217C.4040406@itasoftware.com> <16493326-0713-4954-8976-19ED0C10D74C@itasoftware.com> <836C1566-0760-4000-AAA9-440FBAAB51EA@itasoftware.com> <586901B0-D79A-4AE5-908F-4FFEE9E3AF38@itasoftware.com> <18913F0E-C4B7-4044-8D02-45BCBBA0CDDE@itasoftware.com> Message-ID: On Mon, Jun 7, 2010 at 21:38, Scott McKay wrote: > In the file index.xml, I presume? Yes please. > Sure, no problem. ?Just don't ask me to document all the > stuff that was already in the code, but not yet documented! ?:-) Surely not. Just document the new feature. Thank you! -Hans > > On Jun 7, 2010, at 3:33 PM, Hans H?bner wrote: > >> Scott, >> >> thank you for the patch. ?May I ask you to add a documentation update? >> >> Thanks, >> Hans >> >> On Mon, Jun 7, 2010 at 21:14, Scott McKay wrote: >>> Hans, I've attached a file with the diffs against >>> (what I believe is) the latest version of Hunchentoot. >>> This does what we discussed. >>> >>> >>> >>> >>> >>> >>> On Jun 5, 2010, at 9:29 AM, Hans H?bner wrote: >>> >>>> On Sat, Jun 5, 2010 at 15:01, Scott McKay wrote: >>>>> Right now, the default for 'one-thread-per-request-taskmaster' >>>>> (or whatever it's called) is what it used to be: just keep >>>>> accepting connections. ?If you'd like me to change that to >>>>> "accept N connections and spin off a thread; queue up a few >>>>> more connections; then issue HTTP 503", that would suit me >>>>> just fine. ?It seems like a good, default behavior. ?The one >>>>> question I have is, what should N be and what should the >>>>> increment be beyond which we reject? ?I'm thinking something >>>>> like allow 8 threads, and 2-4 on the queue, but I'll go with >>>>> whatever you think is reasonable. >>>> >>>> The default limit for threads needs to be much larger than 8 as - >>>> correct me if I'm wrong - there is one thread per connection, not per >>>> request. ? This means that the number of threads allowed is basically >>>> identical to the number of simultaneous clients. ?Lets set the default >>>> limit to 100 so that Hunchentoot is not the first thing one needs to >>>> tune when coping with larger loads. ?The listener queue length should >>>> not be too short (something like 30-50) so that load transients can be >>>> handled. >>>> >>>> Enjoy your weekend, >>>> Hans >>>> >>>> _______________________________________________ >>>> tbnl-devel site list >>>> tbnl-devel at common-lisp.net >>>> http://common-lisp.net/mailman/listinfo/tbnl-devel >>> >>> >>> _______________________________________________ >>> tbnl-devel site list >>> tbnl-devel at common-lisp.net >>> http://common-lisp.net/mailman/listinfo/tbnl-devel >>> >> >> _______________________________________________ >> tbnl-devel site list >> tbnl-devel at common-lisp.net >> http://common-lisp.net/mailman/listinfo/tbnl-devel > > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel > From dochang at gmail.com Mon Jun 7 21:19:08 2010 From: dochang at gmail.com (Desmond O. Chang) Date: Tue, 8 Jun 2010 05:19:08 +0800 Subject: [hunchentoot-devel] format string error in HANDLE-REQUEST Message-ID: Hi all, In SBCL, HANDLE-REQUEST raises an error like this if *LOG-LISP-BACKTRACE-P* is NIL: error in FORMAT: no more arguments ~A~:[~*~;~%~:*~A~] ^ [Condition of type SB-FORMAT:FORMAT-ERROR] Just remove the first ~* to fix it, or you can apply the attachment. Thanks, Des. -------------- next part -------------- A non-text attachment was scrubbed... Name: handle-request.diff Type: text/x-diff Size: 665 bytes Desc: not available URL: From vseloved at gmail.com Tue Jun 8 04:06:06 2010 From: vseloved at gmail.com (Vsevolod Dyomkin) Date: Tue, 8 Jun 2010 07:06:06 +0300 Subject: [hunchentoot-devel] format string error in HANDLE-REQUEST In-Reply-To: References: Message-ID: Hi, it's not a problem with Hunchentoot, but rather new version of SBCL or its incompatibility with SLIME (I'm not yet sure). As this error randomly appears in different situations for me. Best, Vsevolod On Tue, Jun 8, 2010 at 12:19 AM, Desmond O. Chang wrote: > Hi all, > > In SBCL, HANDLE-REQUEST raises an error like this if > *LOG-LISP-BACKTRACE-P* is NIL: > > error in FORMAT: no more arguments > ~A~:[~*~;~%~:*~A~] > ^ > [Condition of type SB-FORMAT:FORMAT-ERROR] > > Just remove the first ~* to fix it, or you can apply the attachment. > > Thanks, > Des. > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel > -- vsevolod -------------- next part -------------- An HTML attachment was scrubbed... URL: From stassats at gmail.com Tue Jun 8 05:23:48 2010 From: stassats at gmail.com (Stas Boukarev) Date: Tue, 08 Jun 2010 09:23:48 +0400 Subject: [hunchentoot-devel] format string error in HANDLE-REQUEST In-Reply-To: (Desmond O. Chang's message of "Tue, 8 Jun 2010 05:19:08 +0800") References: Message-ID: <878w6qnlln.fsf@gmail.com> "Desmond O. Chang" writes: > Hi all, > > In SBCL, HANDLE-REQUEST raises an error like this if > *LOG-LISP-BACKTRACE-P* is NIL: > > error in FORMAT: no more arguments > ~A~:[~*~;~%~:*~A~] > ^ > [Condition of type SB-FORMAT:FORMAT-ERROR] > > Just remove the first ~* to fix it, or you can apply the attachment. > > Thanks, > Des. > > diff --git a/source/hunchentoot/acceptor.lisp b/source/hunchentoot/acceptor.lisp > index 44b7559..e5da7f1 100644 > --- a/source/hunchentoot/acceptor.lisp > +++ b/source/hunchentoot/acceptor.lisp > @@ -439,7 +439,7 @@ handler." > (lambda (cond) > (when *log-lisp-errors-p* > (log-message *lisp-errors-log-level* > - "~A~:[~*~;~%~:*~A~]" > + "~A~:[~;~%~:*~A~]" > cond > (and *log-lisp-backtraces-p* (get-backtrace)))) > ;; if the headers were already sent, the error Format string can be simplified to "~A~@[~%~A~]". -- With Best Regards, Stas. From hans.huebner at gmail.com Tue Jun 8 06:17:56 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Tue, 8 Jun 2010 08:17:56 +0200 Subject: [hunchentoot-devel] format string error in HANDLE-REQUEST In-Reply-To: <878w6qnlln.fsf@gmail.com> References: <878w6qnlln.fsf@gmail.com> Message-ID: Desmond, Stas, thank you for pointing at the bug and fixing it. I've committed the simplified format string. -Hans On Tue, Jun 8, 2010 at 07:23, Stas Boukarev wrote: > "Desmond O. Chang" writes: > >> Hi all, >> >> In SBCL, HANDLE-REQUEST raises an error like this if >> *LOG-LISP-BACKTRACE-P* is NIL: >> >> ?error in FORMAT: no more arguments >> ? ?~A~:[~*~;~%~:*~A~] >> ? ? ? ? ?^ >> ? ? [Condition of type SB-FORMAT:FORMAT-ERROR] >> >> Just remove the first ~* to fix it, or you can apply the attachment. >> >> Thanks, >> Des. >> >> diff --git a/source/hunchentoot/acceptor.lisp b/source/hunchentoot/acceptor.lisp >> index 44b7559..e5da7f1 100644 >> --- a/source/hunchentoot/acceptor.lisp >> +++ b/source/hunchentoot/acceptor.lisp >> @@ -439,7 +439,7 @@ handler." >> ? ? ? ? ? ? ? ? ? ?(lambda (cond) >> ? ? ? ? ? ? ? ? ? ? ?(when *log-lisp-errors-p* >> ? ? ? ? ? ? ? ? ? ? ? ?(log-message *lisp-errors-log-level* >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "~A~:[~*~;~%~:*~A~]" >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "~A~:[~;~%~:*~A~]" >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cond >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (and *log-lisp-backtraces-p* (get-backtrace)))) >> ? ? ? ? ? ? ? ? ? ? ?;; if the headers were already sent, the error > > Format string can be simplified to "~A~@[~%~A~]". > > -- > With Best Regards, Stas. > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel > From ch-tbnl at bobobeach.com Tue Jun 15 23:49:01 2010 From: ch-tbnl at bobobeach.com (Cyrus Harmon) Date: Tue, 15 Jun 2010 16:49:01 -0700 Subject: [hunchentoot-devel] less-than-helpful error message Message-ID: <384BDDB7-FDE8-4C6C-9E40-EA4A5FC45A32@bobobeach.com> Esteemed hunchentoot developers, So, while trying to track down an unrelated issue where my handlers aren't getting called anymore, I came across the following issue where failure to open the message log file results in an error, which, in turn, attempts to open the message log file. The problem in this case was that the permissions were bogus for the directory I was trying to open. But, still, we should probably have a nicer error message than "recursive lock attempt" here. thanks, Cyrus Recursive lock attempt #S(SB-THREAD:MUTEX :NAME "global-message-log-lock" :%OWNER # :STATE 1). [Condition of type SIMPLE-ERROR] Restarts: 0: [TERMINATE-THREAD] Terminate this thread (#) Backtrace: 0: (SB-THREAD:GET-MUTEX # # # #) 1: ((FLET #:WITHOUT-INTERRUPTS-BODY-[CALL-WITH-MUTEX]300)) 2: (HUNCHENTOOT::LOG-MESSAGE-TO-FILE :ERROR "Error while processing connection: ~A")[:EXTERNAL] 3: ((FLET #:LAMBDA103) #) 4: (SIGNAL #)[:EXTERNAL] 5: (ERROR "Recursive lock attempt ~S.")[:EXTERNAL] 6: (SB-THREAD:GET-MUTEX # # # #) 7: ((FLET #:WITHOUT-INTERRUPTS-BODY-[CALL-WITH-MUTEX]300)) 8: (SB-THREAD::CALL-WITH-MUTEX ..) 9: (HUNCHENTOOT::LOG-MESSAGE-TO-FILE :ERROR "~A~:[~*~;~%~:*~A~]")[:EXTERNAL] 10: ((FLET #:LAMBDA250) #" {10036AD531}>) 11: (SIGNAL #" {10036AD531}>)[:EXTERNAL] 12: (ERROR SB-INT:SIMPLE-FILE-ERROR)[:EXTERNAL] 13: (SB-IMPL::SIMPLE-FILE-PERROR "error opening ~S" #P"/usr/home/sly/projects/priv.cyrusharmon.org/hunchentoot-launcher/log/hunchentoot-message.log" 13) 14: ((LABELS SB-IMPL::VANILLA-OPEN-ERROR)) 15: (OPEN #P"/usr/home/sly/projects/priv.cyrusharmon.org/hunchentoot-launcher/log/hunchentoot-message.log")[:EXTERNAL] 16: ((FLET SB-THREAD::WITH-MUTEX-THUNK)) 17: ((FLET #:WITHOUT-INTERRUPTS-BODY-[CALL-WITH-MUTEX]300)) 18: (SB-THREAD::CALL-WITH-MUTEX ..) 19: (HUNCHENTOOT::LOG-MESSAGE-TO-FILE :INFO "Default handler called for script ~A")[:EXTERNAL] 20: (HUNCHENTOOT::DEFAULT-HANDLER) 21: ((SB-PCL::FAST-METHOD HUNCHENTOOT:HANDLE-REQUEST (HUNCHENTOOT:ACCEPTOR HUNCHENTOOT:REQUEST)) ..) 22: ((SB-PCL::FAST-METHOD HUNCHENTOOT:PROCESS-REQUEST (T)) # # #) 23: ((SB-PCL::FAST-METHOD HUNCHENTOOT:PROCESS-CONNECTION (HUNCHENTOOT:ACCEPTOR T)) ..) 24: ((SB-PCL::FAST-METHOD HUNCHENTOOT:PROCESS-CONNECTION :AROUND (HUNCHENTOOT:ACCEPTOR T)) ..) 25: ((LAMBDA ())) 26: ((FLET #:WITHOUT-INTERRUPTS-BODY-[BLOCK369]374)) From hans.huebner at gmail.com Wed Jun 16 04:39:56 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Wed, 16 Jun 2010 06:39:56 +0200 Subject: [hunchentoot-devel] less-than-helpful error message In-Reply-To: <384BDDB7-FDE8-4C6C-9E40-EA4A5FC45A32@bobobeach.com> References: <384BDDB7-FDE8-4C6C-9E40-EA4A5FC45A32@bobobeach.com> Message-ID: On Wed, Jun 16, 2010 at 01:49, Cyrus Harmon wrote: > So, while trying to track down an unrelated issue where my handlers aren't getting called anymore, I came across the following issue where failure to open the message log file results in an error, which, in turn, attempts to open the message log file. The problem in this case was that the permissions were bogus for the directory I was trying to open. But, still, we should probably have a nicer error message than "recursive lock attempt" here. I agree. Can you supply a patch that corrects the problem? Using a recursive lock would probably the easiest solution. Thanks, Hans From fbogdanovic at xnet.hr Wed Jun 16 17:59:59 2010 From: fbogdanovic at xnet.hr (a) Date: Wed, 16 Jun 2010 19:59:59 +0200 Subject: [hunchentoot-devel] hunchentoot error log Message-ID: <2D1490383C63460284332AB58A7AE7CE@komp> Hi. I have this piece of code: ----------------------------------------------------------------------------- (defpackage :web (:use :common-lisp :hunchentoot :cl-who :parenscript)) (in-package :web) (start (make-instance 'acceptor :port 8000)) (push (create-prefix-dispatcher "/index.html" 'index) *dispatch-table*) (defun index () (with-html-output-to-string (str) (:html (:head (:title "Test page")) (:body (dotimes (x 10) (htm (:p "Text"))))))) ------------------------------------------------------------------------ and when I go to http://localhost:8000/index.html I get an error: --------------------------------------------------------- Internal Server Error An error has occured. ------------------------------------------------------------ Where is the error in my code ? And where is the hunchentoot error log ? Thanks -------------- next part -------------- An HTML attachment was scrubbed... URL: From patrick.may at mac.com Thu Jun 17 12:30:43 2010 From: patrick.may at mac.com (Patrick May) Date: Thu, 17 Jun 2010 08:30:43 -0400 Subject: [hunchentoot-devel] hunchentoot error log In-Reply-To: <2D1490383C63460284332AB58A7AE7CE@komp> References: <2D1490383C63460284332AB58A7AE7CE@komp> Message-ID: On Jun 16, 2010, at 1:59 PM, a wrote: > Hi. > > I have this piece of code: > > ----------------------------------------------------------------------------- > (defpackage :web > (:use > :common-lisp > :hunchentoot > :cl-who > :parenscript)) > > (in-package :web) > > (start (make-instance 'acceptor :port 8000)) > > (push (create-prefix-dispatcher "/index.html" 'index) *dispatch-table*) > > (defun index () > (with-html-output-to-string (str) > (:html > (:head > (:title "Test page")) > (:body > (dotimes (x 10) > (htm > (:p "Text"))))))) > > ------------------------------------------------------------------------ > > and when I go to http://localhost:8000/index.html I get an error: > > --------------------------------------------------------- > Internal Server Error > An error has occured. > ------------------------------------------------------------ > > Where is the error in my code ? This works for me using Clozure 64-bit on OSX, evaluating each form in Slime. What Lisp and OS are you using? > And where is the hunchentoot error log ? You'll need to set hunchentoot:*message-log-pathname*. Regards, Patrick -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: smime.p7s Type: application/pkcs7-signature Size: 3679 bytes Desc: not available URL: From fbogdanovic at xnet.hr Thu Jun 17 13:59:39 2010 From: fbogdanovic at xnet.hr (a) Date: Thu, 17 Jun 2010 15:59:39 +0200 Subject: [hunchentoot-devel] hunchentoot error log References: <2D1490383C63460284332AB58A7AE7CE@komp> Message-ID: <3B38A6D78DB04D3F883DDD6A287F048A@komp> This works for me using Clozure 64-bit on OSX, evaluating each form in Slime. What Lisp and OS are you using? I'm using Lispworks on win xp. -------------- next part -------------- An HTML attachment was scrubbed... URL: From fbogdanovic at xnet.hr Thu Jun 17 14:20:11 2010 From: fbogdanovic at xnet.hr (a) Date: Thu, 17 Jun 2010 16:20:11 +0200 Subject: [hunchentoot-devel] hunchentoot error log References: <2D1490383C63460284332AB58A7AE7CE@komp> Message-ID: These are the first three lines of error log --------------------------------------------------------------------------------------------------- [2010-06-17 16:11:26 [ERROR]] The variable LET is unbound. # # ------------------------------------------------------------------------------------------------------------------------- Can you tell me where is the error now ? How can LET be a variable, it is a macro ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From fbogdanovic at xnet.hr Fri Jun 18 12:10:38 2010 From: fbogdanovic at xnet.hr (=?iso-8859-2?Q?Haris_Bogdanovi=E6?=) Date: Fri, 18 Jun 2010 14:10:38 +0200 Subject: [hunchentoot-devel] unchentoot-test Message-ID: <360C4A9BC9BF48B384E6F9773511E53D@komp> Hi. I wanted to try hunchentoot-test by typing: (asdf:oos 'asdf:load-op :hunchentoot-test) Everything went ok but when trying to connect by going to: http://127.0.0.1:4242/hunchentoot/test firefox says unable to connect ? I'm using lispworks on windows. Thanks -------------- next part -------------- An HTML attachment was scrubbed... URL: From hans.huebner at gmail.com Fri Jun 18 12:37:26 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Fri, 18 Jun 2010 14:37:26 +0200 Subject: [hunchentoot-devel] unchentoot-test In-Reply-To: <360C4A9BC9BF48B384E6F9773511E53D@komp> References: <360C4A9BC9BF48B384E6F9773511E53D@komp> Message-ID: 2010/6/18 Haris Bogdanovi? : > I wanted to try hunchentoot-test by typing: > (asdf:oos 'asdf:load-op :hunchentoot-test) > Everything went ok but when trying to connect by going to: > http://127.0.0.1:4242/hunchentoot/test > firefox says unable to connect ? > I'm using lispworks on windows. Did you actually start the server? -Hans From dlw at itasoftware.com Tue Jun 22 15:51:06 2010 From: dlw at itasoftware.com (Daniel Weinreb) Date: Tue, 22 Jun 2010 11:51:06 -0400 Subject: [hunchentoot-devel] less-than-helpful error message In-Reply-To: References: <384BDDB7-FDE8-4C6C-9E40-EA4A5FC45A32@bobobeach.com> Message-ID: <4C20DBEA.9060400@itasoftware.com> I'm not sure that's the best solution. Running into trouble while trying to log an error message is always a pain in the neck, but it's usually not best to just go ahead anyway. I try to write fallbacks. (Hans, I'm sure you know about this idea; I'm just saying it might be good in this case.) Here's a simple example of what I mean. (defun safe-format (stream control-string &rest format-arguments) "This is like FORMAT, except that if a condition is signaled during the call to FORMAT, it falls back by printing the FORMAT control string, followed by as many of the arguments as possible. This function never signals any conditions. This means that it can hide errors, so it should not be used widely. It is intended to be used in code that reports errors and stack traces, and in logging." (handler-case (apply #'format stream control-string format-arguments) (serious-condition () (ignore-errors (flet ((print-fallback (stream) (princ "Error during format: " stream) (princ control-string stream) (dolist (arg format-arguments) (princ " " stream) (handler-case (princ arg stream) (serious-condition () (ignore-errors (princ "[error printing argument of type " stream) (ignore-errors (princ (type-of arg) stream)) (princ "]" stream))))))) (if (null stream) (with-output-to-string (strm) (print-fallback strm)) (print-fallback stream))))))) -- Dan Hans H?bner wrote: > On Wed, Jun 16, 2010 at 01:49, Cyrus Harmon wrote: > >> So, while trying to track down an unrelated issue where my handlers aren't getting called anymore, I came across the following issue where failure to open the message log file results in an error, which, in turn, attempts to open the message log file. The problem in this case was that the permissions were bogus for the directory I was trying to open. But, still, we should probably have a nicer error message than "recursive lock attempt" here. >> > > I agree. Can you supply a patch that corrects the problem? Using a > recursive lock would probably the easiest solution. > > Thanks, > Hans > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel > -------------- next part -------------- An HTML attachment was scrubbed... URL: From fbogdanovic at xnet.hr Tue Jun 22 22:42:32 2010 From: fbogdanovic at xnet.hr (=?iso-8859-2?Q?Haris_Bogdanovi=E6?=) Date: Wed, 23 Jun 2010 00:42:32 +0200 Subject: [hunchentoot-devel] hunchentoot working dir Message-ID: Hi. How do I find out hunchentoot working dir ? I want to add pictures to be accessed by my web page so I want to know where to put them. Thanks. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ch-tbnl at bobobeach.com Wed Jun 23 06:33:05 2010 From: ch-tbnl at bobobeach.com (Cyrus Harmon) Date: Tue, 22 Jun 2010 23:33:05 -0700 Subject: [hunchentoot-devel] less-than-helpful error message In-Reply-To: References: <384BDDB7-FDE8-4C6C-9E40-EA4A5FC45A32@bobobeach.com> Message-ID: <1A680BE1-7D34-4B72-AF6D-E0C087DDE5CC@bobobeach.com> I have no idea if this is the right thing to do for lispworks or not, but this seems to work on SBCL. -------------- next part -------------- A non-text attachment was scrubbed... Name: hunchentoot-recursive-lock.patch Type: application/octet-stream Size: 1060 bytes Desc: not available URL: -------------- next part -------------- Thanks, Cyrus On Jun 15, 2010, at 9:39 PM, Hans H?bner wrote: > On Wed, Jun 16, 2010 at 01:49, Cyrus Harmon wrote: >> So, while trying to track down an unrelated issue where my handlers aren't getting called anymore, I came across the following issue where failure to open the message log file results in an error, which, in turn, attempts to open the message log file. The problem in this case was that the permissions were bogus for the directory I was trying to open. But, still, we should probably have a nicer error message than "recursive lock attempt" here. > > I agree. Can you supply a patch that corrects the problem? Using a > recursive lock would probably the easiest solution. > > Thanks, > Hans > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel From edi at agharta.de Wed Jun 23 06:40:12 2010 From: edi at agharta.de (Edi Weitz) Date: Wed, 23 Jun 2010 08:40:12 +0200 Subject: [hunchentoot-devel] less-than-helpful error message In-Reply-To: <1A680BE1-7D34-4B72-AF6D-E0C087DDE5CC@bobobeach.com> References: <384BDDB7-FDE8-4C6C-9E40-EA4A5FC45A32@bobobeach.com> <1A680BE1-7D34-4B72-AF6D-E0C087DDE5CC@bobobeach.com> Message-ID: Cyrus, Thanks for the patch, but I'm order for this one to be accepted it should work for LispWorks as well. I'd look into it myself, but I currently have problems with my arm/shoulder which prevent me from sitting at my desk for longer periods. Cheers, Edi. On Wed, Jun 23, 2010 at 8:33 AM, Cyrus Harmon wrote: > I have no idea if this is the right thing to do for lispworks or not, but this seems to work on SBCL. > > > > > Thanks, > > Cyrus > > On Jun 15, 2010, at 9:39 PM, Hans H?bner wrote: > >> On Wed, Jun 16, 2010 at 01:49, Cyrus Harmon wrote: >>> So, while trying to track down an unrelated issue where my handlers aren't getting called anymore, I came across the following issue where failure to open the message log file results in an error, which, in turn, attempts to open the message log file. The problem in this case was that the permissions were bogus for the directory I was trying to open. But, still, we should probably have a nicer error message than "recursive lock attempt" here. >> >> I agree. ?Can you supply a patch that corrects the problem? ?Using a >> recursive lock would probably the easiest solution. >> >> Thanks, >> Hans >> >> _______________________________________________ >> tbnl-devel site list >> tbnl-devel at common-lisp.net >> http://common-lisp.net/mailman/listinfo/tbnl-devel > > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel > From hans.huebner at gmail.com Wed Jun 23 09:52:16 2010 From: hans.huebner at gmail.com (=?ISO-8859-1?Q?Hans_H=FCbner?=) Date: Wed, 23 Jun 2010 11:52:16 +0200 Subject: [hunchentoot-devel] less-than-helpful error message In-Reply-To: References: <384BDDB7-FDE8-4C6C-9E40-EA4A5FC45A32@bobobeach.com> <1A680BE1-7D34-4B72-AF6D-E0C087DDE5CC@bobobeach.com> Message-ID: Hi, Edi and I discussed this matter and we agreed that my suggestion that using a recursive lock would solve the problem does not really hold. With the same situation (error signaled while holding the lock and logging, resulting in another log invocation), the recursive lock would result in an infinite recursion and finally stack exhaustion. This would not be an improvement. I think Dan's contribution was good: It should be attempted to do fine-grained error handling for the arguments while logging, and errors while logging should certainly not make the code re-enter the logging code. Cyrus, did you actually verify that your patch solves the problem? We might be missing something. Thanks, Hans On Wed, Jun 23, 2010 at 08:40, Edi Weitz wrote: > Cyrus, > > Thanks for the patch, but I'm order for this one to be accepted it > should work for LispWorks as well. ?I'd look into it myself, but I > currently have problems with my arm/shoulder which prevent me from > sitting at my desk for longer periods. > > Cheers, > Edi. > > > On Wed, Jun 23, 2010 at 8:33 AM, Cyrus Harmon wrote: >> I have no idea if this is the right thing to do for lispworks or not, but this seems to work on SBCL. >> >> >> >> >> Thanks, >> >> Cyrus >> >> On Jun 15, 2010, at 9:39 PM, Hans H?bner wrote: >> >>> On Wed, Jun 16, 2010 at 01:49, Cyrus Harmon wrote: >>>> So, while trying to track down an unrelated issue where my handlers aren't getting called anymore, I came across the following issue where failure to open the message log file results in an error, which, in turn, attempts to open the message log file. The problem in this case was that the permissions were bogus for the directory I was trying to open. But, still, we should probably have a nicer error message than "recursive lock attempt" here. >>> >>> I agree. ?Can you supply a patch that corrects the problem? ?Using a >>> recursive lock would probably the easiest solution. >>> >>> Thanks, >>> Hans >>> >>> _______________________________________________ >>> tbnl-devel site list >>> tbnl-devel at common-lisp.net >>> http://common-lisp.net/mailman/listinfo/tbnl-devel >> >> >> _______________________________________________ >> tbnl-devel site list >> tbnl-devel at common-lisp.net >> http://common-lisp.net/mailman/listinfo/tbnl-devel >> > > _______________________________________________ > tbnl-devel site list > tbnl-devel at common-lisp.net > http://common-lisp.net/mailman/listinfo/tbnl-devel > From mikem4rbles at googlemail.com Tue Jun 22 23:24:04 2010 From: mikem4rbles at googlemail.com (Mike Marbles) Date: Tue, 22 Jun 2010 16:24:04 -0700 Subject: [hunchentoot-devel] hunchentoot working dir Message-ID: There is an example of one way to do it in the test-handlers.lisp file in the test directory in the hunchentoot source. -------------- next part -------------- An HTML attachment was scrubbed... URL: From fbogdanovic at xnet.hr Wed Jun 23 20:06:00 2010 From: fbogdanovic at xnet.hr (=?iso-8859-2?Q?Haris_Bogdanovi=E6?=) Date: Wed, 23 Jun 2010 22:06:00 +0200 Subject: [hunchentoot-devel] hunchentoot doesn't show a picture Message-ID: I have this piece of code: ------------------------------------------------------------------------------------------------------------------------- (hunchentoot:start (make-instance 'hunchentoot:acceptor :port 5000)) (push (hunchentoot:create-prefix-dispatcher "/" 'start-page) hunchentoot:*dispatch-table*) (push (hunchentoot:create-folder-dispatcher-and-handler "pics/" "c:") hunchentoot:*dispatch-table*) (defun start-page () (cl-who:with-html-output-to-string (*standard-output* nil :indent t) (:html (:body (:img :alt "alt" :src "pics/pic01.jpg"))))) -------------------------------------------------------------------------------------------------------------------------------- and when I go to http://localhost:5000 I don't see a picture, I see alternative text "alt". Why, where is the problem ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From fbogdanovic at xnet.hr Sat Jun 26 11:33:43 2010 From: fbogdanovic at xnet.hr (=?iso-8859-2?Q?Haris_Bogdanovi=E6?=) Date: Sat, 26 Jun 2010 13:33:43 +0200 Subject: [hunchentoot-devel] USOCKET::%SETUP-WAIT-LIST is undefined Message-ID: <3E3CC3DE65AE4BFDB42F28042E256DDA@komp> Hi. When I try to start hunchentoot with: "(hunchentoot:start (make-instance 'hunchentoot:acceptor :port 8000))" I get: "The function USOCKET::%SETUP-WAIT-LIST is undefined." ? I use emacs/slime/sbcl on windows. -------------- next part -------------- An HTML attachment was scrubbed... URL: