diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index f126accfb86..cd5e97714c7 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -1002,171 +1002,185 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
end = sd.endMap();
for (i = sd.beginMap(); i != end; ++i)
{
- if (i->first == INV_ITEM_ID_LABEL)
- {
- mUUID = i->second;
- continue;
- }
-
- if (i->first == INV_PARENT_ID_LABEL)
- {
- mParentUUID = i->second;
- continue;
- }
+ // Use string length as a fast pre-filter before string comparison
+ const std::string& key = i->first;
+ const LLSD& value = i->second;
+ const size_t key_len = key.length();
- if (i->first == INV_THUMBNAIL_LABEL)
+ switch (key_len)
{
- const LLSD &thumbnail_map = i->second;
- if (thumbnail_map.has(INV_ASSET_ID_LABEL))
- {
- mThumbnailUUID = thumbnail_map[INV_ASSET_ID_LABEL];
- }
- /* Example:
- asset_id
- acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7
- perms
- 8
- service
- 3
- version
- 1
- */
- continue;
- }
-
- if (i->first == INV_THUMBNAIL_ID_LABEL)
- {
- mThumbnailUUID = i->second.asUUID();
- continue;
- }
-
- if (i->first == INV_FAVORITE_LABEL)
- {
- const LLSD& favorite_map = i->second;
- if (favorite_map.has(INV_TOGGLED_LABEL))
- {
- mFavorite = favorite_map[INV_TOGGLED_LABEL].asBoolean();
- }
- continue;
- }
-
- if (i->first == INV_PERMISSIONS_LABEL)
- {
- mPermissions.importLLSD(i->second);
- continue;
- }
-
- if (i->first == INV_SALE_INFO_LABEL)
- {
- // Sale info used to contain next owner perm. It is now in
- // the permissions. Thus, we read that out, and fix legacy
- // objects. It's possible this op would fail, but it
- // should pick up the vast majority of the tasks.
- bool has_perm_mask = false;
- U32 perm_mask = 0;
- if (!mSaleInfo.fromLLSD(i->second, has_perm_mask, perm_mask))
- {
- return false;
- }
- if (has_perm_mask)
- {
- if (perm_mask == PERM_NONE)
+ case 4: // "name", "desc", "type"
+ if (key == INV_NAME_LABEL) // "name"
{
- perm_mask = mPermissions.getMaskOwner();
+ mName = value.asString();
+ LLStringUtil::replaceNonstandardASCII(mName, ' ');
+ LLStringUtil::replaceChar(mName, '|', ' ');
+ continue;
}
- // fair use fix.
- if (!(perm_mask & PERM_COPY))
+ if (key == INV_DESC_LABEL) // "desc"
{
- perm_mask |= PERM_TRANSFER;
+ mDescription = value.asString();
+ LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
+ continue;
}
- mPermissions.setMaskNext(perm_mask);
- }
- continue;
- }
-
- if (i->first == INV_SHADOW_ID_LABEL)
- {
- mAssetUUID = i->second;
- LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
- cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
- continue;
- }
-
- if (i->first == INV_ASSET_ID_LABEL)
- {
- mAssetUUID = i->second;
- continue;
- }
+ if (key == INV_ASSET_TYPE_LABEL) // "type"
+ {
+ if (value.isString())
+ {
+ mType = LLAssetType::lookup(value.asStringRef().c_str());
+ }
+ else if (value.isInteger())
+ {
+ S8 type = (U8)value.asInteger();
+ mType = static_cast(type);
+ }
+ continue;
+ }
+ break;
- if (i->first == INV_LINKED_ID_LABEL)
- {
- mAssetUUID = i->second;
- continue;
- }
+ case 5: // "flags"
+ if (key == INV_FLAGS_LABEL)
+ {
+ if (value.isBinary())
+ {
+ mFlags = ll_U32_from_sd(value);
+ }
+ else if (value.isInteger())
+ {
+ mFlags = value.asInteger();
+ }
+ continue;
+ }
+ break;
- if (i->first == INV_ASSET_TYPE_LABEL)
- {
- LLSD const &label = i->second;
- if (label.isString())
- {
- mType = LLAssetType::lookup(label.asStringRef().c_str());
- }
- else if (label.isInteger())
- {
- S8 type = (U8) label.asInteger();
- mType = static_cast(type);
- }
- continue;
- }
+ case 7: // "item_id"
+ if (key == INV_ITEM_ID_LABEL)
+ {
+ mUUID = value;
+ continue;
+ }
+ break;
- if (i->first == INV_INVENTORY_TYPE_LABEL)
- {
- LLSD const &label = i->second;
- if (label.isString())
- {
- mInventoryType = LLInventoryType::lookup(label.asStringRef().c_str());
- }
- else if (label.isInteger())
- {
- S8 type = (U8) label.asInteger();
- mInventoryType = static_cast(type);
- }
- continue;
- }
+ case 8: // "asset_id", "inv_type"
+ if (key == INV_ASSET_ID_LABEL)
+ {
+ mAssetUUID = value;
+ continue;
+ }
+ if (key == INV_INVENTORY_TYPE_LABEL) // "inv_type"
+ {
+ if (value.isString())
+ {
+ mInventoryType = LLInventoryType::lookup(value.asStringRef().c_str());
+ }
+ else if (value.isInteger())
+ {
+ S8 type = (U8)value.asInteger();
+ mInventoryType = static_cast(type);
+ }
+ continue;
+ }
+ if (key == INV_FAVORITE_LABEL) // "favorite"
+ {
+ if (value.has(INV_TOGGLED_LABEL))
+ {
+ mFavorite = value[INV_TOGGLED_LABEL].asBoolean();
+ }
+ continue;
+ }
+ break;
- if (i->first == INV_FLAGS_LABEL)
- {
- LLSD const &label = i->second;
- if (label.isBinary())
- {
- mFlags = ll_U32_from_sd(label);
- }
- else if (label.isInteger())
- {
- mFlags = label.asInteger();
- }
- continue;
- }
+ case 9: // "parent_id", "shadow_id", "linked_id", "sale_info", "thumbnail"
+ if (key == INV_PARENT_ID_LABEL)
+ {
+ mParentUUID = value;
+ continue;
+ }
+ if (key == INV_SHADOW_ID_LABEL)
+ {
+ mAssetUUID = value;
+ LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+ cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
+ continue;
+ }
+ if (key == INV_LINKED_ID_LABEL)
+ {
+ mAssetUUID = value;
+ continue;
+ }
+ if (key == INV_SALE_INFO_LABEL)
+ {
+ // Sale info used to contain next owner perm. It is now in
+ // the permissions. Thus, we read that out, and fix legacy
+ // objects. It's possible this op would fail, but it
+ // should pick up the vast majority of the tasks.
+ bool has_perm_mask = false;
+ U32 perm_mask = 0;
+ if (!mSaleInfo.fromLLSD(value, has_perm_mask, perm_mask))
+ {
+ return false;
+ }
+ if (has_perm_mask)
+ {
+ if (perm_mask == PERM_NONE)
+ {
+ perm_mask = mPermissions.getMaskOwner();
+ }
+ // fair use fix.
+ if (!(perm_mask & PERM_COPY))
+ {
+ perm_mask |= PERM_TRANSFER;
+ }
+ mPermissions.setMaskNext(perm_mask);
+ }
+ continue;
+ }
+ if (key == INV_THUMBNAIL_LABEL)
+ {
+ if (value.has(INV_ASSET_ID_LABEL))
+ {
+ mThumbnailUUID = value[INV_ASSET_ID_LABEL];
+ }
+ /* Example:
+ asset_id
+ acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7
+ perms
+ 8
+ service
+ 3
+ version
+ 1
+ */
+ continue;
+ }
+ break;
+ case 10: // "created_at"
+ if (key == INV_CREATION_DATE_LABEL)
+ {
+ mCreationDate = value.asInteger();
+ continue;
+ }
+ break;
- if (i->first == INV_NAME_LABEL)
- {
- mName = i->second.asString();
- LLStringUtil::replaceNonstandardASCII(mName, ' ');
- LLStringUtil::replaceChar(mName, '|', ' ');
- continue;
- }
+ case 11: // "permissions"
+ if (key == INV_PERMISSIONS_LABEL)
+ {
+ mPermissions.importLLSD(value);
+ continue;
+ }
+ break;
- if (i->first == INV_DESC_LABEL)
- {
- mDescription = i->second.asString();
- LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
- continue;
- }
+ case 12: // "thumbnail_id"
+ if (key == INV_THUMBNAIL_ID_LABEL)
+ {
+ mThumbnailUUID = value.asUUID();
+ continue;
+ }
+ break;
- if (i->first == INV_CREATION_DATE_LABEL)
- {
- mCreationDate = i->second.asInteger();
- continue;
+ default:
+ // Unknown field - skip
+ break;
}
}
diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp
index 1c5530916f3..f0b7457fa23 100644
--- a/indra/newview/llaisapi.cpp
+++ b/indra/newview/llaisapi.cpp
@@ -1039,6 +1039,19 @@ AISUpdate::AISUpdate(const LLSD& update, AISAPI::COMMAND_TYPE type, const LLSD&
mFetchDepth = request_body["depth"].asInteger();
}
+ // Some tasks are time sensitive, don't wait for them.
+ // Like FETCHCOF which happens on load and is needed for outfit
+ // loading.
+ // FETCHCATEGORYLINKS is used for wearing outfits and fetching
+ // a user selected outfit or for following an outfit link in COF.
+ // Other tasks, like FETCHCATEGORYSUBSET are general background
+ // fetches and can safely wait.
+ // Do count 'time sensitive' tasks in batch timer.
+ mUseTimeout =
+ type != AISAPI::UPDATECATEGORY
+ && type != AISAPI::UPDATEITEM
+ && type != AISAPI::FETCHCOF
+ && type != AISAPI::FETCHCATEGORYLINKS;
mTaskTimer.setTimerExpirySec(AIS_TASK_EXPIRY_SECONDS);
mTaskTimer.start();
@@ -1069,6 +1082,11 @@ void AISUpdate::clearParseResults()
void AISUpdate::checkTimeout()
{
+ if (!mUseTimeout)
+ {
+ // Priority task, don't wait.
+ return;
+ }
if (mTaskTimer.hasExpired() || sBatchTimer.hasExpired())
{
// If we are taking too long, don't starve other tasks,
diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h
index 1dab0dd1f91..b31768d4264 100644
--- a/indra/newview/llaisapi.h
+++ b/indra/newview/llaisapi.h
@@ -109,6 +109,7 @@ class AISAPI
class AISUpdate
{
+ LOG_CLASS(AISUpdate);
public:
AISUpdate(const LLSD& update, AISAPI::COMMAND_TYPE type, const LLSD& request_body);
void parseUpdate(const LLSD& update);
@@ -158,6 +159,7 @@ class AISUpdate
uuid_list_t mCategoryIds;
bool mFetch;
S32 mFetchDepth;
+ bool mUseTimeout;
LLTimer mTaskTimer;
static LLTimer sBatchTimer;
static U32 sBatchFrameCount;
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 8b9aad46416..c72f1d2c358 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -2719,10 +2719,11 @@ bool LLInventoryModel::loadSkeleton(
for(LLSD::array_const_iterator it = options.beginArray(),
end = options.endArray(); it != end; ++it)
{
- LLSD name = (*it)["name"];
- LLSD folder_id = (*it)["folder_id"];
- LLSD parent_id = (*it)["parent_id"];
- LLSD version = (*it)["version"];
+ const LLSD &folder = *it;
+ const LLSD &name = folder["name"];
+ const LLSD &folder_id = folder["folder_id"];
+ const LLSD &parent_id = folder["parent_id"];
+ const LLSD &version = folder["version"];
if(name.isDefined()
&& folder_id.isDefined()
&& parent_id.isDefined()
@@ -2736,7 +2737,7 @@ bool LLInventoryModel::loadSkeleton(
cat->setParent(parent_id.asUUID());
LLFolderType::EType preferred_type = LLFolderType::FT_NONE;
- LLSD type_default = (*it)["type_default"];
+ const LLSD &type_default = folder["type_default"];
if(type_default.isDefined())
{
preferred_type = (LLFolderType::EType)type_default.asInteger();
@@ -3454,6 +3455,8 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
const LLSD& llsd_cats = inventory["categories"];
if (llsd_cats.isArray())
{
+ size_t cats_count = llsd_cats.size();
+ categories.reserve(cats_count);
LLSD::array_const_iterator iter = llsd_cats.beginArray();
LLSD::array_const_iterator end = llsd_cats.endArray();
for (; iter != end; ++iter)
@@ -3472,6 +3475,8 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
const LLSD& llsd_items = inventory["items"];
if (llsd_items.isArray())
{
+ size_t items_count = llsd_items.size();
+ items.reserve(items_count);
LLSD::array_const_iterator iter = llsd_items.beginArray();
LLSD::array_const_iterator end = llsd_items.endArray();
for (; iter != end; ++iter)