Refactor into modules (server)

next
Sayan Nandan 4 years ago
parent 7919f5b40e
commit 76886c13f9
No known key found for this signature in database
GPG Key ID: C31EFD7DDA12AEE0

@ -18,7 +18,7 @@ You can see a list of contributors **[here](./CONTRIBUTORS.md)**
* `FIXME(@<username>)` : Use this when you have made an implementation that can be improved in the future, such as improved efficiency
* `HACK(@<username>)` : Use this when the code you are using a temporary workaround
* `TODO(@<username>)` : Use this when you have kept something incomplete
* `UNSAFE(@<username>` : Use this to explain why the `unsafe` block used is safe
* `UNSAFE(@<username>)` : Use this to explain why the `unsafe` block used is safe
### Formatting

@ -108,7 +108,7 @@ mod benchtool {
if args.len() != 3 {
eprintln!(
"Insufficient arguments!\
\nUSAGE: benchmark <connections> <queries> <packetsize-in-bytes>"
\nUSAGE: tdb-bench <connections> <queries> <packetsize-in-bytes>"
);
std::process::exit(0x100);
}

@ -30,20 +30,6 @@ pub const DEF_QMETALINE_BUFSIZE: usize = 44;
pub const DEF_QMETALAYOUT_BUFSIZE: usize = 576;
/// Default query dataframe buffer size
pub const DEF_QDATAFRAME_BUSIZE: usize = 4096;
pub mod tags {
//! This module is a collection of tags/strings used for evaluating queries
//! and responses
/// `GET` command tag
pub const TAG_GET: &'static str = "GET";
/// `SET` command tag
pub const TAG_SET: &'static str = "SET";
/// `UPDATE` command tag
pub const TAG_UPDATE: &'static str = "UPDATE";
/// `DEL` command tag
pub const TAG_DEL: &'static str = "DEL";
/// `HEYA` command tag
pub const TAG_HEYA: &'static str = "HEYA";
}
pub mod responses {
//! Empty responses, mostly errors, which are statically compiled
use lazy_static::lazy_static;
@ -275,7 +261,7 @@ impl SimpleResponse {
"*!{}!{}!{}\n{}\n{}",
self.respcode,
self.dataframe_buf.len(),
self.metalayout_buf.len(),
self.metalayout_buf.len() + 1,
self.metalayout_buf,
self.dataframe_buf
)
@ -325,19 +311,14 @@ impl QueryBuilder {
}
pub struct SimpleQuery {
metaline: String,
metalayout: String,
dataframe: String,
size_tracker: usize,
}
impl SimpleQuery {
pub fn new() -> Self {
let mut metaline = String::with_capacity(DEF_QMETALINE_BUFSIZE);
metaline.push_str("*!");
SimpleQuery {
metaline,
size_tracker: 0,
metalayout: String::with_capacity(DEF_QMETALAYOUT_BUFSIZE),
dataframe: String::with_capacity(DEF_QDATAFRAME_BUSIZE),
}
@ -347,8 +328,6 @@ impl SimpleQuery {
let ref mut layout = self.metalayout;
let ref mut df = self.dataframe;
let len = cmd.len().to_string();
// Include the newline character in total size
self.size_tracker += cmd.len() + 1;
layout.push('#');
layout.push_str(&len);
df.push_str(cmd);
@ -359,9 +338,8 @@ impl SimpleQuery {
}
pub fn prepare_response(&self) -> (usize, Vec<u8>) {
let resp = format!(
"{}{}!{}\n{}\n{}",
self.metaline,
self.size_tracker,
"*!{}!{}\n{}\n{}",
self.dataframe.len(),
self.metalayout.len() + 1, // include the new line character
self.metalayout,
self.dataframe

@ -19,9 +19,12 @@
*
*/
//! # The core database engine
use crate::protocol::Query;
use crate::queryengine;
use bincode;
use corelib::terrapipe::{tags, ActionType, RespBytes, RespCodes, ResponseBuilder};
use corelib::terrapipe::{ActionType, RespCodes};
use corelib::TResult;
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::collections::{hash_map::Entry, HashMap};
@ -93,100 +96,12 @@ impl CoreDB {
/// Execute a query that has already been validated by `Connection::read_query`
pub fn execute_query(&self, df: Query) -> Vec<u8> {
match df.actiontype {
ActionType::Simple => self.execute_simple(df.data),
ActionType::Simple => queryengine::execute_simple(&self, df.data),
// TODO(@ohsayan): Pipeline commands haven't been implemented yet
ActionType::Pipeline => unimplemented!(),
}
}
/// Execute a simple(*) query
pub fn execute_simple(&self, buf: Vec<String>) -> Vec<u8> {
let mut buf = buf.into_iter();
while let Some(token) = buf.next() {
match token.to_uppercase().as_str() {
tags::TAG_GET => {
// This is a GET query
if let Some(key) = buf.next() {
if buf.next().is_none() {
let res = match self.get(&key.to_string()) {
Ok(v) => v,
Err(e) => return e.into_response(),
};
let mut resp = ResponseBuilder::new_simple(RespCodes::Okay);
resp.add_data(res.to_owned());
return resp.into_response();
}
}
}
tags::TAG_SET => {
// This is a SET query
if let Some(key) = buf.next() {
if let Some(value) = buf.next() {
if buf.next().is_none() {
match self.set(&key.to_string(), &value.to_string()) {
Ok(_) => {
#[cfg(Debug)]
self.print_debug_table();
return RespCodes::Okay.into_response();
}
Err(e) => return e.into_response(),
}
}
}
}
}
tags::TAG_UPDATE => {
// This is an UPDATE query
if let Some(key) = buf.next() {
if let Some(value) = buf.next() {
if buf.next().is_none() {
match self.update(&key.to_string(), &value.to_string()) {
Ok(_) => {
return {
#[cfg(Debug)]
self.print_debug_table();
RespCodes::Okay.into_response()
}
}
Err(e) => return e.into_response(),
}
}
}
}
}
tags::TAG_DEL => {
// This is a DEL query
if let Some(key) = buf.next() {
if buf.next().is_none() {
match self.del(&key.to_string()) {
Ok(_) => {
#[cfg(Debug)]
self.print_debug_table();
return RespCodes::Okay.into_response();
}
Err(e) => return e.into_response(),
}
} else {
}
}
}
tags::TAG_HEYA => {
if buf.next().is_none() {
let mut resp = ResponseBuilder::new_simple(RespCodes::Okay);
resp.add_data("HEY!".to_owned());
return resp.into_response();
}
}
_ => {
return RespCodes::OtherError(Some("Unknown command".to_owned()))
.into_response()
}
}
}
RespCodes::ArgumentError.into_response()
}
/// Create a new `CoreDB` instance
///
/// This also checks if a local backup of previously saved data is available.

@ -23,6 +23,7 @@ use tokio::net::TcpListener;
mod coredb;
mod dbnet;
mod protocol;
mod queryengine;
use coredb::CoreDB;
use dbnet::run;
use tokio::signal;

@ -0,0 +1,125 @@
/*
* Created on Mon Aug 03 2020
*
* This file is a part of the source code for the Terrabase database
* Copyright (c) 2020, Sayan Nandan <ohsayan at outlook dot 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/>.
*
*/
//! # The Query Engine
use crate::coredb::CoreDB;
use corelib::terrapipe::{RespBytes, RespCodes, ResponseBuilder};
pub mod tags {
//! This module is a collection of tags/strings used for evaluating queries
//! and responses
/// `GET` command tag
pub const TAG_GET: &'static str = "GET";
/// `SET` command tag
pub const TAG_SET: &'static str = "SET";
/// `UPDATE` command tag
pub const TAG_UPDATE: &'static str = "UPDATE";
/// `DEL` command tag
pub const TAG_DEL: &'static str = "DEL";
/// `HEYA` command tag
pub const TAG_HEYA: &'static str = "HEYA";
}
/// Execute a simple(*) query
pub fn execute_simple(db: &CoreDB, buf: Vec<String>) -> Vec<u8> {
let mut buf = buf.into_iter();
while let Some(token) = buf.next() {
match token.to_uppercase().as_str() {
tags::TAG_GET => {
// This is a GET query
if let Some(key) = buf.next() {
if buf.next().is_none() {
let res = match db.get(&key.to_string()) {
Ok(v) => v,
Err(e) => return e.into_response(),
};
let mut resp = ResponseBuilder::new_simple(RespCodes::Okay);
resp.add_data(res.to_owned());
return resp.into_response();
}
}
}
tags::TAG_SET => {
// This is a SET query
if let Some(key) = buf.next() {
if let Some(value) = buf.next() {
if buf.next().is_none() {
match db.set(&key.to_string(), &value.to_string()) {
Ok(_) => {
#[cfg(Debug)]
db.print_debug_table();
return RespCodes::Okay.into_response();
}
Err(e) => return e.into_response(),
}
}
}
}
}
tags::TAG_UPDATE => {
// This is an UPDATE query
if let Some(key) = buf.next() {
if let Some(value) = buf.next() {
if buf.next().is_none() {
match db.update(&key.to_string(), &value.to_string()) {
Ok(_) => {
return {
#[cfg(Debug)]
db.print_debug_table();
RespCodes::Okay.into_response()
}
}
Err(e) => return e.into_response(),
}
}
}
}
}
tags::TAG_DEL => {
// This is a DEL query
if let Some(key) = buf.next() {
if buf.next().is_none() {
match db.del(&key.to_string()) {
Ok(_) => {
#[cfg(Debug)]
db.print_debug_table();
return RespCodes::Okay.into_response();
}
Err(e) => return e.into_response(),
}
} else {
}
}
}
tags::TAG_HEYA => {
if buf.next().is_none() {
let mut resp = ResponseBuilder::new_simple(RespCodes::Okay);
resp.add_data("HEY!".to_owned());
return resp.into_response();
}
}
_ => return RespCodes::OtherError(Some("Unknown command".to_owned())).into_response(),
}
}
RespCodes::ArgumentError.into_response()
}
Loading…
Cancel
Save