Module rcu
Read-Copy-Update (RCU) synchronized hash table.
This library provides a Lua-accessible hash table that uses RCU (Read-Copy-Update) for synchronization within the Linux kernel. RCU allows for very fast, lockless read operations, while write operations (updates and deletions) are synchronized to ensure data consistency. This makes it highly suitable for scenarios where read operations significantly outnumber write operations and high concurrency is required.
Keys in the RCU table must be strings. Values must be Lunatik objects
(i.e., userdata created by other Lunatik C modules like data.new()
,
lunatik.runtime()
, etc.) or nil
to delete an entry.
A practical example of its usage can be found in examples/shared.lua
,
which implements an in-memory key-value store.
Class rcu_table
rcu_table:__index (self, key) | Retrieves a value (a Lunatik object) from the RCU table. |
rcu_table:__newindex (self, key, value) | Sets or removes a value in the RCU table. |
rcu_table:map (self, callback) | Iterates over the RCU table and calls a callback for each key-value pair. |
rcu
table ([size=1024]) | Creates a new RCU-synchronized hash table. |
Class rcu_table
rcu.table()
. It behaves like a
standard Lua table for get (__index) and set (__newindex) operations
but uses RCU internally for synchronization.
Keys must be strings. Values stored must be Lunatik objects (e.g., created
via data.new()
, lunatik.runtime()
) or nil
(to remove an entry).
When a Lunatik object is retrieved, it's a new reference to that object.
Usage:
-- Assuming 'data' module is available for creating Lunatik objects -- and 'rcu' module is required. local rcu_store = rcu.table() local my_data = data.new(10) -- Create a Lunatik object my_data:setstring(0, "hello") -- Set a value rcu_store["my_key"] = my_data -- Get a value local retrieved_data = rcu_store["my_key"] if retrieved_data then print(retrieved_data:getstring(0)) -- Output: hello end -- Remove a value rcu_store["my_key"] = nil -- Iterate rcu_store:map(function(k, v_obj) print("Found key:", k, "Value object:", v_obj) end)
- rcu_table:__index (self, key)
-
Retrieves a value (a Lunatik object) from the RCU table.
This is the Lua __index metamethod, allowing table-like access
rcu_table[key]
. Read operations are RCU-protected and lockless.Parameters:
- self rcu_table The RCU table instance.
- key string The key to look up in the table.
Returns:
-
lunatik_object
The Lunatik object associated with the key, or
nil
if the key is not found. A new reference to the object is returned.Usage:
local my_object = my_rcu_table["some_key"] if my_object then -- Use my_object end
- rcu_table:__newindex (self, key, value)
-
Sets or removes a value in the RCU table.
This is the Lua __newindex metamethod, allowing table-like assignment
rcu_table[key] = value
. Write operations are synchronized.Parameters:
- self rcu_table The RCU table instance.
- key string The key to set or update.
- value
lunatik_object or nil
The Lunatik object to associate with the key.
If
nil
, the key-value pair is removed from the table.
Raises:
Error if memory allocation fails during new entry creation.Usage:
local data_obj = data.new(5) -- Assuming 'data' module my_rcu_table["new_key"] = some_lunatik_object my_rcu_table["another_key"] = nil -- Removes 'another_key'
- rcu_table:map (self, callback)
-
Iterates over the RCU table and calls a callback for each key-value pair.
The iteration is RCU-protected. The order of iteration is not guaranteed.
For each entry, a new reference to the value (Lunatik object) is obtained
before calling the callback and released after the callback returns.
Parameters:
- self rcu_table The RCU table instance.
- callback
function
A Lua function that will be called for each entry in the table. The callback receives two arguments:
key
(string): The key of the current entry.value
(lunatik_object): The Lunatik object associated with the key.
Returns:
-
nil
Raises:
Error if the callback function raises an error during its execution.Usage:
-- Example: Iterating and printing content if values are 'data' objects my_rcu_table:map(function(k, v_obj) -- v_obj is the Lunatik object stored for the key. -- If it's a 'data' object (a common use case, see examples/shared.lua): print("Key:", k, "Content from data object:", v_obj:getstring(0)) end)
rcu
- table ([size=1024])
-
Creates a new RCU-synchronized hash table.
Parameters:
- size
integer
Specifies the initial number of hash buckets (internal slots) for the table.
This is not a hard limit on the number of entries the table can store.
The provided
size
will be rounded up to the nearest power of two. Choosing an appropriatesize
involves a trade-off between memory usage and performance:- more buckets (larger
size
): Consumes more memory for the table structure itself, even if many buckets remain empty. However, it reduces the probability of hash collisions, which can significantly speed up operations (lookups, insertions, deletions), especially when storing a large number of entries. - fewer buckets (smaller
size
): Uses less memory for the table's internal array. However, if the number of entries is high relative to the number of buckets, it increases the chance of hash collisions. This means more entries might end up in the same bucket, forming longer linked lists that need to be traversed, thereby slowing down operations.
Guidance: For optimal performance, aim for a
size
that is roughly in the order of, or somewhat larger than, the maximum number of entries you anticipate storing. This helps maintain a low average number of entries per bucket (a low "load factor," ideally close to 1). The table can hold more entries than itssize
(number of buckets), but performance will degrade as the load factor increases. The default is a general-purpose starting point suitable for many common use cases. (default 1024) - more buckets (larger
Returns:
-
rcu_table
A new RCU table object, or raises an error if memory allocation fails.
Usage:
local my_rcu_table = rcu.table() -- Default: 1024 buckets, good for moderate entries. local small_table = rcu.table(128) -- 128 buckets, for fewer expected entries. local large_table = rcu.table(8192) -- 8192 buckets, for many expected entries.
- size
integer
Specifies the initial number of hash buckets (internal slots) for the table.
This is not a hard limit on the number of entries the table can store.
The provided