2018-08-19 19:47:04 +02:00
|
|
|
use std::sync::mpsc as sync_mpsc;
|
|
|
|
use std::time::{Duration, Instant};
|
2019-07-18 13:05:40 +02:00
|
|
|
use std::{io, thread};
|
2018-08-19 19:47:04 +02:00
|
|
|
|
2018-12-10 06:51:35 +01:00
|
|
|
use actix_rt::System;
|
|
|
|
use futures::future::{lazy, Future};
|
2018-12-06 23:04:42 +01:00
|
|
|
use log::{error, info};
|
2018-08-19 19:47:04 +02:00
|
|
|
use slab::Slab;
|
|
|
|
use tokio_timer::Delay;
|
|
|
|
|
2019-07-18 13:05:40 +02:00
|
|
|
use crate::server::Server;
|
|
|
|
use crate::socket::{SocketAddr, SocketListener, StdListener};
|
|
|
|
use crate::worker::{Conn, WorkerClient};
|
|
|
|
use crate::Token;
|
2018-08-19 19:47:04 +02:00
|
|
|
|
|
|
|
pub(crate) enum Command {
|
|
|
|
Pause,
|
|
|
|
Resume,
|
|
|
|
Stop,
|
|
|
|
Worker(WorkerClient),
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ServerSocketInfo {
|
2019-07-18 13:05:40 +02:00
|
|
|
addr: SocketAddr,
|
2018-08-19 19:47:04 +02:00
|
|
|
token: Token,
|
2019-07-18 13:05:40 +02:00
|
|
|
sock: SocketListener,
|
2018-08-19 19:47:04 +02:00
|
|
|
timeout: Option<Instant>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub(crate) struct AcceptNotify(mio::SetReadiness);
|
|
|
|
|
|
|
|
impl AcceptNotify {
|
|
|
|
pub(crate) fn new(ready: mio::SetReadiness) -> Self {
|
|
|
|
AcceptNotify(ready)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn notify(&self) {
|
|
|
|
let _ = self.0.set_readiness(mio::Ready::readable());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for AcceptNotify {
|
|
|
|
fn default() -> Self {
|
|
|
|
AcceptNotify::new(mio::Registration::new2().1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) struct AcceptLoop {
|
|
|
|
cmd_reg: Option<mio::Registration>,
|
|
|
|
cmd_ready: mio::SetReadiness,
|
|
|
|
notify_reg: Option<mio::Registration>,
|
|
|
|
notify_ready: mio::SetReadiness,
|
|
|
|
tx: sync_mpsc::Sender<Command>,
|
|
|
|
rx: Option<sync_mpsc::Receiver<Command>>,
|
2018-12-10 06:51:35 +01:00
|
|
|
srv: Option<Server>,
|
2018-08-19 19:47:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AcceptLoop {
|
2018-12-10 06:51:35 +01:00
|
|
|
pub fn new(srv: Server) -> AcceptLoop {
|
2018-08-19 19:47:04 +02:00
|
|
|
let (tx, rx) = sync_mpsc::channel();
|
|
|
|
let (cmd_reg, cmd_ready) = mio::Registration::new2();
|
|
|
|
let (notify_reg, notify_ready) = mio::Registration::new2();
|
|
|
|
|
|
|
|
AcceptLoop {
|
|
|
|
tx,
|
|
|
|
cmd_ready,
|
|
|
|
cmd_reg: Some(cmd_reg),
|
|
|
|
notify_ready,
|
|
|
|
notify_reg: Some(notify_reg),
|
|
|
|
rx: Some(rx),
|
2018-12-10 06:51:35 +01:00
|
|
|
srv: Some(srv),
|
2018-08-19 19:47:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn send(&self, msg: Command) {
|
|
|
|
let _ = self.tx.send(msg);
|
|
|
|
let _ = self.cmd_ready.set_readiness(mio::Ready::readable());
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_notify(&self) -> AcceptNotify {
|
|
|
|
AcceptNotify::new(self.notify_ready.clone())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn start(
|
2018-10-30 04:29:47 +01:00
|
|
|
&mut self,
|
2019-07-18 13:05:40 +02:00
|
|
|
socks: Vec<(Token, StdListener)>,
|
2018-10-30 04:29:47 +01:00
|
|
|
workers: Vec<WorkerClient>,
|
2018-12-10 06:51:35 +01:00
|
|
|
) {
|
|
|
|
let srv = self.srv.take().expect("Can not re-use AcceptInfo");
|
2018-08-19 19:47:04 +02:00
|
|
|
|
|
|
|
Accept::start(
|
|
|
|
self.rx.take().expect("Can not re-use AcceptInfo"),
|
|
|
|
self.cmd_reg.take().expect("Can not re-use AcceptInfo"),
|
|
|
|
self.notify_reg.take().expect("Can not re-use AcceptInfo"),
|
|
|
|
socks,
|
2018-12-10 06:51:35 +01:00
|
|
|
srv,
|
2018-08-19 19:47:04 +02:00
|
|
|
workers,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Accept {
|
|
|
|
poll: mio::Poll,
|
|
|
|
rx: sync_mpsc::Receiver<Command>,
|
|
|
|
sockets: Slab<ServerSocketInfo>,
|
|
|
|
workers: Vec<WorkerClient>,
|
2018-12-10 06:51:35 +01:00
|
|
|
srv: Server,
|
2018-08-19 19:47:04 +02:00
|
|
|
timer: (mio::Registration, mio::SetReadiness),
|
|
|
|
next: usize,
|
|
|
|
backpressure: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
const DELTA: usize = 100;
|
|
|
|
const CMD: mio::Token = mio::Token(0);
|
|
|
|
const TIMER: mio::Token = mio::Token(1);
|
|
|
|
const NOTIFY: mio::Token = mio::Token(2);
|
|
|
|
|
|
|
|
/// This function defines errors that are per-connection. Which basically
|
|
|
|
/// means that if we get this error from `accept()` system call it means
|
|
|
|
/// next connection might be ready to be accepted.
|
|
|
|
///
|
|
|
|
/// All other errors will incur a timeout before next `accept()` is performed.
|
|
|
|
/// The timeout is useful to handle resource exhaustion errors like ENFILE
|
|
|
|
/// and EMFILE. Otherwise, could enter into tight loop.
|
|
|
|
fn connection_error(e: &io::Error) -> bool {
|
|
|
|
e.kind() == io::ErrorKind::ConnectionRefused
|
|
|
|
|| e.kind() == io::ErrorKind::ConnectionAborted
|
|
|
|
|| e.kind() == io::ErrorKind::ConnectionReset
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Accept {
|
2018-12-06 23:04:42 +01:00
|
|
|
#![allow(clippy::too_many_arguments)]
|
2018-08-19 19:47:04 +02:00
|
|
|
pub(crate) fn start(
|
2018-10-30 04:29:47 +01:00
|
|
|
rx: sync_mpsc::Receiver<Command>,
|
|
|
|
cmd_reg: mio::Registration,
|
|
|
|
notify_reg: mio::Registration,
|
2019-07-18 13:05:40 +02:00
|
|
|
socks: Vec<(Token, StdListener)>,
|
2018-12-10 06:51:35 +01:00
|
|
|
srv: Server,
|
2018-10-30 04:29:47 +01:00
|
|
|
workers: Vec<WorkerClient>,
|
2018-08-19 19:47:04 +02:00
|
|
|
) {
|
|
|
|
let sys = System::current();
|
|
|
|
|
|
|
|
// start accept thread
|
|
|
|
let _ = thread::Builder::new()
|
2018-12-11 03:08:07 +01:00
|
|
|
.name("actix-server accept loop".to_owned())
|
2018-08-19 19:47:04 +02:00
|
|
|
.spawn(move || {
|
|
|
|
System::set_current(sys);
|
|
|
|
let mut accept = Accept::new(rx, socks, workers, srv);
|
|
|
|
|
|
|
|
// Start listening for incoming commands
|
|
|
|
if let Err(err) = accept.poll.register(
|
|
|
|
&cmd_reg,
|
|
|
|
CMD,
|
|
|
|
mio::Ready::readable(),
|
|
|
|
mio::PollOpt::edge(),
|
|
|
|
) {
|
|
|
|
panic!("Can not register Registration: {}", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start listening for notify updates
|
|
|
|
if let Err(err) = accept.poll.register(
|
|
|
|
¬ify_reg,
|
|
|
|
NOTIFY,
|
|
|
|
mio::Ready::readable(),
|
|
|
|
mio::PollOpt::edge(),
|
|
|
|
) {
|
|
|
|
panic!("Can not register Registration: {}", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
accept.poll();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn new(
|
2018-10-30 04:29:47 +01:00
|
|
|
rx: sync_mpsc::Receiver<Command>,
|
2019-07-18 13:05:40 +02:00
|
|
|
socks: Vec<(Token, StdListener)>,
|
2018-10-30 04:29:47 +01:00
|
|
|
workers: Vec<WorkerClient>,
|
2018-12-10 06:51:35 +01:00
|
|
|
srv: Server,
|
2018-08-19 19:47:04 +02:00
|
|
|
) -> Accept {
|
|
|
|
// Create a poll instance
|
|
|
|
let poll = match mio::Poll::new() {
|
|
|
|
Ok(poll) => poll,
|
|
|
|
Err(err) => panic!("Can not create mio::Poll: {}", err),
|
|
|
|
};
|
|
|
|
|
|
|
|
// Start accept
|
|
|
|
let mut sockets = Slab::new();
|
2018-11-03 18:22:04 +01:00
|
|
|
for (hnd_token, lst) in socks.into_iter() {
|
2019-07-18 13:05:40 +02:00
|
|
|
let addr = lst.local_addr();
|
2018-08-19 19:47:04 +02:00
|
|
|
|
2019-07-18 13:05:40 +02:00
|
|
|
let server = lst.into_listener();
|
2018-08-19 19:47:04 +02:00
|
|
|
let entry = sockets.vacant_entry();
|
|
|
|
let token = entry.key();
|
|
|
|
|
|
|
|
// Start listening for incoming connections
|
|
|
|
if let Err(err) = poll.register(
|
|
|
|
&server,
|
|
|
|
mio::Token(token + DELTA),
|
|
|
|
mio::Ready::readable(),
|
|
|
|
mio::PollOpt::edge(),
|
|
|
|
) {
|
|
|
|
panic!("Can not register io: {}", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
entry.insert(ServerSocketInfo {
|
|
|
|
addr,
|
|
|
|
token: hnd_token,
|
|
|
|
sock: server,
|
|
|
|
timeout: None,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Timer
|
|
|
|
let (tm, tmr) = mio::Registration::new2();
|
|
|
|
if let Err(err) =
|
|
|
|
poll.register(&tm, TIMER, mio::Ready::readable(), mio::PollOpt::edge())
|
|
|
|
{
|
|
|
|
panic!("Can not register Registration: {}", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
Accept {
|
|
|
|
poll,
|
|
|
|
rx,
|
|
|
|
sockets,
|
|
|
|
workers,
|
|
|
|
srv,
|
|
|
|
next: 0,
|
|
|
|
timer: (tm, tmr),
|
|
|
|
backpressure: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn poll(&mut self) {
|
|
|
|
// Create storage for events
|
|
|
|
let mut events = mio::Events::with_capacity(128);
|
|
|
|
|
|
|
|
loop {
|
|
|
|
if let Err(err) = self.poll.poll(&mut events, None) {
|
|
|
|
panic!("Poll error: {}", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
for event in events.iter() {
|
|
|
|
let token = event.token();
|
|
|
|
match token {
|
2018-10-29 23:48:56 +01:00
|
|
|
CMD => {
|
|
|
|
if !self.process_cmd() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2018-08-19 19:47:04 +02:00
|
|
|
TIMER => self.process_timer(),
|
|
|
|
NOTIFY => self.backpressure(false),
|
|
|
|
_ => {
|
|
|
|
let token = usize::from(token);
|
|
|
|
if token < DELTA {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
self.accept(token - DELTA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_timer(&mut self) {
|
|
|
|
let now = Instant::now();
|
|
|
|
for (token, info) in self.sockets.iter_mut() {
|
|
|
|
if let Some(inst) = info.timeout.take() {
|
|
|
|
if now > inst {
|
|
|
|
if let Err(err) = self.poll.register(
|
|
|
|
&info.sock,
|
|
|
|
mio::Token(token + DELTA),
|
|
|
|
mio::Ready::readable(),
|
|
|
|
mio::PollOpt::edge(),
|
|
|
|
) {
|
|
|
|
error!("Can not register server socket {}", err);
|
|
|
|
} else {
|
|
|
|
info!("Resume accepting connections on {}", info.addr);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
info.timeout = Some(inst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_cmd(&mut self) -> bool {
|
|
|
|
loop {
|
|
|
|
match self.rx.try_recv() {
|
|
|
|
Ok(cmd) => match cmd {
|
|
|
|
Command::Pause => {
|
|
|
|
for (_, info) in self.sockets.iter_mut() {
|
|
|
|
if let Err(err) = self.poll.deregister(&info.sock) {
|
|
|
|
error!("Can not deregister server socket {}", err);
|
|
|
|
} else {
|
|
|
|
info!("Paused accepting connections on {}", info.addr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Command::Resume => {
|
|
|
|
for (token, info) in self.sockets.iter() {
|
|
|
|
if let Err(err) = self.poll.register(
|
|
|
|
&info.sock,
|
|
|
|
mio::Token(token + DELTA),
|
|
|
|
mio::Ready::readable(),
|
|
|
|
mio::PollOpt::edge(),
|
|
|
|
) {
|
|
|
|
error!("Can not resume socket accept process: {}", err);
|
|
|
|
} else {
|
|
|
|
info!(
|
|
|
|
"Accepting connections on {} has been resumed",
|
|
|
|
info.addr
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Command::Stop => {
|
|
|
|
for (_, info) in self.sockets.iter() {
|
|
|
|
let _ = self.poll.deregister(&info.sock);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Command::Worker(worker) => {
|
|
|
|
self.backpressure(false);
|
|
|
|
self.workers.push(worker);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Err(err) => match err {
|
|
|
|
sync_mpsc::TryRecvError::Empty => break,
|
|
|
|
sync_mpsc::TryRecvError::Disconnected => {
|
|
|
|
for (_, info) in self.sockets.iter() {
|
|
|
|
let _ = self.poll.deregister(&info.sock);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
fn backpressure(&mut self, on: bool) {
|
|
|
|
if self.backpressure {
|
|
|
|
if !on {
|
|
|
|
self.backpressure = false;
|
|
|
|
for (token, info) in self.sockets.iter() {
|
|
|
|
if let Err(err) = self.poll.register(
|
|
|
|
&info.sock,
|
|
|
|
mio::Token(token + DELTA),
|
|
|
|
mio::Ready::readable(),
|
|
|
|
mio::PollOpt::edge(),
|
|
|
|
) {
|
|
|
|
error!("Can not resume socket accept process: {}", err);
|
|
|
|
} else {
|
|
|
|
info!("Accepting connections on {} has been resumed", info.addr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if on {
|
|
|
|
self.backpressure = true;
|
|
|
|
for (_, info) in self.sockets.iter() {
|
|
|
|
let _ = self.poll.deregister(&info.sock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accept_one(&mut self, mut msg: Conn) {
|
|
|
|
if self.backpressure {
|
|
|
|
while !self.workers.is_empty() {
|
|
|
|
match self.workers[self.next].send(msg) {
|
|
|
|
Ok(_) => (),
|
2018-09-14 08:46:01 +02:00
|
|
|
Err(tmp) => {
|
2018-12-10 07:14:29 +01:00
|
|
|
self.srv.worker_died(self.workers[self.next].idx);
|
2018-09-14 08:46:01 +02:00
|
|
|
msg = tmp;
|
2018-08-19 19:47:04 +02:00
|
|
|
self.workers.swap_remove(self.next);
|
|
|
|
if self.workers.is_empty() {
|
|
|
|
error!("No workers");
|
|
|
|
return;
|
|
|
|
} else if self.workers.len() <= self.next {
|
|
|
|
self.next = 0;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.next = (self.next + 1) % self.workers.len();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let mut idx = 0;
|
|
|
|
while idx < self.workers.len() {
|
|
|
|
idx += 1;
|
|
|
|
if self.workers[self.next].available() {
|
|
|
|
match self.workers[self.next].send(msg) {
|
|
|
|
Ok(_) => {
|
|
|
|
self.next = (self.next + 1) % self.workers.len();
|
|
|
|
return;
|
|
|
|
}
|
2018-09-14 08:46:01 +02:00
|
|
|
Err(tmp) => {
|
2018-12-10 07:14:29 +01:00
|
|
|
self.srv.worker_died(self.workers[self.next].idx);
|
2018-09-14 08:46:01 +02:00
|
|
|
msg = tmp;
|
2018-08-19 19:47:04 +02:00
|
|
|
self.workers.swap_remove(self.next);
|
|
|
|
if self.workers.is_empty() {
|
|
|
|
error!("No workers");
|
|
|
|
self.backpressure(true);
|
|
|
|
return;
|
|
|
|
} else if self.workers.len() <= self.next {
|
|
|
|
self.next = 0;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.next = (self.next + 1) % self.workers.len();
|
|
|
|
}
|
|
|
|
// enable backpressure
|
|
|
|
self.backpressure(true);
|
|
|
|
self.accept_one(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accept(&mut self, token: usize) {
|
|
|
|
loop {
|
|
|
|
let msg = if let Some(info) = self.sockets.get_mut(token) {
|
2019-07-18 13:05:40 +02:00
|
|
|
match info.sock.accept() {
|
|
|
|
Ok(Some((io, addr))) => Conn {
|
2018-08-19 19:47:04 +02:00
|
|
|
io,
|
|
|
|
token: info.token,
|
|
|
|
peer: Some(addr),
|
|
|
|
},
|
2019-07-18 13:05:40 +02:00
|
|
|
Ok(None) => return,
|
2018-08-19 19:47:04 +02:00
|
|
|
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => return,
|
|
|
|
Err(ref e) if connection_error(e) => continue,
|
|
|
|
Err(e) => {
|
|
|
|
error!("Error accepting connection: {}", e);
|
|
|
|
if let Err(err) = self.poll.deregister(&info.sock) {
|
|
|
|
error!("Can not deregister server socket {}", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
// sleep after error
|
|
|
|
info.timeout = Some(Instant::now() + Duration::from_millis(500));
|
|
|
|
|
|
|
|
let r = self.timer.1.clone();
|
2018-12-10 06:51:35 +01:00
|
|
|
System::current().arbiter().send(lazy(move || {
|
|
|
|
Delay::new(Instant::now() + Duration::from_millis(510))
|
|
|
|
.map_err(|_| ())
|
|
|
|
.and_then(move |_| {
|
|
|
|
let _ = r.set_readiness(mio::Ready::readable());
|
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}));
|
2018-08-19 19:47:04 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
self.accept_one(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|