-
-
Notifications
You must be signed in to change notification settings - Fork 2
Home
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.
| 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 |
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."
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.
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.
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.
- 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.
- 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.
- Listening for Requests: The daemon listens on a specified port for incoming JSON-formatted requests.
- Processing Payloads: Each request contains an action (Lock, Unlock, Get, Put, Erase) and relevant parameters such as ID, FileName, and Expire.
-
Lock Management:
- New locks are assigned to the requesting ID.
- Expired locks are reset and reassigned.
- Unauthorized unlock or modification attempts are denied.
-
Data Storage:
-
Putstores data with an expiration time. -
Getretrieves stored data if the requesting ID owns it. -
Eraseremoves stored data upon owner request.
-
- Non-blocking Operation: The system handles multiple connections simultaneously without blocking, improving efficiency in distributed environments.
-
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" }
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.
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.
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.

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 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.
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: 167888If you would like to help support this project financially, please click on the heart shaped sponsor's button in the right column of this page.