Skip to content
Rose Heart edited this page Apr 20, 2026 · 35 revisions

JackrabbitDLM: High-Performance Lightweight Distributed Lock Manager

Introduction

JackrabbitDLM is a Distributed Lock Manager (DLM) designed to manage locks and temporary data storage in a networked environment. It operates as a daemon, listening on a specified port for incoming requests in JSON format. These requests can include actions such as locking, unlocking, retrieving, storing, and erasing memory references. The system ensures that lock ownership is maintained by associating each lock with a unique ID, preventing unauthorized access. If a lock expires or is explicitly released, it becomes available for reassignment. The program logs all actions for auditing and debugging purposes. By leveraging a non-blocking socket interface, JackrabbitDLM efficiently handles multiple simultaneous connections, making it suitable for distributed applications requiring concurrency control and temporary state management.

Distributed Lock Manager (DLM) Comparative Analysis

Feature / Requirement Jackrabbit DLM File Locks & Temp Files Database Row Locking Redis (with Redlock) Clustered Platforms (etcd, ZK, Consul)
Primary Design Purpose-built for Locks & Leases Local filesystem hack General data storage In-memory data store Distributed consensus / Service mesh
Deployment Model Multi-machine (Non-clustered) Local only (Single host) Centralized DB Centralized or Clustered Heavily Clustered (Quorum required)
Expiration (TTL) Mandatory on every operation None (Manual cleanup only) Manual (Requires cleanup jobs) Optional (App-discipline dependent) Optional (Lease-based but complex)
Data Privacy Encoded transport & filenames Plain text (Easily readable) Plain text (Unless encrypted) Plain text (By default) Plain text (By default)
State Handling Locks + Temporary Shared Data Files only (No logic) Rows (Schema dependent) Keys and Values Hierarchical nodes or KV pairs
Self-Healing Automatic (Design-enforced) No (Orphaned locks stay) No (Stale claims stay) Conditional (If TTL is set) Yes (Session/Lease based)
Throughput (TPS) High (5,000+ per second) Very Low Low to Moderate Very High Moderate to High
Operational Effort Minimal (Single service) None (Until it breaks) Moderate (DB maintenance) Moderate (Instance management) Very High (Cluster maintenance)
Scale Target Dozens of hosts / 1,000s of processes Single machine only Centralized apps General purpose scaling Global/Enterprise infrastructure
Data Integrity Owner-only updates & erasures Weak (Anyone can delete) Strong (Transaction based) App-level management Strong (Consensus based)
Memory Management Automatic Memory + Disk spill Manual DB-managed RAM-heavy RAM-heavy

Why choose Jackrabbit DLM? (The Practical Advantage)

1. Real Distributed Power without the "Cluster Tax"

Most software that works across multiple machines requires you to set up a "cluster" with complex election logic (Raft or Paxos). Jackrabbit DLM gives you the ability to coordinate 20 machines or 5,000 processes through a single high-speed service. It fills the gap between "local hacks" and "enterprise overkill."

2. Self-Healing is Not an Option, It is the Law

In Redis or a Database, if a developer forgets to set a timeout, a lock can stay stuck forever, crashing your workflow. In Jackrabbit DLM, TTL is mandatory. Every lock and every piece of data has a built-in "death date." If a worker crashes, the system heals itself automatically because the lock simply expires.

3. Purpose-Built IPC (Inter-Process Communication)

Unlike a standard message queue, Jackrabbit DLM allows one process to "own" a resource while others check its status. You can store a small status string (like "Processing Step 2") directly with the lock. This combines communication and coordination into one simple tool.

4. Extreme Efficiency for High-Volume Work

Handling 5,000 transactions per second means Jackrabbit DLM can sit at the center of a busy trading system, an automation farm, or a large-scale job processor without becoming a bottleneck. It delivers this speed with a much smaller memory footprint than a full database or a clustered coordination platform.

Summary for Decision Makers

  • Use Jackrabbit DLM if you need a fast, self-healing, multi-machine coordinator that handles locks and temporary state without the massive operational headache of a clustered platform.

Features

  • Distributed Lock Management: Ensures resource locking across multiple clients.
  • Temporary Data Storage: Supports storing and retrieving data with expiration control.
  • Concurrency Control: Handles multiple simultaneous requests using non-blocking sockets.
  • Security and Ownership Control: Prevents unauthorized access to locked resources.

This all-in-one table provides a complete look at where Jackrabbit DLM sits in the software market. It is designed to help a developer or system architect understand the real-world trade-offs between simple hacks, general-purpose tools, and heavyweight infrastructure.

How It Works

  1. Listening for Requests: The daemon listens on a specified port for incoming JSON-formatted requests.
  2. Processing Payloads: Each request contains an action (Lock, Unlock, Get, Put, Erase) and relevant parameters such as ID, FileName, and Expire.
  3. Lock Management:
    • New locks are assigned to the requesting ID.
    • Expired locks are reset and reassigned.
    • Unauthorized unlock or modification attempts are denied.
  4. Data Storage:
    • Put stores data with an expiration time.
    • Get retrieves stored data if the requesting ID owns it.
    • Erase removes stored data upon owner request.
  5. Non-blocking Operation: The system handles multiple connections simultaneously without blocking, improving efficiency in distributed environments.

JSON Request Examples

  • Lock a Resource:
    { "ID":"DEADBEEF", "FileName":"testData", "Action":"Lock", "Expire":"300" }
  • Unlock a Resource:
    { "ID":"DEADBEEF", "FileName":"testData", "Action":"Unlock" }
  • Store Data:
    { "ID":"DEADBEEF", "FileName":"testData", "Action":"Put", "Expire":"300", "DataStore":"Blah" }
  • Retrieve Data:
    { "ID":"DEADBEEF", "FileName":"testData", "Action":"Get" }
  • Erase Data:
    { "ID":"DEADBEEF", "FileName":"testData", "Action":"Erase" }

Usage

To start the JackrabbitDLM service, run the script with an optional host and port:

./JackrabbitDLM [host] [port]

By default, it binds to all interfaces (0.0.0.0) and listens on port 37373.

Supporting Library

The Locker class in JackrabbitDLM provides a robust framework for managing distributed file locks over a network. It allows clients to acquire, check, and release locks on shared resources using a JSON-based protocol. The class generates unique IDs for each client, ensuring secure lock ownership. The Talker method facilitates communication with the locking server, while the Retry and RetryData functions handle request retries for reliability. The class supports fundamental operations such as Lock and Unlock, along with data management functions like Put, Get, and Erase, allowing users to store and retrieve data associated with locked resources. The implementation prioritizes efficiency through retry logic and configurable timeout settings, ensuring smooth operation in networked environments.

Load Testing/Chart Statistics

This chart is generated from the hourly statistics in JackrabbitDLM.log. Each line in the log produces the data points you see here, plotted logarithmically to show the full range of activity. The statistics reference table below defines every field.

Jackrabbit DLM Statistics

Testing and Example

JackrabbitDLM can be stress-tested using a simulation known as a Lock War, which demonstrates the library’s ability to handle extreme contention scenarios. This test aggressively competes for access to a shared resource, simulating worst-case conditions where multiple processes, referred to as fighters, initiate simultaneous lock, read, and write operations. The number of fighters is specified at runtime, allowing for controlled scalability of the test. Each fighter operates in either Retry Mode (internal to the Locker class), where lock attempts are retried until successful, or Hyper-Aggressive Mode, where a single lock attempt is made without retries.

The simulation launches multiple Locker instances—one per fighter—where each process attempts to acquire a lock on a shared resource. If successful, the process retrieves stored data from memory, increments a counter if data exists, and writes the updated value back 25% of the time. If no data is found, it initializes the memory store. This repeated cycle of lock acquisition, reading, and writing places the DLM under significant load, simulating real-world contention where multiple clients compete for limited resources.

A shell script orchestrates the execution of multiple fighters, each running independently to maximize stress on the DLM. The number of fighters and the mode of operation are passed as parameters, allowing for dynamic test configurations. Performance metrics are collected, including the number of successful and failed lock attempts, read and write operations, and the contention rate—the percentage of failed attempts over total lock requests. The program logs these results along with execution time and process ID, providing valuable insights into the DLM’s efficiency and stability under high-demand conditions. This simulation serves as both a usage demonstration and a testbed for evaluating JackrabbitDLM’s ability to handle concurrent operations at scale.

Security and Access Control

Security always starts with the firewall. It is the first and foremost part of every discussion. Jackrabbit DLM is not a security program; it is a lock manager and a key-value store. It offers lightweight examples of what can be done to ensure plain text is never seen over a network, but it is not designed to be infallible. It is designed with the real-world considerations of security in mind.

In academia, the higher the security, the better. In the real world, that has consequences and costs. Real-world framing is different. Security is the amount of effort and cost of the programmer versus the actual value of the data versus the actual effort an attacker needs to put in to steal it.

While it may seem counterproductive, the end result is very simple. The more layers of security you add to something, the more expensive and slower it becomes. Real security at the business level is about finding the balance between those three metrics.

Nothing is ever unbreakable. In a real business world, that single thought drives practical security measures. Everything is breakable; it is just a matter of how much effort is required versus what the data is worth. That is the whole point of security. From the standpoint of a programmer, my job is to take as little effort as possible, lowering the cost to the business paying me, to provide as much value as possible to protect the data.

Lock managers often keep locks anywhere from a few milliseconds to a few minutes. Having military-grade encryption that would take several seconds to process that kind of lock is extremely problematic in a vast number of situations.

The data store is the most at risk, and this program already has mechanisms where the end user can compress, encrypt, or reshape their data in any way they imagine before it is transmitted to the DLM. From the standpoint of Jackrabbit DLM, it has no idea what that data is or how to access it, creating a zero-trust environment.

It is not security, at least not in an academic context, but it is security in the context of whether or not an attacker is going to spend the effort (money, equipment costs, risk of jail time) to go through the practice of trying to get in the middle or hack this type of system.

Anybody running this software can easily change the alphabet or the decoder. That is the point. I am not trying to defend a military base; I am simply adding enough of a headache that the value of the data simply isn't worth the attack.

You can, with minimal effort, add any level of encryption or obfuscation to your own system. I encourage it simply because you become one less vulnerable system on the planet. The easiest way is simply changing the alphabet. Even if you swap letters or put it in reverse, two systems become different instantly. The best security isn't always the most expensive.

Operational Statistics and Logging

Here is an example of hourly statistics logged by Jackrabbit DLM and the meaning of each item:

Statistic Definition
AData Counts the number of active data records currently stored in memory.
AIn Captures the number of file descriptors reported as ready for inbound activity during a select cycle. This is a snapshot of current inbound socket activity, not a total hourly count.
ALock Counts the number of active lock-only records currently being tracked in memory.
AOut Captures the number of file descriptors reported as ready for outbound activity during a select cycle. This is a snapshot of current outbound socket activity, not a total hourly count.
BadAction Counts requests where the Action value is not recognized as a supported command.
BadPayload Counts malformed or incomplete requests, including invalid JSON, missing required fields, or a Put request missing DataStore.
Corruption Counts erase requests against entries that exist but do not contain a valid DataStore field, indicating a corrupted data record.
DataIn Tracks the total volume of data received through Put requests, measured as the length of the DataStore string.
DataOut Tracks the total volume of data returned through successful Get requests, measured as the length of the DataStore string.
DataOverrun Counts requests dropped because the accumulated payload exceeded the configured maximum payload size.
EraseNF Counts erase requests for entries that were not found.
Erased Tracks data items erased using the Erase action. In code, erase sets the entry expiration to 0, clears the stored data, and removes it during cleanup.
Expired Counts cases where a Lock request found an existing lock entry that had already expired and immediately reassigned it to the new requester.
ExpiredData Counts data records removed during cleanup because their expiration time was reached.
ExpiredLock Counts lock-only records removed during cleanup because their expiration time was reached.
ForcedGC Counts forced garbage collection events triggered after enough deleted data accumulated in memory.
Get Counts successful Get requests that returned a stored DataStore value.
GetNF Counts Get requests that could not return data because the item was missing or because no DataStore was present for that entry.
Idle Counts socket read exception events where the service performs garbage collection and then sleeps briefly.
In Counts total inbound socket events processed by the main loop. This includes new connections and readable client sockets.
Lock Counts successful new lock acquisitions, including locks created for new entries and locks acquired after an expired lock was reclaimed.
NotOwner Counts failed requests where the caller attempted to access, modify, unlock, or erase an entry owned by a different ID.
Out Counts total outbound socket events processed by the main loop.
PutNew Counts new data records created by Put requests.
PutUpdate Counts updates to existing data records by the current owner through Put requests.
Relock Counts cases where the current lock owner renews or extends an existing lock by issuing another Lock request with the same ID.
Unlock Counts successful unlock requests by the current lock owner for an active lock entry.
UnlockNF Counts unlock requests for entries that were not found.
2025-02-19 18:13:14.843674 Jackrabbit DLM 0.0.0.0.125
2025-02-19 18:13:15.377045 AIn: 1, In: 1
2025-02-19 19:00:00.005473 AData: 3, AIn: 1, ALock: 2, AOut: 1, ExpiredData: 177257, Get: 3356, GetNF: 7451, In: 1415544, Lock: 112582, NotOwner: 26441, Out: 951660, PutNew: 177260, PutUpdate: 15706, Unlock: 129052
2025-02-19 20:00:00.000622 AData: 1, AIn: 1, ALock: 3, AOut: 1, ExpiredData: 227614, Get: 4069, GetNF: 9606, In: 1814901, Lock: 144513, NotOwner: 33928, Out: 1216444, PutNew: 227612, PutUpdate: 20001, Unlock: 165238
2025-02-19 21:00:00.007723 AData: 2, AIn: 1, ALock: 4, AOut: 1, ExpiredData: 227645, Get: 4210, GetNF: 9572, In: 1816164, Lock: 144134, NotOwner: 34793, Out: 1217352, PutNew: 227646, PutUpdate: 20035, Unlock: 164998
2025-02-19 22:00:00.005556 AData: 3, AIn: 1, ALock: 4, AOut: 1, ExpiredData: 226971, Get: 4661, GetNF: 9395, In: 1793838, Lock: 141779, NotOwner: 33407, Out: 1202452, PutNew: 226972, PutUpdate: 19582, Unlock: 162150
2025-02-19 23:00:00.006504 AData: 5, AIn: 1, ALock: 3, AOut: 1, ExpiredData: 226609, Get: 4698, GetNF: 9373, In: 1790157, Lock: 141624, NotOwner: 32745, Out: 1199948, PutNew: 226611, PutUpdate: 19602, Unlock: 162066
2025-02-20 00:00:00.013259 AData: 3, AIn: 1, ALock: 2, AOut: 1, ExpiredData: 228630, Get: 4635, GetNF: 9405, In: 1808331, Lock: 142188, NotOwner: 35525, Out: 1212417, PutNew: 228628, PutUpdate: 19683, Unlock: 162713
2025-02-20 01:00:00.001020 AData: 5, AIn: 1, ALock: 2, AOut: 1, Expired: 1, ExpiredData: 221693, Get: 4482, GetNF: 9166, In: 1755004, Lock: 138674, NotOwner: 33659, Out: 1193232, PutNew: 221695, PutUpdate: 18985, Unlock: 158340
2025-02-20 02:00:00.009703 AData: 1, AIn: 1, ALock: 3, AOut: 1, ExpiredData: 228605, Get: 4558, GetNF: 9469, In: 1811942, Lock: 143018, NotOwner: 35071, Out: 1214290, PutNew: 228601, PutUpdate: 19744, Unlock: 163519
2025-02-20 03:00:00.000361 AData: 1, AIn: 1, ALock: 3, AOut: 1, ExpiredData: 228017, Get: 4124, GetNF: 9649, In: 1826142, Lock: 145191, NotOwner: 35542, Out: 1224477, PutNew: 228017, PutUpdate: 20117, Unlock: 166074
2025-02-20 04:00:00.008355 AData: 5, AIn: 1, ALock: 2, AOut: 1, ExpiredData: 228289, Get: 4071, GetNF: 9684, In: 1834488, Lock: 145704, NotOwner: 36643, Out: 1230020, PutNew: 228293, PutUpdate: 20280, Unlock: 166821
2025-02-20 05:00:00.003663 AData: 2, AIn: 1, ALock: 1, AOut: 1, ExpiredData: 229322, Get: 4198, GetNF: 9729, In: 1846296, Lock: 146329, NotOwner: 38026, Out: 1237957, PutNew: 229319, PutUpdate: 20346, Unlock: 167485
2025-02-20 06:00:00.000182 AData: 2, AIn: 2, ALock: 2, AOut: 1, ExpiredData: 230508, Get: 4262, GetNF: 9792, In: 1864893, Lock: 147479, NotOwner: 40199, Out: 1250580, PutNew: 230508, PutUpdate: 20535, Unlock: 168856
2025-02-20 07:00:00.000864 AData: 2, AIn: 1, ALock: 3, AOut: 1, ExpiredData: 231394, Get: 4288, GetNF: 9839, In: 1869909, Lock: 147780, NotOwner: 40557, Out: 1253762, PutNew: 231394, PutUpdate: 20479, Unlock: 168966
2025-02-20 08:00:00.000478 AData: 4, AIn: 2, ALock: 2, AOut: 1, ExpiredData: 231493, Get: 4371, GetNF: 9829, In: 1870059, Lock: 147593, NotOwner: 40836, Out: 1253882, PutNew: 231495, PutUpdate: 20450, Unlock: 168779
2025-02-20 09:00:00.005268 AData: 4, AIn: 1, ALock: 4, AOut: 1, ExpiredData: 232102, Get: 4349, GetNF: 9865, In: 1878864, Lock: 148419, NotOwner: 41181, Out: 1259796, PutNew: 232102, PutUpdate: 20577, Unlock: 169795
2025-02-20 10:00:00.005994 AData: 2, AIn: 1, ALock: 3, AOut: 1, Expired: 1, ExpiredData: 232037, Get: 4336, GetNF: 9877, In: 1877640, Lock: 148275, NotOwner: 41254, Out: 1259119, PutNew: 232035, PutUpdate: 20546, Unlock: 169557
2025-02-20 11:00:00.000360 AData: 5, AIn: 1, ALock: 4, AOut: 1, Expired: 1, ExpiredData: 231858, Get: 4321, GetNF: 9880, In: 1875977, Lock: 148141, NotOwner: 41243, Out: 1257708, PutNew: 231861, PutUpdate: 20518, Unlock: 169361
2025-02-20 12:00:00.000537 AData: 5, AIn: 1, ALock: 5, AOut: 1, ExpiredData: 232031, Get: 4288, GetNF: 9889, In: 1880423, Lock: 148571, NotOwner: 41461, Out: 1261121, PutNew: 232031, PutUpdate: 20623, Unlock: 169945
2025-02-20 13:00:00.000669 AData: 3, AIn: 2, ALock: 2, AOut: 1, ExpiredData: 231186, Get: 4286, GetNF: 9830, In: 1870289, Lock: 147772, NotOwner: 40896, Out: 1253897, PutNew: 231184, PutUpdate: 20476, Unlock: 168985
2025-02-20 14:00:00.004089 AData: 5, AIn: 1, ALock: 3, AOut: 1, ExpiredData: 229892, Get: 4067, GetNF: 9763, In: 1855035, Lock: 146815, NotOwner: 39594, Out: 1243690, PutNew: 229894, PutUpdate: 20324, Unlock: 167888