1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-24 15:19:26 -05:00

feat(ext/flash): add reuseport option on Linux (#16022)

This commit is contained in:
Divy Srivastava 2022-09-28 10:46:29 -07:00 committed by GitHub
parent d677ba67f5
commit e64af6260a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 75 additions and 4 deletions

1
Cargo.lock generated
View file

@ -1094,6 +1094,7 @@ dependencies = [
"rustls",
"rustls-pemfile 1.0.1",
"serde",
"socket2",
"tokio",
]

View file

@ -8,4 +8,4 @@ function handler() {
return new Response("Hello World");
}
serve(handler, { hostname, port });
serve(handler, { hostname, port, reusePort: true });

View file

@ -11,7 +11,7 @@ const {
} = Deno;
const addr = Deno.args[0] || "127.0.0.1:4500";
const [hostname, port] = addr.split(":");
const serverId = op_flash_serve({ hostname, port });
const serverId = op_flash_serve({ hostname, port, reuseport: true });
const serverPromise = opAsync("op_flash_drive_server", serverId);
const fastOps = op_flash_make_request();

View file

@ -0,0 +1,16 @@
if (Deno.build.os !== "linux") {
throw new Error("SO_REUSEPORT is only supported on Linux");
}
const executable = Deno.execPath();
const path = new URL("./deno_http_flash_ops.js", import.meta.url).pathname;
// single flash instance runs on ~1.8 cores
const cpus = navigator.hardwareConcurrency / 2;
const processes = new Array(cpus);
for (let i = 0; i < cpus; i++) {
const proc = Deno.run({
cmd: [executable, "run", "-A", "--unstable", path, Deno.args[0]],
});
processes.push(proc.status());
}
await Promise.all(processes);

View file

@ -0,0 +1,16 @@
if (Deno.build.os !== "linux") {
throw new Error("SO_REUSEPORT is only supported on Linux");
}
const executable = Deno.execPath();
const path = new URL("./deno_http_flash.js", import.meta.url).pathname;
// single flash instance runs on ~1.8 cores
const cpus = navigator.hardwareConcurrency / 2;
const processes = new Array(cpus);
for (let i = 0; i < cpus; i++) {
const proc = Deno.run({
cmd: [executable, "run", "-A", "--unstable", path, Deno.args[0]],
});
processes.push(proc.status());
}
await Promise.all(processes);

View file

@ -1352,6 +1352,9 @@ declare namespace Deno {
/** An AbortSignal to close the server and all connections. */
signal?: AbortSignal;
/** Sets SO_REUSEPORT on Linux. */
reusePort?: boolean;
/** The handler to invoke when route handlers throw an error. */
onError?: (error: unknown) => Response | Promise<Response>;

View file

@ -459,6 +459,7 @@
const listenOpts = {
hostname: options.hostname ?? "127.0.0.1",
port: options.port ?? 9000,
reuseport: options.reusePort ?? false,
};
if (options.cert || options.key) {
if (!options.cert || !options.key) {

View file

@ -26,4 +26,5 @@ mio = { version = "0.8.1", features = ["os-poll", "net"] }
rustls = { version = "0.20" }
rustls-pemfile = "1.0"
serde = { version = "1.0.136", features = ["derive"] }
socket2 = "0.4.7"
tokio = { version = "1.21", features = ["full"] }

View file

@ -37,6 +37,7 @@ use mio::Poll;
use mio::Token;
use serde::Deserialize;
use serde::Serialize;
use socket2::Socket;
use std::cell::RefCell;
use std::cell::UnsafeCell;
use std::collections::HashMap;
@ -806,6 +807,7 @@ pub struct ListenOpts {
key: Option<String>,
hostname: String,
port: u16,
reuseport: bool,
}
fn run_server(
@ -815,8 +817,29 @@ fn run_server(
addr: SocketAddr,
maybe_cert: Option<String>,
maybe_key: Option<String>,
reuseport: bool,
) -> Result<(), AnyError> {
let mut listener = TcpListener::bind(addr)?;
let domain = if addr.is_ipv4() {
socket2::Domain::IPV4
} else {
socket2::Domain::IPV6
};
let socket = Socket::new(domain, socket2::Type::STREAM, None)?;
#[cfg(not(windows))]
socket.set_reuse_address(true)?;
if reuseport {
#[cfg(target_os = "linux")]
socket.set_reuse_port(true)?;
}
let socket_addr = socket2::SockAddr::from(addr);
socket.bind(&socket_addr)?;
socket.listen(128)?;
socket.set_nonblocking(true)?;
let std_listener: std::net::TcpListener = socket.into();
let mut listener = TcpListener::from_std(std_listener);
let mut poll = Poll::new()?;
let token = Token(0);
poll
@ -875,6 +898,7 @@ fn run_server(
.registry()
.register(&mut socket, token, Interest::READABLE)
.unwrap();
let socket = match tls_context {
Some(ref tls_conf) => {
let connection =
@ -1156,8 +1180,17 @@ where
let tx = ctx.tx.clone();
let maybe_cert = opts.cert;
let maybe_key = opts.key;
let reuseport = opts.reuseport;
let join_handle = tokio::task::spawn_blocking(move || {
run_server(tx, listening_tx, close_rx, addr, maybe_cert, maybe_key)
run_server(
tx,
listening_tx,
close_rx,
addr,
maybe_cert,
maybe_key,
reuseport,
)
});
let flash_ctx = state.borrow_mut::<FlashContext>();
let server_id = flash_ctx.next_server_id;