Skip to main content

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

  • Use the aql tool
  • Use the asadm tool
  • Use any of the Aerospike Clients

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.

note

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)