diff --git a/Cargo.lock b/Cargo.lock index a039e55..bd2455b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1003,6 +1003,12 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro-hack" version = "0.5.20+deprecated" @@ -1027,6 +1033,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1149,9 +1185,11 @@ dependencies = [ name = "spatial-db" version = "0.1.0" dependencies = [ + "arrow-array", "axum", "clap", "parquet", + "rand", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index 0f74c62..376987a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +arrow-array = "47.0.0" axum = "0.6.20" clap = { version = "4.4.5", features = ["derive"] } parquet = "47.0.0" +rand = "0.8.5" tokio = { version = "1.32.0", features = ["macros", "rt-multi-thread"] } diff --git a/src/main.rs b/src/main.rs index a6b47cf..dd3d483 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +#![feature(test)] + mod simple_server; mod storage; mod storage_server; diff --git a/src/simple_server/server.rs b/src/simple_server/server.rs index 80db5bc..cceeb56 100644 --- a/src/simple_server/server.rs +++ b/src/simple_server/server.rs @@ -1,12 +1,6 @@ use crate::storage::world::{BlockID, BlockPos, BlockRange, ChunkData, ChunkPos}; use crate::storage_server::StorageServer; -#[derive(Debug, Clone)] -struct SingleBlock { - id: BlockID, - position: BlockPos, -} - #[derive(Debug)] struct MultipleBlocks { id: BlockID, @@ -76,10 +70,8 @@ impl StorageServer for SimpleServer { let chunk = chunk.expect("Could not find chunk"); - println!("Chunk for {:?} is at {:?}", world_position, chunk.pos); - // Find the section that the block is located in - let current_section = &mut chunk.sections[world_position.y / 16]; + let current_section = &mut chunk.sections[world_position.y % 16]; // Find the index that the block is at, and update its state let chunk_array_index = current_section.index_of_block(&world_position); current_section.update_block_at_index(&target_state, chunk_array_index); diff --git a/src/storage/disk_storage.rs b/src/storage/disk_storage.rs new file mode 100644 index 0000000..2b695a8 --- /dev/null +++ b/src/storage/disk_storage.rs @@ -0,0 +1,19 @@ +use super::world::{BlockID, ChunkData, ChunkPos}; +use std::fs::File; + +const DATABASE_FILE_LOCATION: &str = "./persistence"; + +struct RunLengthEncoding { + pairs: Vec<(usize, BlockID)>, +} + +impl RunLengthEncoding { + fn from_chunk(chunk_data: &ChunkData) -> Self { + for section in chunk_data.sections { + for index in section.chunk_data { + // Yes + } + } + } +} + diff --git a/src/storage/mod.rs b/src/storage/mod.rs index f2e43b5..59158dd 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -1,2 +1,2 @@ +// mod disk_storage; pub mod world; - diff --git a/src/storage/world.rs b/src/storage/world.rs index 3aa05ff..60c7bda 100644 --- a/src/storage/world.rs +++ b/src/storage/world.rs @@ -16,8 +16,8 @@ pub struct ChunkPos { impl From<&BlockPos> for ChunkPos { fn from(value: &BlockPos) -> Self { ChunkPos { - x: value.x.rem_euclid(16), - z: value.z.rem_euclid(16), + x: value.x / 16, + z: value.z / 16, } } } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 9d5f059..e418d65 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,2 +1,2 @@ mod insert_one; - +mod performance_testing; diff --git a/src/tests/performance_testing.rs b/src/tests/performance_testing.rs new file mode 100644 index 0000000..327496a --- /dev/null +++ b/src/tests/performance_testing.rs @@ -0,0 +1,154 @@ +extern crate test; + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + simple_server::server::SimpleServer, + storage::world::{BlockID, BlockPos}, + storage_server::StorageServer, + }; + use rand::prelude::*; + use test::Bencher; + + #[bench] + fn bench_add_sequential_elements(b: &mut Bencher) { + let mut server = SimpleServer::new(); + let mut x = 0; + + b.iter(|| { + server.change_block(BlockID::Generic, &BlockPos::new(x, 0, 0)); + x += 1; + }); + } + + #[bench] + fn bench_add_clustered_points(b: &mut Bencher) { + let mut server = SimpleServer::new(); + + let mut rng = rand::thread_rng(); + + static MAX_RANGE: isize = 128; + + b.iter(|| { + let x: isize = rng.gen_range(-MAX_RANGE..MAX_RANGE); + let y: usize = rng.gen::() as usize; + let z: isize = rng.gen_range(-MAX_RANGE..MAX_RANGE); + + server.change_block(BlockID::Generic, &BlockPos::new(x, y, z)); + }); + } + + #[bench] + fn bench_add_spread_out_points(b: &mut Bencher) { + let mut server = SimpleServer::new(); + + let mut rng = rand::thread_rng(); + + static MAX_RANGE: isize = 65536; + + b.iter(|| { + let x: isize = rng.gen_range(-MAX_RANGE..MAX_RANGE); + let y: usize = rng.gen::() as usize; + let z: isize = rng.gen_range(-MAX_RANGE..MAX_RANGE); + + server.change_block(BlockID::Generic, &BlockPos::new(x, y, z)); + }); + } + + #[bench] + fn bench_insert_and_read_clustered(b: &mut Bencher) { + let mut server = SimpleServer::new(); + let mut rng = rand::thread_rng(); + + static NUM_BLOCKS: usize = 1_000; + static MAX_RANGE: isize = 128; + + let mut positions = Vec::with_capacity(NUM_BLOCKS); + + for _ in 0..NUM_BLOCKS { + let x: isize = rng.gen_range(-MAX_RANGE..MAX_RANGE); + let y: usize = rng.gen::() as usize; + let z: isize = rng.gen_range(-MAX_RANGE..MAX_RANGE); + + let pos = BlockPos::new(x, y, z); + + server.change_block(BlockID::Generic, &BlockPos::new(x, y, z)); + + positions.push(pos); + } + + b.iter(|| { + for i in 0..NUM_BLOCKS { + assert_eq!(server.read_block_at(&positions[i]), BlockID::Generic); + } + }); + } + + #[bench] + fn bench_insert_and_read_cache(b: &mut Bencher) { + let mut server = SimpleServer::new(); + let mut rng = rand::thread_rng(); + + static NUM_BLOCKS: usize = 1_000; + static MAX_RANGE: isize = 128; + static EXPANDED_RANGE: isize = 2048; + + let mut positions = Vec::with_capacity(NUM_BLOCKS); + + for _ in 0..NUM_BLOCKS { + let x: isize = rng.gen_range(-MAX_RANGE..MAX_RANGE); + let y: usize = rng.gen::() as usize; + let z: isize = rng.gen_range(-MAX_RANGE..MAX_RANGE); + + let pos = BlockPos::new(x, y, z); + + server.change_block(BlockID::Generic, &BlockPos::new(x, y, z)); + + positions.push(pos); + } + + b.iter(|| { + // Read blocks that are already in the server + for i in 0..NUM_BLOCKS { + assert_eq!(server.read_block_at(&positions[i]), BlockID::Generic); + } + + // Read blocks that might not be in the server, triggering a miss + for _ in 0..NUM_BLOCKS { + let x: isize = rng.gen_range(-EXPANDED_RANGE..EXPANDED_RANGE); + let y: usize = rng.gen::() as usize; + let z: isize = rng.gen_range(-EXPANDED_RANGE..EXPANDED_RANGE); + server.read_block_at(&BlockPos::new(x, y, z)); + } + }); + } + + #[bench] + fn bench_clustered_many_misses(b: &mut Bencher) { + let mut server = SimpleServer::new(); + let mut rng = rand::thread_rng(); + + static NUM_BLOCKS: usize = 1_000; + static MAX_RANGE: isize = 128; + static EXPANDED_RANGE: isize = 2048; + + for _ in 0..NUM_BLOCKS { + let x: isize = rng.gen_range(-MAX_RANGE..MAX_RANGE); + let y: usize = rng.gen::() as usize; + let z: isize = rng.gen_range(-MAX_RANGE..MAX_RANGE); + + server.change_block(BlockID::Generic, &BlockPos::new(x, y, z)); + } + + b.iter(|| { + // Read blocks that might not be in the server, triggering a miss + for _ in 0..NUM_BLOCKS { + let x: isize = rng.gen_range(-EXPANDED_RANGE..EXPANDED_RANGE); + let y: usize = rng.gen::() as usize; + let z: isize = rng.gen_range(-EXPANDED_RANGE..EXPANDED_RANGE); + server.read_block_at(&BlockPos::new(x, y, z)); + } + }); + } +}