A lightweight, SQLite-inspired database engine built from scratch in C with TCP networking support and a JavaScript ORM for seamless integration.
- SQL-like Query Interface: Support for INSERT and SELECT statements
- B+ Tree Storage Engine: Efficient indexing and data retrieval
- ACID Properties: Ensures data consistency and reliability
- Page-based Storage: Optimized memory management with 4KB pages
- Persistent Storage: Data persistence to disk with proper file handling
- Meta Commands: Built-in commands for database introspection (
.btree,.constants,.exit)
- TCP Server: Built-in TCP server for remote database connections
- Multi-client Support: Handle multiple concurrent client connections
- Network Protocol: Custom protocol for database operations over TCP
- B+ Tree Implementation: Self-balancing tree structure for optimal performance
- Node Splitting: Automatic handling of full nodes with splitting algorithm
- Cursor-based Navigation: Efficient row traversal and positioning
- Memory Management: Smart paging system with lazy loading
- Error Handling: Comprehensive error handling and validation
Meta commands for database introspection:
.btree: Displays the current B+ tree structure.constants: Lists important constants used in the database.exit: Exits the database client
Query commands:
insert <id> <name> <email>: Inserts a new row into the databaseselect: Retrieves all rows from the database
make: Compiles the database enginemake clean: Cleans up compiled files and executablesmake run: Runs the database server with a specified database filemake debug: Compiles the database engine with debugging symbols
- Language: C (C99 standard)
- Storage: Custom page-based file format
- Networking: POSIX sockets (TCP/IP)
- Data Structure: B+ Tree for indexing
- Build System: GCC/Make compatible
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β Client App ββββββ€ TCP Network βββββΊβ SimpleDB β
β (JS ORM/CLI) β β Protocol β β Server β
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β Query Engine β
β - Parser β
β - Validator β
β - Executor β
βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β Storage Engine β
β - B+ Tree β
β - Pager β
β - File I/O β
βββββββββββββββββββ
SQL Input β Parser β Validator β Executor β Storage Engine β Disk
- Input Buffer: Handles client input via TCP or stdin
- Parser: Converts SQL strings to internal statement structures
- Validator: Checks syntax, data types, and constraints
- Executor: Processes validated statements using virtual machine approach
- Storage Engine: Manages data persistence and retrieval
Table
βββ Pager (Memory Manager)
β βββ File Descriptor
β βββ Pages Array [0...399]
β βββ File Length
βββ B+ Tree Structure
βββ Internal Nodes (Navigation)
βββ Leaf Nodes (Data Storage)
Page Structure (4KB each):
- Header: Node type, parent pointer, cell count
- Cells: Key-value pairs (ID + serialized row data)
- Metadata: Navigation pointers for tree traversal
graph TD
A[Client Connection] --> B[TCP Server]
B --> C[Input Parser]
C --> D{Command Type}
D -->|Meta Command| E[Meta Handler]
D -->|SQL Statement| F[Statement Validator]
F --> G[Virtual Machine]
G --> H{Statement Type}
H -->|INSERT| I[Insert Handler]
H -->|SELECT| J[Select Handler]
I --> K[B+ Tree Insert]
J --> L[B+ Tree Search]
K --> M[Pager]
L --> M
M --> N[Disk I/O]
- Internal Nodes: Store keys and child pointers for navigation
- Leaf Nodes: Store actual data records with next-leaf pointers
- Splitting Logic: Automatic node splitting when capacity exceeded
- Root Management: Dynamic root creation and management
- Page Size: 4,096 bytes
- Max Pages: 400 (1.6GB theoretical limit)
- Rows per Page: ~13 rows (accounting for B+ tree overhead)
- Max Rows: ~5,200 rows per table
- GCC compiler
- POSIX-compatible system (Linux/macOS)
- Make (optional)
# Clone the repository
git clone <repository-url>
cd simpledb
# Compile the database
gcc -o simpledb *.c -std=c99
# Or using make
make simpledb# Start the database server
./simpledb database.db 8080
# The server will listen on port 8080
# Database file 'database.db' will be created if it doesn't exist-- Connect via telnet or custom client
telnet localhost 8080
-- Insert data
db > insert 1 john john@email.com
Executed.
-- Query data
db > select
(1, john, john@email.com)
Executed.
-- Meta commands
db > .btree
Tree:
- leaf (size 1)
- 1
db > .constants
ROW_SIZE: 293
LEAF_NODE_MAX_CELLS: 13
...
db > .exitA lightweight ORM is provided for easy integration with Node.js applications:
const ORM = require('./sdb');
ORM.connect(8080, '127.0.0.1');
ORM.query('select', (err, result) => {
if (err) return console.error(err);
console.log("Intial Data",result);
});
ORM.query('insert 2 sahil sahil@gmail.com', (err, result) => {
if (err) return console.error(err)
console.log("Data inserted")
});
ORM.query('insert 3 john sahil@gmail.com', (err, result) => {
if (err) return console.error(err)
console.log("Data inserted")
});
ORM.query('select', (err, result) => {
if (err) return console.error(err);
console.log("Final Data",result);
});- Insert Performance: O(log n) - B+ tree insertion
- Search Performance: O(log n) - B+ tree traversal
- Memory Usage: ~4KB per page + minimal overhead
- Concurrency: Single-threaded with connection queuing
- Storage Efficiency: ~13 rows per 4KB page
- UPDATE and DELETE statements
- Indexing on non-primary keys
- Transactions and rollback support
- Connection pooling
- Query optimization
- Schema definitions
- Multi-table support
- Authentication and authorization
- Replication and clustering
- Multi-threading support
- Write-ahead logging (WAL)
- Buffer pool management
- Compression algorithms
- Query caching
- Inspired by SQLite's architecture and design principles
- Reference Article
- B+ Tree implementation based on classic database system concepts
- TCP networking patterns from UNIX socket programming

