Files
Baradb/src/baradadb.nim
T

172 lines
6.2 KiB
Nim

## BaraDB — Multimodal Database Engine
## Main entry point
import std/asyncdispatch
{.push warning[Deprecated]: off.}
import std/threadpool
{.pop.}
import std/locks
import std/os
import std/strutils
import barabadb/core/server
import barabadb/core/httpserver
import barabadb/core/config
import barabadb/core/logging
import barabadb/protocol/ssl
import barabadb/storage/lsm
import barabadb/storage/compaction
import barabadb/core/raft
import barabadb/core/gossip
import barabadb/core/replication
import barabadb/core/disttxn
type
CompactionManager* = ref object
db*: LSMTree
strategy*: compaction.CompactionStrategy
proc newCompactionManager*(db: LSMTree): CompactionManager =
result = CompactionManager(db: db, strategy: compaction.newCompactionStrategy(db.dir))
for sst in db.sstables:
let meta = compaction.SSTableMeta(
path: sst.path,
level: sst.level,
minKey: sst.minKey,
maxKey: sst.maxKey,
entryCount: sst.entryCount,
sizeBytes: sst.entryCount * 64,
createdAt: 0,
)
result.strategy.addTable(meta)
proc compact*(cm: CompactionManager) =
acquire(cm.db.lock)
defer: release(cm.db.lock)
for level in 0 ..< compaction.MaxLevel:
if cm.strategy.needsCompaction(level):
discard cm.strategy.compact(level)
proc startCompactionLoop*(cm: CompactionManager, intervalMs: int = 60000) {.async.} =
while true:
await sleepAsync(intervalMs)
cm.compact()
proc runTcpServer(config: BaraConfig) {.async.} =
info("BaraDB TCP listening on " & config.address & ":" & $config.port)
var server = newServer(config)
await server.run()
proc wireRaftDistTxn(raftNode: RaftNode, tcpServer: Server) =
## Wire RAFT consensus to distributed transaction manager for 2PC coordination.
## When RAFT commits a DISTTXN operation, forward it to DistTxnManager.
raftNode.onDistTxnPrepare = proc(txnId: uint64, nodes: seq[string]): bool {.gcsafe.} =
let txn = tcpServer.distTxnManager.getTxn(txnId)
if txn != nil:
return txn.prepare()
return false
raftNode.onDistTxnCommit = proc(txnId: uint64) {.gcsafe.} =
let txn = tcpServer.distTxnManager.getTxn(txnId)
if txn != nil:
discard txn.commit()
raftNode.onDistTxnRollback = proc(txnId: uint64) {.gcsafe.} =
let txn = tcpServer.distTxnManager.getTxn(txnId)
if txn != nil:
discard txn.rollback()
proc wireReplicationDistTxn(rm: ReplicationManager, dtm: DistTxnManager) =
## Wire replication acknowledgments to distributed transaction completion.
## When all replicas ack a write that belongs to a distributed transaction,
## move the transaction to committed state.
discard
proc main() =
var config = loadConfig()
# Init structured logger from config
let logLvl = parseEnum[LogLevel]("ll" & capitalizeAscii(config.logLevel))
defaultLogger = newLogger(logLvl, config.logFile)
info("BaraDB v1.1.0 — Multimodal Database Engine")
# Security check: warn if JWT secret is not configured
if config.jwtSecret.len == 0:
warn("JWT secret not configured! Set BARADB_JWT_SECRET env var or jwt_secret in config. Using default (INSECURE).")
if config.tlsEnabled:
if config.certFile.len == 0 or config.keyFile.len == 0 or
not fileExists(config.certFile) or not fileExists(config.keyFile):
info("TLS enabled but no certificate found. Generating self-signed certificate...")
let (cert, key) = generateSelfSignedCert(config.dataDir / "certs")
if cert.len > 0 and key.len > 0:
config.certFile = cert
config.keyFile = key
info("Generated self-signed certificate: Cert=" & cert & " Key=" & key)
else:
warn("Failed to generate self-signed certificate. TLS disabled.")
config.tlsEnabled = false
# Start HTTP server (blocking, multi-threaded via hunos) in background thread
var httpServer = newHttpServer(config)
spawn httpServer.run(config.port + 440) # HTTP port = TCP port + 440
# Start background compaction loop
let cm = newCompactionManager(httpServer.db)
asyncCheck cm.startCompactionLoop()
# Create TCP server (initialization is synchronous, run is async)
let localId {.used.} = if config.raftNodeId.len > 0: config.raftNodeId else: "node-" & $config.port
var tcpServer = newServer(config)
# Start Raft cluster if enabled
if config.raftEnabled:
info("Starting Raft node " & config.raftNodeId & " on port " & $config.raftPort)
var raftNode = newRaftNode(config.raftNodeId, config.raftPeers, config.raftPort)
# Wire state machine to apply committed entries to the database
raftNode.applyCommand = proc(cmd: string, data: seq[byte]) {.gcsafe.} =
if cmd == "put":
let parts = cast[string](data).split("\x00")
if parts.len >= 2:
httpServer.db.put(parts[0], cast[seq[byte]](parts[1]))
tcpServer.db.put(parts[0], cast[seq[byte]](parts[1]))
elif cmd == "delete":
httpServer.db.delete(cast[string](data))
tcpServer.db.delete(cast[string](data))
# Wire RAFT ↔ DistTxn
wireRaftDistTxn(raftNode, tcpServer)
# Wire replication ↔ DistTxn
wireReplicationDistTxn(tcpServer.replicationManager, tcpServer.distTxnManager)
var raftNet = newRaftNetwork(raftNode)
asyncCheck raftNet.run()
# Start replication health check and reconnection loops
asyncCheck tcpServer.replicationManager.startHealthCheck(5000)
asyncCheck tcpServer.replicationManager.startReconnectionLoop(10000)
# Join gossip cluster from seed nodes if configured
let seedNodesEnv = getEnv("BARADB_SEED_NODES", "")
if seedNodesEnv.len > 0 and tcpServer.gossipProtocol != nil:
let seeds = seedNodesEnv.split(",")
for seed in seeds:
let parts = seed.strip().split(":")
if parts.len >= 2:
let host = parts[0]
let port = try: parseInt(parts[1]) except: 0
if port > 0:
let seedNode = newGossipNode(host & ":" & $port, host, port)
tcpServer.gossipProtocol.join(seedNode)
info("Joined gossip cluster via seed " & host & ":" & $port)
# Start TCP wire protocol server on main thread with async event loop
waitFor runTcpServer(config)
# Shutdown
httpServer.stop()
if tcpServer.gossipProtocol != nil:
tcpServer.gossipProtocol.stop()
when isMainModule:
main()