NenDB Architecture

NenDB is built on Data-Oriented Design (DOD) principles to maximize performance through cache efficiency, static memory allocation, and batch processing. Every architectural decision prioritizes predictable performance and minimal runtime overhead.

Core Architectural Principles

Data-Oriented Design

Structure data for optimal cache performance and memory access patterns rather than object-oriented abstractions.

  • • Structure-of-Arrays (SoA) layout
  • • Cache-friendly data traversal
  • • Minimal memory fragmentation

Batch Processing

Group operations to amortize costs and maximize throughput across network, disk, and system calls.

  • • Vectorized operations
  • • Reduced per-operation overhead
  • • Optimized memory bandwidth usage

Static Allocation

All memory allocated at startup eliminates runtime allocation overhead and garbage collection pauses.

  • • Zero runtime allocations
  • • Predictable memory usage
  • • No GC pauses or fragmentation

System Architecture

Client Layer

Applications connect via TCP protocol with binary serialization for minimal overhead.

TCP Client → Binary Protocol → Batch Requests → NenDB Server

Server Layer

High-performance TCP server with connection pooling and concurrent batch processing.

Connection Pool → Request Parser → Batch Processor → Response Serializer

Processing Layer

Graph algorithms and data operations optimized for cache performance and inline execution.

Query Engine → DOD Algorithms → Inline Functions → Vectorized Operations

Storage Layer

Write-ahead logging with static memory pools and crash-safe batch commits.

Memory Pools → WAL Buffer → Atomic Commits → Disk Persistence

Data-Oriented Data Structures

Node Storage (Structure-of-Arrays)

// Traditional Object-Oriented (AoS - Array of Structures)
struct Node {
    id: u64,
    type: u32,
    data: []u8,
    edges: []u64,
}
nodes: []Node

// NenDB Data-Oriented (SoA - Structure of Arrays)
struct NodeStorage {
    ids: []u64,        // All node IDs together
    types: []u32,      // All node types together  
    data: [][]u8,      // All node data together
    edges: [][]u64,    // All edge lists together
}

Benefits: Better cache locality, vectorization opportunities, and memory bandwidth utilization when processing multiple nodes.

Batch Operation Queue

struct BatchQueue {
    operation_types: []OpType,    // CREATE, UPDATE, DELETE, QUERY
    node_ids: []u64,             // Target node IDs
    payloads: [][]u8,            // Operation payloads
    batch_size: usize,           // Current batch size
    capacity: usize,             // Maximum batch capacity
}

Benefits: Process multiple operations simultaneously, reduce system call overhead, and optimize memory access patterns.

Memory Management Strategy

Static Allocation Phase

1
Pre-allocate all memory pools at startup
2
Initialize data structures with maximum capacity
3
Setup connection and buffer pools
4
Initialize WAL and recovery structures

Runtime Constraints

Zero Dynamic Allocation

No malloc/free calls during operation - all memory managed through pre-allocated pools

Predictable Performance

Eliminates allocation pauses, fragmentation, and unpredictable memory overhead

Performance Characteristics

100K+
Operations/Second

Batch processing with DOD data structures

<1ms
Query Latency

Cache-optimized data access patterns

95%+
Cache Hit Ratio

Structure-of-arrays memory layout

Key Implementation Details

Inline Functions

Extensive use of inline functions to enable compiler optimizations and eliminate function call overhead in hot paths.

inline fn processNodeBatch(nodes: []Node, operation: Operation) void

Zig 0.15.1 Optimizations

Leverages Zig's compile-time features and new I/O interfaces for zero-overhead abstractions.

  • • Compile-time memory layout optimization
  • • Zero-cost error handling
  • • Vectorization hints and SIMD instructions

Was this page helpful?