# Data Storage

> Where scripts can keep data: script memory, linkset data, experience storage, notecards and object properties.

Script memory is small and lost on reset, so larger or longer-lived scripts store data elsewhere. Each store has a different size, lifetime, speed and audience.

As a rule: [linkset data](#linkset-data) for an object's own persistent state, [experience key-value storage](#experience-persistent-storage) for data shared across objects and regions, [notecards](#notecards) for read-only configuration, and an external server through [HTTP](/features/communications/) for anything bigger.

## Concepts

- Script memory: global variables persist until the script resets
  - Each script has a memory limit, which can be [read](/functions/llGetMemoryLimit/) and [lowered](/functions/llSetMemoryLimit/)
  - Check [free](/functions/llGetFreeMemory/) and [used](/functions/llGetUsedMemory/) memory, or the [profiled peak](/functions/llGetSPMaxMemory/)
- [Linkset data](/functions/llLinksetDataWrite/): up to 128 KiB of string key-value pairs stored in the object, readable and writable by every script in it
  - It survives script resets, taking the object into inventory and rezzing it again
  - Keys can be [protected with a password](/functions/llLinksetDataWriteProtected/)
  - Spreading data across many keys is cheaper than reading and rewriting one large value
  - Changes are reported in the [`linkset_data`](/events/linkset_data/) event
- [Experience persistent storage](/functions/llCreateKeyValue/): scripts compiled to an [experience](/features/experience/) share a key-value store that any object in that experience can use, anywhere on the grid
  - Every call is asynchronous and answers in the [`dataserver`](/events/dataserver/) event
- Notecards are read-only text in the object's inventory, good for configuration that users edit by hand
  - Lines can be read [synchronously](/functions/llGetNotecardLineSync/) when the notecard is cached, or [asynchronously](/functions/llGetNotecardLine/) through `dataserver`
  - From the [`llGetNotecardLineSync` wiki page](https://wiki.secondlife.com/wiki/LlGetNotecardLineSync): "Notecards are cached into a fixed-size buffer, with the oldest (least-recently read) notecard getting removed first. It is not safe to assume a notecard has been previously cached."
  - Reload when the inventory [changes](/constants/CHANGED_INVENTORY/)
- Object properties hold small values
  - In the object's [name](/functions/llSetObjectName/) or [description](/functions/llSetObjectDesc/), or in a prim's hover text or other [prim parameters](/features/prims/)
  - [Start parameters](/functions/llGetStartParameter/) and [start strings](/functions/llGetStartString/) pass data to an object as it is rezzed
- External storage: for large or shared data, [send it to a web service](/functions/llHTTPRequest/) and fetch it back when needed

## Functions and events

- `integer` [`llLinksetDataWrite`](/functions/llLinksetDataWrite/) `(string name, string value)`
- `string` [`llLinksetDataRead`](/functions/llLinksetDataRead/) `(string name)`
- `event` [`linkset_data`](/events/linkset_data/) `(integer action, string name, string value)`
- `key` [`llCreateKeyValue`](/functions/llCreateKeyValue/) `(string k, string v)`
- `key` [`llReadKeyValue`](/functions/llReadKeyValue/) `(string k)`
- `event` [`dataserver`](/events/dataserver/) `(key queryid, string data)`
- `string` [`llGetNotecardLineSync`](/functions/llGetNotecardLineSync/) `(string name, integer line)`
- `key` [`llGetNotecardLine`](/functions/llGetNotecardLine/) `(string name, integer line)`
- `integer` [`llGetFreeMemory`](/functions/llGetFreeMemory/) `()`
- `string` [`llGetStartString`](/functions/llGetStartString/) `()`

## [Linkset data](#linkset-data)

Persistent per-object storage shared by all its scripts, with optional password protection per key ([wiki guide](https://wiki.secondlife.com/wiki/Linkset_data)).

## [Script memory](#script-memory)

Globals live until reset; a script can [lower its own limit](/functions/llSetMemoryLimit/) ([wiki guide](https://wiki.secondlife.com/wiki/LSL_Script_Memory)).

## Scripting Details

### Script memory

- `integer` [`llGetFreeMemory`](/functions/llGetFreeMemory/) `()`: Returns an integer representing the number of free bytes of memory currently available to the script.
- `integer` [`llGetUsedMemory`](/functions/llGetUsedMemory/) `()`: Returns an integer representing the total number of bytes of memory currently used by the script (non-Mono scripts always return 16,384 bytes).
- `integer` [`llGetSPMaxMemory`](/functions/llGetSPMaxMemory/) `()`: Returns an integer representing the maximum memory (in bytes) used by the script while the memory profiler was last active (only valid after using PROFILE_SCRIPT_MEMORY).
- `integer` [`llGetMemoryLimit`](/functions/llGetMemoryLimit/) `()`: Returns an integer representing the maximum memory limit (in bytes) that the script is allowed to allocate.
- `integer` [`llSetMemoryLimit`](/functions/llSetMemoryLimit/) `(integer limit)`: Requests that limit bytes are reserved for the script. Returns TRUE on success or FALSE on failure (has no effect in LSO).

### Linkset data

- `integer` [`llLinksetDataWrite`](/functions/llLinksetDataWrite/) `(string name, string value)`: Creates or updates an unprotected key-value pair (name and value) in the linkset's datastore. Returns an integer success or failure code.
- `string` [`llLinksetDataRead`](/functions/llLinksetDataRead/) `(string name)`: Reads and returns the string value corresponding to key name from the linkset's datastore.
- `integer` [`llLinksetDataDelete`](/functions/llLinksetDataDelete/) `(string name)`: Deletes the unprotected key-value pair specified by name from the linkset's datastore, triggering a linkset_data event.
- `integer` [`llLinksetDataWriteProtected`](/functions/llLinksetDataWriteProtected/) `(string name, string value, string pass)`: Creates or updates a protected key-value pair (name and value) in the linkset's datastore using the passphrase pass. Returns an integer success or failure code.
- `string` [`llLinksetDataReadProtected`](/functions/llLinksetDataReadProtected/) `(string name, string pass)`: Reads and returns the string value of the protected key name from the linkset's datastore using the passphrase pass.
- `integer` [`llLinksetDataDeleteProtected`](/functions/llLinksetDataDeleteProtected/) `(string name, string pass)`: Deletes the protected key-value pair specified by name from the linkset's datastore using the passphrase pass, triggering a linkset_data event.
- `list` [`llLinksetDataFindKeys`](/functions/llLinksetDataFindKeys/) `(string pattern, integer start, integer count)`: Returns an alphabetically sorted list of up to count keys from the datastore that match the regular expression pattern, starting at index start (returns all matching keys if count < 1).
- `list` [`llLinksetDataListKeys`](/functions/llLinksetDataListKeys/) `(integer start, integer count)`: Returns an alphabetically sorted list of up to count keys from the datastore, starting at index start (returns all keys if count < 1).
- `integer` [`llLinksetDataCountKeys`](/functions/llLinksetDataCountKeys/) `()`: Returns an integer representing the total number of unique keys stored in the linkset's datastore.
- `integer` [`llLinksetDataCountFound`](/functions/llLinksetDataCountFound/) `(string pattern)`: Returns the total count of keys in the linkset datastore that match the regular expression pattern.
- `list` [`llLinksetDataDeleteFound`](/functions/llLinksetDataDeleteFound/) `(string pattern, string pass)`: Deletes all keys in the datastore matching the regular expression pattern. Returns a list [num_deleted, num_failed_protected]. Decrypts and deletes protected keys if matching pass is provided.
- `integer` [`llLinksetDataAvailable`](/functions/llLinksetDataAvailable/) `()`: Returns an integer representing the number of bytes available/remaining in the linkset's datastore.
- `void` [`llLinksetDataReset`](/functions/llLinksetDataReset/) `()`: Erases all key-value pairs stored in the linkset's datastore, triggering a linkset_data event (with LINKSETDATA_RESET) in all scripts in the linkset.
- `event` [`linkset_data`](/events/linkset_data/) `(integer action, string name, string value)`: Fires in all scripts in the linkset whenever the datastore has been modified via an llLinksetData function. Passes the action taken, the affected key name, and the new value.

### Experience persistent storage

- `key` [`llCreateKeyValue`](/functions/llCreateKeyValue/) `(string k, string v)`: Starts an asynchronous transaction to create a key-value pair (k and v) associated with the script's experience. Returns a key query handle for the dataserver event. Fails with XP_ERROR_STORAGE_EXCEPTION if the key already exists.
- `key` [`llReadKeyValue`](/functions/llReadKeyValue/) `(string k)`: Starts an asynchronous transaction to read the value associated with key k in the experience. Returns a key query handle for the dataserver event. Fails with XP_ERROR_KEY_NOT_FOUND if the key does not exist.
- `key` [`llUpdateKeyValue`](/functions/llUpdateKeyValue/) `(string k, string v, integer checked, string original_value)`: Starts an asynchronous transaction to update the key k to value v inside the experience datastore. If checked is TRUE, the update fails with XP_ERROR_RETRY_UPDATE unless the existing value matches original_value.
- `key` [`llDeleteKeyValue`](/functions/llDeleteKeyValue/) `(string k)`: Starts an asynchronous transaction to delete the key-value pair associated with key k in the experience. Returns a key query handle for the dataserver event.
- `key` [`llKeysKeyValue`](/functions/llKeysKeyValue/) `(integer first, integer count)`: Starts an asynchronous transaction to retrieve count keys from the experience data store starting at the zero-based index first. Returns a key query handle for the dataserver event. Fails with XP_ERROR_KEY_NOT_FOUND if out of bounds.
- `key` [`llKeyCountKeyValue`](/functions/llKeyCountKeyValue/) `()`: Starts an asynchronous transaction requesting the total count of keys in the experience data store. Returns a key query handle for the dataserver event.
- `key` [`llDataSizeKeyValue`](/functions/llDataSizeKeyValue/) `()`: Starts an asynchronous transaction to request the used and total data storage allocated for the experience. Returns a key query handle for the dataserver event.
- `event` [`dataserver`](/events/dataserver/) `(key queryid, string data)`: Triggered when requested data is returned to the script (e.g., from llRequestAgentData, llRequestInventoryData, or llGetNotecardLine).

### Notecards

- `string` [`llGetNotecardLineSync`](/functions/llGetNotecardLineSync/) `(string name, integer line)`: Synchronously reads the line index line of the notecard name from the region's cache, immediately returning its text without raising a dataserver event. Returns 'NAK' if not cached or 'EOF' if out of bounds.
- `key` [`llGetNotecardLine`](/functions/llGetNotecardLine/) `(string name, integer line)`: Asynchronously requests the line index line of the notecard name from the dataserver. Returns a key query handle for the dataserver event, which will return 'EOF' when reaching past the end of the notecard.
- `key` [`llGetNumberOfNotecardLines`](/functions/llGetNumberOfNotecardLines/) `(string name)`: Asynchronously requests the total line count of the notecard name. Returns a key query handle for the dataserver event.
- `list` [`llFindNotecardTextSync`](/functions/llFindNotecardTextSync/) `(string name, string pattern, integer start, integer count, list options)`: Synchronously searches a cached notecard name for lines containing pattern, returning a list of line and column numbers. Returns a list containing 'NAK' if the notecard is not cached, or an empty list if no matches are found.

### Object properties and external storage

- `void` [`llSetObjectDesc`](/functions/llSetObjectDesc/) `(string description)`: Sets the description of the prim containing the script to description (limited to 127 characters).
- `string` [`llGetObjectDesc`](/functions/llGetObjectDesc/) `()`: Returns a string containing the description of the specific prim containing the script.
- `void` [`llSetObjectName`](/functions/llSetObjectName/) `(string name)`: Sets the name of the prim containing the script to name.
- `string` [`llGetObjectName`](/functions/llGetObjectName/) `()`: Returns a string containing the name of the specific prim containing the script.
- `integer` [`llGetStartParameter`](/functions/llGetStartParameter/) `()`: Returns an integer representing the start/rez parameter passed to the object on creation (returns 0 if rezzed by an agent).
- `string` [`llGetStartString`](/functions/llGetStartString/) `()`: Returns the initialization string passed to the object's root prim on rez with llRezObjectWithParams (via REZ_PARAM_STRING; returns an empty string if rezzed by an agent).
- `key` [`llHTTPRequest`](/functions/llHTTPRequest/) `(string url, list parameters, string body)`: Sends an HTTP request to the specified url containing body and configured via parameters. Raises an http_response event and returns a key query handle identifying the request.
- `event` [`http_response`](/events/http_response/) `(key request_id, integer status, list metadata, string body)`: Triggered when an HTTP response body is received for a pending request_id, or if the request fails or times out.

## Additional

- [`linkset_data`](/events/linkset_data/) — the action that happened
  - [`LINKSETDATA_UPDATE`](/constants/LINKSETDATA_UPDATE/) — a key was created or updated
  - [`LINKSETDATA_DELETE`](/constants/LINKSETDATA_DELETE/) — a key was removed
  - [`LINKSETDATA_MULTIDELETE`](/constants/LINKSETDATA_MULTIDELETE/) — several keys were deleted with [`llLinksetDataDeleteFound`](/functions/llLinksetDataDeleteFound/)
  - [`LINKSETDATA_RESET`](/constants/LINKSETDATA_RESET/) — the store was cleared with [`llLinksetDataReset`](/functions/llLinksetDataReset/)
- [`llLinksetDataWrite`](/functions/llLinksetDataWrite/) — result codes
  - [`LINKSETDATA_OK`](/constants/LINKSETDATA_OK/) — success
  - [`LINKSETDATA_EMEMORY`](/constants/LINKSETDATA_EMEMORY/) — the pair was too large to write
  - [`LINKSETDATA_ENOKEY`](/constants/LINKSETDATA_ENOKEY/) — the key name was empty
  - [`LINKSETDATA_EPROTECTED`](/constants/LINKSETDATA_EPROTECTED/) — the pair is protected
  - [`LINKSETDATA_NOTFOUND`](/constants/LINKSETDATA_NOTFOUND/) — the key could not be found
  - [`LINKSETDATA_NOUPDATE`](/constants/LINKSETDATA_NOUPDATE/) — the value matched the stored value, so nothing changed
- [`dataserver`](/events/dataserver/) for key-value calls — errors, for example
  - [`XP_ERROR_NONE`](/constants/XP_ERROR_NONE/) — no error
  - [`XP_ERROR_KEY_NOT_FOUND`](/constants/XP_ERROR_KEY_NOT_FOUND/) — the key does not exist
  - [`XP_ERROR_QUOTA_EXCEEDED`](/constants/XP_ERROR_QUOTA_EXCEEDED/) — the data quota is met
  - [`XP_ERROR_RETRY_UPDATE`](/constants/XP_ERROR_RETRY_UPDATE/) — a checked update was out of date
- [`llGetNotecardLineSync`](/functions/llGetNotecardLineSync/) — returns [`NAK`](/constants/NAK/) when the notecard is not cached; [`EOF`](/constants/EOF/) marks a line past the end
- [`changed`](/events/changed/) — [`CHANGED_INVENTORY`](/constants/CHANGED_INVENTORY/) when the notecard may have been edited
- [`llRezObjectWithParams`](/functions/llRezObjectWithParams/) — [`REZ_PARAM_STRING`](/constants/REZ_PARAM_STRING/) passes a string read with `llGetStartString`

## Reference

Constant groups: [LinksetDataAction](/constants/groups/LinksetDataAction/) (4), [LinksetDataError](/constants/groups/LinksetDataError/) (6), [ExperienceError](/constants/groups/ExperienceError/) (19)

## Related

See also: [LSL Script Memory (Second Life Wiki)](https://wiki.secondlife.com/wiki/LSL_Script_Memory), [Linkset Data](/categories/linkset_data/), [Linkset data (Second Life Wiki)](https://wiki.secondlife.com/wiki/Linkset_data), [Experience](/features/experience/), [Experience Data](/categories/experience_data/), [Notecard](/categories/notecard/), [Inventory](/features/inventory/), [LSL Notecard (Second Life Wiki)](https://wiki.secondlife.com/wiki/Category:LSL_Notecard), [Prims](/features/prims/), [Communications](/features/communications/), [Data Transmission](/features/data-transmission/), [Guide: linkset resources (reusable prims in linkset data)](/guides/link-numbers/#linkset-resources)
   (planned: Guide: choosing where to store data)

## Related features

- [Data Transmission](/features/data-transmission/)
- [Communications](/features/communications/)
- [Experience](/features/experience/)

## Categories

- [Linkset Data](/categories/linkset_data/)
- [Data Storage](/categories/data_storage/)
- [Notecard](/categories/notecard/)
- [Dataserver](/categories/dataserver/)

---

From lsl.dev: https://lsl.dev/features/data-storage/
