diff --git a/libsky/src/lib.rs b/libsky/src/lib.rs index 7a73c649..15ee9247 100644 --- a/libsky/src/lib.rs +++ b/libsky/src/lib.rs @@ -37,9 +37,9 @@ pub type TResult = Result>; /// The size of the read buffer in bytes pub const BUF_CAP: usize = 8 * 1024; // 8 KB per-connection /// The current version -pub static VERSION: &str = env!("CARGO_PKG_VERSION"); +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); /// The URL -pub static URL: &str = "https://github.com/skytable/skytable"; +pub const URL: &str = "https://github.com/skytable/skytable"; #[macro_export] /// Don't use unwrap_or but use this macro as the optimizer fails to optimize away usages diff --git a/server/src/admin/mod.rs b/server/src/admin/mod.rs index 12fb30a0..1791b211 100644 --- a/server/src/admin/mod.rs +++ b/server/src/admin/mod.rs @@ -27,3 +27,4 @@ //! Modules for administration of Skytable pub mod mksnap; +pub mod sys; diff --git a/server/src/admin/sys.rs b/server/src/admin/sys.rs new file mode 100644 index 00000000..c7c52547 --- /dev/null +++ b/server/src/admin/sys.rs @@ -0,0 +1,71 @@ +/* + * Created on Tue Mar 29 2022 + * + * 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) 2022, Sayan Nandan + * + * 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 . + * +*/ + +use crate::corestore::booltable::BoolTable; +use crate::dbnet::connection::prelude::*; +use crate::protocol::{PROTOCOL_VERSION, PROTOCOL_VERSIONSTRING}; +use ::libsky::VERSION; + +const INFO: &[u8] = b"info"; +const METRIC: &[u8] = b"metric"; +const INFO_PROTOCOL: &[u8] = b"protocol"; +const INFO_PROTOVER: &[u8] = b"protover"; +const INFO_VERSION: &[u8] = b"version"; +const METRIC_HEALTH: &[u8] = b"health"; +const ERR_UNKNOWN_PROPERTY: &[u8] = b"!16\nunknown-property\n"; +const ERR_UNKNOWN_METRIC: &[u8] = b"!14\nunknown-metric\n"; + +const HEALTH_TABLE: BoolTable<&str> = BoolTable::new("good", "critical"); + +action! { + fn sys(_handle: &Corestore, con: &mut T, iter: ActionIter<'_>) { + let mut iter = iter; + ensure_boolean_or_aerr(iter.len() == 2)?; + match unsafe { iter.next_lowercase_unchecked() }.as_ref() { + INFO => sys_info(con, &mut iter).await, + METRIC => sys_metric(con, &mut iter).await, + _ => util::err(groups::UNKNOWN_ACTION), + } + } + fn sys_info(con: &mut T, iter: &mut ActionIter<'_>) { + match unsafe { iter.next_lowercase_unchecked() }.as_ref() { + INFO_PROTOCOL => con.write_response(PROTOCOL_VERSIONSTRING).await?, + INFO_PROTOVER => con.write_response(PROTOCOL_VERSION).await?, + INFO_VERSION => con.write_response(VERSION).await?, + _ => return util::err(ERR_UNKNOWN_PROPERTY), + } + Ok(()) + } + fn sys_metric(con: &mut T, iter: &mut ActionIter<'_>) { + match unsafe { iter.next_lowercase_unchecked() }.as_ref() { + METRIC_HEALTH => { + con.write_response(HEALTH_TABLE[registry::state_okay()]).await? + } + _ => return util::err(ERR_UNKNOWN_METRIC), + } + Ok(()) + } +} diff --git a/server/src/main.rs b/server/src/main.rs index f36abb7e..283581a8 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -62,7 +62,7 @@ mod storage; #[cfg(test)] mod tests; -const PATH: &str = ".sky_pid"; +const PID_FILE_PATH: &str = ".sky_pid"; #[cfg(test)] const ROOT_DIR: &str = env!("ROOT_DIR"); @@ -157,7 +157,7 @@ fn check_args_and_get_cfg() -> (ConfigurationSet, Option) { /// to the same directory which can cause potentially undefined behavior. /// fn run_pre_startup_tasks() -> FileLock { - let mut file = match FileLock::lock(PATH) { + let mut file = match FileLock::lock(PID_FILE_PATH) { Ok(fle) => fle, Err(e) => { log::error!("Startup failure: Failed to lock pid file: {}", e); diff --git a/server/src/protocol/iter.rs b/server/src/protocol/iter.rs index f1de65cc..dd3cd33e 100644 --- a/server/src/protocol/iter.rs +++ b/server/src/protocol/iter.rs @@ -91,6 +91,9 @@ impl<'a> AnyArrayIter<'a> { v.as_slice().to_ascii_lowercase().into_boxed_slice() }) } + pub unsafe fn next_lowercase_unchecked(&mut self) -> Box<[u8]> { + self.next_lowercase().unwrap_or_else(|| impossible!()) + } pub unsafe fn next_uppercase_unchecked(&mut self) -> Box<[u8]> { match self.next_uppercase() { Some(s) => s, diff --git a/server/src/protocol/mod.rs b/server/src/protocol/mod.rs index 0874d822..5b9cc032 100644 --- a/server/src/protocol/mod.rs +++ b/server/src/protocol/mod.rs @@ -57,6 +57,11 @@ use core::hint::unreachable_unchecked; use core::ops; use core::slice; +/// The Skyhash protocol version +pub const PROTOCOL_VERSION: f32 = 1.2; +/// The Skyhash protocol version string (Skyhash-x.y) +pub const PROTOCOL_VERSIONSTRING: &[u8] = b"Skyhash-1.1"; + const ASCII_UNDERSCORE: u8 = b'_'; const ASCII_AMPERSAND: u8 = b'&'; const ASCII_COLON: u8 = b':'; diff --git a/server/src/queryengine/mod.rs b/server/src/queryengine/mod.rs index cce1fd17..a67d06c8 100644 --- a/server/src/queryengine/mod.rs +++ b/server/src/queryengine/mod.rs @@ -174,6 +174,7 @@ async fn execute_stage<'a, T: 'a + ClientConnection, Strm: Stream>( LGET => actions::lists::lget::lget, LMOD => actions::lists::lmod::lmod, WHEREAMI => actions::whereami::whereami, + SYS => admin::sys::sys, { // actions that need other arguments AUTH => auth::auth(con, auth, iter) diff --git a/server/src/resp/mod.rs b/server/src/resp/mod.rs index 3f4a8ecc..bdb4cbd2 100644 --- a/server/src/resp/mod.rs +++ b/server/src/resp/mod.rs @@ -38,6 +38,7 @@ use tokio::io::AsyncWriteExt; pub mod writer; pub const TSYMBOL_UNICODE_STRING: u8 = b'+'; +pub const TSYMBOL_FLOAT: u8 = b'%'; type FutureIoResult<'s> = FutureResult<'s, Result<(), IoError>>; @@ -225,3 +226,18 @@ impl Writable for ObjectID { }) } } + +impl Writable for f32 { + fn write<'s>(self, con: &'s mut impl IsConnection) -> FutureIoResult<'s> { + Box::pin(async move { + let payload = self.to_string(); + let payload_len = Integer64::from(payload.len()); + con.write_lowlevel(&[TSYMBOL_FLOAT]).await?; + con.write_lowlevel(&payload_len).await?; + con.write_lowlevel(&[b'\n']).await?; + con.write_lowlevel(payload.as_bytes()).await?; + con.write_lowlevel(&[b'\n']).await?; + Ok(()) + }) + } +}