Skip to content

Commit 811b6b3

Browse files
committed
limit connections before async
1 parent f719bf6 commit 811b6b3

File tree

3 files changed

+52
-42
lines changed

3 files changed

+52
-42
lines changed

src/HTTP.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ include("clientlayers/ConnectionRequest.jl"); using .ConnectionRequest
7777
include("clientlayers/StreamRequest.jl"); using .StreamRequest
7878

7979
include("download.jl")
80+
include("accept.jl")
8081
include("Servers.jl") ;using .Servers; using .Servers: listen
8182
include("Handlers.jl") ;using .Handlers; using .Handlers: serve
8283
include("parsemultipart.jl") ;using .MultiPartParsing: parse_multipart_form

src/Servers.jl

Lines changed: 4 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ using MbedTLS: SSLContext, SSLConfig
1616
using ConcurrentUtilities: ConcurrentUtilities, Lockable, lock
1717
using ..IOExtras, ..Streams, ..Messages, ..Parsers, ..Connections, ..Exceptions
1818
import ..access_threaded, ..SOCKET_TYPE_TLS, ..@logfmt_str
19+
using ..Accept: acceptmany
1920

2021
TRUE(x) = true
2122
getinet(host::String, port::Integer) = Sockets.InetAddr(parse(IPAddr, host), port)
@@ -366,47 +367,6 @@ function listen!(f, listener::Listener;
366367
return Server(listener, on_shutdown, conns, tsk)
367368
end
368369

369-
using Base: iolock_begin, iolock_end, uv_error, preserve_handle, unpreserve_handle,
370-
StatusClosing, StatusClosed, StatusActive, UV_EAGAIN, UV_ECONNABORTED
371-
using Sockets: accept_nonblock
372-
373-
function acceptmany(server; MAXSIZE=Sockets.BACKLOG_DEFAULT)
374-
result = Vector{TCPSocket}()
375-
sizehint!(result, MAXSIZE)
376-
iolock_begin()
377-
if server.status != StatusActive && server.status != StatusClosing && server.status != StatusClosed
378-
throw(ArgumentError("server not connected, make sure \"listen\" has been called"))
379-
end
380-
while isopen(server)
381-
client = TCPSocket()
382-
err = Sockets.accept_nonblock(server, client)
383-
while err == 0 && length(result) < MAXSIZE # Don't try to fill more than half the buffer
384-
push!(result, client)
385-
client = TCPSocket()
386-
err = Sockets.accept_nonblock(server, client)
387-
end
388-
if length(result) > 0
389-
iolock_end()
390-
return result
391-
end
392-
if err != UV_EAGAIN
393-
uv_error("accept", err)
394-
end
395-
preserve_handle(server)
396-
lock(server.cond)
397-
iolock_end()
398-
try
399-
wait(server.cond)
400-
finally
401-
unlock(server.cond)
402-
unpreserve_handle(server)
403-
end
404-
iolock_begin()
405-
end
406-
uv_error("accept", UV_ECONNABORTED)
407-
nothing
408-
end
409-
410370
""""
411371
Main server loop.
412372
Accepts new tcp connections and spawns async tasks to handle them."
@@ -421,8 +381,10 @@ function listenloop(f, listener, conns, tcpisvalid,
421381
while isopen(listener)
422382
try
423383
for io in acceptmany(listener.server)
384+
# I would prefer this inside the async, so we can loop and accept again,
385+
# but https://github.com/JuliaWeb/HTTP.jl/pull/647/files says it's bad for performance
386+
max_connections < typemax(Int) && Base.acquire(sem)
424387
@async begin
425-
max_connections < typemax(Int) && Base.acquire(sem)
426388
local conn = nothing
427389
isssl = !isnothing(listener.ssl)
428390
try

src/accept.jl

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
2+
module Accept
3+
4+
export acceptmany
5+
6+
using Base: iolock_begin, iolock_end, uv_error, preserve_handle, unpreserve_handle,
7+
StatusClosing, StatusClosed, StatusActive, UV_EAGAIN, UV_ECONNABORTED
8+
using Sockets
9+
10+
function acceptmany(server; MAXSIZE=Sockets.BACKLOG_DEFAULT)
11+
result = Vector{TCPSocket}()
12+
sizehint!(result, MAXSIZE)
13+
iolock_begin()
14+
if server.status != StatusActive && server.status != StatusClosing && server.status != StatusClosed
15+
throw(ArgumentError("server not connected, make sure \"listen\" has been called"))
16+
end
17+
while isopen(server)
18+
client = TCPSocket()
19+
err = Sockets.accept_nonblock(server, client)
20+
while err == 0 && length(result) < MAXSIZE # Don't try to fill more than half the buffer
21+
push!(result, client)
22+
client = TCPSocket()
23+
err = Sockets.accept_nonblock(server, client)
24+
end
25+
if length(result) > 0
26+
iolock_end()
27+
return result
28+
end
29+
if err != UV_EAGAIN
30+
uv_error("accept", err)
31+
end
32+
preserve_handle(server)
33+
lock(server.cond)
34+
iolock_end()
35+
try
36+
wait(server.cond)
37+
finally
38+
unlock(server.cond)
39+
unpreserve_handle(server)
40+
end
41+
iolock_begin()
42+
end
43+
uv_error("accept", UV_ECONNABORTED)
44+
nothing
45+
end
46+
47+
end

0 commit comments

Comments
 (0)