[Feature Request] llLinksetDataWriteWithValidation()
tracked
Lucia Nightfire
Linkset Data allows multiple scripts in the same linkset to read/create/update/delete data.
We currently do not have any LSD functions with an append validation protocol.
Experience KVP updating has a validation protocol w/ feedback which can address race conditions between scripts in the same linkset, different objects in the same region or different objects grid-wide.
The following function satisfies the need stated above for LSD:
integer llLinksetDataWriteWithValidation(string name, string value, string pass, string original_value)
A new failure code constant LINKSETDATA_VALIDATION with value 6 will be needed for this function.
Functionality:
- If name does NOT exist and value is NOT an empty string and original_value is an empty string, the entry is created and 0 is returned, else, 6 is returned.
- If name exists and value is NOT an empty string and original_value matches name's current value and pass matches name's current pass, the entry is updated and 0 or 5 is returned, else, 6 is returned.
- If name exists and value is an empty string and original_value matches name's current value and pass matches name's current pass, the entry is deleted and 0 is returned, else, 6 is returned.
Other typical check failures such as empty name, name not found, pass mismatch, etc. will return the same values as they do now before validation handling is done.
The server is actually already doing these checks in the background to determine what integer value to return with exiting LSD functions. There's just, currently, no validation protection.
This feature offers validation protection for creates, updates and deletes which is a must in an environment where multiple scripts can potentially modify an entry at the same time creating race conditions.
Since it has password input, this function becomes a defacto all-in-one append function for creates, updates and deletes, something even KVP currently doesn't offer.
Log In
Spidey Linden
Merged in a post:
Atomic linkset data operation realizing a semaphore.
Jenna Felton
Motivation
I am creating a system of two scripts currently where one script handles menus and other data operation which need a fast response while the other script is used for sending instant messages (which have 2 seconds delay). And one of the operations can potentially create a large number of sent messages. I can not make the one script prepare the message text in LSD and let the other one send the messages from there, because LSD is used to hold the needed data and I can need the full storage.
The solution I came up with was to send the text for each IM in a separate link message and send those link messages as soon the comm script is ready. This would lead to using two link messages, one (core -> comm) that takes the body of the IM to send and the other (comm -> core) that requests the new one. This solution, however slows down the process. Ideally would be to send a bunch of link messages with text at once and wait until the comm script has handled them. But that can lead to overflowing the event queue if not used carefully.
This leads to a semaphore approach: We use a certain KVP on the LSD, say with a key "semaphore". The value is initialized by "0". Whenever a core script sends a link message it increases this value by 1 and stops doing so when the value reached a certain threshold, maybe 16. When the comm script sends the instant message, it decreases the value by 1. Once it crossed the threshold (we can use a second threshold for example 8) the core script resumes generating link messages to send.
This solution even allows to keep the message generating part within one function within one event: the generator would use busy waiting where it observes the semaphore value to know if it can generate new link messages, although this would break the "fast response" idea, but it is good for other applications.
The solution has only one problem: To update the KVP, a script has to use the llLinksetDataRead and then llLinksetDataWrite operations and since both scripts would call this couple they can do this in the same moment and corrupt the value. Because of this LSD needs a way of atomic value incrementation.
Suggestion
The semaphore is a regular KVP which is initialized by an integer value casted to a string, for example "0".
For the update of this value we need one unprotected and one protected operation:
integer llLinksetDataIncrement(string name, integer increment);
This operation replaces this code:
integer value = (integer)llLinksetDataRead(name);
value = valie + increment;
llLinksetDataWrite(name, (string)value);
return value;
But this code block must be embedded into a critical section not allowing the value to be changed by an other script in between.
This single operation allows to increment the value, decrement it (use a negative increment) and also read it (use a zero increment but you may also use a regular llLinksetDataRead here) and I think it is fully sufficient for many semaphore applications.
The scripter must be sure not to use the regular llLinksetDataWrite to not to corrupt the semaphore value.
The protected operation is similar but it accesses a protected KVP and thus uses a password:
integer llLinksetDataIncrementProtected(string name, integer increment, string password);
Pazako Karu
I see several solutions to this problem using current tech, if you're still having issues.
1: Use linkset_data() event, since its synchronous and fires in all scripts. Exactly how to use is up to you, but you could use the event only for increments, or decrements, or as a response to a 'add one to my counter' flag, etc.
2: Use another linkset key to set a busy flag, only write if 0
3: Use a linkset key for subtractions and another additions and add them to find your queue number
4: while ((integer)llGetEnv("frame_number")%2==0) and ==1 for the other so they wait for an odd or even frame to operate. Riskier, but it does keep things in time very well.
5: Use a third script to keep count, but that's no fun.
While a protected synchronous key would be useful in a few circumstances, the script time for any one of these, including the infinite while loop, is pretty trivial (1/45th of a second).
xaka Chayoo
The ideal solution would be to have inworld data hosting, leaving scripts to do script things, having said that a solution to the problem whilst said data hosting is not available would be:
in the core, KVP to trigger on updated value, initialised at "0", generate msg, count msg to send, write number to KVP, sent flag to halt msg generator send msgs.
at the comms, KVP update with number of msgs, send msgs, decrement counter, on done write "GO" to KVP.
"GO" triggers on KVP update at core, sets flag to generate msgs, process restarts.
Not ideal, but workable with what we got, maybe getting a buffer script into the process, or am I over simplifying it ?
Spidey Linden
marked this post as
tracked
Issue tracked. We have no estimate when it may be implemented. Please see future updates here.
WolfGang Senizen
At this point ll really should just make
llLinksetDataWriteAdvanced
There are a bunch of decent suggestions for LinksetData and we shouldnt need to have endless new functions that then need even more functions to combine functionality.
We could have this instead
llLinksetDataWriteAdvanced(
"key",
"value",
[
LSD_MODE, LSD_MODE_REPLACE,
LSD_VALIDATE, LSD_VALIDATE_EQUAL, "old_value",
LSD_PASSWORD, "secret"
]
)
OR
llLinksetDataWriteAdvanced(
"key",
"value3:",
[
LSD_MODE, LSD_MODE_APPEND,
LSD_VALIDATE, LSD_VALIDATE_MATCH, ".*value2:$",
LSD_PASSWORD, "secret"
]
)
Andromeda Quonset
This seems reasonable. I wonder, is there a simple way to do the opposite action of append?
Lucia Nightfire
Andromeda Quonset You might need to explain what you mean by "opposite action of append".
Andromeda Quonset
Lucia Nightfire If Append is adding an item, the opposite would remove an item.
Lucia Nightfire
Andromeda Quonset LSD "Write" functions are capable of deletes using null strings for key values.