Implement SDSS Header generators
parent
dbc7128c41
commit
b0651c9492
@ -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")
|
||||
}
|
Loading…
Reference in New Issue