llUpdateKeyValue

From Second Life Wiki
Revision as of 11:04, 22 January 2015 by Lady Sumoku (talk | contribs) (Replaced old <LSL> block with <source lang="lsl2">)
Jump to navigation Jump to search

Summary

Function: key llUpdateKeyValue( string k, string v, integer checked, string original_value );

Start an asynchronous transaction to update a key-value pair associated with the given experience key with the given key and value.
Returns a handle (a key) that can be used to identify the corresponding dataserver event to determine if this command succeeded or failed and the results.

• string k The key for the key-value pair
• string v The value for the key-value pair. Maximum 2047 characters, or 4095 if using Mono.
• integer checked If TRUE the update will only happen if original_value matches the value in the key-value store.
• string original_value The value to compare with the current value in the key-value store.

If checked is set to TRUE then the update will only happen if original_value matches the current value in key-value store. This can be used to create an in-use flag so that "Wikipedia logo"Atomicity can be achieved.

Specification

Dataserver

The dataserver callback parameters are:

String Components
• integer success A boolean specifying if the transaction succeeded (1) or not (0).
• integer error An XP_ERROR_* flag that describes why the operation failed.
• string value The value for the key-value pair. Maximum 2047 characters, or 4095 if using Mono. Note! This value may contain commas.

Examples

key trans;
default
{
    state_entry()
    {
        trans = llUpdateKeyValue("FOO", "BLAH", TRUE, "BAR");
    }

    dataserver(key t, string value)
    {
        if (t == trans)
        {
            // our llUpdateKeyValue transaction is done
            list result = llCSV2List(value);
            if (llList2Integer(result, 0) == 1)
            {
                // the key-value pair was successfully updated
                llSay(0, "New key-value pair was successfully updated");
            }
            else
            {
                integer error = llList2Integer(result, 1);
                if(error == XP_ERROR_RETRY_UPDATE)
                    llSay(0, "Key-value update failed, checked value is out of date");
                else
                    llSay(0, "Key-value update failed: " + llGetExperienceErrorMessage(error) );
            }  
        }
    }
}

This script demonstrates how to avoid update conflicts (two scripts updating the store at the same time), performing fully atomic updates is more complicated. If all scripts writing to the key-value store abide by the virtual lock ($DB_Lock), and only do updates in update_db state, then all writes will be atomic.

key tid;
list tids;

default {
    state_entry() {
        state lock_db;
    }
}

state lock_db {
    state_entry() {
        tid = llUpdateKeyValue("$DB_Lock", "LOCK", TRUE, "unlock");
    }
    dataserver(key did, string value) {
        if(did == tid) {
            string payload = llDeleteSubString(value, 0, 1);
            if(llGetSubString(value+",", 0, 1) == "1,"){
                llUpdateKeyValue("$DB_LockedBy", llDumpList2String([llGetOwner(),llGetKey(),llGetLinkKey(!!llGetLinkNumber()),llGetRegionName(),llGetPos(),llGetAttached()],":"), FALSE, "");
                state update_db;
            } else {
                integer err = (integer)payload;
                if(err == XP_ERROR_RETRY_UPDATE) {
                    llSay(0, "Database is already locked!");
                } else {
                    llSay(0, "Key-value update failed: " + llGetExperienceErrorMessage(err) );
                }
                state error;
            }
        }
    }
}

state update_db {
    state_entry() {
        tids = [
            llUpdateKeyValue("CatsPermissable", "5", FALSE, ""),
            llUpdateKeyValue("MonkeyMutations", "3", FALSE, ""),
            llUpdateKeyValue("CodFlavorSupport", "NEVER", FALSE, "")
        ];
    }
    dataserver(key did, string value) {
        integer i = llListFindList(tid, [did]);
        if(~i) {
            string payload = llDeleteSubString(value, 0, 1);
            if(llGetSubString(value+",", 0, 1) == "1,"){
                tids = llDeleteSubList(tids, i, i);
                if(tids == []) {
                    state unlock_db;
                }
            } else {
                llSay(0, "Key-value update failed: " + llGetExperienceErrorMessage((integer)payload) );
                state error;
            }
        }
    }
}

state unlock_db {
    state_entry() {
        tid = llUpdateKeyValue("$DB_Lock", "unlock", TRUE, "LOCK");
    }
    dataserver(key did, string value) {
        if(did == tid) {
            string payload = llDeleteSubString(value, 0, 1);
            if(llGetSubString(value+",", 0, 1) == "1,"){
                state done;
            } else {
                integer err = (integer)payload;
                if(err == XP_ERROR_RETRY_UPDATE) {
                    llSay(0, "Someone has violated the database lock!");
                } else {
                    llSay(0, "Key-value update failed: " + llGetExperienceErrorMessage(err) );
                }
                state error;
            }
        }
    }
}

state done {
    state_entry(){;}
}

state error {
    state_entry(){;}
}

Deep Notes

Signature

function key llUpdateKeyValue( string k, string v, integer checked, string original_value );