Add more LLVM specific optimizations

Just to reduce LLVM bloat
next
Sayan Nandan 3 years ago
parent e30d51a599
commit 79f657b462

@ -32,7 +32,6 @@ use crate::protocol::responses;
use crate::queryengine::ActionIter; use crate::queryengine::ActionIter;
use crate::resp::BytesWrapper; use crate::resp::BytesWrapper;
use bytes::Bytes; use bytes::Bytes;
use core::hint::unreachable_unchecked;
/// Run a `GET` query /// Run a `GET` query
pub async fn get<T, Strm>( pub async fn get<T, Strm>(
@ -48,14 +47,10 @@ where
let res: Option<Bytes> = { let res: Option<Bytes> = {
let reader = handle.get_ref(); let reader = handle.get_ref();
unsafe { unsafe {
// UNSAFE(@ohsayan): unreachable_unchecked is safe because we've already checked if the action // UNSAFE(@ohsayan): this is safe because we've already checked if the action
// group contains one argument (excluding the action itself) // group contains one argument (excluding the action itself)
reader reader
.get( .get(act.next().unsafe_unwrap().as_bytes())
act.next()
.unwrap_or_else(|| unreachable_unchecked())
.as_bytes(),
)
.map(|b| b.get_blob().clone()) .map(|b| b.get_blob().clone())
} }
}; };

@ -54,9 +54,8 @@ where
} }
mod json { mod json {
use crate::util::Unwrappable;
use bytes::Bytes; use bytes::Bytes;
use std::hint::unreachable_unchecked;
pub struct BuiltJSON(Vec<u8>); pub struct BuiltJSON(Vec<u8>);
pub struct JSONBlob(Vec<u8>); pub struct JSONBlob(Vec<u8>);
impl JSONBlob { impl JSONBlob {
@ -79,10 +78,10 @@ mod json {
self.0.push(b','); self.0.push(b',');
} }
pub fn finish(mut self) -> BuiltJSON { pub fn finish(mut self) -> BuiltJSON {
*self.0.last_mut().unwrap_or_else(|| unsafe { *unsafe {
// UNSAFE(@ohsayan): There will always be a value corresponding to last_mut // UNSAFE(@ohsayan): There will always be a value corresponding to last_mut
unreachable_unchecked() self.0.last_mut().unsafe_unwrap()
}) = b'}'; } = b'}';
BuiltJSON(self.0) BuiltJSON(self.0)
} }
} }

@ -27,7 +27,6 @@
use crate::dbnet::connection::prelude::*; use crate::dbnet::connection::prelude::*;
use crate::protocol::responses; use crate::protocol::responses;
use crate::queryengine::ActionIter; use crate::queryengine::ActionIter;
use core::hint::unreachable_unchecked;
/// Run a `KEYLEN` query /// Run a `KEYLEN` query
/// ///
@ -45,14 +44,10 @@ where
let res: Option<usize> = { let res: Option<usize> = {
let reader = handle.get_ref(); let reader = handle.get_ref();
unsafe { unsafe {
// UNSAFE(@ohsayan): unreachable_unchecked() is completely safe as we've already checked // UNSAFE(@ohsayan): this is completely safe as we've already checked
// the number of arguments is one // the number of arguments is one
reader reader
.get( .get(act.next().unsafe_unwrap().as_bytes())
act.next()
.unwrap_or_else(|| unreachable_unchecked())
.as_bytes(),
)
.map(|b| b.get_blob().len()) .map(|b| b.get_blob().len())
} }
}; };

@ -32,7 +32,6 @@ use crate::dbnet::connection::prelude::*;
use crate::protocol::responses; use crate::protocol::responses;
use crate::queryengine::ActionIter; use crate::queryengine::ActionIter;
use coredb::Data; use coredb::Data;
use std::hint::unreachable_unchecked;
/// Run a `SET` query /// Run a `SET` query
pub async fn set<T, Strm>( pub async fn set<T, Strm>(
@ -52,18 +51,14 @@ where
let writer = handle.get_ref(); let writer = handle.get_ref();
// clippy thinks we're doing something complex when we aren't, at all! // clippy thinks we're doing something complex when we aren't, at all!
#[allow(clippy::blocks_in_if_conditions)] #[allow(clippy::blocks_in_if_conditions)]
if writer.true_if_insert( if unsafe {
Data::from(act.next().unwrap_or_else(|| unsafe {
// UNSAFE(@ohsayan): This is completely safe as we've already checked // UNSAFE(@ohsayan): This is completely safe as we've already checked
// that there are exactly 2 arguments // that there are exactly 2 arguments
unreachable_unchecked() writer.true_if_insert(
})), Data::from(act.next().unsafe_unwrap()),
Data::from(act.next().unwrap_or_else(|| unsafe { Data::from(act.next().unsafe_unwrap()),
// UNSAFE(@ohsayan): This is completely safe as we've already checked )
// that there are exactly 2 arguments } {
unreachable_unchecked()
})),
) {
Some(true) Some(true)
} else { } else {
Some(false) Some(false)

@ -137,11 +137,11 @@ where
act.into_iter().for_each(|key| { act.into_iter().for_each(|key| {
// Since we've already checked that the keys don't exist // Since we've already checked that the keys don't exist
// We'll tell the compiler to optimize this // We'll tell the compiler to optimize this
let _ = mut_table.remove(key.as_bytes()).unwrap_or_else(|| unsafe { unsafe {
// UNSAFE(@ohsayan): Since all the values exist, all of them will return // UNSAFE(@ohsayan): Since all the values exist, all of them will return
// some value. Hence, this branch won't ever be reached. Hence, this is safe. // some value. Hence, this branch won't ever be reached. Hence, this is safe.
unreachable_unchecked() let _ = mut_table.remove(key.as_bytes()).unsafe_unwrap();
}); }
}); });
} else { } else {
failed = Some(true); failed = Some(true);
@ -196,17 +196,13 @@ where
} }
// Skip the next value that is coming our way, as we don't need it // Skip the next value that is coming our way, as we don't need it
// right now // right now
let _ = key_iter unsafe {
.next() let _ = key_iter.next().unsafe_unwrap();
.unwrap_or_else(|| unsafe { unreachable_unchecked() }); }
} }
// clippy thinks we're doing something complex when we aren't, at all! // clippy thinks we're doing something complex when we aren't, at all!
#[allow(clippy::blocks_in_if_conditions)] #[allow(clippy::blocks_in_if_conditions)]
if !failed.unwrap_or_else(|| unsafe { if unsafe { !failed.unsafe_unwrap() } {
// UNSAFE(@ohsayan): This is completely safe as a value is assigned to `failed`
// right in the beginning
unreachable_unchecked()
}) {
// Since the failed flag is false, none of the keys existed // Since the failed flag is false, none of the keys existed
// So we can safely update the keys // So we can safely update the keys
while let (Some(key), Some(value)) = (act.next(), act.next()) { while let (Some(key), Some(value)) = (act.next(), act.next()) {

@ -33,7 +33,6 @@ use crate::dbnet::connection::prelude::*;
use crate::protocol::responses; use crate::protocol::responses;
use crate::queryengine::ActionIter; use crate::queryengine::ActionIter;
use coredb::Data; use coredb::Data;
use std::hint::unreachable_unchecked;
/// Run an `UPDATE` query /// Run an `UPDATE` query
pub async fn update<T, Strm>( pub async fn update<T, Strm>(
@ -53,18 +52,14 @@ where
let writer = handle.get_ref(); let writer = handle.get_ref();
// clippy thinks we're doing something complex when we aren't, at all! // clippy thinks we're doing something complex when we aren't, at all!
#[allow(clippy::blocks_in_if_conditions)] #[allow(clippy::blocks_in_if_conditions)]
if writer.true_if_update( if unsafe {
Data::from(act.next().unwrap_or_else(|| unsafe { // UNSAFE(@ohsayan): This is completely safe as we've already checked
// UNSAFE(@ohsayan): We've already checked that the action contains exactly // that there are exactly 2 arguments
// two arguments (excluding the action itself). So, this branch won't ever be reached writer.true_if_update(
unreachable_unchecked() Data::from(act.next().unsafe_unwrap()),
})), Data::from(act.next().unsafe_unwrap()),
Data::from(act.next().unwrap_or_else(|| unsafe { )
// UNSAFE(@ohsayan): We've already checked that the action contains exactly } {
// two arguments (excluding the action itself). So, this branch won't ever be reached
unreachable_unchecked()
})),
) {
Some(true) Some(true)
} else { } else {
Some(false) Some(false)

@ -30,7 +30,6 @@ use crate::diskstore::snapshot::SnapshotEngine;
use crate::diskstore::snapshot::DIR_SNAPSHOT; use crate::diskstore::snapshot::DIR_SNAPSHOT;
use crate::protocol::responses; use crate::protocol::responses;
use crate::queryengine::ActionIter; use crate::queryengine::ActionIter;
use std::hint::unreachable_unchecked;
use std::path::{Component, PathBuf}; use std::path::{Component, PathBuf};
/// Create a snapshot /// Create a snapshot
@ -57,22 +56,22 @@ where
let mut succeeded = None; let mut succeeded = None;
let snaphandle = handle.shared.clone(); let snaphandle = handle.shared.clone();
let snapstatus = snaphandle.snapcfg.as_ref().unwrap_or_else(|| unsafe { let snapstatus = unsafe {
// UNSAFE(@ohsayan) This is safe as we've already checked // UNSAFE(@ohsayan) This is safe as we've already checked
// if snapshots are enabled or not with `is_snapshot_enabled` // if snapshots are enabled or not with `is_snapshot_enabled`
unreachable_unchecked() snaphandle.snapcfg.as_ref().unsafe_unwrap()
}); };
let snapengine = SnapshotEngine::new(snapstatus.max, &handle, None); let snapengine = SnapshotEngine::new(snapstatus.max, &handle, None);
if snapengine.is_err() { if snapengine.is_err() {
was_engine_error = true; was_engine_error = true;
} else if snapstatus.is_busy() { } else if snapstatus.is_busy() {
succeeded = None; succeeded = None;
} else { } else {
let snapengine = snapengine.unwrap_or_else(|_| unsafe { let snapengine = unsafe {
// UNSAFE(@ohsayan) This is safe as we've already checked // UNSAFE(@ohsayan) This is safe as we've already checked
// if snapshots are enabled or not with `is_snapshot_enabled` // if snapshots are enabled or not with `is_snapshot_enabled`
unreachable_unchecked() snapengine.unsafe_unwrap()
}); };
succeeded = Some(snapengine); succeeded = Some(snapengine);
} }
if was_engine_error { if was_engine_error {
@ -99,11 +98,11 @@ where
} }
} else if act.len() == 1 { } else if act.len() == 1 {
// This means that the user wants to create a 'named' snapshot // This means that the user wants to create a 'named' snapshot
let snapname = act.next().unwrap_or_else(|| unsafe { let snapname = unsafe {
// UNSAFE(@ohsayan): We've already checked that the action // UNSAFE(@ohsayan): We've already checked that the action
// contains a second argument, so this can't be reached // contains a second argument, so this can't be reached
unreachable_unchecked() act.next().unsafe_unwrap()
}); };
let mut path = PathBuf::from(DIR_SNAPSHOT); let mut path = PathBuf::from(DIR_SNAPSHOT);
path.push("remote"); path.push("remote");
path.push(snapname.to_owned() + ".snapshot"); path.push(snapname.to_owned() + ".snapshot");

@ -74,6 +74,7 @@ pub mod prelude {
//! //!
//! This module is hollow itself, it only re-exports from `dbnet::con` and `tokio::io` //! This module is hollow itself, it only re-exports from `dbnet::con` and `tokio::io`
pub use super::ProtocolConnectionExt; pub use super::ProtocolConnectionExt;
pub use crate::util::Unwrappable;
pub use tokio::io::{AsyncReadExt, AsyncWriteExt}; pub use tokio::io::{AsyncReadExt, AsyncWriteExt};
} }

@ -59,6 +59,7 @@ mod resp;
mod services; mod services;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
mod util;
const PATH: &str = ".sky_pid"; const PATH: &str = ".sky_pid";

@ -38,8 +38,8 @@
mod element; mod element;
pub mod responses; pub mod responses;
use crate::util::Unwrappable;
pub use element::Element; pub use element::Element;
use std::hint::unreachable_unchecked;
#[derive(Debug)] #[derive(Debug)]
/// # Skyhash Deserializer (Parser) /// # Skyhash Deserializer (Parser)
@ -185,12 +185,10 @@ impl<'a> Parser<'a> {
// 48 is the ASCII code for 0, and 57 is the ascii code for 9 // 48 is the ASCII code for 0, and 57 is the ascii code for 9
// so if 0 is given, the subtraction should give 0; similarly // so if 0 is given, the subtraction should give 0; similarly
// if 9 is given, the subtraction should give us 9! // if 9 is given, the subtraction should give us 9!
let curdig: usize = dig let curdig: usize = unsafe {
.checked_sub(48)
.unwrap_or_else(|| unsafe {
// UNSAFE(@ohsayan): We already know that dig is an ASCII digit // UNSAFE(@ohsayan): We already know that dig is an ASCII digit
unreachable_unchecked() dig.checked_sub(48).unsafe_unwrap()
}) }
.into(); .into();
// The usize can overflow; check that case // The usize can overflow; check that case
let product = match item_usize.checked_mul(10) { let product = match item_usize.checked_mul(10) {
@ -220,12 +218,10 @@ impl<'a> Parser<'a> {
// 48 is the ASCII code for 0, and 57 is the ascii code for 9 // 48 is the ASCII code for 0, and 57 is the ascii code for 9
// so if 0 is given, the subtraction should give 0; similarly // so if 0 is given, the subtraction should give 0; similarly
// if 9 is given, the subtraction should give us 9! // if 9 is given, the subtraction should give us 9!
let curdig: u64 = dig let curdig: u64 = unsafe {
.checked_sub(48)
.unwrap_or_else(|| unsafe {
// UNSAFE(@ohsayan): We already know that dig is an ASCII digit // UNSAFE(@ohsayan): We already know that dig is an ASCII digit
unreachable_unchecked() dig.checked_sub(48).unsafe_unwrap()
}) }
.into(); .into();
// Now the entire u64 can overflow, so let's attempt to check it // Now the entire u64 can overflow, so let's attempt to check it
let product = match item_u64.checked_mul(10) { let product = match item_u64.checked_mul(10) {
@ -379,14 +375,11 @@ impl<'a> Parser<'a> {
// of the next query // of the next query
// clippy thinks we're doing something complex when we aren't, at all! // clippy thinks we're doing something complex when we aren't, at all!
#[allow(clippy::blocks_in_if_conditions)] #[allow(clippy::blocks_in_if_conditions)]
if self if unsafe {
.will_cursor_give_char(b'*', true)
.unwrap_or_else(|_| unsafe {
// UNSAFE(@ohsayan): This will never be the case because we'll always get a result and no error value // UNSAFE(@ohsayan): This will never be the case because we'll always get a result and no error value
// as we've passed true which will yield Ok(true) even if there is no byte ahead // as we've passed true which will yield Ok(true) even if there is no byte ahead
unreachable_unchecked() self.will_cursor_give_char(b'*', true).unsafe_unwrap()
}) } {
{
Ok((Query::SimpleQuery(single_group), self.cursor)) Ok((Query::SimpleQuery(single_group), self.cursor))
} else { } else {
// the next item isn't the beginning of a query but something else? // the next item isn't the beginning of a query but something else?

@ -0,0 +1,59 @@
/*
* Created on Fri Jun 25 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/>.
*
*/
/// # Unsafe unwrapping
///
/// This trait provides a method `unsafe_unwrap` that is potentially unsafe and has
/// the ability to **violate multiple safety gurantees** that rust provides. So,
/// if you get `SIGILL`s or `SIGSEGV`s, by using this trait, blame yourself.
pub unsafe trait Unwrappable<T> {
/// Unwrap a _nullable_ (almost) type to get its value while asserting that the value
/// cannot ever be null
///
/// ## Safety
/// The trait is unsafe, and so is this function. You can wreck potential havoc if you
/// use this heedlessly
///
unsafe fn unsafe_unwrap(self) -> T;
}
unsafe impl<T, E> Unwrappable<T> for Result<T, E> {
unsafe fn unsafe_unwrap(self) -> T {
match self {
Ok(t) => t,
Err(_) => core::hint::unreachable_unchecked(),
}
}
}
unsafe impl<T> Unwrappable<T> for Option<T> {
unsafe fn unsafe_unwrap(self) -> T {
match self {
Some(t) => t,
None => core::hint::unreachable_unchecked(),
}
}
}
Loading…
Cancel
Save