Changelog¶
Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
v1.10.0 - 2026-02-24¶
Changed¶
- Server: 64-shard lock manager — replaced single
sync.Mutexwith 64fnv32-keyed shards and a separateconnMufor connection tracking, reducing contention under concurrent load - Server: buffered CSPRNG token generation — token generation now buffers 4096 bytes (256 tokens) per
crypto/randsyscall, amortising syscall overhead by 256× - Server: pre-formatted protocol responses — common response status lines (
ok,timeout,error_*,queued) are pre-computed[]byteconstants; dynamic responses usestrconv.AppendIntinstead offmt.Sprintf - Server: O(1) waiter queue grant — replaced O(n)
copyon every waiter grant with aWaiterHeadindex; the slice is compacted when more than half is consumed - Server: deferred waiter allocation —
Acquireno longer allocates a waiter struct on the fast path when capacity is immediately available - Benchmark: persistent connections —
cmd/benchnow usesclient.Dialonce per worker goroutine and calls the low-levelAcquire/ReleaseAPI, measuring lock latency instead of TCP connection overhead - Benchmark:
--connectionsflag — optional flag to control the number of persistent connections per worker (default: 1)
v1.9.0 - 2026-02-24¶
Added¶
cmd/bench— Go benchmark tool for measuring lock acquire/release latency and throughput under concurrent load- Configurable workers, rounds, key prefix, acquire timeout, lease TTL, and server addresses
- Reports total ops, wall time, throughput (ops/s), mean, min, max, p50, p99, and stdev latencies
v1.8.1 - 2026-02-24¶
Fixed¶
- Client: data races in
LockandSemaphoretypes — multiple fields (conn,token,lease,cancelRenew) were accessed without holding the mutex inAcquire,Enqueue,Wait,Release, andClosemethods - Client:
Lock.WaitandSemaphore.Waitconnection leak on timeout — the connection was left open in an ambiguous state after a Wait timeout (enqueue state consumed, no lock held); now properly closed - Client:
Lock.WaitandSemaphore.Waitconnection leak on non-timeout errors — connections were not closed on server errors, only on context cancellation - Client:
EnqueueandSemEnqueuemissingerror_max_waitershandling — theerror_max_waitersserver response was not parsed, causing a genericErrServerinstead ofErrMaxWaiters - Client:
ErrMaxWaiterssentinel error added — new sentinel for theerror_max_waitersprotocol status, consistent withErrMaxLocksandErrLimitMismatch - Client:
startRenewgoroutine leak — old renewal goroutines were cancelled but not waited on before starting new ones, risking concurrent renewals; now callsstopRenew()which waits for the old goroutine to exit - Client:
readLineoff-by-one buffer overflow — buffer was[maxResponseBytes + 1]bytebut the overflow check used>instead of>=, allowing one extra byte to be written past the intended limit - Server: protocol error recovery disconnect — read-level errors (timeout, line too long) now disconnect the client since the protocol stream may be desynchronized; parse-level errors continue safely
- Server:
handleConnauth error could ignoreReadRequesterror — when the auth read returned an error, the nilreqwas still accessed forreq.Cmd; now returnserror_authon any read failure during auth - Server: concurrent map access in
connOwnedtracking — lock ownership tracking was not consistently protected by the mutex in all code paths - Config:
GCMaxIdleTimevalidation — negative values for--gc-max-idlewere silently accepted; now0is explicitly allowed (meaning "prune immediately") while the env var override is correctly applied - Config:
WriteTimeoutof 0 handling — a zero write timeout no longer sets an immediate deadline on writes; it correctly disables write deadlines
Added¶
--auth-token-fileflag andDFLOCKD_AUTH_TOKEN_FILEenv var for loading the auth token from a file instead of passing it on the command line (avoids leaking the secret in the process list)
Documentation¶
- Added
ErrMaxWaitersto the client error table - Added
--auth-token-fileandDFLOCKD_AUTH_TOKEN_FILEto README, server docs, and configuration tables - Documented auth token resolution priority order
v1.8.0 - 2026-02-24¶
Added¶
- Graceful shutdown drain with configurable timeout: active connections are given time to finish before being force-closed
--shutdown-timeoutflag andDFLOCKD_SHUTDOWN_TIMEOUT_Senv var (default: 30 seconds, 0 = wait forever)- Connection tracking via
sync.Mapto enable force-close on shutdown deadline - Integration tests for graceful shutdown drain and force-close scenarios
Fixed¶
- Indentation bug in protocol error write block (
server.go:202-204)
Changed¶
- Extracted shared accept-loop and shutdown logic into private
serve()method, eliminating duplication betweenRunandRunOnListener
v1.7.0 - 2026-02-24¶
Added¶
--max-connectionsflag andDFLOCKD_MAX_CONNECTIONSenv var to limit concurrent connections (default: 0 = unlimited)--max-waitersflag andDFLOCKD_MAX_WAITERSenv var to limit waiter queue depth per lock/semaphore key (default: 0 = unlimited)ErrMaxWaiterssentinel error anderror_max_waitersprotocol status for rejected waiters--write-timeoutflag andDFLOCKD_WRITE_TIMEOUT_Senv var to set write deadlines on responses (default: 5 seconds)writeResponseserver helper that sets and clearsSetWriteDeadlineon every write- Unit tests for max waiters across all four enqueue paths (FIFOAcquire, FIFOEnqueue, SemAcquire, SemEnqueue)
- Integration tests for max connections, max waiters, and write timeout
Changed¶
- Default bind address changed from
0.0.0.0to127.0.0.1for safer defaults
v1.6.0 - 2026-02-18¶
Added¶
- Optional token-based authentication for client connections
- Server flag
--auth-tokenand env varDFLOCKD_AUTH_TOKENto set a shared secret authprotocol command for clients to authenticate before issuing other commandsAuthenticateclient function for low-level auth on a*ConnAuthTokenfield onLockandSemaphorehigh-level types for automatic auth on connectErrAuthsentinel error returned when authentication fails- Constant-time token comparison using
crypto/subtleto prevent timing attacks - Auth integration tests for both server and client packages
- Documentation for auth in protocol spec, server docs, client docs, and examples
v1.4.0 - 2026-02-18¶
Added¶
- Runtime
statsprotocol command returning a JSON snapshot of active connections, held locks, semaphores, and idle entries awaiting GC Stats()method onLockManagerfor programmatic access to server state- Documentation for
statscommand in protocol spec, server docs, and examples
v1.3.0 - 2026-02-18¶
Added¶
- Optional TLS encryption for client-server communication
- Server flags
--tls-cert/--tls-keyand env varsDFLOCKD_TLS_CERT/DFLOCKD_TLS_KEYto enable TLS DialTLSclient function for low-level TLS connectionsTLSConfigfield onLockandSemaphorehigh-level types- TLS integration tests for both server and client packages
internal/testutilpackage with ephemeral self-signed certificate helper for tests
v1.2.0 - 2026-02-16¶
Added¶
- Distributed key-based semaphore support allowing up to N concurrent holders per key
- Five new protocol commands:
sl(acquire),sr(release),sn(renew),se(enqueue),sw(wait) - Per-request
limitparameter; first acquirer sets the limit, subsequent requests must match or receiveerror_limit_mismatch ErrLimitMismatchsentinel error anderror_limit_mismatchprotocol status- Protocol error code 13 for zero or negative semaphore limit
- Low-level client functions:
SemAcquire,SemRelease,SemRenew,SemEnqueue,SemWait - High-level
Semaphoretype withAcquire,Enqueue,Wait,Release,Close,Tokenand automatic background lease renewal - Semaphore lease expiry, GC pruning, and disconnect cleanup integrated into existing background loops
- Semaphore keys share the
--max-locksbudget with lock keys - Comprehensive test suite for semaphore functionality (62 new tests across all layers)
- Documentation for semaphore commands in protocol spec, client docs, server docs, and README
Fixed¶
CleanupConnectionearly return when a connection had no lock keys, which would skip cleanup of other connection state
v1.1.0 - 2026-02-16¶
Added¶
- Go client package (
client/) with low-level protocol API (Acquire,Release,Renew,Enqueue,Wait) and high-levelLocktype - Automatic background lease renewal in
Locktype with configurableRenewRatio - CRC32-based sharding (
CRC32Shard) matching the Python client'sstable_hash_shard - Functional options pattern (
WithLeaseTTL) for optional protocol parameters - Context cancellation support for
Lock.AcquireandLock.Wait - Integration test suite for the Go client (12 tests)
v1.0.0 - 2026-02-15¶
Added¶
- Complete server rewrite from Python to Go, delivering a single static binary with no runtime dependencies
- Standard Go project layout (
cmd/dflockd/,internal/config/,internal/lock/,internal/protocol/,internal/server/) - Comprehensive test suite (49 tests) covering lock operations, protocol parsing, and integration scenarios
--versionflag printing the embedded version string- Cross-platform binary builds via GoReleaser (linux/darwin/windows on amd64/arm64, tar.gz archives, zip for Windows, SHA256 checksums)
- Automated GitHub Releases workflow triggered on
v*tag push - Dependabot configuration for Go module updates
Changed¶
- CI and docs workflows updated for Go codebase
- Makefile simplified for Go build toolchain with
VERSIONldflags support
Removed¶
- Python server, async client, and sync client
- TypeScript client
- Python test suite, benchmark scripts, and example scripts
- Sharding module and documentation
- Built
site/artifacts
v0.5.0 - 2026-02-14¶
Added¶
- Two-phase lock acquisition with
e(enqueue) andw(wait) protocol commands fifo_enqueue()andfifo_wait()server functions for split enqueue/wait flowenqueue()andwait()module-level functions in async and sync clientsDistributedLock.enqueue()andDistributedLock.wait()methods in async and sync clientsStatus.acquiredandStatus.queuedserver response statusesNotEnqueuedErrorandEnqueuedStateserver internals for two-phase state tracking- Connection cleanup for two-phase enqueued state on disconnect
- Two-phase example script (
examples/two_phase_demo.py) - Documentation for two-phase flow in protocol, client, architecture, and examples docs
v0.4.1 - 2026-02-07¶
Added¶
--auto-release-on-disconnect/--no-auto-release-on-disconnectCLI flag
Fixed¶
DFLOCKD_DFLOCKD_READ_TIMEOUT_Senv var typo in README (nowDFLOCKD_READ_TIMEOUT_S)- Server configuration env var names in README missing
DFLOCKD_prefix MAX_LOCKSdefault in README corrected from256to1024
v0.4.0 - 2026-02-07¶
Added¶
- Documentation site (MkDocs Material) with architecture, configuration, client, protocol, and sharding guides
DFLOCKD_AUTO_RELEASE_ON_DISCONNECTdocumented in server configuration
Fixed¶
- Pyright CI dependency
- Ruff dev dependency
Changed¶
- Bump
actions/checkoutfrom 4 to 6 - Bump
actions/setup-pythonfrom 5 to 6 - Bump
actions/upload-pages-artifactfrom 3 to 4 - Bump
astral-sh/setup-uvfrom 4 to 7 - Update
uv-buildrequirement from >=0.9.28,<0.10.0 to >=0.9.28,<0.11.0
v0.3.0 - 2026-02-07¶
Added¶
- Async lock server with strict FIFO ordering per key
- Automatic lease expiry with configurable TTL and sweep interval
- Background garbage collection of idle lock state
- Automatic lock release on client disconnect
- Async client (
dflockd.client) withDistributedLockcontext manager - Sync client (
dflockd.sync_client) withDistributedLockcontext manager - Background lease renewal for both async and sync clients
- Multi-server sharding with
stable_hash_shard(CRC-32) - Custom sharding strategy support via
ShardingStrategycallable - Configurable
renew_ratiofor controlling renewal frequency - CLI with
--host,--port,--default-lease-ttl,--max-locks, and other flags - Environment variable configuration with
DFLOCKD_prefix (overrides CLI flags) - TypeScript client (
ts/) - Async and sync benchmark scripts (
examples/bench_async.py,examples/bench_sync.py) - CI workflow with linting, type checking, and tests (Python 3.13, 3.14)
- GitHub Pages documentation deployment workflow