Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable maximum connections to be configured manually #182

Merged
merged 4 commits into from
Jun 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

All changes in this project will be noted in this file.

## Unreleased

### Additions

- The maximum number of clients can now be manually configured [see [#182](https://github.com/skytable/skytable/pull/182)]

### Fixes

- Ability to connect to the server over TLS has been restored in `skysh` [see [#181](https://github.com/skytable/skytable/pull/181)]

## Version 0.6.2 [2021-06-24]

### Fixes
Expand Down
3 changes: 2 additions & 1 deletion examples/config-files/template.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ host = "127.0.0.1" # The IP address to which you want sdb to bind to
port = 2003 # The port to which you want sdb to bind to
# Set `noart` to true if you want to disable terminal artwork
noart = false
maxcon = 50000 # set the maximum number of clients that the server can accept

# This key is *OPTIONAL*
[bgsave]
Expand All @@ -30,4 +31,4 @@ failsafe = true # stops accepting writes if snapshotting fails
key = "/path/to/keyfile.pem"
chain = "/path/to/chain.pem"
port = 2004
only = true # optional to enable SSL-only requests
only = true # optional to enable SSL-only requests
131 changes: 131 additions & 0 deletions server/src/arbiter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Created on Sat Jun 26 2021
*
* This file is a part of Skytable
* Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source
* NoSQL database written by Sayan Nandan ("the Author") with the
* vision to provide flexibility in data modelling without compromising
* on performance, queryability or scalability.
*
* Copyright (c) 2021, Sayan Nandan <ohsayan@outlook.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/

use crate::config::BGSave;
use crate::config::SnapshotConfig;
use crate::coredb::CoreDB;
use crate::dbnet::{self, Terminator};
use crate::diskstore::snapshot::DIR_REMOTE_SNAPSHOT;
use crate::services;
use crate::PortConfig;
use std::fs;
use tokio::sync::broadcast;

#[cfg(unix)]
use core::{future::Future, pin::Pin, task::Context, task::Poll};
#[cfg(unix)]
use tokio::signal::unix::{signal as fnsignal, Signal, SignalKind};
#[cfg(unix)]
/// Object to bind to unix-specific signals
pub struct UnixTerminationSignal {
sigterm: Signal,
}

#[cfg(unix)]
impl UnixTerminationSignal {
pub fn init() -> Result<Self, String> {
let sigterm = fnsignal(SignalKind::terminate())
.map_err(|e| format!("Failed to bind to signal with: {}", e))?;
Ok(Self { sigterm })
}
}

#[cfg(unix)]
impl Future for UnixTerminationSignal {
type Output = Option<()>;

fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
self.sigterm.poll_recv(ctx)
}
}

/// Start the server waiting for incoming connections or a termsig
pub async fn run(
ports: PortConfig,
bgsave_cfg: BGSave,
snapshot_cfg: SnapshotConfig,
restore_filepath: Option<String>,
maxcon: usize,
) -> Result<CoreDB, String> {
// Intialize the broadcast channel
let (signal, _) = broadcast::channel(1);

// create the data directories and intialize the coredb
fs::create_dir_all(&*DIR_REMOTE_SNAPSHOT)
.map_err(|e| format!("Failed to create data directories: '{}'", e))?;
let db = CoreDB::new(&snapshot_cfg, restore_filepath)
.map_err(|e| format!("Error while initializing database: {}", e))?;

// initialize the background services
let bgsave_handle = tokio::spawn(services::bgsave::bgsave_scheduler(
db.clone(),
bgsave_cfg,
Terminator::new(signal.subscribe()),
));
let snapshot_handle = tokio::spawn(services::snapshot::snapshot_service(
db.clone(),
snapshot_cfg,
Terminator::new(signal.subscribe()),
));

// bind the ctrlc handler
let sig = tokio::signal::ctrl_c();

// start the server (single or multiple listeners)
let mut server = dbnet::connect(ports, maxcon, db.clone(), signal.clone()).await?;

#[cfg(not(unix))]
{
// Non-unix, usually Windows specific signal handling.
// FIXME(@ohsayan): For now, let's just
// bother with ctrl+c, we'll move ahead as users require them
tokio::select! {
_ = server.run_server() => {}
_ = sig => {}
}
}
#[cfg(unix)]
{
let sigterm = UnixTerminationSignal::init()?;
// apart from CTRLC, the only other thing we care about is SIGTERM
// FIXME(@ohsayan): Maybe we should respond to SIGHUP too?
tokio::select! {
_ = server.run_server() => {},
_ = sig => {},
_ = sigterm => {}
}
}

log::info!("Signalling all workers to shut down");
// drop the signal and let others exit
drop(signal);
server.finish_with_termsig().await;

// wait for the background services to terminate
let _ = snapshot_handle.await;
let _ = bgsave_handle.await;
Ok(db)
}
6 changes: 6 additions & 0 deletions server/src/cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ args:
long: stop-write-on-fail
takes_value: true
help: Stop accepting writes if any persistence method except BGSAVE fails (defaults to true)
- maxcon:
required: false
long: maxcon
takes_value: true
help: Set the maximum number of connections
value_name: maxcon
subcommands:
- upgrade:
about: Upgrades old datsets to the latest format supported by this server edition
Expand Down
45 changes: 37 additions & 8 deletions server/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
//! This module provides tools to handle configuration files and settings

use crate::compat;
use crate::dbnet::MAXIMUM_CONNECTION_LIMIT;
use core::hint::unreachable_unchecked;
#[cfg(test)]
use libsky::TResult;
Expand Down Expand Up @@ -114,6 +115,8 @@ pub struct ConfigKeyServer {
/// The noart key is an `Option`al boolean value which is set to true
/// for secure environments to disable terminal artwork
noart: Option<bool>,
/// The maximum number of clients
maxclient: Option<usize>,
}

/// The snapshot section in the TOML file
Expand Down Expand Up @@ -260,6 +263,8 @@ pub struct ParsedConfig {
pub snapshot: SnapshotConfig,
/// Port configuration
pub ports: PortConfig,
/// The maximum number of connections
pub maxcon: usize,
}

impl ParsedConfig {
Expand Down Expand Up @@ -327,6 +332,7 @@ impl ParsedConfig {
port: cfg_info.server.port,
}
},
maxcon: libsky::option_unwrap_or!(cfg_info.server.maxclient, MAXIMUM_CONNECTION_LIMIT),
}
}
#[cfg(test)]
Expand All @@ -340,12 +346,14 @@ impl ParsedConfig {
bgsave: BGSave,
snapshot: SnapshotConfig,
ports: PortConfig,
maxcon: usize,
) -> Self {
ParsedConfig {
noart,
bgsave,
snapshot,
ports,
maxcon,
}
}
/// Create a default `ParsedConfig` with the following setup defaults:
Expand All @@ -361,6 +369,7 @@ impl ParsedConfig {
bgsave: BGSave::default(),
snapshot: SnapshotConfig::default(),
ports: PortConfig::new_insecure_only(DEFAULT_IPV4, 2003),
maxcon: MAXIMUM_CONNECTION_LIMIT,
}
}
/// Returns `false` if `noart` is enabled. Otherwise it returns `true`
Expand Down Expand Up @@ -442,6 +451,7 @@ pub fn get_config_file_or_return_cfg() -> Result<ConfigType<ParsedConfig, String
let saveduration = matches.value_of("saveduration");
let sslkey = matches.value_of("sslkey");
let sslchain = matches.value_of("sslchain");
let maxcon = matches.value_of("maxcon");
let cli_has_overrideable_args = host.is_some()
|| port.is_some()
|| noart
Expand All @@ -451,6 +461,7 @@ pub fn get_config_file_or_return_cfg() -> Result<ConfigType<ParsedConfig, String
|| saveduration.is_some()
|| sslchain.is_some()
|| sslkey.is_some()
|| maxcon.is_some()
|| sslonly;
if filename.is_some() && cli_has_overrideable_args {
return Err(ConfigError::CfgError(
Expand Down Expand Up @@ -483,6 +494,17 @@ pub fn get_config_file_or_return_cfg() -> Result<ConfigType<ParsedConfig, String
},
None => "127.0.0.1".parse().unwrap(),
};
let maxcon: usize = match maxcon {
Some(limit) => match limit.parse() {
Ok(l) => l,
Err(_) => {
return Err(ConfigError::CliArgErr(
"Invalid value for `--maxcon`. Expected a valid positive integer",
));
}
},
None => MAXIMUM_CONNECTION_LIMIT,
};
let bgsave = if nosave {
if saveduration.is_some() {
// If there is both `nosave` and `saveduration` - the arguments aren't logically correct!
Expand Down Expand Up @@ -582,7 +604,7 @@ pub fn get_config_file_or_return_cfg() -> Result<ConfigType<ParsedConfig, String
));
}
};
let cfg = ParsedConfig::new(noart, bgsave, snapcfg, portcfg);
let cfg = ParsedConfig::new(noart, bgsave, snapcfg, portcfg, maxcon);
return Ok(ConfigType::Custom(cfg, restorefile));
}
if let Some(filename) = filename {
Expand Down Expand Up @@ -686,7 +708,8 @@ mod tests {
noart: true,
bgsave: BGSave::default(),
snapshot: SnapshotConfig::default(),
ports: PortConfig::default()
ports: PortConfig::default(),
maxcon: MAXIMUM_CONNECTION_LIMIT
}
);
}
Expand All @@ -704,7 +727,8 @@ mod tests {
ports: PortConfig::new_insecure_only(
IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)),
DEFAULT_PORT
)
),
maxcon: MAXIMUM_CONNECTION_LIMIT
}
);
}
Expand All @@ -726,7 +750,8 @@ mod tests {
"/path/to/chain.pem".into(),
2004
)
)
),
MAXIMUM_CONNECTION_LIMIT
)
);
}
Expand All @@ -748,7 +773,8 @@ mod tests {
noart: false,
bgsave: BGSave::new(true, 600),
snapshot: SnapshotConfig::default(),
ports: PortConfig::default()
ports: PortConfig::default(),
maxcon: MAXIMUM_CONNECTION_LIMIT
}
);
}
Expand All @@ -767,7 +793,8 @@ mod tests {
noart: false,
bgsave: BGSave::default(),
snapshot: SnapshotConfig::default(),
ports: PortConfig::default()
ports: PortConfig::default(),
maxcon: MAXIMUM_CONNECTION_LIMIT
}
)
}
Expand All @@ -786,7 +813,8 @@ mod tests {
noart: false,
bgsave: BGSave::new(true, 600),
snapshot: SnapshotConfig::default(),
ports: PortConfig::default()
ports: PortConfig::default(),
maxcon: MAXIMUM_CONNECTION_LIMIT
}
)
}
Expand All @@ -801,7 +829,8 @@ mod tests {
snapshot: SnapshotConfig::Enabled(SnapshotPref::new(3600, 4, true)),
bgsave: BGSave::default(),
noart: false,
ports: PortConfig::default()
ports: PortConfig::default(),
maxcon: MAXIMUM_CONNECTION_LIMIT
}
);
}
Expand Down
Loading