node.native icon indicating copy to clipboard operation
node.native copied to clipboard

Segmentation fault when concurrent requests arrives.

Open hmonfared opened this issue 11 years ago • 7 comments

with a single connection and many requests, there is no problem. but I send multiply requests concurrently, segmentation fault occurs ( line 336 in http.h ).

how to produce the error :

ab -k -n 50000 -c 100 -t 20 http://localhost:8080/ This is ApacheBench, Version 2.3 <$Revision: 1430300 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient) apr_socket_recv: Connection reset by peer (104) Total of 14 requests completed

full Stack trace from gdb :

(gdb) bt full #0 0x00000000004089a7 in native::http::client_context::~client_context()::{lambda()#1}::operator()() const () at ./native/http.h:336

    std::__ioinit = {static _S_refcount = <optimized out>, 
      static _S_synced_with_stdio = <optimized out>}

#1 0x000000000040c473 in std::_Function_handler<void (), native::http::client_context::~client_context()::{lambda()#1}>::_M_invoke(std::_Any_data const&) (

__functor=...) at /usr/include/c++/4.8/functional:2071

No locals. #2 0x000000000040d112 in std::function<void ()>::operator()() const (

this=0x642750) at /usr/include/c++/4.8/functional:2464

No locals. #3 0x000000000040b60a in native::internal::callback_object<std::function<void ()> >::invoke<>() (this=0x642740) at ./native/callback.h:46

No locals. #4 0x00000000004098ef in native::callbacks::invoke<std::function<void ()>>(void*, int) (target=0x642550, cid=0) at ./native/callback.h:84

    __PRETTY_FUNCTION__ = "static typename std::result_of<_Functor(_ArgTypes ...)>::type native::callbacks::invoke(void*, int, A&& ...) [with callback_t = std::function<void()>; A = {}; typename std::result_of<_Functor(_ArgType"...
    x = 0x642740

#5 0x00000000004067db in native::base::handle::close(std::function<void ()>)::{lambda(uv_handle_s_)#1}::operator()(uv_handle_s_) const (__closure=0x0,

hmonfared avatar Nov 10 '13 04:11 hmonfared

with this modification, error disappears :

            if(socket_)
            {
                // TODO: maybe close() does not affect socket_ pointer itself. So, delete socket_ does not have to be inside the callback.
                socket_->close([=](){
                    //delete socket_;
                    //socket_ = nullptr;
                });
                delete socket_;
            }

benchmark result after modification :

monfared@monfared-ubuntu:~/node.native$ ab -k -n 800000 -c 300 http://localhost:8080/ This is ApacheBench, Version 2.3 <$Revision: 1430300 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient) Completed 80000 requests Completed 160000 requests Completed 240000 requests Completed 320000 requests Completed 400000 requests Completed 480000 requests Completed 560000 requests Completed 640000 requests Completed 720000 requests Completed 800000 requests Finished 800000 requests

Server Software:
Server Hostname: localhost Server Port: 8080

Document Path: / Document Length: 8 bytes

Concurrency Level: 300 Time taken for tests: 20.055 seconds Complete requests: 800000 Failed requests: 0 Write errors: 0 Keep-Alive requests: 0 Total transferred: 57600000 bytes HTML transferred: 6400000 bytes Requests per second: 39890.78 #/sec Time per request: 7.521 ms Time per request: 0.025 [ms](mean, across all concurrent requests) Transfer rate: 2804.82 [Kbytes/sec] received

Connection Times (ms) min mean[+/-sd] median max Connect: 0 1 6.4 0 1000 Processing: 1 3 0.4 3 9 Waiting: 1 3 0.6 3 7 Total: 2 4 6.4 4 1004

Percentage of the requests served within a certain time (ms) 50% 4 66% 4 75% 4 80% 4 90% 4 95% 4 98% 4 99% 6 100% 1004 (longest request)

hmonfared avatar Nov 10 '13 05:11 hmonfared

It's strange this problem. As far as I can see, the news & deletes match up for the socket objects. The same regions of memory are being allocated, deleted and reallocated to hold sockets, but it naively looks like they're doing the right thing. I'm going to try out std::unique_ptr as a solution; see if that works.

sebjameswml avatar Nov 20 '13 11:11 sebjameswml

@hmonfared - take a look at my pull request to see my resolution for this problem.

sebjameswml avatar Nov 22 '13 11:11 sebjameswml

Hi, Thanks, It worked fine, except that the performance was dropped about 1000 transactions per second comparing with my modified version. I got following result with same benchmarking options: Total transferred: 57600000 bytes HTML transferred: 6400000 bytes Requests per second: 38703.70 #/sec Time per request: 7.751 ms Time per request: 0.026 [ms](mean, across all concurrent requests) Transfer rate: 2721.35 [Kbytes/sec] received maybe it is because of shared_ptr overhead. Regards Hassan H. Monfared

hmonfared avatar Nov 23 '13 07:11 hmonfared

Hi @hmonfared - yes the additional processing time in the shared_ptr code, plus actually calling free() for every connection. This is unavoidable, I think.

sebjameswml avatar Nov 25 '13 11:11 sebjameswml

Hi @sebjameswml , thanks for the reply. of course shared_ptr is faile-safe, but can't you call 'delete' operator explicitly as I did ? : if(socket_) { socket_->close(={}); delete socket_; }

hmonfared avatar Nov 25 '13 11:11 hmonfared

Hi Hassan, sorry - I missed your bit of code - I mis-read it as simply commenting out the existing code.

sebjameswml avatar Nov 25 '13 11:11 sebjameswml