Developing UDF Modules
Modules Written in Lua
A Lua module
is a collection of variables and functions contained in a single file. Modules can be imported and used by other Lua modules, including UDFs. A module name must not conflict with other Lua objects pre-registered by the Aerospike server. The following module names should be avoided:
- aerospike
- bytes
- geojson
- iterator
- list
- map
- record
- stream
Restrictions on Lua io and os libraries
Because of potential security vulnerabilities, the following restrictions on Lua libraries are enforced.
- Calling functions from the Lua
io
library is not allowed. - The only functions from the Lua
os
library that can be called are as follows:os.clock()
os.date()
os.difftime()
os.time()
Creating a Module
In the following example, we define a local table exports
in the file mymodule.lua. This module will be
populated with the functions to be exported.
local exports = {}
function exports.hello()
return "Hello "
end
function exports.world()
return "World!"
end
return exports
Registering a Module
Lua Modules must be registered with the Aerospike Server.
To install your modules, you may
To register the module using asadm:
Admin> enable
Admin+> manage udfs add mymodule.lua path path/to/mymodule.lua
Successfully added UDF mymodule.lua
Admin+>
Admin+> show udfs
~~~~~~~~~~UDF Modules (2021-01-23 02:00:18 UTC)~~~~~~~~~~~
Filename| Hash|Type
mymodule.lua|7fae110826972135a3c3b8a812d43243e7c7a23c|LUA
Number of rows: 1
To register the module using aql:
aql> register module 'mymodule.lua'
OK, 1 module added.
aql> show modules
+-----------------+--------------------------------------------+-------+
| filename | hash | type |
+-----------------+--------------------------------------------+-------+
| "mymodule.lua" | "4e4dfd2ac120e161f69d1dfbab14eec157d0eaaf" | "LUA" |
+-----------------+--------------------------------------------+-------+
Another module can now require
mymodule.lua into a local variable and use
it.
Example: A Hello World UDF
In a file example.lua
local mm = require('mymodule')
function helloworld(rec)
return mm.hello() .. mm.world()
end
In aql
aql> register module 'example.lua'
OK, 1 module added.
aql> show modules
+-----------------+--------------------------------------------+-------+
| filename | hash | type |
+-----------------+--------------------------------------------+-------+
| "example.lua" | "c42bf3f4a6f8f727efcfb884c97ee894764f1dc7" | "LUA" |
| "mymodule.lua" | "4e4dfd2ac120e161f69d1dfbab14eec157d0eaaf" | "LUA" |
+-----------------+--------------------------------------------+-------+
2 rows in set (0.002 secs)
aql> insert into test.foo (PK, x) values ('1', 24)
OK, 1 record affected.
aql> execute example.helloworld() on test.foo where PK='1'
+----------------+
| helloworld |
+----------------+
| "Hello World!" |
+----------------+
1 row in set (0.001 secs)
Using C functions in UDF Modules
Aerospike UDFs written in Lua can call C functions from shared objects. For more information read about the C API for Lua.
Make sure you compile the module to be loaded into Aerospike using the correct version of Lua.
Example: Compiling and Registering a Shared Object
In this example the file power.c contains sample C code:
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
static int go(lua_State * L) {
int rtrn = lua_tonumber(L, -1); /* Get the single number arg */
lua_pushnumber(L,rtrn*rtrn); /* square it and push the return */
return 1;
}
static const struct luaL_reg golib [] = {
{"go", go},
{NULL, NULL}
};
int luaopen_power(lua_State * L) {
luaL_openlib(L, "go", golib, 0);
return 1;
}
The Lua UDF module use.lua requires and calls the power.so shared object
function thepower(rec, basenum)
local power = require("power")
local rtn = power.go(basenum);
--info(rtn)
return rtn
end
Get the Lua Source
Download the Lua 5.1.4 library to allow for the necessary Lua code to be linked.
Compile
gcc -fPIC -o power.so -shared power.c -I /usr/include/
Register and Execute
In aql:
aql> register module 'power.so'
OK, 1 module added.
aql> register module 'use.lua'
OK, 1 module added.
aql> show modules
+-----------------+--------------------------------------------+-------+
| filename | hash | type |
+-----------------+--------------------------------------------+-------+
| "example.lua" | "c42bf3f4a6f8f727efcfb884c97ee894764f1dc7" | "LUA" |
| "power.so" | "99703e01482f065c62f0d0c55ba6b1f3214e3601" | "LUA" |
| "use.lua" | "5093704498b333e57d7dd033b529c4b4e0d99edb" | "LUA" |
| "mymodule.lua" | "4e4dfd2ac120e161f69d1dfbab14eec157d0eaaf" | "LUA" |
+-----------------+--------------------------------------------+-------+
4 rows in set (0.002 secs)
aql> execute use.thepower(4) on test.foo where PK='1'
+----------+
| thepower |
+----------+
| 16 |
+----------+
1 row in set (0.001 secs)