Are lua UDF functions transactional?

Greetings!

I am using aerospike server as a response cache system. The system is multienvironment. The system does the following:

  1. gets cached response for a user.
  2. deletes the cache.
  3. fills the cache with new response for the same user.

However, due to the multienvironment it can happen that after the cache is retrieved, the same user calls the system from another instance and the system fills the response again, but the response will be deleted if any slight lattency from the 1st query.

I implemented a UDF lua function, used in the apply() method - all works fine. My question is is this lua script transactional? Meaning that the mentioned above scenario won’t happen in case of multienv users. Here is the lua code: function get_and_delete(rec, bin) local response = rec[bin]

aerospike:remove(rec)

return response

end

Thanks in advance!

Yes, it is transactional but also not very efficient.

As of Aerospike 4.7.0.2 you can use the delete record operation which doesn’t require context switching to a LUA VM.

[AER-6096] - (KVS) Added delete of entire record as an operation (e.g. to enable atomic read then delete).

For java this would be:

Record record = client.operate(params.writePolicy, key,
    Operation.get(),
    Operation.delete(),
    Operation.put(bin1),
    Operation.put(bin2),
    ...);
1 Like

Thank you for the reply, however I tried the operate() method after going through the php client api but as I understand operate() requires write/increment as a first operation with optional post-read/delete actions?

No, I don’t believe that is the case, was there documentation that indicated this (which may need fixing) or did you test it?

Could you share a code snippet?

It is from here: https://www.aerospike.com/docs/client/php/usage/kvs/write.html To combine multiple bin operations on a single record with optional post-write reads for the modified bin values:

$operations = [
  ["op" => Aerospike::OPERATOR_READ,   "bin" => "test"],
  ["op" => Aerospike::OPERATOR_DELETE,   "bin" => "test"],
];
$status = $db->operate($key, $operations, $returned);
if ($status == Aerospike::OK) {
  var_dump($returned); // display the age
}

I literally tested with the above snippet and I kept getting either timeout, or AS_ERR_UNKNOWN.

I can recheck again for sure, since you claim it should work - most probably was a missusage by me. Anyway - I would like to point out that the udf lua script actually works faster for me than the basic get and remove consecutive calls.

If you want to delete the record, you shouldn’t need to specify a bin name. Similarly, if you wanted to read all the bins, you wouldn’t specify the bin name here either.

Actually the client dev just informed me that the delete operation doesn’t accept a bin argument, so that was probably causing an error (though I would have expected to see ‘PARAMETER’ and not ‘UNKNOWN’.)

1 Like

Hi @Miroslav_Isikiyski, Thanks for posting!

If you are looking to read a bin from the record, then delete the record in 1 call to operate, this should do the trick.

<?php

$HOST_ADDR = ("localhost");
$HOST_PORT = (3000);

echo "Connecting to the host\n";
$config = array("hosts" => array(array("addr" => $HOST_ADDR, "port" => $HOST_PORT)));
$db = new Aerospike($config, false);

echo "Writing a record in test.characters with PK=1234\n";
$digest = $db->getKeyDigest("test", "characters", 1234);
$key = $db->initKey("test", "characters", $digest, true);
$put_vals = array("email" => "freudian.circuits@hal-inst.org", "name" => "Perceptron");
$status = $db->put($key, $put_vals);

echo "Read the 'name' bin\n";
echo "Delete the record\n";
$operations = array(
    array("op" => Aerospike::OPERATOR_READ, "bin" => "name"),
    array("op" => Aerospike::OPERATOR_DELETE));
$res = $db->operate($key, $operations, $returned);
var_dump($returned);

$db->close();
?>

Hope this helps!

1 Like

Thank you both for the replies!

I used the same logic as Dylan’s example:

private function getAndDelete(string $userKey): string
    {
        $operations = [
            ["op" => \Aerospike::OPERATOR_READ, "bin" => 'testBIN'],
            ["op" => \Aerospike::OPERATOR_DELETE],
        ];

        $status = $this->aerospike->operate(
            $this->aerospike->initKey('testNS', 'testSET', $userKey), $operations, $returned
        );

        var_dump($returned);
        var_dump($status);


        if ($status != \Aerospike::OK || empty($returned)) {
            return '';
        }

        return $returned;
    }

And I get NULL for $returned and AS_ERR_PARAMETER for $status.

Can you double check that you are running Aerospike 4.7.0.2 or later, also PARAMETER errors typically log a warning in the server logs, could you share that warning?

1 Like

oohhh… sorry about not checking the version earlier… Yeah… on local environment I use 3.14

root@aerospike:/# asinfo -v build
3.14.1.4

On live we use even lower - 3.12.1 All makes sense now.

Anyway thank you for the fruitful discussion - I will stick to the UDF implementation I have and some day if we upgrade our aerospikes I will have the reference here as well :slight_smile:

Thanks, Miroslav

That is really old :steam_locomotive: the rebalance algorithms in 3.13 and earlier have a few serious design flaws. The flaws are rare but possible, and basically result in partitions thinking they are in sync when they aren’t (which basically means data loss). In 3.13 there is an operational switch to the new protocols where we redesigned the rebalance algorithms.

1 Like
© 2015 Copyright Aerospike, Inc. | All rights reserved. Creators of the Aerospike Database.