96 lines
5.8 KiB
Markdown
96 lines
5.8 KiB
Markdown
# Inventory models, hierarchy, and cache
|
|
|
|
The native inventory layer mirrors the value and hierarchy behavior of
|
|
LibreMetaverse's `InventoryBase`, `InventoryItem`, `InventoryFolder`,
|
|
`InventoryNode`, and `Inventory` types without depending on a network
|
|
transport. Concrete item subclasses remain concrete when inserted, queried,
|
|
notified, or restored from disk; link detection is based on `AssetType`, not on
|
|
the Rust wrapper type. This preserves the C# misclassified-link behavior.
|
|
|
|
Store mutation is serialized by one inventory state lock. Parent/child and link
|
|
indexes and recursive item counts are rebuilt as one transaction, with cycle
|
|
and depth bounds. Missing parents become placeholder folders until their real
|
|
folder record arrives. Self-loops and longer parent cycles remain queryable but
|
|
are not linked into a cyclic ownership graph. Removing a folder removes its
|
|
bounded descendant subtree. Root and library roots are tracked independently,
|
|
and direct system folders can be found by `FolderType`. Sorting supports the
|
|
`ByDate`, `FoldersByName`, and `SystemFoldersToTop` flags.
|
|
|
|
Added, updated, and removed notifications clone their arguments and subscriber
|
|
list before invoking observers. No inventory, node, or subscriber lock is held
|
|
during a callback, so observers may safely query or mutate the store. A panic
|
|
in one observer is isolated by the shared event registry.
|
|
|
|
Cache files start with `INVCACHE`, a little-endian format version, owner and
|
|
root identities, and tagged concrete records. Reads are limited to 64 MiB,
|
|
one million records, one MiB per string, and a 512-level hierarchy. Invalid
|
|
magic, versions, UTF-8, enums, duplicate IDs, zero IDs, truncated records, and
|
|
trailing data are rejected before the live store is replaced. Synchronous
|
|
restore returns `-1` for compatibility; asynchronous restore returns the typed
|
|
error. Saves snapshot under the state lock, release it before I/O, write and
|
|
sync a same-directory temporary file, then replace the destination. The
|
|
replacement includes a rollback path on platforms that cannot rename over an
|
|
existing file.
|
|
|
|
The focused compatibility suites are
|
|
`inventory_store_semantics` and `misclassified_link_semantics`; native unit
|
|
tests additionally cover concrete cache round trips, permissions, corruption,
|
|
unknown versions, system-folder sorting, and callback re-entry.
|
|
|
|
## UDP inventory manager
|
|
|
|
`InventoryManager` now owns the live inventory protocol boundary. Login installs
|
|
the agent and library skeletons in the transport-free store, while validated
|
|
`UpdateCreateInventoryItem`, `BulkUpdateInventory`, `FetchInventoryReply`, and
|
|
`InventoryDescendents` replies populate or reconcile it. Create and copy callback
|
|
IDs, item fetches, task replies, and inventory offers are correlated independently;
|
|
cancelling one waiter removes only that waiter. A cleanup worker bounds abandoned
|
|
requests to one minute, and the manager rejects more than 4,096 pending operations.
|
|
|
|
Outbound create, update, move, copy, remove, give, rez/derez, script-state, and
|
|
task-inventory operations build the generated protocol packet types. Generated
|
|
multi-block packets use the packet codec's `encode_multiple` path, so large batches
|
|
are split according to the UDP transport bounds while retaining the same agent,
|
|
session, transaction, callback, owner, and permission data. Capability-backed
|
|
inventory fetch and folder-content responses are parsed before becoming visible in
|
|
the store. Asset, material, script, notecard, and thumbnail upload bodies remain a
|
|
separate asset-pipeline concern.
|
|
|
|
Legacy task inventory uses a correlated `ReplyTaskInventory` filename followed by
|
|
a `RequestXfer` transfer. The implementation confirms packets, handles duplicate
|
|
or out-of-order packet numbers deterministically, aborts cancelled transfers, and
|
|
rejects announced or accumulated data above 16 MiB. Task text parsing is capped at
|
|
100,000 entries and accepts both plain asset IDs and the reference shadow-ID XOR
|
|
encoding. The capability path applies the same byte and entry limits.
|
|
|
|
No store lock is held across an await, a packet send, or an observer callback.
|
|
Reply data is decoded and validated before store mutation, and event registries
|
|
snapshot subscribers before invoking them. Focused coverage lives in
|
|
`inventory_manager_semantics`, `task_inventory_semantics`, and the native
|
|
`inventory_manager::tests` fake-packet cases for callback isolation, bulk-copy
|
|
completion, stale folder versions, offers, capability events, and bounded Xfer.
|
|
|
|
## Inventory API v3
|
|
|
|
`InventoryAISClient` implements the `InventoryAPIv3` and `LibraryAPIv3`
|
|
capability resources for categories, children, links, individual items, the
|
|
current outfit folder, orphans, and trash. Requests preserve the AIS verbs and
|
|
resource shapes, including `COPY` with its `Destination` header, transaction
|
|
IDs, depth/subset queries, and LLSD XML request content type. The client uses
|
|
the injected capability HTTP transport, so tests and applications can record
|
|
requests deterministically without replacing inventory logic.
|
|
|
|
Successful response bodies are fully decoded and validated before any local
|
|
state changes. Embedded folders, concrete items, and links are parsed together;
|
|
object or mesh links with the legacy texture inventory type are corrected to
|
|
attachments. Side-effect removals and category version updates are combined
|
|
with returned objects and installed atomically through a detached candidate
|
|
inventory graph. Malformed, oversized, cancelled, or timed-out responses leave
|
|
the live store unchanged, and no store lock crosses an await or callback.
|
|
|
|
AIS remains capability-optional. Missing capabilities and HTTP failures return
|
|
the fixed false/empty compatibility results, while cancellation is propagated.
|
|
The existing `InventoryManager` UDP fallback remains the contract-correct path
|
|
for operations whose capability is absent; AIS reconciliation shares that
|
|
manager's transport-independent store and observer ordering.
|