Compare commits

...

5 Commits

Author SHA256 Message Date
paulhorn c7a2534ad8 Merge pull request 'E0 is done' (#5) from E0 into main
Reviewed-on: #5
2026-06-27 12:02:54 +02:00
paulhorn a1d70cde59 test: page_insert and page_get 2026-06-27 11:51:22 +02:00
paulhorn 6829a98c90 feat: page_get implemented in page.c 2026-06-27 11:45:04 +02:00
paulhorn 03f99a0bb3 chore: fixed README.md 2026-06-27 11:33:34 +02:00
paulhorn 88a1d9875b feat: page_insert implemented in page.c 2026-06-27 11:27:20 +02:00
3 changed files with 118 additions and 46 deletions
+38 -38
View File
@@ -396,60 +396,60 @@ gantt
### Stages in Detail
- [ ] **E0 - Project Structure + Build System**
- CMake project: compile and link C and C++ together
- Directory structure: `src/`, `include/`, `test/`, `docs/`, `examples/`
- CI: Gitea Actions with `cmake --build` + `ctest`
- First exercise: compile a C file and a C++ file and link them via `extern "C"`
- CMake project: compile and link C and C++ together
- Directory structure: `src/`, `include/`, `test/`, `docs/`, `examples/`
- CI: Gitea Actions with `cmake --build` + `ctest`
- First exercise: compile a C file and a C++ file and link them via `extern "C"`
- [ ] **E1 - In-Memory Row-Store / Delta (C)**
- Slotted Page: 4 KiB byte array, header, slots, `page_insert()` / `page_get()`
- Heap: multiple Slotted Pages, `heap_insert()` / `heap_full_scan()`
- C++ wrapper: `RowStore` class encapsulating C functions
- Tests: insert, scan, page overflow
- Slotted Page: 4 KiB byte array, header, slots, `page_insert()` / `page_get()`
- Heap: multiple Slotted Pages, `heap_insert()` / `heap_full_scan()`
- C++ wrapper: `RowStore` class encapsulating C functions
- Tests: insert, scan, page overflow
- [ ] **E2 - Mini-SQL Parser (C++)**
- Tokenizer: `SELECT`, `INSERT`, `WHERE`, identifiers, integers, strings
- Parser: recursive descent -> AST (class hierarchy with Visitor pattern)
- Executor: `INSERT INTO t VALUES(...)` + `SELECT ... WHERE id = ?`
- Tests: parse roundtrips, executor integration
- Tokenizer: `SELECT`, `INSERT`, `WHERE`, identifiers, integers, strings
- Parser: recursive descent -> AST (class hierarchy with Visitor pattern)
- Executor: `INSERT INTO t VALUES(...)` + `SELECT ... WHERE id = ?`
- Tests: parse roundtrips, executor integration
- [ ] **E3 - In-Memory Column-Store / Main (C)**
- Column vectors: one array per column instead of per row
- Dictionary encoding: sorted dictionary + value-ID vector
- Advanced compression: Prefix, RLE, Cluster, Sparse, Indirect
- C++ wrapper: `ColumnStore` class
- Tests: measure compression ratio, scan performance
- Column vectors: one array per column instead of per row
- Dictionary encoding: sorted dictionary + value-ID vector
- Advanced compression: Prefix, RLE, Cluster, Sparse, Indirect
- C++ wrapper: `ColumnStore` class
- Tests: measure compression ratio, scan performance
- [ ] **E4 - Delta-Merge**
- Periodic merge: Delta (Row) -> Main (Column)
- Row-to-column transposition
- Rebuild dictionary, apply compression
- Merge trigger: threshold (e.g. every 1000 inserts)
- Tests: data identical before/after merge, compression takes effect
- Periodic merge: Delta (Row) -> Main (Column)
- Row-to-column transposition
- Rebuild dictionary, apply compression
- Merge trigger: threshold (e.g. every 1000 inserts)
- Tests: data identical before/after merge, compression takes effect
- [ ] **E5 - Query Router (HTAP Proof)**
- Point query -> row path (Delta, then B+Tree on Main)
- Aggregation -> column path (Main scan)
- Read queries always see Delta union Main
- Tests: same query, both paths, same result
- Point query -> row path (Delta, then B+Tree on Main)
- Aggregation -> column path (Main scan)
- Read queries always see Delta union Main
- Tests: same query, both paths, same result
- [ ] **E6 - SQL Extensions (C++)**
- `GROUP BY` + aggregate functions: `SUM`, `COUNT`, `AVG`, `MIN`, `MAX`
- `JOIN` (nested loop, then hash join)
- `ORDER BY` + `LIMIT`
- Tests: TPC-H inspired mini queries
- `GROUP BY` + aggregate functions: `SUM`, `COUNT`, `AVG`, `MIN`, `MAX`
- `JOIN` (nested loop, then hash join)
- `ORDER BY` + `LIMIT`
- Tests: TPC-H inspired mini queries
- [ ] **E7 - MVCC / Transactions (C++)**
- Snapshot isolation: each transaction sees a consistent state
- Transaction IDs and version chains
- Consistent read view during Delta-Merge
- Tests: concurrent read + write, isolation verified
- Snapshot isolation: each transaction sees a consistent state
- Transaction IDs and version chains
- Consistent read view during Delta-Merge
- Tests: concurrent read + write, isolation verified
- [ ] **E8 - *(optional)* Persistence (C + C++)**
- WAL: Write-Ahead Log in C (sequential writes)
- Snapshot: periodic checkpoint
- Recovery: WAL replay after crash
- Turning "proof" into "real DB"
- WAL: Write-Ahead Log in C (sequential writes)
- Snapshot: periodic checkpoint
- Recovery: WAL replay after crash
- Turning "proof" into "real DB"
---
+31 -8
View File
@@ -79,17 +79,40 @@ page_free(Page * p)
int
page_insert(Page * p, const void * data, size_t len)
{
(void) p;
(void) data;
(void) len;
return -1; /* noch nicht implementiert */
PageHeader * h = header(p);
/* Wo endet der letzte Slot? */
size_t slots_end = sizeof(PageHeader) + ((h->num_slots + 1) * sizeof(Slot));
/* Passt das neue Tuple noch rein? */
if (h->free_space_offset - len < slots_end) return -1; /* Page voll */
/* Tuple-Daten von hinten schreiben */
h->free_space_offset -= (uint16_t) len;
memcpy(p->raw + h->free_space_offset, data, len);
/* Neuen Slot anlegen */
Slot * s = (Slot *) (p->raw + sizeof(PageHeader)) + h->num_slots;
s->offset = h->free_space_offset;
s->length = (uint16_t) len;
/* Slot-ID zurueckgeben, dann Counter erhoehen */
uint16_t slot_id = h->num_slots;
h->num_slots++;
return (int) slot_id;
}
void *
page_get(Page * p, uint16_t slot_id, size_t * out_len)
{
(void) p;
(void) slot_id;
(void) out_len;
return NULL; /* noch nicht implementiert */
PageHeader * h = header(p);
if (slot_id >= h->num_slots) return NULL; /* Slot existiert nicht */
Slot * s = (Slot *) (p->raw + sizeof(PageHeader)) + slot_id;
if (out_len) *out_len = s->length;
return p->raw + s->offset;
}
+49
View File
@@ -8,6 +8,7 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
static void
test_create_returns_non_null(void)
@@ -28,12 +29,60 @@ test_insert_returns_slot_id(void)
printf(" OK: Insert\n");
}
static void
test_insert_and_get(void)
{
Page * p = page_create(1);
int slot = page_insert(p, "ABAP", 4);
assert(slot == 0);
size_t len = 0;
void * result = page_get(p, 0, &len);
assert(result != NULL);
assert(len == 4);
assert(memcmp(result, "ABAP", 4) == 0);
page_free(p);
printf(" OK: insert + get roundtrip\n");
}
static void
test_multiple_inserts(void)
{
Page * p = page_create(2);
assert(page_insert(p, "ABAP", 4) == 0);
assert(page_insert(p, "HANA", 4) == 1);
assert(page_insert(p, "CDS", 3) == 2);
size_t len = 0;
assert(memcmp(page_get(p, 0, &len), "ABAP", 4) == 0);
assert(memcmp(page_get(p, 1, &len), "HANA", 4) == 0);
assert(memcmp(page_get(p, 2, &len), "CDS", 3) == 0);
page_free(p);
printf(" OK: multiple inserts\n");
}
static void
test_invalid_slot_returns_null(void)
{
Page * p = page_create(3);
assert(page_get(p, 99, NULL) == NULL);
page_free(p);
printf(" OK: invalid slot returns NULL\n");
}
int
main(void)
{
printf("=== test_page ===\n");
test_create_returns_non_null();
test_insert_returns_slot_id();
test_insert_and_get();
test_multiple_inserts();
test_invalid_slot_returns_null();
printf("All tests passed.\n");
return 0;
}