Transaction atomicity has been implemented for NornicDB storage operations.
-
pkg/storage/transaction.go(NEW)Transactionstruct with operation bufferingCreateNode,UpdateNode,DeleteNode- Node operationsCreateEdge,DeleteEdge- Edge operationsCommit()- Apply all buffered operations atomicallyRollback()- Discard all buffered operations- Read-your-writes support via
GetNode()
-
pkg/storage/memory.go(MODIFIED)- Added
BeginTransaction()method to create new transactions - Added internal unlocked methods for atomic commit:
createNodeUnlocked()updateNodeUnlocked()deleteNodeUnlocked()createEdgeUnlocked()deleteEdgeUnlocked()
- Added
-
pkg/storage/transaction_test.go(NEW)- 12 comprehensive unit tests
- 2 benchmarks
✅ Atomicity - All operations commit together or none do ✅ Operation Buffering - Changes are invisible until commit ✅ Read-Your-Writes - Transaction can see its own uncommitted changes ✅ Rollback - Discard all buffered operations ✅ Closed Transaction Detection - Error if operating on closed tx
engine := storage.NewMemoryEngine()
tx := engine.BeginTransaction()
// Operations are buffered, not yet visible in engine
tx.CreateNode(&Node{ID: "user-1", Labels: []string{"User"}})
tx.CreateNode(&Node{ID: "user-2", Labels: []string{"User"}})
tx.CreateEdge(&Edge{ID: "e1", StartNode: "user-1", EndNode: "user-2", Type: "FOLLOWS"})
// Read-your-writes works
node, _ := tx.GetNode("user-1") // Returns the buffered node
// Either commit all...
err := tx.Commit()
// ...or rollback all
// tx.Rollback()BenchmarkTransaction_CommitNodes-16 129,942 10,618 ns/op 10,737 B/op 96 allocs/op
BenchmarkTransaction_RollbackNodes-16 224,329 5,403 ns/op 6,776 B/op 66 allocs/op
Interpretation:
- Committing 10 nodes takes ~10.6μs (~1μs per node)
- Rolling back 10 nodes takes ~5.4μs (faster - no storage writes)
- Memory overhead: ~1KB per node in transaction buffer
| Package | Coverage |
|---|---|
pkg/storage |
85.2% |
pkg/filter |
96.0% |
pkg/search |
89.8% |
pkg/decay |
87.4% |
pkg/inference |
85.5% |
=== RUN TestTransaction_CreateNode_Basic
--- PASS: TestTransaction_CreateNode_Basic (0.00s)
=== RUN TestTransaction_Rollback
--- PASS: TestTransaction_Rollback (0.00s)
=== RUN TestTransaction_Atomicity
--- PASS: TestTransaction_Atomicity (0.00s)
=== RUN TestTransaction_DeleteNode
--- PASS: TestTransaction_DeleteNode (0.00s)
=== RUN TestTransaction_UpdateNode
--- PASS: TestTransaction_UpdateNode (0.00s)
=== RUN TestTransaction_CreateEdge
--- PASS: TestTransaction_CreateEdge (0.00s)
=== RUN TestTransaction_CreateEdgeWithNewNodes
--- PASS: TestTransaction_CreateEdgeWithNewNodes (0.00s)
=== RUN TestTransaction_DeleteEdge
--- PASS: TestTransaction_DeleteEdge (0.00s)
=== RUN TestTransaction_ClosedTransaction
--- PASS: TestTransaction_ClosedTransaction (0.00s)
=== RUN TestTransaction_IsActive
--- PASS: TestTransaction_IsActive (0.00s)
=== RUN TestTransaction_Isolation
--- PASS: TestTransaction_Isolation (0.00s)
=== RUN TestTransaction_MultipleOperationTypes
--- PASS: TestTransaction_MultipleOperationTypes (0.00s)
PASS
- Connect Transaction to Bolt
handleBegin(),handleCommit(),handleRollback() - Store active transaction in Session struct
- Route Cypher write operations through transaction
- Snapshot isolation (prevent dirty reads from other transactions)
- Deadlock detection
- Transaction timeouts
- Savepoints
Imagine you're rearranging furniture in your room:
- BEGIN = "I'm going to rearrange my room"
- Operations = Moving furniture around (but not committing yet)
- COMMIT = "Yes! I like this arrangement, keep it!"
- ROLLBACK = "Nope, put everything back where it was"
The transaction remembers where everything was before, so if you change your mind (ROLLBACK), everything goes back to the original spots!
Implemented: November 26, 2025