kevo/pkg/transaction/example_test.go
Jeremy Tregunna 6fc3be617d
Some checks failed
Go Tests / Run Tests (1.24.2) (push) Has been cancelled
feat: Initial release of kevo storage engine.
Adds a complete LSM-based storage engine with these features:
- Single-writer based architecture for the storage engine
- WAL for durability, and hey it's configurable
- MemTable with skip list implementation for fast read/writes
- SSTable with block-based structure for on-disk level-based storage
- Background compaction with tiered strategy
- ACID transactions
- Good documentation (I hope)
2025-04-20 14:06:50 -06:00

136 lines
3.5 KiB
Go

package transaction_test
import (
"fmt"
"os"
"github.com/jer/kevo/pkg/engine"
"github.com/jer/kevo/pkg/transaction"
"github.com/jer/kevo/pkg/wal"
)
// Disable all logs in tests
func init() {
wal.DisableRecoveryLogs = true
}
func Example() {
// Create a temporary directory for the example
tempDir, err := os.MkdirTemp("", "transaction_example_*")
if err != nil {
fmt.Printf("Failed to create temp directory: %v\n", err)
return
}
defer os.RemoveAll(tempDir)
// Create a new storage engine
eng, err := engine.NewEngine(tempDir)
if err != nil {
fmt.Printf("Failed to create engine: %v\n", err)
return
}
defer eng.Close()
// Add some initial data directly to the engine
if err := eng.Put([]byte("user:1001"), []byte("Alice")); err != nil {
fmt.Printf("Failed to add user: %v\n", err)
return
}
if err := eng.Put([]byte("user:1002"), []byte("Bob")); err != nil {
fmt.Printf("Failed to add user: %v\n", err)
return
}
// Create a read-only transaction
readTx, err := transaction.NewTransaction(eng, transaction.ReadOnly)
if err != nil {
fmt.Printf("Failed to create read transaction: %v\n", err)
return
}
// Query data using the read transaction
value, err := readTx.Get([]byte("user:1001"))
if err != nil {
fmt.Printf("Failed to get user: %v\n", err)
} else {
fmt.Printf("Read transaction found user: %s\n", value)
}
// Create an iterator to scan all users
fmt.Println("All users (read transaction):")
iter := readTx.NewIterator()
for iter.SeekToFirst(); iter.Valid(); iter.Next() {
fmt.Printf(" %s: %s\n", iter.Key(), iter.Value())
}
// Commit the read transaction
if err := readTx.Commit(); err != nil {
fmt.Printf("Failed to commit read transaction: %v\n", err)
return
}
// Create a read-write transaction
writeTx, err := transaction.NewTransaction(eng, transaction.ReadWrite)
if err != nil {
fmt.Printf("Failed to create write transaction: %v\n", err)
return
}
// Modify data within the transaction
if err := writeTx.Put([]byte("user:1003"), []byte("Charlie")); err != nil {
fmt.Printf("Failed to add user: %v\n", err)
return
}
if err := writeTx.Delete([]byte("user:1001")); err != nil {
fmt.Printf("Failed to delete user: %v\n", err)
return
}
// Changes are visible within the transaction
fmt.Println("All users (write transaction before commit):")
iter = writeTx.NewIterator()
for iter.SeekToFirst(); iter.Valid(); iter.Next() {
fmt.Printf(" %s: %s\n", iter.Key(), iter.Value())
}
// But not in the main engine yet
val, err := eng.Get([]byte("user:1003"))
if err != nil {
fmt.Println("New user not yet visible in engine (correct)")
} else {
fmt.Printf("Unexpected: user visible before commit: %s\n", val)
}
// Commit the write transaction
if err := writeTx.Commit(); err != nil {
fmt.Printf("Failed to commit write transaction: %v\n", err)
return
}
// Now changes are visible in the engine
fmt.Println("All users (after commit):")
users := []string{"user:1001", "user:1002", "user:1003"}
for _, key := range users {
val, err := eng.Get([]byte(key))
if err != nil {
fmt.Printf(" %s: <deleted>\n", key)
} else {
fmt.Printf(" %s: %s\n", key, val)
}
}
// Output:
// Read transaction found user: Alice
// All users (read transaction):
// user:1001: Alice
// user:1002: Bob
// All users (write transaction before commit):
// user:1002: Bob
// user:1003: Charlie
// New user not yet visible in engine (correct)
// All users (after commit):
// user:1001: <deleted>
// user:1002: Bob
// user:1003: Charlie
}