Skip to content
This repository has been archived by the owner on Apr 15, 2023. It is now read-only.

Commit

Permalink
More trait implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
chotchki committed Sep 24, 2021
1 parent 116ab63 commit f20b728
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 64 deletions.
46 changes: 39 additions & 7 deletions src/engine/io/page_formats/item_id_data.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! Pointer type to indicate where an item is inside a page
//! See here for doc: https://www.postgresql.org/docs/current/storage-page-layout.html
use crate::engine::io::ConstEncodedSize;
use crate::engine::io::{
format_traits::{Parseable, Serializable},
ConstEncodedSize,
};

use super::{UInt12, UInt12Error};
use bytes::{Buf, BufMut};
Expand All @@ -23,20 +26,25 @@ impl ItemIdData {
let length_usize = self.length.to_u16() as usize;
offset_usize..(offset_usize + length_usize)
}
}

pub fn serialize(&self, buffer: &mut impl BufMut) {
UInt12::serialize_packed(buffer, &[self.offset, self.length]);
impl ConstEncodedSize for ItemIdData {
fn encoded_size() -> usize {
3
}
}

pub fn parse(buffer: &mut impl Buf) -> Result<Self, ItemIdDataError> {
impl Parseable<ItemIdDataError> for ItemIdData {
type Output = Self;
fn parse(buffer: &mut impl Buf) -> Result<Self, ItemIdDataError> {
let items = UInt12::parse_packed(buffer, 2)?;
Ok(ItemIdData::new(items[0], items[1]))
}
}

impl ConstEncodedSize for ItemIdData {
fn encoded_size() -> usize {
3
impl Serializable for ItemIdData {
fn serialize(&self, buffer: &mut impl BufMut) {
UInt12::serialize_packed(buffer, &[self.offset, self.length]);
}
}

Expand All @@ -47,3 +55,27 @@ pub enum ItemIdDataError {
#[error(transparent)]
UInt12Error(#[from] UInt12Error),
}

#[cfg(test)]
mod tests {
use bytes::BytesMut;

use crate::constants::PAGE_SIZE;

use super::*;

#[test]
fn test_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
let iid = ItemIdData::new(UInt12::new(1)?, UInt12::new(2)?);

let mut buffer = BytesMut::with_capacity(PAGE_SIZE as usize);
iid.serialize(&mut buffer);

let mut buffer = buffer.freeze();
let result = ItemIdData::parse(&mut buffer)?;

assert_eq!(iid, result);

Ok(())
}
}
31 changes: 16 additions & 15 deletions src/engine/io/page_formats/page_data.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::engine::io::format_traits::{Parseable, Serializable};
use crate::engine::io::{ConstEncodedSize, EncodedSize};
use crate::engine::objects::SqlTuple;
use crate::engine::transactions::TransactionId;
Expand Down Expand Up @@ -95,20 +96,6 @@ impl PageData {
}
}

pub fn serialize(&self, buffer: &mut impl BufMut) {
self.page_header.serialize(buffer);

//Now write items data in order
self.item_ids.iter().for_each(|f| f.serialize(buffer));

//Fill the free space
let free_space = vec![0; self.page_header.get_free_space()];
buffer.put_slice(&free_space);

//Write items in reverse order
self.rows.iter().rev().for_each(|r| r.serialize(buffer));
}

pub fn parse(
table: Arc<Table>,
page: PageOffset,
Expand Down Expand Up @@ -141,8 +128,22 @@ impl PageData {
rows,
})
}
}

impl Serializable for PageData {
fn serialize(&self, buffer: &mut impl BufMut) {
self.page_header.serialize(buffer);

//Todo implement updates, just unsure if it should be here
//Now write items data in order
self.item_ids.iter().for_each(|f| f.serialize(buffer));

//Fill the free space
let free_space = vec![0; self.page_header.get_free_space()];
buffer.put_slice(&free_space);

//Write items in reverse order
self.rows.iter().rev().for_each(|r| r.serialize(buffer));
}
}

#[derive(Debug, Error)]
Expand Down
21 changes: 12 additions & 9 deletions src/engine/io/page_formats/page_header.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! See https://www.postgresql.org/docs/current/storage-page-layout.html for reference documentation
//! I'm only implementing enough for my needs until proven otherwise
use crate::engine::io::ConstEncodedSize;
use crate::engine::io::{format_traits::Parseable, ConstEncodedSize};

use super::{ItemIdData, UInt12, UInt12Error};
use bytes::{Buf, BufMut};
Expand Down Expand Up @@ -59,14 +59,6 @@ impl PageHeader {
pub fn serialize(&self, buffer: &mut impl BufMut) {
UInt12::serialize_packed(buffer, &[self.pd_lower, self.pd_upper]);
}

pub fn parse(buffer: &mut impl Buf) -> Result<Self, PageHeaderError> {
let items = UInt12::parse_packed(buffer, 2)?;
Ok(PageHeader {
pd_lower: items[0],
pd_upper: items[1],
})
}
}

impl Default for PageHeader {
Expand All @@ -81,6 +73,17 @@ impl ConstEncodedSize for PageHeader {
}
}

impl Parseable<PageHeaderError> for PageHeader {
type Output = Self;
fn parse(buffer: &mut impl Buf) -> Result<Self, PageHeaderError> {
let items = UInt12::parse_packed(buffer, 2)?;
Ok(PageHeader {
pd_lower: items[0],
pd_upper: items[1],
})
}
}

#[derive(Debug, Error)]
pub enum PageHeaderError {
#[error("Not enough space to add")]
Expand Down
51 changes: 30 additions & 21 deletions src/engine/io/page_formats/page_offset.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::{
constants::{PAGES_PER_FILE, PAGE_SIZE},
engine::io::ConstEncodedSize,
engine::io::{
format_traits::{Parseable, Serializable},
ConstEncodedSize,
},
};
use bytes::{Buf, BufMut};
use std::{
Expand All @@ -9,33 +12,14 @@ use std::{
mem::size_of,
num::TryFromIntError,
ops::{Add, AddAssign, Mul},
process::Output,
};
use thiserror::Error;

#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct PageOffset(pub usize);

impl PageOffset {
pub fn serialize(&self, buffer: &mut impl BufMut) {
//TODO switch this and other serialize calls to usize based once my pull request is accepted
//https://github.com/tokio-rs/bytes/pull/511
buffer.put_uint_le(self.0 as u64, size_of::<usize>());
}

pub fn parse(buffer: &mut impl Buf) -> Result<Self, PageOffsetError> {
if buffer.remaining() < size_of::<usize>() {
return Err(PageOffsetError::BufferTooShort(
size_of::<usize>(),
buffer.remaining(),
));
}

let value = buffer.get_uint_le(size_of::<usize>());
let page = usize::try_from(value)?;

Ok(PageOffset(page))
}

/// This will calculate a page offset based on the max file count and the offset from the first
/// non-zero page in a file.
///
Expand Down Expand Up @@ -115,6 +99,23 @@ impl fmt::Display for PageOffset {
}
}

impl Parseable<PageOffsetError> for PageOffset {
type Output = Self;
fn parse(buffer: &mut impl Buf) -> Result<Self, PageOffsetError> {
if buffer.remaining() < size_of::<usize>() {
return Err(PageOffsetError::BufferTooShort(
size_of::<usize>(),
buffer.remaining(),
));
}

let value = buffer.get_uint_le(size_of::<usize>());
let page = usize::try_from(value)?;

Ok(PageOffset(page))
}
}

impl Mul for PageOffset {
type Output = PageOffset;

Expand All @@ -123,6 +124,14 @@ impl Mul for PageOffset {
}
}

impl Serializable for PageOffset {
fn serialize(&self, buffer: &mut impl BufMut) {
//TODO switch this and other serialize calls to usize based once my pull request is accepted
//https://github.com/tokio-rs/bytes/pull/511
buffer.put_uint_le(self.0 as u64, size_of::<usize>());
}
}

#[derive(Debug, Error, PartialEq)]
pub enum PageOffsetError {
#[error("Not enough space to parse usize need {0} got {1}")]
Expand Down
30 changes: 18 additions & 12 deletions src/engine/io/row_formats/item_pointer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//!
//! We will be treating this a little different since our size will be based on usize
use crate::engine::io::format_traits::{Parseable, Serializable};
use crate::engine::io::page_formats::{PageOffset, PageOffsetError};
use crate::engine::io::ConstEncodedSize;

Expand All @@ -24,16 +25,11 @@ impl ItemPointer {
pub fn new(page: PageOffset, count: UInt12) -> ItemPointer {
ItemPointer { page, count }
}
}

pub fn serialize(&self, buffer: &mut impl BufMut) {
self.page.serialize(buffer);
UInt12::serialize_packed(buffer, &[self.count]);
}

pub fn parse(buffer: &mut impl Buf) -> Result<Self, ItemPointerError> {
let po = PageOffset::parse(buffer)?;
let items = UInt12::parse_packed(buffer, 1)?;
Ok(ItemPointer::new(po, items[0]))
impl ConstEncodedSize for ItemPointer {
fn encoded_size() -> usize {
size_of::<usize>() + UInt12::encoded_size()
}
}

Expand All @@ -45,9 +41,19 @@ impl fmt::Display for ItemPointer {
}
}

impl ConstEncodedSize for ItemPointer {
fn encoded_size() -> usize {
size_of::<usize>() + UInt12::encoded_size()
impl Parseable<ItemPointerError> for ItemPointer {
type Output = Self;
fn parse(buffer: &mut impl Buf) -> Result<Self, ItemPointerError> {
let po = PageOffset::parse(buffer)?;
let items = UInt12::parse_packed(buffer, 1)?;
Ok(ItemPointer::new(po, items[0]))
}
}

impl Serializable for ItemPointer {
fn serialize(&self, buffer: &mut impl BufMut) {
self.page.serialize(buffer);
UInt12::serialize_packed(buffer, &[self.count]);
}
}

Expand Down

0 comments on commit f20b728

Please sign in to comment.