Implement SDSS Header generators

next
Sayan Nandan 1 year ago
parent dbc7128c41
commit b0651c9492
No known key found for this signature in database
GPG Key ID: 42EEDF4AE9D96B54

@ -155,3 +155,12 @@ macro_rules! pairvec {
macro_rules! intovec {
($($x:expr),* $(,)?) => { vec![$(core::convert::From::from($x),)*] };
}
macro_rules! sizeof {
($ty:ty) => {
::core::mem::size_of::<$ty>()
};
($ty:ty, $by:literal) => {
::core::mem::size_of::<$ty>() * $by
};
}

@ -34,4 +34,5 @@ mod error;
mod idx;
mod mem;
mod ql;
mod storage;
mod sync;

@ -0,0 +1,312 @@
/*
* Created on Mon May 15 2023
*
* 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) 2023, 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/>.
*
*/
/*
SDSS Header
---
SDSS headers have two sections:
- Static record: fixed-size record with fixed-layout
- Dynamic record: variable-size record with version-dependent layout (> 256B)
+--------------------------------------------------------------+
| |
| STATIC RECORD |
| 128B |
+--------------------------------------------------------------+
+--------------------------------------------------------------+
| |
| |
| DYNAMIC RECORD |
| (256+?)B |
| |
+--------------------------------------------------------------+
We collectively define this as the SDSS Header. We'll attempt to statically compute
most of the sections, but for variable records we can't do the same. Also, our target
is to keep the SDSS Header at around 4K with page-padding.
*/
/*
Static record
---
[MAGIC (8B), [HEADER_VERSION(4B), PTR_WIDTH(1B), ENDIAN(1B), ARCH(1B), OPERATING SYSTEM(1B)]]
HEADS UP: Static record is always little endian
*/
use super::versions::HeaderVersion;
const SR0_MAGIC: u64 = 0x4F48534159414E21;
const SR2_PTR_WIDTH: u8 = HostPointerWidth::new().value_u8();
const SR3_ENDIAN: u8 = HostEndian::new().value_u8();
const SR4_ARCH: u8 = HostArch::new().value_u8();
const SR5_OS: u8 = HostOS::new().value_u8();
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, sky_macros::EnumMethods)]
pub enum HostArch {
X86 = 0,
X86_64 = 1,
ARM = 2,
ARM64 = 3,
MIPS = 4,
PowerPC = 5,
}
impl HostArch {
pub const fn new() -> Self {
if cfg!(target_arch = "x86") {
HostArch::X86
} else if cfg!(target_arch = "x86_64") {
HostArch::X86_64
} else if cfg!(target_arch = "arm") {
HostArch::ARM
} else if cfg!(target_arch = "aarch64") {
HostArch::ARM64
} else if cfg!(target_arch = "mips") {
HostArch::MIPS
} else if cfg!(target_arch = "powerpc") {
HostArch::PowerPC
} else {
panic!("Unsupported target architecture")
}
}
pub const fn new_with_val(v: u8) -> Self {
match v {
0 => HostArch::X86,
1 => HostArch::X86_64,
2 => HostArch::ARM,
3 => HostArch::ARM64,
4 => HostArch::MIPS,
5 => HostArch::PowerPC,
_ => panic!("unknown arch"),
}
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, sky_macros::EnumMethods)]
pub enum HostOS {
// T1
Linux = 0,
Windows = 1,
MacOS = 2,
// T2
Android = 3,
AppleiOS = 4,
FreeBSD = 5,
OpenBSD = 6,
NetBSD = 7,
WASI = 8,
Emscripten = 9,
// T3
Solaris = 10,
Fuchsia = 11,
Redox = 12,
DragonFly = 13,
}
impl HostOS {
pub const fn new() -> Self {
if cfg!(target_os = "linux") {
HostOS::Linux
} else if cfg!(target_os = "windows") {
HostOS::Windows
} else if cfg!(target_os = "macos") {
HostOS::MacOS
} else if cfg!(target_os = "android") {
HostOS::Android
} else if cfg!(target_os = "ios") {
HostOS::AppleiOS
} else if cfg!(target_os = "freebsd") {
HostOS::FreeBSD
} else if cfg!(target_os = "openbsd") {
HostOS::OpenBSD
} else if cfg!(target_os = "netbsd") {
HostOS::NetBSD
} else if cfg!(target_os = "dragonfly") {
HostOS::DragonFly
} else if cfg!(target_os = "redox") {
HostOS::Redox
} else if cfg!(target_os = "fuchsia") {
HostOS::Fuchsia
} else if cfg!(target_os = "solaris") {
HostOS::Solaris
} else if cfg!(target_os = "emscripten") {
HostOS::Emscripten
} else if cfg!(target_os = "wasi") {
HostOS::WASI
} else {
panic!("unknown os")
}
}
pub const fn new_with_val(v: u8) -> Self {
match v {
0 => HostOS::Linux,
1 => HostOS::Windows,
2 => HostOS::MacOS,
3 => HostOS::Android,
4 => HostOS::AppleiOS,
5 => HostOS::FreeBSD,
6 => HostOS::OpenBSD,
7 => HostOS::NetBSD,
8 => HostOS::WASI,
9 => HostOS::Emscripten,
10 => HostOS::Solaris,
11 => HostOS::Fuchsia,
12 => HostOS::Redox,
13 => HostOS::DragonFly,
_ => panic!("unknown OS"),
}
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, sky_macros::EnumMethods)]
pub enum HostEndian {
Big = 0,
Little = 1,
}
impl HostEndian {
pub const fn new() -> Self {
if cfg!(target_endian = "little") {
Self::Little
} else {
Self::Big
}
}
pub const fn new_with_val(v: u8) -> Self {
match v {
0 => HostEndian::Big,
1 => HostEndian::Little,
_ => panic!("Unknown endian"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, sky_macros::EnumMethods)]
#[repr(u8)]
pub enum HostPointerWidth {
P32 = 0,
P64 = 1,
}
impl HostPointerWidth {
pub const fn new() -> Self {
match sizeof!(usize) {
4 => Self::P32,
8 => Self::P64,
_ => panic!("unknown pointer width"),
}
}
pub const fn new_with_val(v: u8) -> Self {
match v {
0 => HostPointerWidth::P32,
1 => HostPointerWidth::P64,
_ => panic!("Unknown pointer width"),
}
}
}
#[derive(Debug)]
pub struct StaticRecordUV {
data: [u8; 16],
}
impl StaticRecordUV {
pub const fn create(sr1_version: HeaderVersion) -> Self {
let mut data = [0u8; 16];
let magic_buf = SR0_MAGIC.to_le_bytes();
let version_buf = sr1_version.little_endian_u64();
let mut i = 0usize;
while i < sizeof!(u64) {
data[i] = magic_buf[i];
data[i + sizeof!(u64)] = version_buf[i];
i += 1;
}
data[sizeof!(u64, 2) - 4] = SR2_PTR_WIDTH;
data[sizeof!(u64, 2) - 3] = SR3_ENDIAN;
data[sizeof!(u64, 2) - 2] = SR4_ARCH;
data[sizeof!(u64, 2) - 1] = SR5_OS;
Self { data }
}
pub const fn read_p0_magic(&self) -> u64 {
self.read_qword(0)
}
pub const fn read_p1_header_version(&self) -> HeaderVersion {
HeaderVersion::__new(self.read_dword(sizeof!(u64)))
}
pub const fn read_p2_ptr_width(&self) -> HostPointerWidth {
HostPointerWidth::new_with_val(self.read_byte(12))
}
pub const fn read_p3_endian(&self) -> HostEndian {
HostEndian::new_with_val(self.read_byte(13))
}
pub const fn read_p4_arch(&self) -> HostArch {
HostArch::new_with_val(self.read_byte(14))
}
pub const fn read_p5_os(&self) -> HostOS {
HostOS::new_with_val(self.read_byte(15))
}
}
impl_stack_read_primitives!(unsafe impl for StaticRecordUV {});
/*
File identity
*/
/// The file scope
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, sky_macros::EnumMethods)]
pub enum FileScope {
TransactionLog = 0,
TransactionLogCompacted = 1,
}
impl FileScope {
pub const fn new(id: u32) -> Self {
match id {
0 => Self::TransactionLog,
1 => Self::TransactionLogCompacted,
_ => panic!("unknown filescope"),
}
}
}
#[test]
fn test_static_record_encode_decode() {
let static_record = StaticRecordUV::create(super::versions::v1::V1_HEADER_VERSION);
assert_eq!(static_record.read_p0_magic(), SR0_MAGIC);
assert_eq!(
static_record.read_p1_header_version(),
super::versions::v1::V1_HEADER_VERSION
);
assert_eq!(static_record.read_p2_ptr_width(), HostPointerWidth::new());
assert_eq!(static_record.read_p3_endian(), HostEndian::new());
assert_eq!(static_record.read_p4_arch(), HostArch::new());
assert_eq!(static_record.read_p5_os(), HostOS::new());
}

@ -0,0 +1,65 @@
/*
* Created on Thu May 18 2023
*
* 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) 2023, 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/>.
*
*/
// HACK(@ohsayan): until const traits are stable, this is the silly stuff we have to resort to
macro_rules! impl_stack_read_primitives {
(unsafe impl for $ty:ty {}) => {
impl $ty {
const fn read_byte(&self, position: usize) -> u8 {
self.data[position]
}
const fn read_word(&self, position: usize) -> u16 {
unsafe {
core::mem::transmute([self.read_byte(position), self.read_byte(position + 1)])
}
}
const fn read_dword(&self, position: usize) -> u32 {
unsafe {
core::mem::transmute([
self.read_word(position),
self.read_word(position + sizeof!(u16)),
])
}
}
const fn read_qword(&self, position: usize) -> u64 {
unsafe {
core::mem::transmute([
self.read_dword(position),
self.read_dword(position + sizeof!(u32)),
])
}
}
const fn read_xmmword(&self, position: usize) -> u128 {
unsafe {
core::mem::transmute([
self.read_qword(position),
self.read_qword(position + sizeof!(u64)),
])
}
}
}
};
}

@ -0,0 +1,34 @@
/*
* Created on Mon May 15 2023
*
* 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) 2023, 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/>.
*
*/
//! Implementations of the Skytable Disk Storage Subsystem (SDSS)
#[macro_use]
mod macros;
mod header;
mod versions;
// impls
mod v1;

@ -0,0 +1,278 @@
/*
* Created on Mon May 15 2023
*
* 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) 2023, 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/>.
*
*/
/*
* SDSS Header layout:
*
* +--------------------------------------------------------------+
* | |
* | STATIC RECORD |
* | 128B |
* +--------------------------------------------------------------+
* +--------------------------------------------------------------+
* | |
* | |
* | DYNAMIC RECORD |
* | (256+?)B |
* | +--------------------------------------------+ |
* | | | |
* | | METADATA RECORD | |
* | | 256B | |
* | +--------------------------------------------+ |
* | +--------------------------------------------+ |
* | | | |
* | | VARIABLE HOST RECORD | |
* | | ?B | |
* | +--------------------------------------------+ |
* +--------------------------------------------------------------+
*
*/
use crate::engine::storage::{
header::{FileScope, StaticRecordUV},
versions::{self, DriverVersion, ServerVersion},
};
/// Static record
pub struct StaticRecord {
base: StaticRecordUV,
}
impl StaticRecord {
pub const fn new() -> Self {
Self {
base: StaticRecordUV::create(versions::v1::V1_HEADER_VERSION),
}
}
}
/*
Dynamic record (1/2)
---
Metadata record (8B x 3 + (4B x 2)):
+----------+----------+----------+---------+
| Server | Driver | File |File|Spec|
| version | Version | Scope |Spec|ID |
+----------+----------+----------+---------+
*/
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, sky_macros::EnumMethods)]
#[repr(u8)]
pub enum FileSpecifier {
GNSTxnLog = 0,
}
impl FileSpecifier {
pub const fn new(v: u32) -> Self {
match v {
0 => Self::GNSTxnLog,
_ => panic!("unknown filespecifier"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct FileSpecifierVersion(u32);
impl FileSpecifierVersion {
pub const fn __new(v: u32) -> Self {
Self(v)
}
}
pub struct MetadataRecord {
data: [u8; 32],
}
impl_stack_read_primitives!(unsafe impl for MetadataRecord {});
impl MetadataRecord {
pub const fn new(
scope: FileScope,
specifier: FileSpecifier,
specifier_id: FileSpecifierVersion,
) -> Self {
let mut ret = [0u8; 32];
let mut i = 0;
// read buf
let server_version = versions::v1::V1_SERVER_VERSION.native_endian();
let driver_version = versions::v1::V1_DRIVER_VERSION.native_endian();
let file_scope = scope.value_qword().to_ne_bytes();
// specifier + specifier ID
let file_specifier_and_id: u64 =
unsafe { core::mem::transmute([specifier.value_u8() as u32, specifier_id.0]) };
let file_specifier_and_id = file_specifier_and_id.to_ne_bytes();
while i < sizeof!(u64) {
ret[i] = server_version[i];
ret[i + sizeof!(u64, 1)] = driver_version[i];
ret[i + sizeof!(u64, 2)] = file_scope[i];
ret[i + sizeof!(u64, 3)] = file_specifier_and_id[i];
i += 1;
}
Self { data: ret }
}
pub const fn read_p0_server_version(&self) -> ServerVersion {
ServerVersion::__new(self.read_qword(0))
}
pub const fn read_p1_driver_version(&self) -> DriverVersion {
DriverVersion::__new(self.read_qword(sizeof!(u64)))
}
pub const fn read_p2_file_scope(&self) -> FileScope {
FileScope::new(self.read_qword(sizeof!(u128)) as u32)
}
pub const fn read_p3_file_spec(&self) -> FileSpecifier {
FileSpecifier::new(self.read_dword(sizeof!(u64, 3)))
}
pub const fn read_p4_file_spec_version(&self) -> FileSpecifierVersion {
FileSpecifierVersion(self.read_dword(sizeof!(u64, 3) + sizeof!(u32)))
}
}
/*
Dynamic Record (2/2)
---
Variable record (?B; > 56B):
- 16B: Host epoch time in nanoseconds
- 16B: Host uptime in nanoseconds
- 08B:
- 04B: Host setting version ID
- 04B: Host run mode
- 08B: Host startup counter
- 08B: Host name length
- ??B: Host name
*/
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, sky_macros::EnumMethods)]
#[repr(u8)]
pub enum HostRunMode {
Dev = 0,
Prod = 1,
}
impl HostRunMode {
pub const fn new_with_val(v: u8) -> Self {
match v {
0 => Self::Dev,
1 => Self::Prod,
_ => panic!("unknown hostrunmode"),
}
}
}
impl_stack_read_primitives!(unsafe impl for VariableHostRecord {});
pub struct VariableHostRecord {
data: [u8; 56],
host_name: Box<[u8]>,
}
impl VariableHostRecord {
pub fn new(
p0_host_epoch_time: u128,
p1_host_uptime: u128,
p2a_host_setting_version_id: u32,
p2b_host_run_mode: HostRunMode,
p3_host_startup_counter: u64,
p5_host_name: Box<[u8]>,
) -> Self {
let p4_host_name_length = p5_host_name.len();
let mut variable_record_fl = [0u8; 56];
variable_record_fl[0..16].copy_from_slice(&p0_host_epoch_time.to_ne_bytes());
variable_record_fl[16..32].copy_from_slice(&p1_host_uptime.to_ne_bytes());
variable_record_fl[32..36].copy_from_slice(&p2a_host_setting_version_id.to_ne_bytes());
variable_record_fl[36..40]
.copy_from_slice(&(p2b_host_run_mode.value_u8() as u32).to_ne_bytes());
variable_record_fl[40..48].copy_from_slice(&p3_host_startup_counter.to_ne_bytes());
variable_record_fl[48..56].copy_from_slice(&(p4_host_name_length as u64).to_ne_bytes());
Self {
data: variable_record_fl,
host_name: p5_host_name,
}
}
pub const fn read_p0_epoch_time(&self) -> u128 {
self.read_xmmword(0)
}
pub const fn read_p1_uptime(&self) -> u128 {
self.read_xmmword(sizeof!(u128))
}
pub const fn read_p2a_setting_version_id(&self) -> u32 {
self.read_dword(sizeof!(u128, 2))
}
pub const fn read_p2b_run_mode(&self) -> HostRunMode {
HostRunMode::new_with_val(self.read_dword(sizeof!(u128, 2) + sizeof!(u32)) as u8)
}
pub const fn read_p3_startup_counter(&self) -> u64 {
self.read_qword(sizeof!(u128, 2) + sizeof!(u32, 2))
}
pub const fn read_p4_host_name_length(&self) -> u64 {
self.read_qword(sizeof!(u128, 2) + sizeof!(u32, 2) + sizeof!(u64))
}
pub fn read_p5_host_name(&self) -> &[u8] {
&self.host_name
}
}
#[test]
fn test_metadata_record_encode_decode() {
let md = MetadataRecord::new(
FileScope::TransactionLog,
FileSpecifier::GNSTxnLog,
FileSpecifierVersion(1),
);
assert_eq!(md.read_p0_server_version(), versions::v1::V1_SERVER_VERSION);
assert_eq!(md.read_p1_driver_version(), versions::v1::V1_DRIVER_VERSION);
assert_eq!(md.read_p2_file_scope(), FileScope::TransactionLog);
assert_eq!(md.read_p3_file_spec(), FileSpecifier::GNSTxnLog);
assert_eq!(md.read_p4_file_spec_version(), FileSpecifierVersion(1));
}
#[test]
fn test_variable_host_record_encode_decode() {
const HOST_UPTIME: u128 = u128::MAX - 434324903;
const HOST_SETTING_VERSION_ID: u32 = 245;
const HOST_RUN_MODE: HostRunMode = HostRunMode::Prod;
const HOST_STARTUP_COUNTER: u64 = u32::MAX as _;
const HOST_NAME: &str = "skycloud";
use std::time::*;
let time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
let vhr = VariableHostRecord::new(
time,
HOST_UPTIME,
HOST_SETTING_VERSION_ID,
HOST_RUN_MODE,
HOST_STARTUP_COUNTER,
HOST_NAME.as_bytes().to_owned().into_boxed_slice(),
);
assert_eq!(vhr.read_p0_epoch_time(), time);
assert_eq!(vhr.read_p1_uptime(), HOST_UPTIME);
assert_eq!(vhr.read_p2a_setting_version_id(), HOST_SETTING_VERSION_ID);
assert_eq!(vhr.read_p2b_run_mode(), HOST_RUN_MODE);
assert_eq!(vhr.read_p3_startup_counter(), HOST_STARTUP_COUNTER);
assert_eq!(vhr.read_p4_host_name_length(), HOST_NAME.len() as u64);
assert_eq!(vhr.read_p5_host_name(), HOST_NAME.as_bytes());
}

@ -0,0 +1,27 @@
/*
* Created on Mon May 15 2023
*
* 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) 2023, 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/>.
*
*/
mod header_impl;

@ -0,0 +1,85 @@
/*
* Created on Mon May 15 2023
*
* 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) 2023, 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/>.
*
*/
//! SDSS Based Storage Engine versions
pub mod server_version;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
/// The header version
///
/// The header version is part of the static record and *barely* changes (almost like once in a light year)
pub struct HeaderVersion(u32);
impl HeaderVersion {
pub const fn __new(v: u32) -> Self {
Self(v)
}
pub const fn little_endian_u64(&self) -> [u8; 8] {
(self.0 as u64).to_le_bytes()
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
/// The server version (based on tag index)
pub struct ServerVersion(u64);
impl ServerVersion {
pub const fn __new(v: u64) -> Self {
Self(v)
}
pub const fn native_endian(&self) -> [u8; 8] {
self.0.to_ne_bytes()
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
/// The driver version
pub struct DriverVersion(u64);
impl DriverVersion {
pub const fn __new(v: u64) -> Self {
Self(v)
}
pub const fn native_endian(&self) -> [u8; 8] {
self.0.to_ne_bytes()
}
}
pub mod v1 {
//! The first SDSS based storage engine implementation.
//! Target tag: 0.8.0
use super::{DriverVersion, HeaderVersion, ServerVersion};
/// The SDSS header version UID
pub const V1_HEADER_VERSION: HeaderVersion = HeaderVersion(0);
/// The server version UID
pub const V1_SERVER_VERSION: ServerVersion =
ServerVersion(super::server_version::fetch_id("v0.8.0") as _);
/// The driver version UID
pub const V1_DRIVER_VERSION: DriverVersion = DriverVersion(0);
}

@ -0,0 +1,103 @@
/*
* Created on Wed May 17 2023
*
* 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) 2023, 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/>.
*
*/
const VERSION_TAGS: [&str; 52] = [
"v0.1.0",
"v0.2.0",
"v0.3.0",
"v0.3.1",
"v0.3.2",
"v0.4.0-alpha.1",
"v0.4.0-alpha.2",
"v0.4.0",
"v0.4.1-alpha.1",
"v0.4.1",
"v0.4.2-alpha.1",
"v0.4.2",
"v0.4.3-alpha.1",
"v0.4.3",
"v0.4.4",
"v0.4.5-alpha.1",
"v0.4.5-alpha.2",
"v0.4.5",
"v0.5.0-alpha.1",
"v0.5.0-alpha.2",
"v0.5.0",
"v0.5.1-alpha.1",
"v0.5.1",
"v0.5.2",
"v0.5.3",
"v0.6.0",
"v0.6.1",
"v0.6.2-testrelease.1",
"v0.6.2",
"v0.6.3-alpha.1",
"v0.6.3",
"v0.6.4-alpha.1",
"v0.6.4",
"v0.7.0-RC.1",
"v0.7.0-alpha.1",
"v0.7.0-alpha.2",
"v0.7.0-beta.1",
"v0.7.0",
"v0.7.1-alpha.1",
"v0.7.1",
"v0.7.2-alpha.1",
"v0.7.2",
"v0.7.3-alpha.1",
"v0.7.3-alpha.2",
"v0.7.3-alpha.3",
"v0.7.3",
"v0.7.4",
"v0.7.5",
"v0.7.6",
"v0.7.7",
"v0.8.0-alpha.1",
"v0.8.0",
];
const VERSION_TAGS_LEN: usize = VERSION_TAGS.len();
pub const fn fetch_id(id: &str) -> usize {
// this is ct, so a O(n) doesn't matter
let mut i = 0;
while i < VERSION_TAGS_LEN {
let bytes = VERSION_TAGS[i].as_bytes();
let given = id.as_bytes();
let mut j = 0;
let mut eq = true;
while (j < bytes.len()) & (bytes.len() == given.len()) {
if bytes[i] != given[i] {
eq = false;
break;
}
j += 1;
}
if eq {
return i;
}
i += 1;
}
panic!("version not found")
}

@ -47,7 +47,7 @@ use {
proc_macro::TokenStream,
proc_macro2::TokenStream as TokenStream2,
quote::quote,
syn::{Data, DataStruct, DeriveInput, Fields, Lit},
syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields, Lit, Meta, NestedMeta},
};
mod dbtest_fn;
@ -226,3 +226,51 @@ fn wrapper(item: DeriveInput) -> TokenStream2 {
}
}
}
#[proc_macro_derive(EnumMethods)]
pub fn derive_value_methods(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let enum_name = &ast.ident;
let mut repr_type = None;
// Get repr attribute
for attr in &ast.attrs {
if attr.path.is_ident("repr") {
if let Meta::List(list) = attr.parse_meta().unwrap() {
if let Some(NestedMeta::Meta(Meta::Path(path))) = list.nested.first() {
repr_type = Some(path.get_ident().unwrap().to_string());
}
}
}
}
let repr_type = repr_type.expect("Must have repr(u8) or repr(u16) etc.");
// Ensure all variants have explicit discriminants
if let Data::Enum(data) = &ast.data {
for variant in &data.variants {
match &variant.fields {
Fields::Unit => {
if variant.discriminant.as_ref().is_none() {
panic!("All enum variants must have explicit discriminants");
}
}
_ => panic!("All enum variants must be unit variants"),
}
}
} else {
panic!("This derive macro only works on enums");
}
let repr_type_ident = syn::Ident::new(&repr_type, proc_macro2::Span::call_site());
let repr_type_ident_func = syn::Ident::new(
&format!("value_{repr_type}"),
proc_macro2::Span::call_site(),
);
let gen = quote! {
impl #enum_name {
pub const fn #repr_type_ident_func(&self) -> #repr_type_ident { unsafe { core::mem::transmute(*self) } }
pub const fn value_word(&self) -> usize { self.#repr_type_ident_func() as usize }
pub const fn value_qword(&self) -> u64 { self.#repr_type_ident_func() as u64 }
}
};
gen.into()
}

Loading…
Cancel
Save