Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat table scan #1

Merged
merged 18 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/file/file_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ impl FileManager {
}
}

/// append_block 指定したファイルに新しいブロックを追加して、そのブロックのIDを返す
pub fn append_block(&mut self, filename: &str) -> Result<BlockId> {
let block = BlockId::new(filename.to_string(), self.block_count(filename)? as i32);
let offset = block.num * self.block_size;
Expand Down
106 changes: 106 additions & 0 deletions src/index/hash/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use super::Index;
use crate::{
query::{constant::Constant, scan::Scan as _},
record::{layout::Layout, rid::RID, table_scan::TableScan},
tx::transaction::Transaction,
};
use anyhow::{anyhow, Result};
use std::sync::{Arc, Mutex};

const NUM_BUCKETS: u64 = 100;

pub struct HashIndex {
tx: Arc<Mutex<Transaction>>,
index_name: String,
layout: Arc<Layout>,
search_key: Option<Constant>,
table_scan: Option<TableScan>,
}

impl HashIndex {
pub fn new(tx: Arc<Mutex<Transaction>>, index_name: String, layout: Arc<Layout>) -> Self {
Self {
tx,
index_name,
layout,
search_key: None,
table_scan: None,
}
}

pub fn search_cost(num_blocks: u64, _: u64) -> u64 {
num_blocks / NUM_BUCKETS
}
}

impl Index for HashIndex {
fn before_first(&mut self, search_key: Constant) -> Result<()> {
self.close();
let hash_code = search_key.hash_code();
self.search_key = Some(search_key);

let bucket = hash_code % NUM_BUCKETS;
let table_name = format!("{}{}", self.index_name, bucket);

self.table_scan = Some(TableScan::new(
self.tx.clone(),
table_name,
self.layout.clone(),
)?);

Ok(())
}

fn next(&mut self) -> Result<bool> {
let Some(table_scan) = self.table_scan.as_mut() else {
return Ok(false);
};
let Some(search_key) = self.search_key.as_ref() else {
return Ok(false);
};

while table_scan.next()? {
if table_scan.get_value("dataval")? == *search_key {
return Ok(true);
}
}
Ok(false)
}

fn get_data_rid(&mut self) -> Result<RID> {
let table_scan = self.table_scan.as_mut().ok_or(anyhow!("no table_scan"))?;
let block_num = table_scan.get_int("block")?;
let id = table_scan.get_int("id")?;
Ok(RID::new(block_num, id))
}

fn insert(&mut self, data_value: Constant, data_rid: RID) -> Result<()> {
self.before_first(data_value.clone())?;
let table_scan = self.table_scan.as_mut().ok_or(anyhow!("no table_scan"))?;
table_scan.insert()?;
table_scan.set_int("block", data_rid.block_num)?;
table_scan.set_int("id", data_rid.slot)?;
table_scan.set_value("dataval", data_value)?;
todo!()
}

fn delete(&mut self, data_value: Constant, data_rid: RID) -> Result<()> {
self.before_first(data_value)?;
while self.next()? {
if self.get_data_rid()? == data_rid {
self.table_scan
.as_mut()
.ok_or(anyhow!("no table_scan"))?
.delete()?;
return Ok(());
}
}
Ok(())
}

fn close(&mut self) {
if let Some(table_scan) = self.table_scan.as_mut() {
table_scan.close()
}
}
}
13 changes: 13 additions & 0 deletions src/index/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use crate::{query::constant::Constant, record::rid::RID};
use anyhow::Result;

pub mod hash;

pub trait Index {
fn before_first(&mut self, search_key: Constant) -> Result<()>;
fn next(&mut self) -> Result<bool>;
fn get_data_rid(&mut self) -> Result<RID>;
fn delete(&mut self, data_value: Constant, data_rid: RID) -> Result<()>;
fn insert(&mut self, data_value: Constant, data_rid: RID) -> Result<()>;
fn close(&mut self);
}
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ use std::mem::size_of;

pub mod buffer;
pub mod file;
pub mod index;
pub mod log;
pub mod macros;
pub mod metadata;
pub mod query;
pub mod record;
pub mod server;
pub mod tx;
Expand Down
6 changes: 6 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[macro_export]
macro_rules! unlock {
($e: expr) => {{
$e.lock().unwrap()
}};
}
80 changes: 80 additions & 0 deletions src/metadata/index_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use super::stat_info::StatInfo;
use crate::{
index::hash::HashIndex,
record::{
layout::Layout,
schema::{FieldTypes, Schema},
},
tx::transaction::Transaction,
};
use anyhow::{bail, Result};
use std::sync::{Arc, Mutex};

pub struct IndexInfo {
index_name: String,
field_name: String,
tx: Arc<Mutex<Transaction>>,
table_schema: Arc<Schema>,
index_layout: Arc<Layout>,
stat_info: StatInfo,
}

impl IndexInfo {
pub fn new(
index_name: String,
field_name: String,
table_schema: Arc<Schema>,
tx: Arc<Mutex<Transaction>>,
stat_info: StatInfo,
) -> Result<Self> {
let mut schema = Schema::default();
schema.add_int_field("block");
schema.add_int_field("id");
match schema.r#type(&field_name) {
Some(FieldTypes::Integer) => {
schema.add_int_field("dataval");
}
Some(FieldTypes::Varchar) => {
let length = table_schema.length(&field_name).unwrap();
schema.add_string_field("dataval", length);
}
None => bail!("field not found"),
}

let index_info = Self {
index_name,
field_name,
tx,
table_schema,
index_layout: Arc::new(Layout::try_from_schema(Arc::new(schema))?),
stat_info,
};

Ok(index_info)
}

pub fn open(&mut self) -> HashIndex {
HashIndex::new(
self.tx.clone(),
self.index_name.clone(),
self.index_layout.clone(),
)
}

pub fn blocks_accessed(&self) -> u64 {
let rpb = self.tx.lock().unwrap().block_size() / self.index_layout.slot_size;
let num_blocks = self.stat_info.num_records / rpb;
HashIndex::search_cost(num_blocks as u64, rpb as u64)
}

pub fn records_output(&self) -> i32 {
self.stat_info.num_records / self.stat_info.distinct_values(self.field_name.clone())
}

pub fn distinct_values(&self, field_name: String) -> i32 {
if field_name != self.field_name {
return 1;
}
self.stat_info.num_records / self.stat_info.distinct_values(field_name.clone())
}
}
97 changes: 97 additions & 0 deletions src/metadata/index_manager.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use super::{
index_info::IndexInfo,
stat_manager::StatManager,
table_manager::{TableManager, MAX_NAME},
};
use crate::{
query::scan::Scan,
record::{layout::Layout, schema::Schema, table_scan::TableScan},
tx::transaction::Transaction,
unlock,
};
use anyhow::Result;
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};

pub struct IndexManager {
layout: Arc<Layout>,
table_manager: Arc<Mutex<TableManager>>,
stat_manager: Arc<Mutex<StatManager>>,
}

impl IndexManager {
pub fn new(
is_new: bool,
table_manager: Arc<Mutex<TableManager>>,
stat_manager: Arc<Mutex<StatManager>>,
tx: Arc<Mutex<Transaction>>,
) -> Result<Self> {
if is_new {
let mut schema = Schema::default();
schema.add_string_field("indexname", MAX_NAME);
schema.add_string_field("tablename", MAX_NAME);
schema.add_string_field("fieldname", MAX_NAME);
unlock!(table_manager).create_table("idxcat", Arc::new(schema), tx.clone())?;
}

let layout = Arc::new(unlock!(table_manager).get_layout("idxcat", tx.clone())?);

Ok(Self {
layout,
table_manager,
stat_manager,
})
}

pub fn create_index(
&mut self,
index_name: String,
table_name: String,
field_name: String,
tx: Arc<Mutex<Transaction>>,
) -> Result<()> {
let mut ts = TableScan::new(tx, table_name.clone(), self.layout.clone())?;
ts.insert()?;
ts.set_string("indexname", &index_name)?;
ts.set_string("tablename", &table_name)?;
ts.set_string("fieldname", &field_name)?;
Ok(())
}

pub fn get_index_info(
&mut self,
table_name: String,
tx: Arc<Mutex<Transaction>>,
) -> Result<HashMap<String, IndexInfo>> {
let mut result = HashMap::new();

let mut ts = TableScan::new(tx.clone(), table_name.clone(), self.layout.clone())?;

while ts.next()? {
if ts.get_string("tablename")? == table_name.clone() {
let index_name = ts.get_string("indexname")?;
let field_name = ts.get_string("fieldname")?;
let table_layout = Arc::new(
unlock!(self.table_manager).get_layout(table_name.clone(), tx.clone())?,
);
let table_stat_info = self.stat_manager.lock().unwrap().get_stat_info(
table_name.clone(),
table_layout.clone(),
tx.clone(),
)?;
let index_info = IndexInfo::new(
index_name.clone(),
field_name,
table_layout.schema.clone(),
tx.clone(),
table_stat_info,
)?;
result.insert(index_name, index_info);
}
}

Ok(result)
}
}
Empty file.
7 changes: 7 additions & 0 deletions src/metadata/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub mod index_info;
pub mod index_manager;
pub mod metadata_manager;
pub mod stat_info;
pub mod stat_manager;
pub mod table_manager;
pub mod view_manager;
18 changes: 18 additions & 0 deletions src/metadata/stat_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#[derive(Clone)]
pub struct StatInfo {
pub num_blocks: i32,
pub num_records: i32,
}

impl StatInfo {
pub fn new(num_blocks: i32, num_records: i32) -> Self {
Self {
num_blocks,
num_records,
}
}

pub fn distinct_values(&self, _field_name: String) -> i32 {
1 + (self.num_records / 3)
}
}
Loading
Loading