GitHub - samarkandiy/scalodb

4 min read Original article ↗

ScaloDB - Reusable Database Library

A high-performance, embeddable key-value database for Go applications.

Features

  • Embedded Mode: Use directly in your application (2-5M ops/sec)
  • Server Mode: Run as standalone server (500K-3M ops/sec)
  • MVCC: Lock-free concurrent reads
  • WAL: Write-ahead logging for durability
  • Thread-Safe: Use from multiple goroutines
  • Simple API: Easy integration

Quick Start

Installation

# Copy this folder to your project
cp -r scalodb /path/to/your/project/

# Or use as Go module
cd scalodb
go mod init github.com/yourusername/scalodb

Embedded Mode

package main

import (
    "fmt"
    "scalodb"
)

func main() {
    // Create database
    db, _ := scalodb.New(&scalodb.Config{
        WALPath: "myapp.wal",
    })
    defer db.Close()

    // Use it
    db.Put("user:1001", []byte("John Doe"))
    value, _ := db.Get("user:1001")
    fmt.Println(string(value))
}

Server Mode

package main

import (
    "log"
    "scalodb"
)

func main() {
    db, _ := scalodb.New(&scalodb.Config{
        Addr:     ":8080",
        MaxConns: 10000,
        WALPath:  "server.wal",
    })
    defer db.Close()

    log.Println("Starting server on :8080")
    db.StartAndWait()
}

API Reference

Configuration

type Config struct {
    Addr      string  // Listen address (":8080"), empty for embedded
    MaxConns  int     // Max connections (default: 1000)
    WALPath   string  // WAL file path (default: "scalodb.wal")
    EnableWAL bool    // Enable WAL (default: true)
}

Operations

// Create database
db, err := scalodb.New(&scalodb.Config{})

// Store data
err = db.Put(key string, value []byte)

// Retrieve data
value, err := db.Get(key string)

// Delete data
err = db.Delete(key string)

// Scan all data
data, err := db.Scan()

// Get statistics
stats := db.Stats()

// Close database
err = db.Close()

Server Control

// Start server (non-blocking)
err = db.Start()

// Start and wait (blocking)
err = db.StartAndWait()

// Stop server
err = db.Stop()

Example Code

All examples are included in the documentation below.

Use Cases

Session Store

type SessionStore struct {
    db *scalodb.DB
}

func NewSessionStore() (*SessionStore, error) {
    db, err := scalodb.New(&scalodb.Config{
        WALPath: "sessions.wal",
    })
    return &SessionStore{db: db}, err
}

func (s *SessionStore) Set(id string, data []byte) error {
    return s.db.Put("session:"+id, data)
}

func (s *SessionStore) Get(id string) ([]byte, error) {
    return s.db.Get("session:" + id)
}

Cache Layer

type Cache struct {
    db *scalodb.DB
}

func NewCache() (*Cache, error) {
    db, err := scalodb.New(&scalodb.Config{
        WALPath:   "cache.wal",
        EnableWAL: false, // No persistence for cache
    })
    return &Cache{db: db}, err
}

func (c *Cache) Set(key string, value []byte) error {
    return c.db.Put("cache:"+key, value)
}

func (c *Cache) Get(key string) ([]byte, error) {
    return c.db.Get("cache:" + key)
}

REST API Backend

func main() {
    db, _ := scalodb.New(&scalodb.Config{})
    defer db.Close()

    http.HandleFunc("/api/data", func(w http.ResponseWriter, r *http.Request) {
        key := r.URL.Query().Get("key")
        
        switch r.Method {
        case "GET":
            value, _ := db.Get(key)
            w.Write(value)
        case "POST":
            value, _ := io.ReadAll(r.Body)
            db.Put(key, value)
        }
    })

    http.ListenAndServe(":8080", nil)
}

Performance

  • Embedded Mode: 2-5M operations/second
  • Server Mode: 500K-3M operations/second
  • Concurrent Reads: Lock-free with MVCC
  • Durability: WAL with crash recovery
  • Scalability: Horizontal via sharding

Thread Safety

ScaloDB is fully thread-safe:

db, _ := scalodb.New(&scalodb.Config{})

go func() { db.Put("key1", []byte("value1")) }()
go func() { db.Put("key2", []byte("value2")) }()
go func() { value, _ := db.Get("key1") }()

Documentation

  • README.md - This file (complete documentation)
  • LIBRARY_USAGE.md - Detailed API documentation
  • REUSABLE_SUMMARY.md - Quick reference guide

Architecture

scalodb-library/
├── scalodb.go          # Main library API
├── storage/            # Storage engine
│   ├── engine.go       # Main engine
│   ├── mvcc.go         # MVCC implementation
│   └── wal.go          # Write-ahead log
└── README.md           # This file

Integration

With Gin

r := gin.Default()

r.GET("/data/:key", func(c *gin.Context) {
    value, _ := db.Get(c.Param("key"))
    c.Data(200, "text/plain", value)
})

r.POST("/data/:key", func(c *gin.Context) {
    value, _ := c.GetRawData()
    db.Put(c.Param("key"), value)
    c.Status(201)
})

With Echo

e := echo.New()

e.GET("/data/:key", func(c echo.Context) error {
    value, _ := db.Get(c.Param("key"))
    return c.Blob(200, "text/plain", value)
})

e.POST("/data/:key", func(c echo.Context) error {
    value, _ := io.ReadAll(c.Request().Body)
    db.Put(c.Param("key"), value)
    return c.NoContent(201)
})

Best Practices

  1. Always defer Close(): Ensures WAL is flushed

    db, _ := scalodb.New(&scalodb.Config{})
    defer db.Close()
  2. Use key prefixes: Organize your data

    db.Put("user:1001:profile", data)
    db.Put("session:abc123", data)
    db.Put("cache:homepage", data)
  3. Handle errors: Don't ignore returns

    if err := db.Put(key, value); err != nil {
        log.Printf("Failed: %v", err)
    }
  4. Monitor stats: Track growth

    stats := db.Stats()
    log.Printf("Keys: %d, Size: %d", stats.TotalKeys, stats.TotalSize)

Comparison: Embedded vs Server

Feature Embedded Server
Performance Fastest Fast
Multi-process No Yes
Network No Yes
Setup Simple Requires server
Use case Single app Microservices

License

MIT License - Free to use in any project

Support

  • See examples/ for code samples
  • Read LIBRARY_USAGE.md for detailed docs
  • Check REUSABLE_SUMMARY.md for quick reference