Atomic Operations on List and Map Data Types - C, Java, and Go clients

go

#1

Hi,

Are there native ways to work with list and map data types (not LDTs) using the C, Java, and Go clients? If not, is this on the roadmap? I’m hoping to see similar atomic operations as are available for the LDT versions of these to avoid read-roundtrips on write.

Thanks, Alyssa NodePrime


#2

Hi Alyssa,

Aerospike has the ability to execute a Lua (UDF) function against a record. The UDF execution is atomic, and the record is locked, just as it is during a write. So, you can write a simply Lua function to manipulate Lists and Maps on the database directly.

We have plans to provide a suite of functions to provide features similar to your request, we just need to find the time to do it. We would love it if users such as yourself can help contribute libraries of functions for the larger community of Aerospike users to share and enjoy.

As an example, if you wanted to have a UDF that simply appends a value to a bin containing a list, you can create a file named lists.lua, containing:

local function create_or_update(rec)
    if aerospike:exists(rec) then
        return aerospike:update(rec)
    else
        return aerospike:create(rec)
    end
end

function append(rec, bin, value)
    local l = rec[bin]
    list.append(l, value)
    rec[bin] = l
    return create_or_update(rec)
end

All UDFs can be called from newer client libraries, without needing a special API for that library.


#3

Thx for the hints. I also think there is a need for such API, and I saw at least one another thread someone asked about this feature.

With your hints and some reading on the [UDF developer guide] (http://www.aerospike.com/docs/udf/udf_guide.html), I am able to develop a Lua UDF that meet my need. As an example for other people who may be interested, details are as follows:

  • map_ext.lua
function putAll(rec, bin, val)
    local m1 = rec[bin]
    if m1==nil  then m1 = map() end
    local m2 = val
    local m3 = map.merge( m1, m2, function(v1, v2)
        return v2
    end )
    rec[bin] = m3
    info("putAll() - m1: %s, m2: %s, m3: %s", tostring(m1), tostring(m2), tostring(m3))

    if aerospike:exists(rec) then aerospike:update(rec) else aerospike:create(rec) end
end
  • Register with AQL
  register module 'map_ext.lua'
  • Call in Java as
        client.execute(
                new WritePolicy(),
                new Key("MyNameSpace", "MySet", "MyRecordKey"),
                "map_ext", "putAll",
                Value.get("MyBinName"),
                Value.getAsMap(new HashMap() {{
                    put("A", 1);
                    put("B", 2);
                }}));
  • some hints:
    • read the developer guide, esp the best practice section. it mentioned about disable lua cache, and the registered lua script will show up at “/opt/aerospike/usr/udf/lua” by default. Using splitted windows to edit and execute the code.
    • for Java, there is a com.aerospike.examples.UserDefinedFunction example that show how to call UDF

#4

Thanks! As a follow up, how would I go about calling the UDF with a list in the Go client?


#5

Atomic list operations were added in release 3.7.0 of the server. Atomic map operations are in-progress.