Giter Club home page Giter Club logo

feophant's Introduction

FeOphant

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

We now have support for persistent storage! Not crash safe but I'm getting there!

Latest Build codecov dependency status

Website

Launch

Launch the server ./feophant

Lauch a postgres client application to test ./pgbench -i -h 127.0.0.1 -p 50000 ./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

  • Connecting unauthenticated using a postgres client/driver.
  • You can create tables, insert data and query single tables.
  • Data is persisted to disk, not crash safe and the on disk format is NOT stable.

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's memory safety and strong type system.

  • Multi-threaded async design based on Tokio instead of Postgres's multi-process design.

    • Perk of this is not needing to manage SYSV shared memory. (Postgres largely fixed this but I think its still worth noting).
  • Want to avoid vaccuum for transaction wrap around. Will try 64-bit transaction IDs but might go to 128-bit.

    • I can avoid the need to freeze Transaction IDs however the hint bits will need scanning to ensure that they are updated.
  • Replacing OIDs with UUIDv4s.

  • I think I've figured out what the core divergeance from Postgres that I'm interested in. I love Postgres's transactional DDLs but version controlling a schema is awful. What if I make the database server a library and your schema is code? You supply a new binary that runs as the database server and if you need to change it you just deploy the binary instead? Then the compiler can optimize out anything you don't need to run the system in your use case. The hardest part is dealing with schema changes that affect your on disk format.

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 end up having an enum to hold data and another enum to validate and match the sub type. The RFC to fix this was postponed indefinately.

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.

feophant's People

Contributors

chotchki avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

isgasho

feophant's Issues

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.

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.

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.

Implement Page Level Locking

So I have a fully ready free space map but I can't avoid the locking issue anymore despite it also being the next item on the todo list.

So I started trying to bake in locks and I've hit my normal do I go for a read or write lock approach? I think I may have screwed up the lock manager design, oops too much in silos!

So what I really need in a lock manager is this:

  • multi-threaded access
  • ability to read page
  • ability to write a page without causing collisions

I'm debating do I need to put a check-in / check-out layer on top of file manager.
So I could expose an api for the following:
Read - Easy
ReadForUpdate - This is the hard part
Ideally
Append - Needs to be serialized
//Ignoring Delete/shrink for now

I should treat this as a lesson for not implementing something outside the greater system and realizing I can't integrate it.

Implement Fossa Cleanup

Right now I have licensing issues as identified by Fossa. These are not due to the code but the various support tools around the code.

To fix this I will need to restructure the project to separate testing tools from the core code. They are already separated but its hard for Fossa to tell. However since I'm not selling presenting this code as production ready, meh, I'll fix it later.

Implement Fuzzing

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

The number of managers in io is excessive

I've been using a series of layered providers I've been calling managers and its gotten overly complex.

I need a better naming convention and package organization structure.

Extract the creation of new page offsets

Currently page offsets are generated as part of the insertion into the file system. However this results in a bad assumption in a couple layers of the stack.

My issue is that the code ends up assuming when a new page is inserted that it will result in the logical next page.

If I can avoid the extraction I would prefer it, we'll see.

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.

Implement the ability to drop tables

Right now pgbench fails on an initial attempt to drop the tables. We should add drop support.

drop table if exists pgbench_accounts, pgbench_branches, pgbench_history, pgbench_tellers

Fix pg codec DDOS vulnerability

  • 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.

Switch from next_free_offset to free space based

Currently new pages are selected based on appending to the end instead of based on pages being in use or not.

Switch this to using just the free space map.

Row manager will make use of the free/full markings.
Index manager will make use of them as inuse/not used.

Figure out the longer term license for FeOphant

At the moment I have the license set to AGPL3.0 but that IS NOT conducive to getting people interested in this as a library. Once I get to a MVP I need to consider strongly relicensing to BSD/Apache/MIT something.

As I write this I might make the decision sooner than later.

Improve how page handling is done

Currently all pages in the system are being handled via Tokio's BytesMut struct and related traits. This struct is awesome for giving me easy read/write methods on an underlying set of pointers.

However I have discovered a critical issue that I am uncertain how to solve effectively.

So right now I have a combination of features in my lock/cache system:

  • Reader/Writer locks for a given page
  • A least recently used cache of pages
  • A way to check out pages and if discarded a way to purge the cache.

The issue I am facing is as follows:

  1. A page is is checked out for read or write.
  2. Read/writes are done to it but are discarded for any number of reasons.
  3. The next process checks out the same page.
  4. The process will not see the entire page since it has been consumed partially. This leads to interesting and painful bugs as I discovered in my index work.

Implement index pointer validation

The BTreeLeafs have a doubly linked list to scan back and forth once you reach the bottom.

They are stored in multiple pages so if the database crashes they could be corrupted.

To work around this until I figure out a better way I can scan each leaf on database startup.

Will need to determine if the database shuts down unclean or not.

Implement where clauses

Will likely need to have to start tracing columns from analyizing through to later stages.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.