FeOphant

A SQL database server written in Rust and inspired by PostreSQL.

Just a toy for the moment, but I'm actively working to fix that!

Latest Build codecov

Website

Launch

Launch the server ./feophant

Lauch a postgres client application to test ./pgbench -h 127.0.0.1 -p 50000 ./psql -h 127.0.0.1 -p 50000

Benchmark to aid in profiling cargo instruments --bench feophant_benchmark -t time

What works user facing

You can currently start the server, connect to it and have it throw tons of errors. To support more there is a ton of infrastructure required to wire up next steps.

Current TODO List - Subject to constant change!

TODO

Add support for defining a primary key on a table. This implies the following functionality: * Index support through the stack down to the page level. * The concept of unique indexes. * Transactional support for indexes. * Failure of a statement on constraint violation. Unsure if I'll end up with a general constraint system from this.

Based on reading this really means implementing Btree indexes. They don't seem to be that bad to understand/implement.

First and most important question, how should the index layers work? Are they transactional? (I don't think so until I implement a visability map) How should the low level layer function? Should I have an Index config struct I pass around or just a table + columns + unique or not + type Index Config it is

Index Manager -> for a given table IO Manager -> Handle Page Load / Store / Update

Implemented the formats but I think I need to add locking to the I/O manager. At a minimum I need to support a get for update, update and release lock. I'm not sure I understand how this should work :(. I think need to commit to another layer.

Implemented stronger page checking to make sure we don't store something that won't work on the file system.

Back to indexes for now. I need to make a decision on how to handle them hitting the file system. Postgres uses a series of OIDs to map onto disk.

I've been using uuids, I think I'm going to continue that. That would also solve the postgres fork approach.

I'll have to switch IOManager to use uuid instead of Table as a key. Upside, I'm basically already doing that. (done)

Next up implementing the index manager to add entries to the index.

I'm having a hard time figuring this out, I might work to do the operations on the tree before I keep messing with the serialization protocols. I'm just worries they are directly linked.

Got further into the index manager. Unfortunately I need a lock manager to let it even pass the smell test. Time to go on a wild goose chase again! (This project is great for someone with ADHD to have fun on!)

The lock manager design/code is done but I'm not happy with using a rwlock to protect a tag. I really want to have the lock protect the content but that needs a way for me to support writeback. I think I need to build out two more things, a WAL mechanism and a buffer manager.

I guess I need to commit to doing this for reals. However I am worried about reaching a point of partially working for a while like when I did the type fixing. We'll see how this goes.

For now, the index implementation is now on hold until I get an integrated I/O subsystem and a stubbed out WAL.

The real I/O subsystem has been written and tested. About to integrate it. Real integration tests using a non feophant postgres rust driver are also working.

I/O subsystem integrated but I'm not happy with the performance. I'm debating a caching layer above the file_manager. I need to get some benchmarks together so I know if I'm actually helping.

TODO

Implement where clauses, will likely need to have to start tracing columns from analyizing through to later stages.

TODO

Implement support for running a fuzzer against the code base to ensure we are keeping the code at a high quality.

TODO

Implement delete for tuples

TODO

pgbench setup can run successfully, in memory

TODO

Ensure data about table structures is thread safe in the face of excessive Arc usage.

See where I can pass read only data by reference instead of uisng Arc everywhere

TODO

Support a row with more than 4kb of text in it.

TODO

Implement sorting.

TODO

Implement column aliasing

TODO

Implement subselect.

TODO

Implement Updates.

TODO

Did some reading on how the buffer manager works and my implementation seems to be firmly in the right direction. Take that knowledge and implement persistence

1.0 Release Criteria

Longer Term TODO

This is stuff that I should get to but aren't vital to getting to a minimal viable product. * Right now the main function runs the server from primitives. The Tokio Tower layer will probably do it better. * The codec that parses the network traffic is pretty naive. You could make the server allocate 2GB of data for a DDOS easily. * * We should either add state to the codec or change how it parses to produce chunked requests. That means that when the 2GB offer is reached the server can react and terminate before we accept too much data. Its a little more nuanced than that, 2GB input might be okay but we should make decisions based on users and roles. * There is an extension that removes the need to lock tables to repack / vaccum. Figure out how it works! * * https://github.com/reorg/pg_repack * Investigate if the zheap table format would be better to implement. * Until I get past a WAL implementation and planner costs I don't think its worth it. * Since I extended the size of transaction IDs, I probably have a larger issue on my hands than normal postgres. * Reading into the zheap approach I'm thinking that I might have some space saving options availible for me. In particular if a tuple is frozen so its always availible I could remove the xmin/xmax and pack more into the page. Need more thinking however my approach of questioning the storage efficency of each part of data seems to be worth it.

Postgres Divergance

Its kinda pointless to blindly reproduce what has already been done so I'm making the following changes to the db server design vs Postgres.

Rust Notes

How to setup modules sanely: https://dev.to/stevepryde/intro-to-rust-modules-3g8k

Reasonable application error type creation: https://github.com/dtolnay/anyhow

Library Errors: https://github.com/dtolnay/thiserror

Rust's inability to treat enum variants as a type is a HUGE pain. I cheated and separated serialization from deserialization.

Legal Stuff (Note I'm not a lawyer!)

I am explicitly striving for SQL+Driver compatibility with PostgreSQL so things such as system tables and code that handles them will be named the same. I don't think this violates their trademark policy but if I am please just reach out to me! I have also gone with a pretty restrictive license but I'm not tied to it if that is causing an issue for others who are using the code.