diff options
23 files changed, 2100 insertions, 2104 deletions
@@ -527,3 +527,4 @@ cea1632c002c065985ebea15eeeb4aac90f50545 5.0.2-release 02c24e9f4f7d8aa0de75f27817dda098582f4936 5.0.3-release 022709ef76a331cac1ba6ef1a6da8a5e9ef63f5a 5.0.4-release b4d76b5590fdf8bab72c64442353753a527cbc44 5.0.5-release +3e5035dfd8af49bd4c0009f0a76ef46a15991a45 5.0.6-release diff --git a/doc/contributions.txt b/doc/contributions.txt index eb012ee318..79ff7161f6 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -1302,6 +1302,7 @@ Sovereign Engineer MAINT-6218 MAINT-6913 STORM-2143 + MAINT-7343 SpacedOut Frye VWR-34 VWR-45 diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 3a4b5dad18..b849be9f16 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -152,7 +152,7 @@ public: static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer - + static const std::string& badLookup(); // error string when a lookup fails protected: diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 2ddb3edbdd..cfca42809a 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -572,7 +572,7 @@ namespace LLError mFunctionString += std::string(mFunction) + ":"; for (size_t i = 0; i < mTagCount; i++) { - mTagString += std::string("#") + mTags[i] + ((i == mTagCount - 1) ? "" : ","); + mTagString += std::string("#") + mTags[i] + ((i == mTagCount - 1) ? " " : ","); } } diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index bcf4e52b8f..596d57c7b7 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -60,64 +60,60 @@ static LLTrace::CountStatHandle<> sFailedDownloadCount("faileddownloads", "Numbe const LLUUID CATEGORIZE_LOST_AND_FOUND_ID(std::string("00000000-0000-0000-0000-000000000010")); -const U64 TOXIC_ASSET_LIFETIME = (120 * 1000000); // microseconds - -LLTempAssetStorage::~LLTempAssetStorage() -{ -} +const U64 TOXIC_ASSET_LIFETIME = (120 * 1000000); // microseconds ///---------------------------------------------------------------------------- /// LLAssetInfo ///---------------------------------------------------------------------------- LLAssetInfo::LLAssetInfo( void ) -: mDescription(), - mName(), - mUuid(), - mCreatorID(), - mType( LLAssetType::AT_NONE ) + : mDescription(), + mName(), + mUuid(), + mCreatorID(), + mType( LLAssetType::AT_NONE ) { } LLAssetInfo::LLAssetInfo( const LLUUID& object_id, const LLUUID& creator_id, - LLAssetType::EType type, const char* name, - const char* desc ) -: mUuid( object_id ), - mCreatorID( creator_id ), - mType( type ) + LLAssetType::EType type, const char* name, + const char* desc ) + : mUuid( object_id ), + mCreatorID( creator_id ), + mType( type ) { - setName( name ); - setDescription( desc ); + setName( name ); + setDescription( desc ); } LLAssetInfo::LLAssetInfo( const LLNameValue& nv ) { - setFromNameValue( nv ); + setFromNameValue( nv ); } // make sure the name is short enough, and strip all pipes since they // are reserved characters in our inventory tracking system. void LLAssetInfo::setName( const std::string& name ) { - if( !name.empty() ) - { - mName.assign( name, 0, llmin((U32)name.size(), (U32)DB_INV_ITEM_NAME_STR_LEN) ); - mName.erase( std::remove(mName.begin(), mName.end(), '|'), - mName.end() ); - } + if( !name.empty() ) + { + mName.assign( name, 0, llmin((U32)name.size(), (U32)DB_INV_ITEM_NAME_STR_LEN) ); + mName.erase( std::remove(mName.begin(), mName.end(), '|'), + mName.end() ); + } } // make sure the name is short enough, and strip all pipes since they // are reserved characters in our inventory tracking system. void LLAssetInfo::setDescription( const std::string& desc ) { - if( !desc.empty() ) - { - mDescription.assign( desc, 0, llmin((U32)desc.size(), - (U32)DB_INV_ITEM_DESC_STR_LEN) ); - mDescription.erase( std::remove(mDescription.begin(), - mDescription.end(), '|'), - mDescription.end() ); - } + if( !desc.empty() ) + { + mDescription.assign( desc, 0, llmin((U32)desc.size(), + (U32)DB_INV_ITEM_DESC_STR_LEN) ); + mDescription.erase( std::remove(mDescription.begin(), + mDescription.end(), '|'), + mDescription.end() ); + } } // Assets (aka potential inventory items) can be applied to an @@ -130,31 +126,31 @@ void LLAssetInfo::setDescription( const std::string& desc ) // value=<creatorid>|<name>|<description>| void LLAssetInfo::setFromNameValue( const LLNameValue& nv ) { - std::string str; - std::string buf; - std::string::size_type pos1; - std::string::size_type pos2; - - // convert the name to useful information - str.assign( nv.mName ); - pos1 = str.find('|'); - buf.assign( str, 0, pos1++ ); - mType = LLAssetType::lookup( buf ); - buf.assign( str, pos1, std::string::npos ); - mUuid.set( buf ); - - // convert the value to useful information - str.assign( nv.getAsset() ); - pos1 = str.find('|'); - buf.assign( str, 0, pos1++ ); - mCreatorID.set( buf ); - pos2 = str.find( '|', pos1 ); - buf.assign( str, pos1, (pos2++) - pos1 ); - setName( buf ); - buf.assign( str, pos2, std::string::npos ); - setDescription( buf ); - LL_DEBUGS("AssetStorage") << "uuid: " << mUuid << LL_ENDL; - LL_DEBUGS("AssetStorage") << "creator: " << mCreatorID << LL_ENDL; + std::string str; + std::string buf; + std::string::size_type pos1; + std::string::size_type pos2; + + // convert the name to useful information + str.assign( nv.mName ); + pos1 = str.find('|'); + buf.assign( str, 0, pos1++ ); + mType = LLAssetType::lookup( buf ); + buf.assign( str, pos1, std::string::npos ); + mUuid.set( buf ); + + // convert the value to useful information + str.assign( nv.getAsset() ); + pos1 = str.find('|'); + buf.assign( str, 0, pos1++ ); + mCreatorID.set( buf ); + pos2 = str.find( '|', pos1 ); + buf.assign( str, pos1, (pos2++) - pos1 ); + setName( buf ); + buf.assign( str, pos2, std::string::npos ); + setDescription( buf ); + LL_DEBUGS("AssetStorage") << "uuid: " << mUuid << LL_ENDL; + LL_DEBUGS("AssetStorage") << "creator: " << mCreatorID << LL_ENDL; } ///---------------------------------------------------------------------------- @@ -162,15 +158,15 @@ void LLAssetInfo::setFromNameValue( const LLNameValue& nv ) ///---------------------------------------------------------------------------- LLBaseDownloadRequest::LLBaseDownloadRequest(const LLUUID &uuid, const LLAssetType::EType type) -: mUUID(uuid), -mType(type), -mDownCallback(NULL), -mUserData(NULL), -mHost(), -mIsTemp(FALSE), -mIsPriority(FALSE), -mDataSentInFirstPacket(FALSE), -mDataIsInVFS(FALSE) + : mUUID(uuid), + mType(type), + mDownCallback(NULL), + mUserData(NULL), + mHost(), + mIsTemp(FALSE), + mIsPriority(FALSE), + mDataSentInFirstPacket(FALSE), + mDataIsInVFS(FALSE) { // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been // running a message system loop. @@ -194,12 +190,13 @@ LLBaseDownloadRequest* LLBaseDownloadRequest::getCopy() ///---------------------------------------------------------------------------- LLAssetRequest::LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType type) -: LLBaseDownloadRequest(uuid, type), - mUpCallback( NULL ), - mInfoCallback( NULL ), - mIsLocal(FALSE), - mIsUserWaiting(FALSE), - mTimeout(LL_ASSET_STORAGE_TIMEOUT) + : LLBaseDownloadRequest(uuid, type), + mUpCallback( NULL ), + mInfoCallback( NULL ), + mIsLocal(FALSE), + mIsUserWaiting(FALSE), + mTimeout(LL_ASSET_STORAGE_TIMEOUT), + mBytesFetched(0) { } @@ -211,31 +208,31 @@ LLAssetRequest::~LLAssetRequest() // virtual LLSD LLAssetRequest::getTerseDetails() const { - LLSD sd; - sd["asset_id"] = getUUID(); - sd["type_long"] = LLAssetType::lookupHumanReadable(getType()); - sd["type"] = LLAssetType::lookup(getType()); - sd["time"] = mTime.value(); - time_t timestamp = (time_t) mTime.value(); - std::ostringstream time_string; - time_string << ctime(×tamp); - sd["time_string"] = time_string.str(); - return sd; + LLSD sd; + sd["asset_id"] = getUUID(); + sd["type_long"] = LLAssetType::lookupHumanReadable(getType()); + sd["type"] = LLAssetType::lookup(getType()); + sd["time"] = mTime.value(); + time_t timestamp = (time_t) mTime.value(); + std::ostringstream time_string; + time_string << ctime(×tamp); + sd["time_string"] = time_string.str(); + return sd; } // virtual LLSD LLAssetRequest::getFullDetails() const { - LLSD sd = getTerseDetails(); - sd["host"] = mHost.getIPandPort(); - sd["requesting_agent"] = mRequestingAgentID; - sd["is_temp"] = mIsTemp; - sd["is_local"] = mIsLocal; - sd["is_priority"] = mIsPriority; - sd["data_send_in_first_packet"] = mDataSentInFirstPacket; - sd["data_is_in_vfs"] = mDataIsInVFS; - - return sd; + LLSD sd = getTerseDetails(); + sd["host"] = mHost.getIPandPort(); + sd["requesting_agent"] = mRequestingAgentID; + sd["is_temp"] = mIsTemp; + sd["is_local"] = mIsLocal; + sd["is_priority"] = mIsPriority; + sd["data_send_in_first_packet"] = mDataSentInFirstPacket; + sd["data_is_in_vfs"] = mDataIsInVFS; + + return sd; } LLBaseDownloadRequest* LLAssetRequest::getCopy() @@ -248,7 +245,7 @@ LLBaseDownloadRequest* LLAssetRequest::getCopy() ///---------------------------------------------------------------------------- LLInvItemRequest::LLInvItemRequest(const LLUUID &uuid, const LLAssetType::EType type) -: LLBaseDownloadRequest(uuid, type) + : LLBaseDownloadRequest(uuid, type) { } @@ -267,9 +264,9 @@ LLBaseDownloadRequest* LLInvItemRequest::getCopy() ///---------------------------------------------------------------------------- LLEstateAssetRequest::LLEstateAssetRequest(const LLUUID &uuid, const LLAssetType::EType atype, - EstateAssetType etype) -: LLBaseDownloadRequest(uuid, atype), - mEstateAssetType(etype) + EstateAssetType etype) + : LLBaseDownloadRequest(uuid, atype), + mEstateAssetType(etype) { } @@ -299,152 +296,150 @@ LLBaseDownloadRequest* LLEstateAssetRequest::getCopy() LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, LLVFS *static_vfs, const LLHost &upstream_host) { - _init(msg, xfer, vfs, static_vfs, upstream_host); + _init(msg, xfer, vfs, static_vfs, upstream_host); } - LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, - LLVFS *vfs, LLVFS *static_vfs) + LLVFS *vfs, LLVFS *static_vfs) { - _init(msg, xfer, vfs, static_vfs, LLHost()); + _init(msg, xfer, vfs, static_vfs, LLHost()); } - void LLAssetStorage::_init(LLMessageSystem *msg, - LLXferManager *xfer, - LLVFS *vfs, - LLVFS *static_vfs, - const LLHost &upstream_host) + LLXferManager *xfer, + LLVFS *vfs, + LLVFS *static_vfs, + const LLHost &upstream_host) { - mShutDown = FALSE; - mMessageSys = msg; - mXferManager = xfer; - mVFS = vfs; - mStaticVFS = static_vfs; - - setUpstream(upstream_host); - msg->setHandlerFuncFast(_PREHASH_AssetUploadComplete, processUploadComplete, (void **)this); + mShutDown = FALSE; + mMessageSys = msg; + mXferManager = xfer; + mVFS = vfs; + mStaticVFS = static_vfs; + + setUpstream(upstream_host); + msg->setHandlerFuncFast(_PREHASH_AssetUploadComplete, processUploadComplete, (void **)this); } LLAssetStorage::~LLAssetStorage() { - mShutDown = TRUE; - - _cleanupRequests(TRUE, LL_ERR_CIRCUIT_GONE); - - if (gMessageSystem) - { - // Warning! This won't work if there's more than one asset storage. - // unregister our callbacks with the message system - gMessageSystem->setHandlerFuncFast(_PREHASH_AssetUploadComplete, NULL, NULL); - } - - // Clear the toxic asset map - mToxicAssetMap.clear(); + mShutDown = TRUE; + + _cleanupRequests(TRUE, LL_ERR_CIRCUIT_GONE); + + if (gMessageSystem) + { + // Warning! This won't work if there's more than one asset storage. + // unregister our callbacks with the message system + gMessageSystem->setHandlerFuncFast(_PREHASH_AssetUploadComplete, NULL, NULL); + } + + // Clear the toxic asset map + mToxicAssetMap.clear(); } void LLAssetStorage::setUpstream(const LLHost &upstream_host) { - LL_DEBUGS("AppInit") << "AssetStorage: Setting upstream provider to " << upstream_host << LL_ENDL; - - mUpstreamHost = upstream_host; + LL_DEBUGS("AppInit") << "AssetStorage: Setting upstream provider to " << upstream_host << LL_ENDL; + + mUpstreamHost = upstream_host; } void LLAssetStorage::checkForTimeouts() { - _cleanupRequests(FALSE, LL_ERR_TCP_TIMEOUT); + _cleanupRequests(FALSE, LL_ERR_TCP_TIMEOUT); } void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) { - F64Seconds mt_secs = LLMessageSystem::getMessageTimeSeconds(); - - request_list_t timed_out; - S32 rt; - for (rt = 0; rt < RT_COUNT; rt++) - { - request_list_t* requests = getRequestList((ERequestType)rt); - for (request_list_t::iterator iter = requests->begin(); - iter != requests->end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* tmp = *curiter; - // if all is true, we want to clean up everything - // otherwise just check for timed out requests - // EXCEPT for upload timeouts - if (all - || ((RT_DOWNLOAD == rt) - && LL_ASSET_STORAGE_TIMEOUT < (mt_secs - tmp->mTime))) - { - LL_WARNS() << "Asset " << getRequestName((ERequestType)rt) << " request " - << (all ? "aborted" : "timed out") << " for " - << tmp->getUUID() << "." - << LLAssetType::lookup(tmp->getType()) << LL_ENDL; - - timed_out.push_front(tmp); - iter = requests->erase(curiter); - } - } - } - - LLAssetInfo info; - for (request_list_t::iterator iter = timed_out.begin(); - iter != timed_out.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* tmp = *curiter; - if (tmp->mUpCallback) - { - tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LL_EXSTAT_NONE); - } - if (tmp->mDownCallback) - { - tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LL_EXSTAT_NONE); - } - if (tmp->mInfoCallback) - { - tmp->mInfoCallback(&info, tmp->mUserData, error); - } - delete tmp; - } + F64Seconds mt_secs = LLMessageSystem::getMessageTimeSeconds(); + + request_list_t timed_out; + S32 rt; + for (rt = 0; rt < RT_COUNT; rt++) + { + request_list_t* requests = getRequestList((ERequestType)rt); + for (request_list_t::iterator iter = requests->begin(); + iter != requests->end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* tmp = *curiter; + // if all is true, we want to clean up everything + // otherwise just check for timed out requests + // EXCEPT for upload timeouts + if (all + || ((RT_DOWNLOAD == rt) + && LL_ASSET_STORAGE_TIMEOUT < (mt_secs - tmp->mTime))) + { + LL_WARNS("AssetStorage") << "Asset " << getRequestName((ERequestType)rt) << " request " + << (all ? "aborted" : "timed out") << " for " + << tmp->getUUID() << "." + << LLAssetType::lookup(tmp->getType()) << LL_ENDL; + + timed_out.push_front(tmp); + iter = requests->erase(curiter); + } + } + } + + LLAssetInfo info; + for (request_list_t::iterator iter = timed_out.begin(); + iter != timed_out.end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* tmp = *curiter; + if (tmp->mUpCallback) + { + tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LL_EXSTAT_NONE); + } + if (tmp->mDownCallback) + { + tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LL_EXSTAT_NONE); + } + if (tmp->mInfoCallback) + { + tmp->mInfoCallback(&info, tmp->mUserData, error); + } + delete tmp; + } } BOOL LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType type) { - return mStaticVFS->getExists(uuid, type) || mVFS->getExists(uuid, type); + return mStaticVFS->getExists(uuid, type) || mVFS->getExists(uuid, type); } bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type, - LLGetAssetCallback callback, void *user_data) -{ - if (user_data) - { - // The *user_data should not be passed without a callback to clean it up. - llassert(callback != NULL); - } - - BOOL exists = mStaticVFS->getExists(uuid, type); - if (exists) - { - LLVFile file(mStaticVFS, uuid, type); - U32 size = file.getSize(); - if (size > 0) - { - // we've already got the file - if (callback) - { - callback(mStaticVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); - } - return true; - } - else - { - LL_WARNS() << "Asset vfile " << uuid << ":" << type - << " found in static cache with bad size " << file.getSize() << ", ignoring" << LL_ENDL; - } - } - return false; + LLGetAssetCallback callback, void *user_data) +{ + if (user_data) + { + // The *user_data should not be passed without a callback to clean it up. + llassert(callback != NULL); + } + + BOOL exists = mStaticVFS->getExists(uuid, type); + if (exists) + { + LLVFile file(mStaticVFS, uuid, type); + U32 size = file.getSize(); + if (size > 0) + { + // we've already got the file + if (callback) + { + callback(mStaticVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); + } + return true; + } + else + { + LL_WARNS("AssetStorage") << "Asset vfile " << uuid << ":" << type + << " found in static cache with bad size " << file.getSize() << ", ignoring" << LL_ENDL; + } + } + return false; } /////////////////////////////////////////////////////////////////////////// @@ -452,526 +447,506 @@ bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAsse /////////////////////////////////////////////////////////////////////////// // IW - uuid is passed by value to avoid side effects, please don't re-add & -void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LLGetAssetCallback callback, void *user_data, BOOL is_priority) -{ - LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << LL_ENDL; - - LL_DEBUGS("AssetStorage") << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << LL_ENDL; - - if (user_data) - { - // The *user_data should not be passed without a callback to clean it up. - llassert(callback != NULL); - } - - if (mShutDown) - { - LL_DEBUGS("AssetStorage") << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << LL_ENDL; - - if (callback) - { - add(sFailedDownloadCount, 1); - callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_NONE); - } - return; - } - - if (uuid.isNull()) - { - // Special case early out for NULL uuid and for shutting down - if (callback) - { - add(sFailedDownloadCount, 1); - callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); - } - return; - } - - // Try static VFS first. - if (findInStaticVFSAndInvokeCallback(uuid,type,callback,user_data)) - { - LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in static VFS" << LL_ENDL; - return; - } - - BOOL exists = mVFS->getExists(uuid, type); - LLVFile file(mVFS, uuid, type); - U32 size = exists ? file.getSize() : 0; - - if (size > 0) - { - // we've already got the file - // theoretically, partial files w/o a pending request shouldn't happen - // unless there's a weird error - if (callback) - { - callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); - } - - LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << LL_ENDL; - } - else - { - if (exists) - { - LL_WARNS() << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; - file.remove(); - } - - BOOL duplicate = FALSE; - - // check to see if there's a pending download of this uuid already - for (request_list_t::iterator iter = mPendingDownloads.begin(); - iter != mPendingDownloads.end(); ++iter ) - { - LLAssetRequest *tmp = *iter; - if ((type == tmp->getType()) && (uuid == tmp->getUUID())) - { - if (callback == tmp->mDownCallback && user_data == tmp->mUserData) - { - // this is a duplicate from the same subsystem - throw it away - LL_WARNS() << "Discarding duplicate request for asset " << uuid - << "." << LLAssetType::lookup(type) << LL_ENDL; - return; - } - - // this is a duplicate request - // queue the request, but don't actually ask for it again - duplicate = TRUE; - } - } - if (duplicate) - { - LL_DEBUGS("AssetStorage") << "Adding additional non-duplicate request for asset " << uuid - << "." << LLAssetType::lookup(type) << LL_ENDL; - } - - // This can be overridden by subclasses - _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority); - } - +void LLAssetStorage::getAssetData(const LLUUID uuid, + LLAssetType::EType type, + LLGetAssetCallback callback, + void *user_data, + BOOL is_priority) +{ + LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << LL_ENDL; + + LL_DEBUGS("AssetStorage") << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << LL_ENDL; + + if (user_data) + { + // The *user_data should not be passed without a callback to clean it up. + llassert(callback != NULL); + } + + if (mShutDown) + { + LL_DEBUGS("AssetStorage") << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << LL_ENDL; + + if (callback) + { + add(sFailedDownloadCount, 1); + callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_NONE); + } + return; + } + + if (uuid.isNull()) + { + // Special case early out for NULL uuid and for shutting down + if (callback) + { + add(sFailedDownloadCount, 1); + callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); + } + return; + } + + // Try static VFS first. + if (findInStaticVFSAndInvokeCallback(uuid,type,callback,user_data)) + { + LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in static VFS" << LL_ENDL; + return; + } + + BOOL exists = mVFS->getExists(uuid, type); + LLVFile file(mVFS, uuid, type); + U32 size = exists ? file.getSize() : 0; + + if (size > 0) + { + // we've already got the file + // theoretically, partial files w/o a pending request shouldn't happen + // unless there's a weird error + if (callback) + { + callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); + } + + LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << LL_ENDL; + } + else + { + if (exists) + { + LL_WARNS("AssetStorage") << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; + file.remove(); + } + + BOOL duplicate = FALSE; + + // check to see if there's a pending download of this uuid already + for (request_list_t::iterator iter = mPendingDownloads.begin(); + iter != mPendingDownloads.end(); ++iter ) + { + LLAssetRequest *tmp = *iter; + if ((type == tmp->getType()) && (uuid == tmp->getUUID())) + { + if (callback == tmp->mDownCallback && user_data == tmp->mUserData) + { + // this is a duplicate from the same subsystem - throw it away + LL_WARNS("AssetStorage") << "Discarding duplicate request for asset " << uuid + << "." << LLAssetType::lookup(type) << LL_ENDL; + return; + } + + // this is a duplicate request + // queue the request, but don't actually ask for it again + duplicate = TRUE; + } + } + if (duplicate) + { + LL_DEBUGS("AssetStorage") << "Adding additional non-duplicate request for asset " << uuid + << "." << LLAssetType::lookup(type) << LL_ENDL; + } + + _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority); + } } -// -// *NOTE: Logic here is replicated in LLViewerAssetStorage::_queueDataRequest. -// Changes here may need to be replicated in the viewer's derived class. -// -void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType atype, - LLGetAssetCallback callback, - void *user_data, BOOL duplicate, - BOOL is_priority) -{ - if (mUpstreamHost.isOk()) - { - // stash the callback info so we can find it after we get the response message - LLAssetRequest *req = new LLAssetRequest(uuid, atype); - req->mDownCallback = callback; - req->mUserData = user_data; - req->mIsPriority = is_priority; - - mPendingDownloads.push_back(req); - - if (!duplicate) - { - // send request message to our upstream data provider - // Create a new asset transfer. - LLTransferSourceParamsAsset spa; - spa.setAsset(uuid, atype); - - // Set our destination file, and the completion callback. - LLTransferTargetParamsVFile tpvf; - tpvf.setAsset(uuid, atype); - tpvf.setCallback(downloadCompleteCallback, *req); - - //LL_INFOS() << "Starting transfer for " << uuid << LL_ENDL; - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET); - ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f)); - } - } - else - { - // uh-oh, we shouldn't have gotten here - LL_WARNS() << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; - if (callback) - { - add(sFailedDownloadCount, 1); - callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); - } - } +// static +void LLAssetStorage::removeAndCallbackPendingDownloads(const LLUUID& file_id, LLAssetType::EType file_type, + const LLUUID& callback_id, LLAssetType::EType callback_type, + S32 result_code, LLExtStat ext_status) +{ + // find and callback ALL pending requests for this UUID + // SJB: We process the callbacks in reverse order, I do not know if this is important, + // but I didn't want to mess with it. + request_list_t requests; + for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin(); + iter != gAssetStorage->mPendingDownloads.end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* tmp = *curiter; + if ((tmp->getUUID() == file_id) && (tmp->getType()== file_type)) + { + requests.push_front(tmp); + iter = gAssetStorage->mPendingDownloads.erase(curiter); + } + } + for (request_list_t::iterator iter = requests.begin(); + iter != requests.end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* tmp = *curiter; + if (tmp->mDownCallback) + { + if (result_code!= LL_ERR_NOERR) + { + add(sFailedDownloadCount, 1); + } + tmp->mDownCallback(gAssetStorage->mVFS, callback_id, callback_type, tmp->mUserData, result_code, ext_status); + } + delete tmp; + } } - void LLAssetStorage::downloadCompleteCallback( - S32 result, - const LLUUID& file_id, - LLAssetType::EType file_type, - LLBaseDownloadRequest* user_data, LLExtStat ext_status) -{ - LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << file_id << " downloadCompleteCallback" << LL_ENDL; - - LL_DEBUGS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback() for " << file_id - << "," << LLAssetType::lookup(file_type) << LL_ENDL; - LLAssetRequest* req = (LLAssetRequest*)user_data; - if(!req) - { - LL_WARNS() << "LLAssetStorage::downloadCompleteCallback called without" - "a valid request." << LL_ENDL; - return; - } - if (!gAssetStorage) - { - LL_WARNS() << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << LL_ENDL; - return; - } - - LLUUID callback_id; - LLAssetType::EType callback_type; - - // Inefficient since we're doing a find through a list that may have thousands of elements. - // This is due for refactoring; we will probably change mPendingDownloads into a set. - request_list_t::iterator download_iter = std::find(gAssetStorage->mPendingDownloads.begin(), - gAssetStorage->mPendingDownloads.end(), - req); - - if (download_iter != gAssetStorage->mPendingDownloads.end()) - { - callback_id = file_id; - callback_type = file_type; - } - else - { - // either has already been deleted by _cleanupRequests or it's a transfer. - callback_id = req->getUUID(); - callback_type = req->getType(); - } - - if (LL_ERR_NOERR == result) - { - // we might have gotten a zero-size file - LLVFile vfile(gAssetStorage->mVFS, callback_id, callback_type); - if (vfile.getSize() <= 0) - { - LL_WARNS() << "downloadCompleteCallback has non-existent or zero-size asset " << callback_id << LL_ENDL; - - result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; - vfile.remove(); - } - } - - // find and callback ALL pending requests for this UUID - // SJB: We process the callbacks in reverse order, I do not know if this is important, - // but I didn't want to mess with it. - request_list_t requests; - for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin(); - iter != gAssetStorage->mPendingDownloads.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* tmp = *curiter; - if ((tmp->getUUID() == file_id) && (tmp->getType()== file_type)) - { - requests.push_front(tmp); - iter = gAssetStorage->mPendingDownloads.erase(curiter); - } - } - for (request_list_t::iterator iter = requests.begin(); - iter != requests.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* tmp = *curiter; - if (tmp->mDownCallback) - { - if (result != LL_ERR_NOERR) - { - add(sFailedDownloadCount, 1); - } - tmp->mDownCallback(gAssetStorage->mVFS, callback_id, callback_type, tmp->mUserData, result, ext_status); - } - delete tmp; - } -} - -void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id, - const LLUUID &asset_id, LLAssetType::EType atype, EstateAssetType etype, - LLGetAssetCallback callback, void *user_data, BOOL is_priority) -{ - LL_DEBUGS() << "LLAssetStorage::getEstateAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << ", estatetype " << etype << LL_ENDL; - - // - // Probably will get rid of this early out? - // - if (asset_id.isNull()) - { - // Special case early out for NULL uuid - if (callback) - { - add(sFailedDownloadCount, 1); - callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); - } - return; - } - - // Try static VFS first. - if (findInStaticVFSAndInvokeCallback(asset_id,atype,callback,user_data)) - { - return; - } - - BOOL exists = mVFS->getExists(asset_id, atype); - LLVFile file(mVFS, asset_id, atype); - U32 size = exists ? file.getSize() : 0; - - if (size > 0) - { - // we've already got the file - // theoretically, partial files w/o a pending request shouldn't happen - // unless there's a weird error - if (callback) - { - callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); - } - } - else - { - if (exists) - { - LL_WARNS() << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; - file.remove(); - } - - // See whether we should talk to the object's originating sim, or the upstream provider. - LLHost source_host; - if (object_sim.isOk()) - { - source_host = object_sim; - } - else - { - source_host = mUpstreamHost; - } - if (source_host.isOk()) - { - // stash the callback info so we can find it after we get the response message - LLEstateAssetRequest req(asset_id, atype, etype); - req.mDownCallback = callback; - req.mUserData = user_data; - req.mIsPriority = is_priority; - - // send request message to our upstream data provider - // Create a new asset transfer. - LLTransferSourceParamsEstate spe; - spe.setAgentSession(agent_id, session_id); - spe.setEstateAssetType(etype); - - // Set our destination file, and the completion callback. - LLTransferTargetParamsVFile tpvf; - tpvf.setAsset(asset_id, atype); - tpvf.setCallback(downloadEstateAssetCompleteCallback, req); - - LL_DEBUGS("AssetStorage") << "Starting transfer for " << asset_id << LL_ENDL; - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET); - ttcp->requestTransfer(spe, tpvf, 100.f + (is_priority ? 1.f : 0.f)); - } - else - { - // uh-oh, we shouldn't have gotten here - LL_WARNS() << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; - if (callback) - { - add(sFailedDownloadCount, 1); - callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); - } - } - } + S32 result, + const LLUUID& file_id, + LLAssetType::EType file_type, + LLBaseDownloadRequest* user_data, + LLExtStat ext_status) +{ + LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << file_id << " downloadCompleteCallback" << LL_ENDL; + + LL_DEBUGS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback() for " << file_id + << "," << LLAssetType::lookup(file_type) << LL_ENDL; + LLAssetRequest* req = (LLAssetRequest*)user_data; + if(!req) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback called without" + "a valid request." << LL_ENDL; + return; + } + if (!gAssetStorage) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << LL_ENDL; + return; + } + + LLUUID callback_id; + LLAssetType::EType callback_type; + + // Inefficient since we're doing a find through a list that may have thousands of elements. + // This is due for refactoring; we will probably change mPendingDownloads into a set. + request_list_t::iterator download_iter = std::find(gAssetStorage->mPendingDownloads.begin(), + gAssetStorage->mPendingDownloads.end(), + req); + + if (download_iter != gAssetStorage->mPendingDownloads.end()) + { + callback_id = file_id; + callback_type = file_type; + } + else + { + // either has already been deleted by _cleanupRequests or it's a transfer. + callback_id = req->getUUID(); + callback_type = req->getType(); + } + + if (LL_ERR_NOERR == result) + { + // we might have gotten a zero-size file + LLVFile vfile(gAssetStorage->mVFS, callback_id, callback_type); + if (vfile.getSize() <= 0) + { + LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset " << callback_id << LL_ENDL; + + result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; + vfile.remove(); + } + else + { +#if 1 + for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin(); + iter != gAssetStorage->mPendingDownloads.end(); ++iter ) + { + LLAssetRequest* dlreq = *iter; + if ((dlreq->getUUID() == file_id) && (dlreq->getType()== file_type)) + { + dlreq->mBytesFetched = vfile.getSize(); + } + } +#endif + } + } + + removeAndCallbackPendingDownloads(file_id, file_type, callback_id, callback_type, ext_status, result); +} + +void LLAssetStorage::getEstateAsset( + const LLHost &object_sim, + const LLUUID &agent_id, + const LLUUID &session_id, + const LLUUID &asset_id, + LLAssetType::EType atype, + EstateAssetType etype, + LLGetAssetCallback callback, + void *user_data, + BOOL is_priority) +{ + LL_DEBUGS() << "LLAssetStorage::getEstateAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << ", estatetype " << etype << LL_ENDL; + + // + // Probably will get rid of this early out? + // + if (asset_id.isNull()) + { + // Special case early out for NULL uuid + if (callback) + { + add(sFailedDownloadCount, 1); + callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); + } + return; + } + + // Try static VFS first. + if (findInStaticVFSAndInvokeCallback(asset_id,atype,callback,user_data)) + { + return; + } + + BOOL exists = mVFS->getExists(asset_id, atype); + LLVFile file(mVFS, asset_id, atype); + U32 size = exists ? file.getSize() : 0; + + if (size > 0) + { + // we've already got the file + // theoretically, partial files w/o a pending request shouldn't happen + // unless there's a weird error + if (callback) + { + callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); + } + } + else + { + if (exists) + { + LL_WARNS("AssetStorage") << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; + file.remove(); + } + + // See whether we should talk to the object's originating sim, or the upstream provider. + LLHost source_host; + if (object_sim.isOk()) + { + source_host = object_sim; + } + else + { + source_host = mUpstreamHost; + } + if (source_host.isOk()) + { + // stash the callback info so we can find it after we get the response message + LLEstateAssetRequest req(asset_id, atype, etype); + req.mDownCallback = callback; + req.mUserData = user_data; + req.mIsPriority = is_priority; + + // send request message to our upstream data provider + // Create a new asset transfer. + LLTransferSourceParamsEstate spe; + spe.setAgentSession(agent_id, session_id); + spe.setEstateAssetType(etype); + + // Set our destination file, and the completion callback. + LLTransferTargetParamsVFile tpvf; + tpvf.setAsset(asset_id, atype); + tpvf.setCallback(downloadEstateAssetCompleteCallback, req); + + LL_DEBUGS("AssetStorage") << "Starting transfer for " << asset_id << LL_ENDL; + LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET); + ttcp->requestTransfer(spe, tpvf, 100.f + (is_priority ? 1.f : 0.f)); + } + else + { + // uh-oh, we shouldn't have gotten here + LL_WARNS("AssetStorage") << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; + if (callback) + { + add(sFailedDownloadCount, 1); + callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); + } + } + } } void LLAssetStorage::downloadEstateAssetCompleteCallback( - S32 result, - const LLUUID& file_id, - LLAssetType::EType file_type, - LLBaseDownloadRequest* user_data, - LLExtStat ext_status) -{ - LLEstateAssetRequest *req = (LLEstateAssetRequest*)user_data; - if(!req) - { - LL_WARNS() << "LLAssetStorage::downloadEstateAssetCompleteCallback called" - " without a valid request." << LL_ENDL; - return; - } - if (!gAssetStorage) - { - LL_WARNS() << "LLAssetStorage::downloadEstateAssetCompleteCallback called" - " without any asset system, aborting!" << LL_ENDL; - return; - } - - req->setUUID(file_id); - req->setType(file_type); - if (LL_ERR_NOERR == result) - { - // we might have gotten a zero-size file - LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getAType()); - if (vfile.getSize() <= 0) - { - LL_WARNS() << "downloadCompleteCallback has non-existent or zero-size asset!" << LL_ENDL; - - result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; - vfile.remove(); - } - } - - if (result != LL_ERR_NOERR) - { - add(sFailedDownloadCount, 1); - } - req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getAType(), req->mUserData, result, ext_status); -} - -void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id, - const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id, - const LLUUID &asset_id, LLAssetType::EType atype, - LLGetAssetCallback callback, void *user_data, BOOL is_priority) -{ - LL_DEBUGS() << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << LL_ENDL; - - // - // Probably will get rid of this early out? - // - //if (asset_id.isNull()) - //{ - // // Special case early out for NULL uuid - // if (callback) - // { - // callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE); - // } - // return; - //} - - bool exists = false; - U32 size = 0; - - if(asset_id.notNull()) - { - // Try static VFS first. - if (findInStaticVFSAndInvokeCallback( asset_id, atype, callback, user_data)) - { - return; - } - - exists = mVFS->getExists(asset_id, atype); - LLVFile file(mVFS, asset_id, atype); - size = exists ? file.getSize() : 0; - if(exists && size < 1) - { - LL_WARNS() << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; - file.remove(); - } - - } - - if (size > 0) - { - // we've already got the file - // theoretically, partial files w/o a pending request shouldn't happen - // unless there's a weird error - if (callback) - { - callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); - } - } - else - { - // See whether we should talk to the object's originating sim, - // or the upstream provider. - LLHost source_host; - if (object_sim.isOk()) - { - source_host = object_sim; - } - else - { - source_host = mUpstreamHost; - } - if (source_host.isOk()) - { - // stash the callback info so we can find it after we get the response message - LLInvItemRequest req(asset_id, atype); - req.mDownCallback = callback; - req.mUserData = user_data; - req.mIsPriority = is_priority; - - // send request message to our upstream data provider - // Create a new asset transfer. - LLTransferSourceParamsInvItem spi; - spi.setAgentSession(agent_id, session_id); - spi.setInvItem(owner_id, task_id, item_id); - spi.setAsset(asset_id, atype); - - // Set our destination file, and the completion callback. - LLTransferTargetParamsVFile tpvf; - tpvf.setAsset(asset_id, atype); - tpvf.setCallback(downloadInvItemCompleteCallback, req); - - LL_DEBUGS("AssetStorage") << "Starting transfer for inventory asset " - << item_id << " owned by " << owner_id << "," << task_id - << LL_ENDL; - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET); - ttcp->requestTransfer(spi, tpvf, 100.f + (is_priority ? 1.f : 0.f)); - } - else - { - // uh-oh, we shouldn't have gotten here - LL_WARNS() << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; - if (callback) - { - add(sFailedDownloadCount, 1); - callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); - } - } - } + S32 result, + const LLUUID& file_id, + LLAssetType::EType file_type, + LLBaseDownloadRequest* user_data, + LLExtStat ext_status) +{ + LLEstateAssetRequest *req = (LLEstateAssetRequest*)user_data; + if(!req) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadEstateAssetCompleteCallback called" + " without a valid request." << LL_ENDL; + return; + } + if (!gAssetStorage) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadEstateAssetCompleteCallback called" + " without any asset system, aborting!" << LL_ENDL; + return; + } + + req->setUUID(file_id); + req->setType(file_type); + if (LL_ERR_NOERR == result) + { + // we might have gotten a zero-size file + LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getAType()); + if (vfile.getSize() <= 0) + { + LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset!" << LL_ENDL; + + result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; + vfile.remove(); + } + } + + if (result != LL_ERR_NOERR) + { + add(sFailedDownloadCount, 1); + } + req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getAType(), req->mUserData, result, ext_status); +} + +void LLAssetStorage::getInvItemAsset( + const LLHost &object_sim, + const LLUUID &agent_id, + const LLUUID &session_id, + const LLUUID &owner_id, + const LLUUID &task_id, + const LLUUID &item_id, + const LLUUID &asset_id, + LLAssetType::EType atype, + LLGetAssetCallback callback, + void *user_data, + BOOL is_priority) +{ + LL_DEBUGS() << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << LL_ENDL; + + bool exists = false; + U32 size = 0; + + if(asset_id.notNull()) + { + // Try static VFS first. + if (findInStaticVFSAndInvokeCallback( asset_id, atype, callback, user_data)) + { + return; + } + + exists = mVFS->getExists(asset_id, atype); + LLVFile file(mVFS, asset_id, atype); + size = exists ? file.getSize() : 0; + if(exists && size < 1) + { + LL_WARNS("AssetStorage") << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; + file.remove(); + } + + } + + if (size > 0) + { + // we've already got the file + // theoretically, partial files w/o a pending request shouldn't happen + // unless there's a weird error + if (callback) + { + callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); + } + } + else + { + // See whether we should talk to the object's originating sim, + // or the upstream provider. + LLHost source_host; + if (object_sim.isOk()) + { + source_host = object_sim; + } + else + { + source_host = mUpstreamHost; + } + if (source_host.isOk()) + { + // stash the callback info so we can find it after we get the response message + LLInvItemRequest req(asset_id, atype); + req.mDownCallback = callback; + req.mUserData = user_data; + req.mIsPriority = is_priority; + + // send request message to our upstream data provider + // Create a new asset transfer. + LLTransferSourceParamsInvItem spi; + spi.setAgentSession(agent_id, session_id); + spi.setInvItem(owner_id, task_id, item_id); + spi.setAsset(asset_id, atype); + + LL_DEBUGS("ViewerAsset") << "requesting inv item id " << item_id << " asset_id " << asset_id << " type " << LLAssetType::lookup(atype) << LL_ENDL; + + // Set our destination file, and the completion callback. + LLTransferTargetParamsVFile tpvf; + tpvf.setAsset(asset_id, atype); + tpvf.setCallback(downloadInvItemCompleteCallback, req); + + LL_DEBUGS("AssetStorage") << "Starting transfer for inventory asset " + << item_id << " owned by " << owner_id << "," << task_id + << LL_ENDL; + LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET); + ttcp->requestTransfer(spi, tpvf, 100.f + (is_priority ? 1.f : 0.f)); + } + else + { + // uh-oh, we shouldn't have gotten here + LL_WARNS("AssetStorage") << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; + if (callback) + { + add(sFailedDownloadCount, 1); + callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); + } + } + } } void LLAssetStorage::downloadInvItemCompleteCallback( - S32 result, - const LLUUID& file_id, - LLAssetType::EType file_type, - LLBaseDownloadRequest* user_data, - LLExtStat ext_status) -{ - LLInvItemRequest *req = (LLInvItemRequest*)user_data; - if(!req) - { - LL_WARNS() << "LLAssetStorage::downloadEstateAssetCompleteCallback called" - " without a valid request." << LL_ENDL; - return; - } - if (!gAssetStorage) - { - LL_WARNS() << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << LL_ENDL; - return; - } - - req->setUUID(file_id); - req->setType(file_type); - if (LL_ERR_NOERR == result) - { - // we might have gotten a zero-size file - LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType()); - if (vfile.getSize() <= 0) - { - LL_WARNS() << "downloadCompleteCallback has non-existent or zero-size asset!" << LL_ENDL; - - result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; - vfile.remove(); - } - } - - if (result != LL_ERR_NOERR) - { - add(sFailedDownloadCount, 1); - } - req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), req->mUserData, result, ext_status); + S32 result, + const LLUUID& file_id, + LLAssetType::EType file_type, + LLBaseDownloadRequest* user_data, + LLExtStat ext_status) +{ + LLInvItemRequest *req = (LLInvItemRequest*)user_data; + if(!req) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadEstateAssetCompleteCallback called" + " without a valid request." << LL_ENDL; + return; + } + if (!gAssetStorage) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << LL_ENDL; + return; + } + + req->setUUID(file_id); + req->setType(file_type); + if (LL_ERR_NOERR == result) + { + // we might have gotten a zero-size file + LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType()); + if (vfile.getSize() <= 0) + { + LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset!" << LL_ENDL; + + result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; + vfile.remove(); + } + } + + if (result != LL_ERR_NOERR) + { + add(sFailedDownloadCount, 1); + } + req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), req->mUserData, result, ext_status); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -979,654 +954,558 @@ void LLAssetStorage::downloadInvItemCompleteCallback( ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // static -void LLAssetStorage::uploadCompleteCallback(const LLUUID& uuid, void *user_data, S32 result, LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - if (!gAssetStorage) - { - LL_WARNS() << "LLAssetStorage::uploadCompleteCallback has no gAssetStorage!" << LL_ENDL; - return; - } - LLAssetRequest *req = (LLAssetRequest *)user_data; - BOOL success = TRUE; - - if (result) - { - LL_WARNS() << "LLAssetStorage::uploadCompleteCallback " << result << ":" << getErrorString(result) << " trying to upload file to upstream provider" << LL_ENDL; - success = FALSE; - } - - // we're done grabbing the file, tell the client - gAssetStorage->mMessageSys->newMessageFast(_PREHASH_AssetUploadComplete); - gAssetStorage->mMessageSys->nextBlockFast(_PREHASH_AssetBlock); - gAssetStorage->mMessageSys->addUUIDFast(_PREHASH_UUID, uuid); - gAssetStorage->mMessageSys->addS8Fast(_PREHASH_Type, req->getType()); - gAssetStorage->mMessageSys->addBOOLFast(_PREHASH_Success, success); - gAssetStorage->mMessageSys->sendReliable(req->mHost); - - delete req; +void LLAssetStorage::uploadCompleteCallback( + const LLUUID& uuid, + void *user_data, + S32 result, + LLExtStat ext_status) // StoreAssetData callback (fixed) +{ + if (!gAssetStorage) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::uploadCompleteCallback has no gAssetStorage!" << LL_ENDL; + return; + } + LLAssetRequest *req = (LLAssetRequest *)user_data; + BOOL success = TRUE; + + if (result) + { + LL_WARNS("AssetStorage") << "LLAssetStorage::uploadCompleteCallback " << result << ":" << getErrorString(result) << " trying to upload file to upstream provider" << LL_ENDL; + success = FALSE; + } + + // we're done grabbing the file, tell the client + gAssetStorage->mMessageSys->newMessageFast(_PREHASH_AssetUploadComplete); + gAssetStorage->mMessageSys->nextBlockFast(_PREHASH_AssetBlock); + gAssetStorage->mMessageSys->addUUIDFast(_PREHASH_UUID, uuid); + gAssetStorage->mMessageSys->addS8Fast(_PREHASH_Type, req->getType()); + gAssetStorage->mMessageSys->addBOOLFast(_PREHASH_Success, success); + gAssetStorage->mMessageSys->sendReliable(req->mHost); + + delete req; } void LLAssetStorage::processUploadComplete(LLMessageSystem *msg, void **user_data) { - LLAssetStorage *this_ptr = (LLAssetStorage *)user_data; - LLUUID uuid; - S8 asset_type_s8; - LLAssetType::EType asset_type; - BOOL success = FALSE; - - msg->getUUIDFast(_PREHASH_AssetBlock, _PREHASH_UUID, uuid); - msg->getS8Fast(_PREHASH_AssetBlock, _PREHASH_Type, asset_type_s8); - msg->getBOOLFast(_PREHASH_AssetBlock, _PREHASH_Success, success); - - asset_type = (LLAssetType::EType)asset_type_s8; - this_ptr->_callUploadCallbacks(uuid, asset_type, success, LL_EXSTAT_NONE); + LLAssetStorage *this_ptr = (LLAssetStorage *)user_data; + LLUUID uuid; + S8 asset_type_s8; + LLAssetType::EType asset_type; + BOOL success = FALSE; + + msg->getUUIDFast(_PREHASH_AssetBlock, _PREHASH_UUID, uuid); + msg->getS8Fast(_PREHASH_AssetBlock, _PREHASH_Type, asset_type_s8); + msg->getBOOLFast(_PREHASH_AssetBlock, _PREHASH_Success, success); + + asset_type = (LLAssetType::EType)asset_type_s8; + this_ptr->_callUploadCallbacks(uuid, asset_type, success, LL_EXSTAT_NONE); } void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status ) { - // SJB: We process the callbacks in reverse order, I do not know if this is important, - // but I didn't want to mess with it. - request_list_t requests; - for (request_list_t::iterator iter = mPendingUploads.begin(); - iter != mPendingUploads.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* req = *curiter; - if ((req->getUUID() == uuid) && (req->getType() == asset_type)) - { - requests.push_front(req); - iter = mPendingUploads.erase(curiter); - } - } - for (request_list_t::iterator iter = mPendingLocalUploads.begin(); - iter != mPendingLocalUploads.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* req = *curiter; - if ((req->getUUID() == uuid) && (req->getType() == asset_type)) - { - requests.push_front(req); - iter = mPendingLocalUploads.erase(curiter); - } - } - for (request_list_t::iterator iter = requests.begin(); - iter != requests.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* req = *curiter; - if (req->mUpCallback) - { - req->mUpCallback(uuid, req->mUserData, (success ? LL_ERR_NOERR : LL_ERR_ASSET_REQUEST_FAILED ), ext_status ); - } - delete req; - } + // SJB: We process the callbacks in reverse order, I do not know if this is important, + // but I didn't want to mess with it. + request_list_t requests; + for (request_list_t::iterator iter = mPendingUploads.begin(); + iter != mPendingUploads.end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* req = *curiter; + if ((req->getUUID() == uuid) && (req->getType() == asset_type)) + { + requests.push_front(req); + iter = mPendingUploads.erase(curiter); + } + } + for (request_list_t::iterator iter = mPendingLocalUploads.begin(); + iter != mPendingLocalUploads.end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* req = *curiter; + if ((req->getUUID() == uuid) && (req->getType() == asset_type)) + { + requests.push_front(req); + iter = mPendingLocalUploads.erase(curiter); + } + } + for (request_list_t::iterator iter = requests.begin(); + iter != requests.end(); ) + { + request_list_t::iterator curiter = iter++; + LLAssetRequest* req = *curiter; + if (req->mUpCallback) + { + req->mUpCallback(uuid, req->mUserData, (success ? LL_ERR_NOERR : LL_ERR_ASSET_REQUEST_FAILED ), ext_status ); + } + delete req; + } } LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStorage::ERequestType rt) { - switch (rt) - { - case RT_DOWNLOAD: - return &mPendingDownloads; - case RT_UPLOAD: - return &mPendingUploads; - case RT_LOCALUPLOAD: - return &mPendingLocalUploads; - default: - LL_WARNS() << "Unable to find request list for request type '" << rt << "'" << LL_ENDL; - return NULL; - } + switch (rt) + { + case RT_DOWNLOAD: + return &mPendingDownloads; + case RT_UPLOAD: + return &mPendingUploads; + case RT_LOCALUPLOAD: + return &mPendingLocalUploads; + default: + LL_WARNS("AssetStorage") << "Unable to find request list for request type '" << rt << "'" << LL_ENDL; + return NULL; + } } const LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStorage::ERequestType rt) const { - switch (rt) - { - case RT_DOWNLOAD: - return &mPendingDownloads; - case RT_UPLOAD: - return &mPendingUploads; - case RT_LOCALUPLOAD: - return &mPendingLocalUploads; - default: - LL_WARNS() << "Unable to find request list for request type '" << rt << "'" << LL_ENDL; - return NULL; - } + switch (rt) + { + case RT_DOWNLOAD: + return &mPendingDownloads; + case RT_UPLOAD: + return &mPendingUploads; + case RT_LOCALUPLOAD: + return &mPendingLocalUploads; + default: + LL_WARNS("AssetStorage") << "Unable to find request list for request type '" << rt << "'" << LL_ENDL; + return NULL; + } } // static std::string LLAssetStorage::getRequestName(LLAssetStorage::ERequestType rt) { - switch (rt) - { - case RT_DOWNLOAD: - return "download"; - case RT_UPLOAD: - return "upload"; - case RT_LOCALUPLOAD: - return "localupload"; - default: - LL_WARNS() << "Unable to find request name for request type '" << rt << "'" << LL_ENDL; - return ""; - } + switch (rt) + { + case RT_DOWNLOAD: + return "download"; + case RT_UPLOAD: + return "upload"; + case RT_LOCALUPLOAD: + return "localupload"; + default: + LL_WARNS("AssetStorage") << "Unable to find request name for request type '" << rt << "'" << LL_ENDL; + return ""; + } } S32 LLAssetStorage::getNumPending(LLAssetStorage::ERequestType rt) const { - const request_list_t* requests = getRequestList(rt); - S32 num_pending = -1; - if (requests) - { - num_pending = requests->size(); - } - return num_pending; + const request_list_t* requests = getRequestList(rt); + S32 num_pending = -1; + if (requests) + { + num_pending = requests->size(); + } + return num_pending; } S32 LLAssetStorage::getNumPendingDownloads() const { - return getNumPending(RT_DOWNLOAD); + return getNumPending(RT_DOWNLOAD); } S32 LLAssetStorage::getNumPendingUploads() const { - return getNumPending(RT_UPLOAD); + return getNumPending(RT_UPLOAD); } S32 LLAssetStorage::getNumPendingLocalUploads() { - return getNumPending(RT_LOCALUPLOAD); + return getNumPending(RT_LOCALUPLOAD); } -// virtual LLSD LLAssetStorage::getPendingDetails(LLAssetStorage::ERequestType rt, - LLAssetType::EType asset_type, - const std::string& detail_prefix) const + LLAssetType::EType asset_type, + const std::string& detail_prefix) const { - const request_list_t* requests = getRequestList(rt); - LLSD sd; - sd["requests"] = getPendingDetailsImpl(requests, asset_type, detail_prefix); - return sd; + const request_list_t* requests = getRequestList(rt); + LLSD sd; + sd["requests"] = getPendingDetailsImpl(requests, asset_type, detail_prefix); + return sd; } -// virtual LLSD LLAssetStorage::getPendingDetailsImpl(const LLAssetStorage::request_list_t* requests, - LLAssetType::EType asset_type, - const std::string& detail_prefix) const -{ - LLSD details; - if (requests) - { - request_list_t::const_iterator it = requests->begin(); - request_list_t::const_iterator end = requests->end(); - for ( ; it != end; ++it) - { - LLAssetRequest* req = *it; - if ( (LLAssetType::AT_NONE == asset_type) - || (req->getType() == asset_type) ) - { - LLSD row = req->getTerseDetails(); - - std::ostringstream detail; - detail << detail_prefix << "/" << LLAssetType::lookup(req->getType()) - << "/" << req->getUUID(); - row["detail"] = LLURI(detail.str()); - - details.append(row); - } - } - } - return details; + LLAssetType::EType asset_type, + const std::string& detail_prefix) const +{ + LLSD details; + if (requests) + { + request_list_t::const_iterator it = requests->begin(); + request_list_t::const_iterator end = requests->end(); + for ( ; it != end; ++it) + { + LLAssetRequest* req = *it; + if ( (LLAssetType::AT_NONE == asset_type) + || (req->getType() == asset_type) ) + { + LLSD row = req->getTerseDetails(); + + std::ostringstream detail; + detail << detail_prefix << "/" << LLAssetType::lookup(req->getType()) + << "/" << req->getUUID(); + row["detail"] = LLURI(detail.str()); + + details.append(row); + } + } + } + return details; } // static const LLAssetRequest* LLAssetStorage::findRequest(const LLAssetStorage::request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id) -{ - if (requests) - { - // Search the requests list for the asset. - request_list_t::const_iterator iter = requests->begin(); - request_list_t::const_iterator end = requests->end(); - for (; iter != end; ++iter) - { - const LLAssetRequest* req = *iter; - if (asset_type == req->getType() && - asset_id == req->getUUID() ) - { - return req; - } - } - } - return NULL; + LLAssetType::EType asset_type, + const LLUUID& asset_id) +{ + if (requests) + { + // Search the requests list for the asset. + request_list_t::const_iterator iter = requests->begin(); + request_list_t::const_iterator end = requests->end(); + for (; iter != end; ++iter) + { + const LLAssetRequest* req = *iter; + if (asset_type == req->getType() && + asset_id == req->getUUID() ) + { + return req; + } + } + } + return NULL; } // static LLAssetRequest* LLAssetStorage::findRequest(LLAssetStorage::request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id) -{ - if (requests) - { - // Search the requests list for the asset. - request_list_t::iterator iter = requests->begin(); - request_list_t::iterator end = requests->end(); - for (; iter != end; ++iter) - { - LLAssetRequest* req = *iter; - if (asset_type == req->getType() && - asset_id == req->getUUID() ) - { - return req; - } - } - } - return NULL; + LLAssetType::EType asset_type, + const LLUUID& asset_id) +{ + if (requests) + { + // Search the requests list for the asset. + request_list_t::iterator iter = requests->begin(); + request_list_t::iterator end = requests->end(); + for (; iter != end; ++iter) + { + LLAssetRequest* req = *iter; + if (asset_type == req->getType() && + asset_id == req->getUUID() ) + { + return req; + } + } + } + return NULL; } -// virtual LLSD LLAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt, - LLAssetType::EType asset_type, - const LLUUID& asset_id) const + LLAssetType::EType asset_type, + const LLUUID& asset_id) const { - const request_list_t* requests = getRequestList(rt); - return getPendingRequestImpl(requests, asset_type, asset_id); + const request_list_t* requests = getRequestList(rt); + return getPendingRequestImpl(requests, asset_type, asset_id); } -// virtual LLSD LLAssetStorage::getPendingRequestImpl(const LLAssetStorage::request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id) const + LLAssetType::EType asset_type, + const LLUUID& asset_id) const { - LLSD sd; - const LLAssetRequest* req = findRequest(requests, asset_type, asset_id); - if (req) - { - sd = req->getFullDetails(); - } - return sd; + LLSD sd; + const LLAssetRequest* req = findRequest(requests, asset_type, asset_id); + if (req) + { + sd = req->getFullDetails(); + } + return sd; } -// virtual bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt, - LLAssetType::EType asset_type, - const LLUUID& asset_id) + LLAssetType::EType asset_type, + const LLUUID& asset_id) { - request_list_t* requests = getRequestList(rt); - if (deletePendingRequestImpl(requests, asset_type, asset_id)) - { - LL_DEBUGS("AssetStorage") << "Asset " << getRequestName(rt) << " request for " - << asset_id << "." << LLAssetType::lookup(asset_type) - << " removed from pending queue." << LL_ENDL; - return true; - } - return false; + request_list_t* requests = getRequestList(rt); + if (deletePendingRequestImpl(requests, asset_type, asset_id)) + { + LL_DEBUGS("AssetStorage") << "Asset " << getRequestName(rt) << " request for " + << asset_id << "." << LLAssetType::lookup(asset_type) + << " removed from pending queue." << LL_ENDL; + return true; + } + return false; } -// virtual bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id) -{ - LLAssetRequest* req = findRequest(requests, asset_type, asset_id); - if (req) - { - // Remove the request from this list. - requests->remove(req); - S32 error = LL_ERR_TCP_TIMEOUT; - // Run callbacks. - if (req->mUpCallback) - { - req->mUpCallback(req->getUUID(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED); - } - if (req->mDownCallback) - { - add(sFailedDownloadCount, 1); - req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED); - } - if (req->mInfoCallback) - { - LLAssetInfo info; - req->mInfoCallback(&info, req->mUserData, error); - } - delete req; - return true; - } - - return false; + LLAssetType::EType asset_type, + const LLUUID& asset_id) +{ + LLAssetRequest* req = findRequest(requests, asset_type, asset_id); + if (req) + { + // Remove the request from this list. + requests->remove(req); + S32 error = LL_ERR_TCP_TIMEOUT; + // Run callbacks. + if (req->mUpCallback) + { + req->mUpCallback(req->getUUID(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED); + } + if (req->mDownCallback) + { + add(sFailedDownloadCount, 1); + req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED); + } + if (req->mInfoCallback) + { + LLAssetInfo info; + req->mInfoCallback(&info, req->mUserData, error); + } + delete req; + return true; + } + + return false; } // static const char* LLAssetStorage::getErrorString(S32 status) { - switch( status ) - { - case LL_ERR_NOERR: - return "No error"; + switch( status ) + { + case LL_ERR_NOERR: + return "No error"; - case LL_ERR_ASSET_REQUEST_FAILED: - return "Asset request: failed"; + case LL_ERR_ASSET_REQUEST_FAILED: + return "Asset request: failed"; - case LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE: - return "Asset request: non-existent file"; + case LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE: + return "Asset request: non-existent file"; - case LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE: - return "Asset request: asset not found in database"; + case LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE: + return "Asset request: asset not found in database"; - case LL_ERR_EOF: - return "End of file"; + case LL_ERR_EOF: + return "End of file"; - case LL_ERR_CANNOT_OPEN_FILE: - return "Cannot open file"; + case LL_ERR_CANNOT_OPEN_FILE: + return "Cannot open file"; - case LL_ERR_FILE_NOT_FOUND: - return "File not found"; + case LL_ERR_FILE_NOT_FOUND: + return "File not found"; - case LL_ERR_TCP_TIMEOUT: - return "File transfer timeout"; + case LL_ERR_TCP_TIMEOUT: + return "File transfer timeout"; - case LL_ERR_CIRCUIT_GONE: - return "Circuit gone"; + case LL_ERR_CIRCUIT_GONE: + return "Circuit gone"; - case LL_ERR_PRICE_MISMATCH: - return "Viewer and server do not agree on price"; + case LL_ERR_PRICE_MISMATCH: + return "Viewer and server do not agree on price"; - default: - return "Unknown status"; - } + default: + return "Unknown status"; + } } - - -void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, BOOL is_priority) +void LLAssetStorage::getAssetData(const LLUUID uuid, + LLAssetType::EType type, + void (*callback)(const char*, + const LLUUID&, + void *, + S32, + LLExtStat), + void *user_data, + BOOL is_priority) { - // check for duplicates here, since we're about to fool the normal duplicate checker - for (request_list_t::iterator iter = mPendingDownloads.begin(); - iter != mPendingDownloads.end(); ) - { - LLAssetRequest* tmp = *iter++; - if (type == tmp->getType() && - uuid == tmp->getUUID() && - legacyGetDataCallback == tmp->mDownCallback && - callback == ((LLLegacyAssetRequest *)tmp->mUserData)->mDownCallback && - user_data == ((LLLegacyAssetRequest *)tmp->mUserData)->mUserData) - { - // this is a duplicate from the same subsystem - throw it away - LL_DEBUGS("AssetStorage") << "Discarding duplicate request for UUID " << uuid << LL_ENDL; - return; - } - } - - - LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest; - - legacy->mDownCallback = callback; - legacy->mUserData = user_data; - - getAssetData(uuid, type, legacyGetDataCallback, (void **)legacy, - is_priority); -} + // check for duplicates here, since we're about to fool the normal duplicate checker + for (request_list_t::iterator iter = mPendingDownloads.begin(); + iter != mPendingDownloads.end(); ) + { + LLAssetRequest* tmp = *iter++; + if (type == tmp->getType() && + uuid == tmp->getUUID() && + legacyGetDataCallback == tmp->mDownCallback && + callback == ((LLLegacyAssetRequest *)tmp->mUserData)->mDownCallback && + user_data == ((LLLegacyAssetRequest *)tmp->mUserData)->mUserData) + { + // this is a duplicate from the same subsystem - throw it away + LL_DEBUGS("AssetStorage") << "Discarding duplicate request for UUID " << uuid << LL_ENDL; + return; + } + } + + + LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest; -// static -void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 status, LLExtStat ext_status) -{ - LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data; - std::string filename; - - // Check if the asset is marked toxic, and don't load bad stuff - BOOL toxic = gAssetStorage->isAssetToxic( uuid ); - - if ( !status - && !toxic ) - { - LLVFile file(vfs, uuid, type); - - std::string uuid_str; - - uuid.toString(uuid_str); - filename = llformat("%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type)); - - LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ - if (fp) - { - const S32 buf_size = 65536; - U8 copy_buf[buf_size]; - while (file.read(copy_buf, buf_size)) /* Flawfinder: ignore */ - { - if (fwrite(copy_buf, file.getLastBytesRead(), 1, fp) < 1) - { - // return a bad file error if we can't write the whole thing - status = LL_ERR_CANNOT_OPEN_FILE; - } - } - - fclose(fp); - } - else - { - status = LL_ERR_CANNOT_OPEN_FILE; - } - } - - if (status != LL_ERR_NOERR) - { - add(sFailedDownloadCount, 1); - } - legacy->mDownCallback(filename.c_str(), uuid, legacy->mUserData, status, ext_status); - delete legacy; -} - -// this is overridden on the viewer and the sim, so it doesn't really do anything -// virtual -void LLAssetStorage::storeAssetData( - const LLTransactionID& tid, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file, - bool is_priority, - bool store_local, - bool user_waiting, - F64Seconds timeout) -{ - LL_WARNS() << "storeAssetData: wrong version called" << LL_ENDL; - // LLAssetStorage metric: Virtual base call - reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 1" ); -} - -// virtual -// this does nothing, viewer and sim both override this. -void LLAssetStorage::storeAssetData( - const LLUUID& asset_id, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file , - bool is_priority, - bool store_local, - const LLUUID& requesting_agent_id, - bool user_waiting, - F64Seconds timeout) -{ - LL_WARNS() << "storeAssetData: wrong version called" << LL_ENDL; - // LLAssetStorage metric: Virtual base call - reportMetric( asset_id, asset_type, LLStringUtil::null, requesting_agent_id, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 2" ); -} + legacy->mDownCallback = callback; + legacy->mUserData = user_data; -// virtual -// this does nothing, viewer and sim both override this. -void LLAssetStorage::storeAssetData( - const std::string& filename, - const LLUUID& asset_id, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file, - bool is_priority, - bool user_waiting, - F64Seconds timeout) -{ - LL_WARNS() << "storeAssetData: wrong version called" << LL_ENDL; - // LLAssetStorage metric: Virtual base call - reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 3" ); + getAssetData(uuid, type, legacyGetDataCallback, (void **)legacy, + is_priority); } -// virtual -// this does nothing, viewer and sim both override this. -void LLAssetStorage::storeAssetData( - const std::string& filename, - const LLTransactionID &transactoin_id, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file, - bool is_priority, - bool user_waiting, - F64Seconds timeout) -{ - LL_WARNS() << "storeAssetData: wrong version called" << LL_ENDL; - // LLAssetStorage metric: Virtual base call - reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 4" ); +// static +void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, + const LLUUID &uuid, + LLAssetType::EType type, + void *user_data, + S32 status, + LLExtStat ext_status) +{ + LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data; + std::string filename; + + // Check if the asset is marked toxic, and don't load bad stuff + BOOL toxic = gAssetStorage->isAssetToxic( uuid ); + + if ( !status + && !toxic ) + { + LLVFile file(vfs, uuid, type); + + std::string uuid_str; + + uuid.toString(uuid_str); + filename = llformat("%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type)); + + LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ + if (fp) + { + const S32 buf_size = 65536; + U8 copy_buf[buf_size]; + while (file.read(copy_buf, buf_size)) /* Flawfinder: ignore */ + { + if (fwrite(copy_buf, file.getLastBytesRead(), 1, fp) < 1) + { + // return a bad file error if we can't write the whole thing + status = LL_ERR_CANNOT_OPEN_FILE; + } + } + + fclose(fp); + } + else + { + status = LL_ERR_CANNOT_OPEN_FILE; + } + } + + if (status != LL_ERR_NOERR) + { + add(sFailedDownloadCount, 1); + } + legacy->mDownCallback(filename.c_str(), uuid, legacy->mUserData, status, ext_status); + delete legacy; } // static void LLAssetStorage::legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status) { - LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data; - if (legacy && legacy->mUpCallback) - { - legacy->mUpCallback(uuid, legacy->mUserData, status, ext_status); - } - delete legacy; + LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data; + if (legacy && legacy->mUpCallback) + { + legacy->mUpCallback(uuid, legacy->mUserData, status, ext_status); + } + delete legacy; } -// virtual -void LLAssetStorage::addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name) -{ } - -// virtual -BOOL LLAssetStorage::hasTempAssetData(const LLUUID& texture_id) const -{ return FALSE; } - -// virtual -std::string LLAssetStorage::getTempAssetHostName(const LLUUID& texture_id) const -{ return std::string(); } - -// virtual -LLUUID LLAssetStorage::getTempAssetAgentID(const LLUUID& texture_id) const -{ return LLUUID::null; } - -// virtual -void LLAssetStorage::removeTempAssetData(const LLUUID& asset_id) -{ } - -// virtual -void LLAssetStorage::removeTempAssetDataByAgentID(const LLUUID& agent_id) -{ } - -// virtual -void LLAssetStorage::dumpTempAssetData(const LLUUID& avatar_id) const -{ } - -// virtual -void LLAssetStorage::clearTempAssetData() -{ } - // static void LLAssetStorage::reportMetric( const LLUUID& asset_id, const LLAssetType::EType asset_type, const std::string& in_filename, - const LLUUID& agent_id, S32 asset_size, EMetricResult result, - const char *file, const S32 line, const std::string& in_message ) -{ - if( !metric_recipient ) - { - LL_DEBUGS("AssetStorage") << "Couldn't store LLAssetStoreage::reportMetric - no metrics_recipient" << LL_ENDL; - return; - } - - std::string filename(in_filename); - if (filename.empty()) - filename = ll_safe_string(file); - - // Create revised message - new_message = "in_message :: file:line" - std::stringstream new_message; - new_message << in_message << " :: " << filename << ":" << line; - - // Change always_report to true if debugging... do not check it in this way - static bool always_report = false; - const char *metric_name = "LLAssetStorage::Metrics"; - - bool success = result == MR_OKAY; - - if( (!success) || always_report ) - { - LLSD stats; - stats["asset_id"] = asset_id; - stats["asset_type"] = asset_type; - stats["filename"] = filename; - stats["agent_id"] = agent_id; - stats["asset_size"] = (S32)asset_size; - stats["result"] = (S32)result; - - metric_recipient->recordEventDetails( metric_name, new_message.str(), success, stats); - } - else - { - metric_recipient->recordEvent(metric_name, new_message.str(), success); - } + const LLUUID& agent_id, S32 asset_size, EMetricResult result, + const char *file, const S32 line, const std::string& in_message ) +{ + if( !metric_recipient ) + { + LL_DEBUGS("AssetStorage") << "Couldn't store LLAssetStoreage::reportMetric - no metrics_recipient" << LL_ENDL; + return; + } + + std::string filename(in_filename); + if (filename.empty()) + filename = ll_safe_string(file); + + // Create revised message - new_message = "in_message :: file:line" + std::stringstream new_message; + new_message << in_message << " :: " << filename << ":" << line; + + // Change always_report to true if debugging... do not check it in this way + static bool always_report = false; + const char *metric_name = "LLAssetStorage::Metrics"; + + bool success = result == MR_OKAY; + + if( (!success) || always_report ) + { + LLSD stats; + stats["asset_id"] = asset_id; + stats["asset_type"] = asset_type; + stats["filename"] = filename; + stats["agent_id"] = agent_id; + stats["asset_size"] = (S32)asset_size; + stats["result"] = (S32)result; + + metric_recipient->recordEventDetails( metric_name, new_message.str(), success, stats); + } + else + { + metric_recipient->recordEvent(metric_name, new_message.str(), success); + } } // Check if an asset is in the toxic map. If it is, the entry is updated -BOOL LLAssetStorage::isAssetToxic( const LLUUID& uuid ) +BOOL LLAssetStorage::isAssetToxic( const LLUUID& uuid ) { - BOOL is_toxic = FALSE; - - if ( !uuid.isNull() ) - { - toxic_asset_map_t::iterator iter = mToxicAssetMap.find( uuid ); - if ( iter != mToxicAssetMap.end() ) - { // Found toxic asset - (*iter).second = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME; - is_toxic = TRUE; - } - } - return is_toxic; + BOOL is_toxic = FALSE; + + if ( !uuid.isNull() ) + { + toxic_asset_map_t::iterator iter = mToxicAssetMap.find( uuid ); + if ( iter != mToxicAssetMap.end() ) + { // Found toxic asset + (*iter).second = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME; + is_toxic = TRUE; + } + } + return is_toxic; } // Clean the toxic asset list, remove old entries -void LLAssetStorage::flushOldToxicAssets( BOOL force_it ) -{ - // Scan and look for old entries - U64 now = LLFrameTimer::getTotalTime(); - toxic_asset_map_t::iterator iter = mToxicAssetMap.begin(); - while ( iter != mToxicAssetMap.end() ) - { - if ( force_it - || (*iter).second < now ) - { // Too old - remove it - mToxicAssetMap.erase( iter++ ); - } - else - { - iter++; - } - } +void LLAssetStorage::flushOldToxicAssets( BOOL force_it ) +{ + // Scan and look for old entries + U64 now = LLFrameTimer::getTotalTime(); + toxic_asset_map_t::iterator iter = mToxicAssetMap.begin(); + while ( iter != mToxicAssetMap.end() ) + { + if ( force_it + || (*iter).second < now ) + { // Too old - remove it + mToxicAssetMap.erase( iter++ ); + } + else + { + iter++; + } + } } // Add an item to the toxic asset map -void LLAssetStorage::markAssetToxic( const LLUUID& uuid ) -{ - if ( !uuid.isNull() ) - { - // Set the value to the current time. Creates a new entry if needed - mToxicAssetMap[ uuid ] = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME; - } +void LLAssetStorage::markAssetToxic( const LLUUID& uuid ) +{ + if ( !uuid.isNull() ) + { + // Set the value to the current time. Creates a new entry if needed + mToxicAssetMap[ uuid ] = LLFrameTimer::getTotalTime() + TOXIC_ASSET_LIFETIME; + } } diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h index 0f23754096..33b88473b9 100644 --- a/indra/llmessage/llassetstorage.h +++ b/indra/llmessage/llassetstorage.h @@ -138,6 +138,7 @@ public: BOOL mIsUserWaiting; // We don't want to try forever if a user is waiting for a result. F64Seconds mTimeout; // Amount of time before timing out. LLUUID mRequestingAgentID; // Only valid for uploads from an agent + F64 mBytesFetched; virtual LLSD getTerseDetails() const; virtual LLSD getFullDetails() const; @@ -186,18 +187,9 @@ typedef std::map<LLUUID,U64,lluuid_less> toxic_asset_map_t; // we can use bind and remove the userData parameter. // typedef void (*LLGetAssetCallback)(LLVFS *vfs, const LLUUID &asset_id, - LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status); + LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status); -class LLTempAssetStorage -{ -public: - virtual ~LLTempAssetStorage() =0; - virtual void addTempAssetData(const LLUUID& asset_id, - const LLUUID& agent_id, - const std::string& host_name) = 0; -}; - -class LLAssetStorage : public LLTempAssetStorage +class LLAssetStorage { public: // VFS member is public because static child methods need it :( @@ -240,12 +232,11 @@ public: void setUpstream(const LLHost &upstream_host); - virtual BOOL hasLocalAsset(const LLUUID &uuid, LLAssetType::EType type); + BOOL hasLocalAsset(const LLUUID &uuid, LLAssetType::EType type); // public interface methods // note that your callback may get called BEFORE the function returns - - virtual void getAssetData(const LLUUID uuid, LLAssetType::EType atype, LLGetAssetCallback cb, void *user_data, BOOL is_priority = FALSE); + void getAssetData(const LLUUID uuid, LLAssetType::EType atype, LLGetAssetCallback cb, void *user_data, BOOL is_priority = FALSE); /* * TransactionID version @@ -260,25 +251,11 @@ public: bool is_priority = false, bool store_local = false, bool user_waiting= false, - F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT); - - /* - * AssetID version - * Sim needs both store_local and requesting_agent_id. - */ - virtual void storeAssetData( - const LLUUID& asset_id, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file = false, - bool is_priority = false, - bool store_local = false, - const LLUUID& requesting_agent_id = LLUUID::null, - bool user_waiting= false, - F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT); + F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT) = 0; - virtual void checkForTimeouts(); + virtual void logAssetStorageInfo() = 0; + + void checkForTimeouts(); void getEstateAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id, const LLUUID &asset_id, LLAssetType::EType atype, EstateAssetType etype, @@ -303,17 +280,17 @@ protected: bool findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type, LLGetAssetCallback callback, void *user_data); - virtual LLSD getPendingDetailsImpl(const request_list_t* requests, - LLAssetType::EType asset_type, - const std::string& detail_prefix) const; + LLSD getPendingDetailsImpl(const request_list_t* requests, + LLAssetType::EType asset_type, + const std::string& detail_prefix) const; - virtual LLSD getPendingRequestImpl(const request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id) const; + LLSD getPendingRequestImpl(const request_list_t* requests, + LLAssetType::EType asset_type, + const LLUUID& asset_id) const; - virtual bool deletePendingRequestImpl(request_list_t* requests, - LLAssetType::EType asset_type, - const LLUUID& asset_id); + bool deletePendingRequestImpl(request_list_t* requests, + LLAssetType::EType asset_type, + const LLUUID& asset_id); public: static const LLAssetRequest* findRequest(const request_list_t* requests, @@ -332,19 +309,23 @@ public: S32 getNumPendingLocalUploads(); S32 getNumPending(ERequestType rt) const; - virtual LLSD getPendingDetails(ERequestType rt, - LLAssetType::EType asset_type, - const std::string& detail_prefix) const; + LLSD getPendingDetails(ERequestType rt, + LLAssetType::EType asset_type, + const std::string& detail_prefix) const; - virtual LLSD getPendingRequest(ERequestType rt, - LLAssetType::EType asset_type, - const LLUUID& asset_id) const; + LLSD getPendingRequest(ERequestType rt, + LLAssetType::EType asset_type, + const LLUUID& asset_id) const; - virtual bool deletePendingRequest(ERequestType rt, - LLAssetType::EType asset_type, - const LLUUID& asset_id); + bool deletePendingRequest(ERequestType rt, + LLAssetType::EType asset_type, + const LLUUID& asset_id); + static void removeAndCallbackPendingDownloads(const LLUUID& file_id, LLAssetType::EType file_type, + const LLUUID& callback_id, LLAssetType::EType callback_type, + S32 result_code, LLExtStat ext_status); + // download process callbacks static void downloadCompleteCallback( S32 result, @@ -370,23 +351,10 @@ public: static const char* getErrorString( S32 status ); // deprecated file-based methods + // Not overriden void getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, BOOL is_priority = FALSE); /* - * AssetID version. - */ - virtual void storeAssetData( - const std::string& filename, - const LLUUID& asset_id, - LLAssetType::EType type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file = false, - bool is_priority = false, - bool user_waiting = false, - F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT); - - /* * TransactionID version */ virtual void storeAssetData( @@ -398,23 +366,11 @@ public: bool temp_file = false, bool is_priority = false, bool user_waiting = false, - F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT); + F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT) = 0; static void legacyGetDataCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType, void *user_data, S32 status, LLExtStat ext_status); static void legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status); - // Temp assets are stored on sim nodes, they have agent ID and location data associated with them. - // This is a no-op for non-http asset systems - virtual void addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name); - virtual BOOL hasTempAssetData(const LLUUID& texture_id) const; - virtual std::string getTempAssetHostName(const LLUUID& texture_id) const; - virtual LLUUID getTempAssetAgentID(const LLUUID& texture_id) const; - virtual void removeTempAssetData(const LLUUID& asset_id); - virtual void removeTempAssetDataByAgentID(const LLUUID& agent_id); - // Pass LLUUID::null for all - virtual void dumpTempAssetData(const LLUUID& avatar_id) const; - virtual void clearTempAssetData(); - // add extra methods to handle metadata protected: @@ -424,7 +380,7 @@ protected: virtual void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type, void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), void *user_data, BOOL duplicate, - BOOL is_priority); + BOOL is_priority) = 0; private: void _init(LLMessageSystem *msg, diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index de31425c27..fbc984692d 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -14694,6 +14694,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>AssetStorageLogFrequency</key> + <map> + <key>Comment</key> + <string>Seconds between display of AssetStorage info in log (0 for never)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>60.0</real> + </map> <key>LogWearableAssetSave</key> <map> <key>Comment</key> @@ -14767,6 +14778,15 @@ <key>Value</key> <real>1</real> </map> + <key>PoolSizeAssetStorage</key> + <map> + <key>Comment</key> + <string>Coroutine Pool size for AssetStorage requests</string> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <real>12</real> + </map> <!-- Settings below are for back compatibility only. They are not used in current viewer anymore. But they can't be removed to avoid diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a26ee2204b..da247c7bf6 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -839,12 +839,6 @@ bool LLAppViewer::init() LLMachineID::init(); { - // Viewer metrics initialization - //static LLCachedControl<bool> metrics_submode(gSavedSettings, - // "QAModeMetrics", - // false, - // "Enables QA features (logging, faster cycling) for metrics collector"); - if (gSavedSettings.getBOOL("QAModeMetrics")) { app_metrics_qa_mode = true; @@ -5927,23 +5921,14 @@ void LLAppViewer::metricsSend(bool enable_reporting) { std::string caps_url = regionp->getCapability("ViewerMetrics"); - if (gSavedSettings.getBOOL("QAModeMetrics")) - { - dump_sequential_xml("metric_asset_stats",gViewerAssetStats->asLLSD(true)); - } - - // Make a copy of the main stats to send into another thread. - // Receiving thread takes ownership. - LLViewerAssetStats * main_stats(new LLViewerAssetStats(*gViewerAssetStats)); - main_stats->stop(); - + LLSD sd = gViewerAssetStats->asLLSD(true); + // Send a report request into 'thread1' to get the rest of the data // and provide some additional parameters while here. LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, gAgentSessionID, gAgentID, - main_stats); - main_stats = 0; // Ownership transferred + sd); } else { diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index f7e0e32256..c4d1917567 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -343,10 +343,6 @@ LLMeshRepository gMeshRepo; const S32 MESH_HEADER_SIZE = 4096; // Important: assumption is that headers fit in this space -const S32 REQUEST_HIGH_WATER_MIN = 32; // Limits for GetMesh regions -const S32 REQUEST_HIGH_WATER_MAX = 150; // Should remain under 2X throttle -const S32 REQUEST_LOW_WATER_MIN = 16; -const S32 REQUEST_LOW_WATER_MAX = 75; const S32 REQUEST2_HIGH_WATER_MIN = 32; // Limits for GetMesh2 regions const S32 REQUEST2_HIGH_WATER_MAX = 100; @@ -808,10 +804,8 @@ LLMeshRepoThread::LLMeshRepoThread() mHttpLargeOptions(), mHttpHeaders(), mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), - mHttpLegacyPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), mHttpLargePolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), - mHttpPriority(0), - mGetMeshVersion(2) + mHttpPriority(0) { LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); @@ -828,7 +822,6 @@ LLMeshRepoThread::LLMeshRepoThread() mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_VND_LL_MESH); mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_MESH2); - mHttpLegacyPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_MESH1); mHttpLargePolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_LARGE_MESH); } @@ -1103,13 +1096,9 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) } // Mutex: must be holding mMutex when called -void LLMeshRepoThread::setGetMeshCaps(const std::string & get_mesh1, - const std::string & get_mesh2, - int pref_version) +void LLMeshRepoThread::setGetMeshCap(const std::string & mesh_cap) { - mGetMeshCapability = get_mesh1; - mGetMesh2Capability = get_mesh2; - mGetMeshVersion = pref_version; + mGetMeshCapability = mesh_cap; } @@ -1117,29 +1106,14 @@ void LLMeshRepoThread::setGetMeshCaps(const std::string & get_mesh1, // over a GetMesh cap. // // Mutex: acquires mMutex -void LLMeshRepoThread::constructUrl(LLUUID mesh_id, std::string * url, int * version) +void LLMeshRepoThread::constructUrl(LLUUID mesh_id, std::string * url) { std::string res_url; - int res_version(2); if (gAgent.getRegion()) { LLMutexLock lock(mMutex); - - // Get a consistent pair of (cap string, version). The - // locking could be eliminated here without loss of safety - // by using a set of staging values in setGetMeshCaps(). - - if (! mGetMesh2Capability.empty() && mGetMeshVersion > 1) - { - res_url = mGetMesh2Capability; - res_version = 2; - } - else - { - res_url = mGetMeshCapability; - res_version = 1; - } + res_url = mGetMeshCapability; } if (! res_url.empty()) @@ -1149,19 +1123,15 @@ void LLMeshRepoThread::constructUrl(LLUUID mesh_id, std::string * url, int * ver } else { - LL_WARNS_ONCE(LOG_MESH) << "Current region does not have GetMesh capability! Cannot load " + LL_WARNS_ONCE(LOG_MESH) << "Current region does not have ViewerAsset capability! Cannot load " << mesh_id << ".mesh" << LL_ENDL; } *url = res_url; - *version = res_version; } // Issue an HTTP GET request with byte range using the right -// policy class. Large requests go to the large request class. -// If the current region supports GetMesh2, we prefer that for -// smaller requests otherwise we try to use the traditional -// GetMesh capability and connection concurrency. +// policy class. // // @return Valid handle or LLCORE_HTTP_HANDLE_INVALID. // If the latter, actual status is found in @@ -1169,7 +1139,7 @@ void LLMeshRepoThread::constructUrl(LLUUID mesh_id, std::string * url, int * ver // next call to this method. // // Thread: repo -LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int cap_version, +LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, size_t offset, size_t len, const LLCore::HttpHandler::ptr_t &handler) { @@ -1180,16 +1150,14 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int c if (len < LARGE_MESH_FETCH_THRESHOLD) { - handle = mHttpRequest->requestGetByteRange((2 == cap_version - ? mHttpPolicyClass - : mHttpLegacyPolicyClass), - mHttpPriority, - url, - (disable_range_req ? size_t(0) : offset), - (disable_range_req ? size_t(0) : len), - mHttpOptions, - mHttpHeaders, - handler); + handle = mHttpRequest->requestGetByteRange( mHttpPolicyClass, + mHttpPriority, + url, + (disable_range_req ? size_t(0) : offset), + (disable_range_req ? size_t(0) : len), + mHttpOptions, + mHttpHeaders, + handler); if (LLCORE_HTTP_HANDLE_INVALID != handle) { ++LLMeshRepository::sHTTPRequestCount; @@ -1279,14 +1247,13 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) } //reading from VFS failed for whatever reason, fetch from sim - int cap_version(2); std::string http_url; - constructUrl(mesh_id, &http_url, &cap_version); + constructUrl(mesh_id, &http_url); if (!http_url.empty()) { LLMeshHandlerBase::ptr_t handler(new LLMeshSkinInfoHandler(mesh_id, offset, size)); - LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler); + LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler); if (LLCORE_HTTP_HANDLE_INVALID == handle) { LL_WARNS(LOG_MESH) << "HTTP GET request failed for skin info on mesh " << mID @@ -1372,14 +1339,13 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) } //reading from VFS failed for whatever reason, fetch from sim - int cap_version(2); std::string http_url; - constructUrl(mesh_id, &http_url, &cap_version); + constructUrl(mesh_id, &http_url); if (!http_url.empty()) { LLMeshHandlerBase::ptr_t handler(new LLMeshDecompositionHandler(mesh_id, offset, size)); - LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler); + LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler); if (LLCORE_HTTP_HANDLE_INVALID == handle) { LL_WARNS(LOG_MESH) << "HTTP GET request failed for decomposition mesh " << mID @@ -1464,14 +1430,13 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) } //reading from VFS failed for whatever reason, fetch from sim - int cap_version(2); std::string http_url; - constructUrl(mesh_id, &http_url, &cap_version); + constructUrl(mesh_id, &http_url); if (!http_url.empty()) { LLMeshHandlerBase::ptr_t handler(new LLMeshPhysicsShapeHandler(mesh_id, offset, size)); - LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler); + LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler); if (LLCORE_HTTP_HANDLE_INVALID == handle) { LL_WARNS(LOG_MESH) << "HTTP GET request failed for physics shape on mesh " << mID @@ -1558,9 +1523,8 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) //either cache entry doesn't exist or is corrupt, request header from simulator bool retval = true; - int cap_version(2); std::string http_url; - constructUrl(mesh_params.getSculptID(), &http_url, &cap_version); + constructUrl(mesh_params.getSculptID(), &http_url); if (!http_url.empty()) { @@ -1569,7 +1533,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) //NOTE -- this will break of headers ever exceed 4KB LLMeshHandlerBase::ptr_t handler(new LLMeshHeaderHandler(mesh_params, 0, MESH_HEADER_SIZE)); - LLCore::HttpHandle handle = getByteRange(http_url, cap_version, 0, MESH_HEADER_SIZE, handler); + LLCore::HttpHandle handle = getByteRange(http_url, 0, MESH_HEADER_SIZE, handler); if (LLCORE_HTTP_HANDLE_INVALID == handle) { LL_WARNS(LOG_MESH) << "HTTP GET request failed for mesh header " << mID @@ -1645,14 +1609,13 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) } //reading from VFS failed for whatever reason, fetch from sim - int cap_version(2); std::string http_url; - constructUrl(mesh_id, &http_url, &cap_version); + constructUrl(mesh_id, &http_url); if (!http_url.empty()) { LLMeshHandlerBase::ptr_t handler(new LLMeshLODHandler(mesh_params, lod, offset, size)); - LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler); + LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler); if (LLCORE_HTTP_HANDLE_INVALID == handle) { LL_WARNS(LOG_MESH) << "HTTP GET request failed for LOD on mesh " << mID @@ -3292,8 +3255,7 @@ void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * /* body */, S3 LLMeshRepository::LLMeshRepository() : mMeshMutex(NULL), mMeshThreadCount(0), - mThread(NULL), - mGetMeshVersion(2) + mThread(NULL) { } @@ -3476,35 +3438,21 @@ void LLMeshRepository::notifyLoadedMeshes() { //called from main thread LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); - if (1 == mGetMeshVersion) - { - // Legacy GetMesh operation with high connection concurrency - LLMeshRepoThread::sMaxConcurrentRequests = gSavedSettings.getU32("MeshMaxConcurrentRequests"); - LLMeshRepoThread::sRequestHighWater = llclamp(2 * S32(LLMeshRepoThread::sMaxConcurrentRequests), - REQUEST_HIGH_WATER_MIN, - REQUEST_HIGH_WATER_MAX); - LLMeshRepoThread::sRequestLowWater = llclamp(LLMeshRepoThread::sRequestHighWater / 2, - REQUEST_LOW_WATER_MIN, - REQUEST_LOW_WATER_MAX); - } - else - { - // GetMesh2 operation with keepalives, etc. With pipelining, - // we'll increase this. See llappcorehttp and llcorehttp for - // discussion on connection strategies. - LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); - S32 scale(app_core_http.isPipelined(LLAppCoreHttp::AP_MESH2) - ? (2 * LLAppCoreHttp::PIPELINING_DEPTH) - : 5); - - LLMeshRepoThread::sMaxConcurrentRequests = gSavedSettings.getU32("Mesh2MaxConcurrentRequests"); - LLMeshRepoThread::sRequestHighWater = llclamp(scale * S32(LLMeshRepoThread::sMaxConcurrentRequests), - REQUEST2_HIGH_WATER_MIN, - REQUEST2_HIGH_WATER_MAX); - LLMeshRepoThread::sRequestLowWater = llclamp(LLMeshRepoThread::sRequestHighWater / 2, - REQUEST2_LOW_WATER_MIN, - REQUEST2_LOW_WATER_MAX); - } + // GetMesh2 operation with keepalives, etc. With pipelining, + // we'll increase this. See llappcorehttp and llcorehttp for + // discussion on connection strategies. + LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); + S32 scale(app_core_http.isPipelined(LLAppCoreHttp::AP_MESH2) + ? (2 * LLAppCoreHttp::PIPELINING_DEPTH) + : 5); + + LLMeshRepoThread::sMaxConcurrentRequests = gSavedSettings.getU32("Mesh2MaxConcurrentRequests"); + LLMeshRepoThread::sRequestHighWater = llclamp(scale * S32(LLMeshRepoThread::sMaxConcurrentRequests), + REQUEST2_HIGH_WATER_MIN, + REQUEST2_HIGH_WATER_MAX); + LLMeshRepoThread::sRequestLowWater = llclamp(LLMeshRepoThread::sRequestHighWater / 2, + REQUEST2_LOW_WATER_MIN, + REQUEST2_LOW_WATER_MAX); //clean up completed upload threads for (std::vector<LLMeshUploadThread*>::iterator iter = mUploads.begin(); iter != mUploads.end(); ) @@ -3610,15 +3558,10 @@ void LLMeshRepository::notifyLoadedMeshes() if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived()) { region_name = gAgent.getRegion()->getName(); - const bool use_v1(gSavedSettings.getBOOL("MeshUseGetMesh1")); - const std::string mesh1(gAgent.getRegion()->getCapability("GetMesh")); - const std::string mesh2(gAgent.getRegion()->getCapability("GetMesh2")); - mGetMeshVersion = (mesh2.empty() || use_v1) ? 1 : 2; - mThread->setGetMeshCaps(mesh1, mesh2, mGetMeshVersion); + const std::string mesh_cap(gAgent.getRegion()->getViewerAssetUrl()); + mThread->setGetMeshCap(mesh_cap); LL_DEBUGS(LOG_MESH) << "Retrieving caps for region '" << region_name - << "', GetMesh2: " << mesh2 - << ", GetMesh: " << mesh1 - << ", using version: " << mGetMeshVersion + << "', ViewerAsset cap: " << mesh_cap << LL_ENDL; } } diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 30f042845a..23af837f6f 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -279,7 +279,6 @@ public: LLCore::HttpOptions::ptr_t mHttpLargeOptions; LLCore::HttpHeaders::ptr_t mHttpHeaders; LLCore::HttpRequest::policy_t mHttpPolicyClass; - LLCore::HttpRequest::policy_t mHttpLegacyPolicyClass; LLCore::HttpRequest::policy_t mHttpLargePolicyClass; LLCore::HttpRequest::priority_t mHttpPriority; @@ -287,8 +286,6 @@ public: http_request_set mHttpRequestSet; // Outstanding HTTP requests std::string mGetMeshCapability; - std::string mGetMesh2Capability; - int mGetMeshVersion; LLMeshRepoThread(); ~LLMeshRepoThread(); @@ -335,12 +332,10 @@ public: // mesh fetch URLs. // // Mutex: must be holding mMutex when called - void setGetMeshCaps(const std::string & get_mesh1, - const std::string & get_mesh2, - int pref_version); + void setGetMeshCap(const std::string & get_mesh); // Mutex: acquires mMutex - void constructUrl(LLUUID mesh_id, std::string * url, int * version); + void constructUrl(LLUUID mesh_id, std::string * url); private: // Issue a GET request to a URL with 'Range' header using @@ -349,7 +344,7 @@ private: // or dispose of handler. // // Threads: Repo thread only - LLCore::HttpHandle getByteRange(const std::string & url, int cap_version, + LLCore::HttpHandle getByteRange(const std::string & url, size_t offset, size_t len, const LLCore::HttpHandler::ptr_t &handler); }; @@ -585,8 +580,6 @@ public: void uploadError(LLSD& args); void updateInventory(inventory_data data); - - int mGetMeshVersion; // Shadows value in LLMeshRepoThread }; extern LLMeshRepository gMeshRepo; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 07b3dc1aa4..b78d0b51d5 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -30,8 +30,6 @@ #include <map> #include <algorithm> -#include "llstl.h" - #include "lltexturefetch.h" #include "lldir.h" @@ -485,7 +483,7 @@ private: void recordTextureStart(bool is_http); // Threads: Ttf - void recordTextureDone(bool is_http); + void recordTextureDone(bool is_http, F64 byte_count); void lockWorkMutex() { mWorkMutex.lock(); } void unlockWorkMutex() { mWorkMutex.unlock(); } @@ -824,7 +822,7 @@ public: TFReqSendMetrics(const std::string & caps_url, const LLUUID & session_id, const LLUUID & agent_id, - LLViewerAssetStats * main_stats); + LLSD& stats_sd); TFReqSendMetrics & operator=(const TFReqSendMetrics &); // Not defined virtual ~TFReqSendMetrics(); @@ -835,7 +833,7 @@ public: const std::string mCapsURL; const LLUUID mSessionID; const LLUUID mAgentID; - LLViewerAssetStats * mMainStats; + LLSD mStatsSD; private: LLCore::HttpHandler::ptr_t mHandler; @@ -1351,7 +1349,7 @@ bool LLTextureFetchWorker::doWork(S32 param) if (region) { - std::string http_url = region->getHttpUrl() ; + std::string http_url = region->getViewerAssetUrl(); if (!http_url.empty()) { if (mFTType != FTT_DEFAULT) @@ -1426,6 +1424,20 @@ bool LLTextureFetchWorker::doWork(S32 param) } if (processSimulatorPackets()) { + // Capture some measure of total size for metrics + F64 byte_count = 0; + if (mLastPacket >= mFirstPacket) + { + for (S32 i=mFirstPacket; i<=mLastPacket; i++) + { + llassert_always((i>=0) && (i<mPackets.size())); + if (mPackets[i]) + { + byte_count += mPackets[i]->mSize; + } + } + } + LL_DEBUGS(LOG_TXT) << mID << ": Loaded from Sim. Bytes: " << mFormattedImage->getDataSize() << LL_ENDL; mFetcher->removeFromNetworkQueue(this, false); if (mFormattedImage.isNull() || !mFormattedImage->getDataSize()) @@ -1443,7 +1455,8 @@ bool LLTextureFetchWorker::doWork(S32 param) } setState(DECODE_IMAGE); mWriteToCacheState = SHOULD_WRITE; - recordTextureDone(false); + + recordTextureDone(false, byte_count); } else { @@ -2093,7 +2106,7 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe mFetcher->removeFromHTTPQueue(mID, data_size); - recordTextureDone(true); + recordTextureDone(true, data_size); } // -Mw @@ -2222,6 +2235,7 @@ bool LLTextureFetchWorker::processSimulatorPackets() S32 buffer_size = mFormattedImage->getDataSize(); for (S32 i = mFirstPacket; i<=mLastPacket; i++) { + llassert_always((i>=0) && (i<mPackets.size())); llassert_always(mPackets[i]); buffer_size += mPackets[i]->mSize; } @@ -2493,14 +2507,15 @@ void LLTextureFetchWorker::recordTextureStart(bool is_http) // Threads: Ttf -void LLTextureFetchWorker::recordTextureDone(bool is_http) +void LLTextureFetchWorker::recordTextureDone(bool is_http, F64 byte_count) { if (mMetricsStartTime.value()) { LLViewerAssetStatsFF::record_response(LLViewerAssetType::AT_TEXTURE, - is_http, - LLImageBase::TYPE_AVATAR_BAKE == mType, - LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime); + is_http, + LLImageBase::TYPE_AVATAR_BAKE == mType, + LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime, + byte_count); mMetricsStartTime = (U32Seconds)0; } LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_TEXTURE, @@ -3863,9 +3878,9 @@ void LLTextureFetch::commandSetRegion(U64 region_handle) void LLTextureFetch::commandSendMetrics(const std::string & caps_url, const LLUUID & session_id, const LLUUID & agent_id, - LLViewerAssetStats * main_stats) + LLSD& stats_sd) { - TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, session_id, agent_id, main_stats); + TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, session_id, agent_id, stats_sd); cmdEnqueue(req); } @@ -3974,22 +3989,20 @@ TFReqSetRegion::doWork(LLTextureFetch *) } TFReqSendMetrics::TFReqSendMetrics(const std::string & caps_url, - const LLUUID & session_id, - const LLUUID & agent_id, - LLViewerAssetStats * main_stats): + const LLUUID & session_id, + const LLUUID & agent_id, + LLSD& stats_sd): LLTextureFetch::TFRequest(), mCapsURL(caps_url), mSessionID(session_id), mAgentID(agent_id), - mMainStats(main_stats), + mStatsSD(stats_sd), mHandler(new AssetReportHandler) {} TFReqSendMetrics::~TFReqSendMetrics() { - delete mMainStats; - mMainStats = 0; } @@ -4010,26 +4023,19 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) static volatile bool reporting_started(false); static volatile S32 report_sequence(0); - // We've taken over ownership of the stats copy at this - // point. Get a working reference to it for merging here - // but leave it in 'this'. Destructor will rid us of it. - LLViewerAssetStats & main_stats = *mMainStats; - - LLViewerAssetStats::AssetStats stats; - main_stats.getStats(stats, true); - //LLSD merged_llsd = main_stats.asLLSD(); + // In mStatsSD, we have a copy we own of the LLSD representation + // of the asset stats. Add some additional fields and ship it off. + static const S32 metrics_data_version = 2; + bool initial_report = !reporting_started; - stats.session_id = mSessionID; - stats.agent_id = mAgentID; - stats.message = "ViewerAssetMetrics"; - stats.sequence = static_cast<bool>(report_sequence); - stats.initial = initial_report; - stats.break_ = static_cast<bool>(LLTextureFetch::svMetricsDataBreak); - - LLSD sd; - LLParamSDParser parser; - parser.writeSD(sd, stats); + mStatsSD["session_id"] = mSessionID; + mStatsSD["agent_id"] = mAgentID; + mStatsSD["message"] = "ViewerAssetMetrics"; + mStatsSD["sequence"] = report_sequence; + mStatsSD["initial"] = initial_report; + mStatsSD["version"] = metrics_data_version; + mStatsSD["break"] = static_cast<bool>(LLTextureFetch::svMetricsDataBreak); // Update sequence number if (S32_MAX == ++report_sequence) @@ -4040,8 +4046,13 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) // Limit the size of the stats report if necessary. - sd["truncated"] = truncate_viewer_metrics(10, sd); + mStatsSD["truncated"] = truncate_viewer_metrics(10, mStatsSD); + if (gSavedSettings.getBOOL("QAModeMetrics")) + { + dump_sequential_xml("metric_asset_stats",mStatsSD); + } + if (! mCapsURL.empty()) { // Don't care about handle, this is a fire-and-forget operation. @@ -4049,7 +4060,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) fetcher->getMetricsPolicyClass(), report_priority, mCapsURL, - sd, + mStatsSD, LLCore::HttpOptions::ptr_t(), fetcher->getMetricsHeaders(), mHandler); @@ -4063,7 +4074,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) // In QA mode, Metrics submode, log the result for ease of testing if (fetcher->isQAMode()) { - LL_INFOS(LOG_TXT) << ll_pretty_print_sd(sd) << LL_ENDL; + LL_INFOS(LOG_TXT) << "ViewerAssetMetrics as submitted\n" << ll_pretty_print_sd(mStatsSD) << LL_ENDL; } return true; @@ -4580,7 +4591,7 @@ void LLTextureFetchDebugger::debugHTTP() return; } - mHTTPUrl = region->getHttpUrl(); + mHTTPUrl = region->getViewerAssetUrl(); if (mHTTPUrl.empty()) { LL_INFOS(LOG_TXT) << "Fetch Debugger : Current region URL undefined. Cannot fetch textures through HTTP." << LL_ENDL; diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index 072e6a3307..cfa312ccd9 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -160,7 +160,7 @@ public: void commandSendMetrics(const std::string & caps_url, const LLUUID & session_id, const LLUUID & agent_id, - LLViewerAssetStats * main_stats); + LLSD& stats_sd); // Threads: T* void commandDataBreak(); diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp index 54ac29723f..14e05fd440 100644 --- a/indra/newview/llviewerassetstats.cpp +++ b/indra/newview/llviewerassetstats.cpp @@ -80,6 +80,47 @@ * */ +namespace LLTrace +{ +// This little bit of shimmery is to allow the creation of +// default-constructed stat and event handles so we can make arrays of +// the things. + +// The only sensible way to use this function is to immediately make a +// copy of the contents, since it always returns the same pointer. +const char *makeNewAutoName() +{ + static char name[64]; + static S32 auto_namer_number = 0; + snprintf(name,64,"auto_name_%d",auto_namer_number); + auto_namer_number++; + return name; +} + +template <typename T = F64> +class DCCountStatHandle: + public CountStatHandle<T> +{ +public: + DCCountStatHandle(const char *name = makeNewAutoName(), const char *description=NULL): + CountStatHandle<T>(name,description) + { + } +}; + +template <typename T = F64> +class DCEventStatHandle: + public EventStatHandle<T> +{ +public: + DCEventStatHandle(const char *name = makeNewAutoName(), const char *description=NULL): + EventStatHandle<T>(name,description) + { + } +}; + +} + namespace LLViewerAssetStatsFF { static EViewerAssetCategories asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool is_temp) @@ -90,176 +131,45 @@ namespace LLViewerAssetStatsFF // - wearables (clothing, bodyparts) which directly affect // user experiences when they log in // - sounds - // - gestures + // - gestures, including animations // - everything else. // - llassert_always(50 == LLViewerAssetType::AT_COUNT); - // Multiple asset definitions are floating around so this requires some - // maintenance and attention. - static const EViewerAssetCategories asset_to_bin_map[LLViewerAssetType::AT_COUNT] = - { - EVACTextureTempHTTPGet, // (0) AT_TEXTURE - EVACSoundUDPGet, // AT_SOUND - EVACOtherGet, // AT_CALLINGCARD - EVACOtherGet, // AT_LANDMARK - EVACOtherGet, // AT_SCRIPT - EVACWearableUDPGet, // AT_CLOTHING - EVACOtherGet, // AT_OBJECT - EVACOtherGet, // AT_NOTECARD - EVACOtherGet, // AT_CATEGORY - EVACOtherGet, // AT_ROOT_CATEGORY - EVACOtherGet, // (10) AT_LSL_TEXT - EVACOtherGet, // AT_LSL_BYTECODE - EVACOtherGet, // AT_TEXTURE_TGA - EVACWearableUDPGet, // AT_BODYPART - EVACOtherGet, // AT_TRASH - EVACOtherGet, // AT_SNAPSHOT_CATEGORY - EVACOtherGet, // AT_LOST_AND_FOUND - EVACSoundUDPGet, // AT_SOUND_WAV - EVACOtherGet, // AT_IMAGE_TGA - EVACOtherGet, // AT_IMAGE_JPEG - EVACGestureUDPGet, // (20) AT_ANIMATION - EVACGestureUDPGet, // AT_GESTURE - EVACOtherGet, // AT_SIMSTATE - EVACOtherGet, // AT_FAVORITE - EVACOtherGet, // AT_LINK - EVACOtherGet, // AT_LINK_FOLDER - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // (30) - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // (40) - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // - EVACOtherGet, // AT_MESH - // (50) - }; - - if (at < 0 || at >= LLViewerAssetType::AT_COUNT) - { - return EVACOtherGet; - } - EViewerAssetCategories ret(asset_to_bin_map[at]); - if (EVACTextureTempHTTPGet == ret) - { - // Indexed with [is_temp][with_http] - static const EViewerAssetCategories texture_bin_map[2][2] = - { - { - EVACTextureNonTempUDPGet, - EVACTextureNonTempHTTPGet, - }, - { - EVACTextureTempUDPGet, - EVACTextureTempHTTPGet, - } - }; - - ret = texture_bin_map[is_temp][with_http]; - } + EViewerAssetCategories ret; + switch (at) + { + case LLAssetType::AT_TEXTURE: + if (is_temp) + ret = with_http ? EVACTextureTempHTTPGet : EVACTextureTempUDPGet; + else + ret = with_http ? EVACTextureNonTempHTTPGet : EVACTextureNonTempUDPGet; + break; + case LLAssetType::AT_SOUND: + case LLAssetType::AT_SOUND_WAV: + ret = with_http ? EVACSoundHTTPGet : EVACSoundUDPGet; + break; + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_BODYPART: + ret = with_http ? EVACWearableHTTPGet : EVACWearableUDPGet; + break; + case LLAssetType::AT_ANIMATION: + case LLAssetType::AT_GESTURE: + ret = with_http ? EVACGestureHTTPGet : EVACGestureUDPGet; + break; + case LLAssetType::AT_LANDMARK: + ret = with_http ? EVACLandmarkHTTPGet : EVACLandmarkUDPGet; + break; + default: + ret = with_http ? EVACOtherHTTPGet : EVACOtherUDPGet; + break; + } return ret; } - static LLTrace::CountStatHandle<> sEnqueueAssetRequestsTempTextureHTTP ("enqueuedassetrequeststemptexturehttp", - "Number of temporary texture asset http requests enqueued"), - sEnqueueAssetRequestsTempTextureUDP ("enqueuedassetrequeststemptextureudp", - "Number of temporary texture asset udp requests enqueued"), - sEnqueueAssetRequestsNonTempTextureHTTP("enqueuedassetrequestsnontemptexturehttp", - "Number of texture asset http requests enqueued"), - sEnqueueAssetRequestsNonTempTextureUDP ("enqueuedassetrequestsnontemptextureudp", - "Number of texture asset udp requests enqueued"), - sEnqueuedAssetRequestsWearableUdp ("enqueuedassetrequestswearableudp", - "Number of wearable asset requests enqueued"), - sEnqueuedAssetRequestsSoundUdp ("enqueuedassetrequestssoundudp", - "Number of sound asset requests enqueued"), - sEnqueuedAssetRequestsGestureUdp ("enqueuedassetrequestsgestureudp", - "Number of gesture asset requests enqueued"), - sEnqueuedAssetRequestsOther ("enqueuedassetrequestsother", - "Number of other asset requests enqueued"); - - static LLTrace::CountStatHandle<>* sEnqueued[EVACCount] = { - &sEnqueueAssetRequestsTempTextureHTTP, - &sEnqueueAssetRequestsTempTextureUDP, - &sEnqueueAssetRequestsNonTempTextureHTTP, - &sEnqueueAssetRequestsNonTempTextureUDP, - &sEnqueuedAssetRequestsWearableUdp, - &sEnqueuedAssetRequestsSoundUdp, - &sEnqueuedAssetRequestsGestureUdp, - &sEnqueuedAssetRequestsOther - }; - - static LLTrace::CountStatHandle<> sDequeueAssetRequestsTempTextureHTTP ("dequeuedassetrequeststemptexturehttp", - "Number of temporary texture asset http requests dequeued"), - sDequeueAssetRequestsTempTextureUDP ("dequeuedassetrequeststemptextureudp", - "Number of temporary texture asset udp requests dequeued"), - sDequeueAssetRequestsNonTempTextureHTTP("dequeuedassetrequestsnontemptexturehttp", - "Number of texture asset http requests dequeued"), - sDequeueAssetRequestsNonTempTextureUDP ("dequeuedassetrequestsnontemptextureudp", - "Number of texture asset udp requests dequeued"), - sDequeuedAssetRequestsWearableUdp ("dequeuedassetrequestswearableudp", - "Number of wearable asset requests dequeued"), - sDequeuedAssetRequestsSoundUdp ("dequeuedassetrequestssoundudp", - "Number of sound asset requests dequeued"), - sDequeuedAssetRequestsGestureUdp ("dequeuedassetrequestsgestureudp", - "Number of gesture asset requests dequeued"), - sDequeuedAssetRequestsOther ("dequeuedassetrequestsother", - "Number of other asset requests dequeued"); - - static LLTrace::CountStatHandle<>* sDequeued[EVACCount] = { - &sDequeueAssetRequestsTempTextureHTTP, - &sDequeueAssetRequestsTempTextureUDP, - &sDequeueAssetRequestsNonTempTextureHTTP, - &sDequeueAssetRequestsNonTempTextureUDP, - &sDequeuedAssetRequestsWearableUdp, - &sDequeuedAssetRequestsSoundUdp, - &sDequeuedAssetRequestsGestureUdp, - &sDequeuedAssetRequestsOther - }; - - static LLTrace::EventStatHandle<F64Seconds > sResponseAssetRequestsTempTextureHTTP ("assetresponsetimestemptexturehttp", - "Time spent responding to temporary texture asset http requests"), - sResponseAssetRequestsTempTextureUDP ("assetresponsetimestemptextureudp", - "Time spent responding to temporary texture asset udp requests"), - sResponseAssetRequestsNonTempTextureHTTP("assetresponsetimesnontemptexturehttp", - "Time spent responding to texture asset http requests"), - sResponseAssetRequestsNonTempTextureUDP ("assetresponsetimesnontemptextureudp", - "Time spent responding to texture asset udp requests"), - sResponsedAssetRequestsWearableUdp ("assetresponsetimeswearableudp", - "Time spent responding to wearable asset requests"), - sResponsedAssetRequestsSoundUdp ("assetresponsetimessoundudp", - "Time spent responding to sound asset requests"), - sResponsedAssetRequestsGestureUdp ("assetresponsetimesgestureudp", - "Time spent responding to gesture asset requests"), - sResponsedAssetRequestsOther ("assetresponsetimesother", - "Time spent responding to other asset requests"); - - static LLTrace::EventStatHandle<F64Seconds >* sResponse[EVACCount] = { - &sResponseAssetRequestsTempTextureHTTP, - &sResponseAssetRequestsTempTextureUDP, - &sResponseAssetRequestsNonTempTextureHTTP, - &sResponseAssetRequestsNonTempTextureUDP, - &sResponsedAssetRequestsWearableUdp, - &sResponsedAssetRequestsSoundUdp, - &sResponsedAssetRequestsGestureUdp, - &sResponsedAssetRequestsOther - }; + static LLTrace::DCCountStatHandle<> sEnqueued[EVACCount]; + static LLTrace::DCCountStatHandle<> sDequeued[EVACCount]; + static LLTrace::DCEventStatHandle<> sBytesFetched[EVACCount]; + static LLTrace::DCEventStatHandle<F64Seconds > sResponse[EVACCount]; } // ------------------------------------------------------ @@ -353,6 +263,26 @@ void LLViewerAssetStats::setRegion(region_handle_t region_handle) mRegionHandle = region_handle; } +template <typename T> +void LLViewerAssetStats::getStat(LLTrace::Recording& rec, T& req, LLViewerAssetStatsFF::EViewerAssetCategories cat, bool compact_output) +{ + using namespace LLViewerAssetStatsFF; + + if (!compact_output + || rec.getSampleCount(sEnqueued[cat]) + || rec.getSampleCount(sDequeued[cat]) + || rec.getSampleCount(sResponse[cat])) + { + req .enqueued(rec.getSampleCount(sEnqueued[cat])) + .dequeued(rec.getSampleCount(sDequeued[cat])) + .resp_count(rec.getSampleCount(sResponse[cat])) + .resp_min(rec.getMin(sResponse[cat]).value()) + .resp_max(rec.getMax(sResponse[cat]).value()) + .resp_mean(rec.getMean(sResponse[cat]).value()) + .resp_mean_bytes(rec.getMean(sBytesFetched[cat])); + } +} + void LLViewerAssetStats::getStats(AssetStats& stats, bool compact_output) { using namespace LLViewerAssetStatsFF; @@ -365,108 +295,22 @@ void LLViewerAssetStats::getStats(AssetStats& stats, bool compact_output) { RegionStats& r = stats.regions.add(); LLTrace::Recording& rec = it->second; - if (!compact_output - || rec.getSum(*sEnqueued[EVACTextureTempHTTPGet]) - || rec.getSum(*sDequeued[EVACTextureTempHTTPGet]) - || rec.getSum(*sResponse[EVACTextureTempHTTPGet]).value()) - { - r.get_texture_temp_http .enqueued((S32)rec.getSum(*sEnqueued[EVACTextureTempHTTPGet])) - .dequeued((S32)rec.getSum(*sDequeued[EVACTextureTempHTTPGet])) - .resp_count((S32)rec.getSum(*sResponse[EVACTextureTempHTTPGet]).value()) - .resp_min(rec.getMin(*sResponse[EVACTextureTempHTTPGet]).value()) - .resp_max(rec.getMax(*sResponse[EVACTextureTempHTTPGet]).value()) - .resp_mean(rec.getMean(*sResponse[EVACTextureTempHTTPGet]).value()); - } - if (!compact_output - || rec.getSum(*sEnqueued[EVACTextureTempUDPGet]) - || rec.getSum(*sDequeued[EVACTextureTempUDPGet]) - || rec.getSum(*sResponse[EVACTextureTempUDPGet]).value()) - { - r.get_texture_temp_udp .enqueued((S32)rec.getSum(*sEnqueued[EVACTextureTempUDPGet])) - .dequeued((S32)rec.getSum(*sDequeued[EVACTextureTempUDPGet])) - .resp_count((S32)rec.getSum(*sResponse[EVACTextureTempUDPGet]).value()) - .resp_min(rec.getMin(*sResponse[EVACTextureTempUDPGet]).value()) - .resp_max(rec.getMax(*sResponse[EVACTextureTempUDPGet]).value()) - .resp_mean(rec.getMean(*sResponse[EVACTextureTempUDPGet]).value()); - } - if (!compact_output - || rec.getSum(*sEnqueued[EVACTextureNonTempHTTPGet]) - || rec.getSum(*sDequeued[EVACTextureNonTempHTTPGet]) - || rec.getSum(*sResponse[EVACTextureNonTempHTTPGet]).value()) - { - r.get_texture_non_temp_http .enqueued((S32)rec.getSum(*sEnqueued[EVACTextureNonTempHTTPGet])) - .dequeued((S32)rec.getSum(*sDequeued[EVACTextureNonTempHTTPGet])) - .resp_count((S32)rec.getSum(*sResponse[EVACTextureNonTempHTTPGet]).value()) - .resp_min(rec.getMin(*sResponse[EVACTextureNonTempHTTPGet]).value()) - .resp_max(rec.getMax(*sResponse[EVACTextureNonTempHTTPGet]).value()) - .resp_mean(rec.getMean(*sResponse[EVACTextureNonTempHTTPGet]).value()); - } - - if (!compact_output - || rec.getSum(*sEnqueued[EVACTextureNonTempUDPGet]) - || rec.getSum(*sDequeued[EVACTextureNonTempUDPGet]) - || rec.getSum(*sResponse[EVACTextureNonTempUDPGet]).value()) - { - r.get_texture_non_temp_udp .enqueued((S32)rec.getSum(*sEnqueued[EVACTextureNonTempUDPGet])) - .dequeued((S32)rec.getSum(*sDequeued[EVACTextureNonTempUDPGet])) - .resp_count((S32)rec.getSum(*sResponse[EVACTextureNonTempUDPGet]).value()) - .resp_min(rec.getMin(*sResponse[EVACTextureNonTempUDPGet]).value()) - .resp_max(rec.getMax(*sResponse[EVACTextureNonTempUDPGet]).value()) - .resp_mean(rec.getMean(*sResponse[EVACTextureNonTempUDPGet]).value()); - } - - if (!compact_output - || rec.getSum(*sEnqueued[EVACWearableUDPGet]) - || rec.getSum(*sDequeued[EVACWearableUDPGet]) - || rec.getSum(*sResponse[EVACWearableUDPGet]).value()) - { - r.get_wearable_udp .enqueued((S32)rec.getSum(*sEnqueued[EVACWearableUDPGet])) - .dequeued((S32)rec.getSum(*sDequeued[EVACWearableUDPGet])) - .resp_count((S32)rec.getSum(*sResponse[EVACWearableUDPGet]).value()) - .resp_min(rec.getMin(*sResponse[EVACWearableUDPGet]).value()) - .resp_max(rec.getMax(*sResponse[EVACWearableUDPGet]).value()) - .resp_mean(rec.getMean(*sResponse[EVACWearableUDPGet]).value()); - } - - if (!compact_output - || rec.getSum(*sEnqueued[EVACSoundUDPGet]) - || rec.getSum(*sDequeued[EVACSoundUDPGet]) - || rec.getSum(*sResponse[EVACSoundUDPGet]).value()) - { - r.get_sound_udp .enqueued((S32)rec.getSum(*sEnqueued[EVACSoundUDPGet])) - .dequeued((S32)rec.getSum(*sDequeued[EVACSoundUDPGet])) - .resp_count((S32)rec.getSum(*sResponse[EVACSoundUDPGet]).value()) - .resp_min(rec.getMin(*sResponse[EVACSoundUDPGet]).value()) - .resp_max(rec.getMax(*sResponse[EVACSoundUDPGet]).value()) - .resp_mean(rec.getMean(*sResponse[EVACSoundUDPGet]).value()); - } - - if (!compact_output - || rec.getSum(*sEnqueued[EVACGestureUDPGet]) - || rec.getSum(*sDequeued[EVACGestureUDPGet]) - || rec.getSum(*sResponse[EVACGestureUDPGet]).value()) - { - r.get_gesture_udp .enqueued((S32)rec.getSum(*sEnqueued[EVACGestureUDPGet])) - .dequeued((S32)rec.getSum(*sDequeued[EVACGestureUDPGet])) - .resp_count((S32)rec.getSum(*sResponse[EVACGestureUDPGet]).value()) - .resp_min(rec.getMin(*sResponse[EVACGestureUDPGet]).value()) - .resp_max(rec.getMax(*sResponse[EVACGestureUDPGet]).value()) - .resp_mean(rec.getMean(*sResponse[EVACGestureUDPGet]).value()); - } - - if (!compact_output - || rec.getSum(*sEnqueued[EVACOtherGet]) - || rec.getSum(*sDequeued[EVACOtherGet]) - || rec.getSum(*sResponse[EVACOtherGet]).value()) - { - r.get_other .enqueued((S32)rec.getSum(*sEnqueued[EVACOtherGet])) - .dequeued((S32)rec.getSum(*sDequeued[EVACOtherGet])) - .resp_count((S32)rec.getSum(*sResponse[EVACOtherGet]).value()) - .resp_min(rec.getMin(*sResponse[EVACOtherGet]).value()) - .resp_max(rec.getMax(*sResponse[EVACOtherGet]).value()) - .resp_mean(rec.getMean(*sResponse[EVACOtherGet]).value()); - } + getStat(rec, r.get_texture_temp_http, EVACTextureTempHTTPGet, compact_output); + getStat(rec, r.get_texture_temp_udp, EVACTextureTempUDPGet, compact_output); + getStat(rec, r.get_texture_non_temp_http, EVACTextureNonTempHTTPGet, compact_output); + getStat(rec, r.get_texture_non_temp_udp, EVACTextureNonTempUDPGet, compact_output); + getStat(rec, r.get_wearable_http, EVACWearableHTTPGet, compact_output); + getStat(rec, r.get_wearable_udp, EVACWearableUDPGet, compact_output); + getStat(rec, r.get_sound_http, EVACSoundHTTPGet, compact_output); + getStat(rec, r.get_sound_udp, EVACSoundUDPGet, compact_output); + getStat(rec, r.get_gesture_http, EVACGestureHTTPGet, compact_output); + getStat(rec, r.get_gesture_udp, EVACGestureUDPGet, compact_output); + getStat(rec, r.get_landmark_http, EVACLandmarkHTTPGet, compact_output); + getStat(rec, r.get_landmark_udp, EVACLandmarkUDPGet, compact_output); + getStat(rec, r.get_other_http, EVACOtherHTTPGet, compact_output); + getStat(rec, r.get_other_udp, EVACOtherUDPGet, compact_output); + S32 fps = (S32)rec.getLastValue(LLStatViewer::FPS_SAMPLE); if (!compact_output || fps != 0) { @@ -479,10 +323,10 @@ void LLViewerAssetStats::getStats(AssetStats& stats, bool compact_output) grid_from_region_handle(it->first, &grid_x, &grid_y); r .grid_x(grid_x) .grid_y(grid_y) - .duration(F64Microseconds(rec.getDuration()).value()); + .duration(F64Seconds(rec.getDuration()).value()); } - stats.duration(mCurRecording ? F64Microseconds(mCurRecording->getDuration()).value() : 0.0); + stats.duration(mCurRecording ? F64Seconds(mCurRecording->getDuration()).value() : 0.0); } LLSD LLViewerAssetStats::asLLSD(bool compact_output) @@ -518,21 +362,22 @@ void record_enqueue(LLViewerAssetType::EType at, bool with_http, bool is_temp) { const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp)); - add(*sEnqueued[int(eac)], 1); + add(sEnqueued[int(eac)], 1); } void record_dequeue(LLViewerAssetType::EType at, bool with_http, bool is_temp) { const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp)); - add(*sDequeued[int(eac)], 1); + add(sDequeued[int(eac)], 1); } -void record_response(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration) +void record_response(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration, F64 bytes) { const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp)); - record(*sResponse[int(eac)], F64Microseconds(duration)); + record(sResponse[int(eac)], F64Seconds(duration)); + record(sBytesFetched[int(eac)], bytes); } void init() @@ -561,7 +406,8 @@ LLViewerAssetStats::AssetRequestType::AssetRequestType() resp_count("resp_count"), resp_min("resp_min"), resp_max("resp_max"), - resp_mean("resp_mean") + resp_mean("resp_mean"), + resp_mean_bytes("resp_mean_bytes") {} LLViewerAssetStats::FPSStats::FPSStats() @@ -576,10 +422,16 @@ LLViewerAssetStats::RegionStats::RegionStats() get_texture_temp_udp("get_texture_temp_udp"), get_texture_non_temp_http("get_texture_non_temp_http"), get_texture_non_temp_udp("get_texture_non_temp_udp"), + get_wearable_http("get_wearable_http"), get_wearable_udp("get_wearable_udp"), + get_sound_http("get_sound_http"), get_sound_udp("get_sound_udp"), + get_gesture_http("get_gesture_http"), get_gesture_udp("get_gesture_udp"), - get_other("get_other"), + get_landmark_http("get_landmark_http"), + get_landmark_udp("get_landmark_udp"), + get_other_http("get_other_http"), + get_other_udp("get_other_udp"), fps("fps"), grid_x("grid_x"), grid_y("grid_y"), diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h index 9d425c82fc..718c284224 100644 --- a/indra/newview/llviewerassetstats.h +++ b/indra/newview/llviewerassetstats.h @@ -39,6 +39,29 @@ #include "lltrace.h" #include "llinitparam.h" +namespace LLViewerAssetStatsFF +{ + enum EViewerAssetCategories + { + EVACTextureTempHTTPGet, //< Texture GETs - temp/baked, HTTP + EVACTextureTempUDPGet, //< Texture GETs - temp/baked, UDP + EVACTextureNonTempHTTPGet, //< Texture GETs - perm, HTTP + EVACTextureNonTempUDPGet, //< Texture GETs - perm, UDP + EVACWearableHTTPGet, //< Wearable GETs HTTP + EVACWearableUDPGet, //< Wearable GETs UDP + EVACSoundHTTPGet, //< Sound GETs HTTP + EVACSoundUDPGet, //< Sound GETs UDP + EVACGestureHTTPGet, //< Gesture GETs HTTP + EVACGestureUDPGet, //< Gesture GETs UDP + EVACLandmarkHTTPGet, //< Landmark GETs HTTP + EVACLandmarkUDPGet, //< Landmark GETs UDP + EVACOtherHTTPGet, //< Other GETs HTTP + EVACOtherUDPGet, //< Other GETs UDP + + EVACCount // Must be last + }; +} + /** * @class LLViewerAssetStats * @brief Records performance aspects of asset access operations. @@ -74,6 +97,7 @@ * LLViewerAssetStatsFF is provided for conditional test-and-call * operations. */ + class LLViewerAssetStats : public LLStopWatchControlsMixin<LLViewerAssetStats> { public: @@ -98,13 +122,14 @@ public: resp_count; Mandatory<F64> resp_min, resp_max, - resp_mean; + resp_mean, + resp_mean_bytes; AssetRequestType(); }; struct FPSStats : public LLInitParam::Block<FPSStats> - { + { Mandatory<S32> count; Mandatory<F64> min, max, @@ -113,15 +138,21 @@ public: }; struct RegionStats : public LLInitParam::Block<RegionStats> - { + { Optional<AssetRequestType> get_texture_temp_http, get_texture_temp_udp, get_texture_non_temp_http, get_texture_non_temp_udp, + get_wearable_http, get_wearable_udp, + get_sound_http, get_sound_udp, + get_gesture_http, get_gesture_udp, - get_other; + get_landmark_http, + get_landmark_udp, + get_other_http, + get_other_udp; Optional<FPSStats> fps; Optional<S32> grid_x, grid_y; @@ -165,6 +196,11 @@ public: // Retrieve current metrics for all visited regions (NULL region UUID/handle excluded) // Uses AssetStats structure seen above void getStats(AssetStats& stats, bool compact_output); + + // Retrieve a single asset request type (taken from a single region) + template <typename T> + void getStat(LLTrace::Recording& rec, T& req, LLViewerAssetStatsFF::EViewerAssetCategories cat, bool compact_output); + LLSD asLLSD(bool compact_output); protected: @@ -205,19 +241,6 @@ extern LLViewerAssetStats * gViewerAssetStats; namespace LLViewerAssetStatsFF { - enum EViewerAssetCategories - { - EVACTextureTempHTTPGet, //< Texture GETs - temp/baked, HTTP - EVACTextureTempUDPGet, //< Texture GETs - temp/baked, UDP - EVACTextureNonTempHTTPGet, //< Texture GETs - perm, HTTP - EVACTextureNonTempUDPGet, //< Texture GETs - perm, UDP - EVACWearableUDPGet, //< Wearable GETs - EVACSoundUDPGet, //< Sound GETs - EVACGestureUDPGet, //< Gesture GETs - EVACOtherGet, //< Other GETs - - EVACCount // Must be last - }; /** * @brief Allocation and deallocation of globals. @@ -250,7 +273,7 @@ void record_enqueue(LLViewerAssetType::EType at, bool with_http, bool is_temp); void record_dequeue(LLViewerAssetType::EType at, bool with_http, bool is_temp); void record_response(LLViewerAssetType::EType at, bool with_http, bool is_temp, - LLViewerAssetStats::duration_t duration); + LLViewerAssetStats::duration_t duration, F64 bytes=0); void record_avatar_stats(); diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index 2db9c7e67c..e0b64403ef 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -33,9 +33,17 @@ #include "message.h" #include "llagent.h" +#include "llappcorehttp.h" +#include "llviewerregion.h" + #include "lltransfersourceasset.h" #include "lltransfertargetvfile.h" #include "llviewerassetstats.h" +#include "llcoros.h" +#include "llcoproceduremanager.h" +#include "lleventcoro.h" +#include "llsdutil.h" +#include "llworld.h" ///---------------------------------------------------------------------------- /// LLViewerAssetRequest @@ -51,267 +59,283 @@ class LLViewerAssetRequest : public LLAssetRequest { public: - LLViewerAssetRequest(const LLUUID &uuid, const LLAssetType::EType type) - : LLAssetRequest(uuid, type), - mMetricsStartTime(0) - { - } - - LLViewerAssetRequest & operator=(const LLViewerAssetRequest &); // Not defined - // Default assignment operator valid - - // virtual - ~LLViewerAssetRequest() - { - recordMetrics(); - } + LLViewerAssetRequest(const LLUUID &uuid, const LLAssetType::EType type, bool with_http) + : LLAssetRequest(uuid, type), + mMetricsStartTime(0), + mWithHTTP(with_http) + { + } + + LLViewerAssetRequest & operator=(const LLViewerAssetRequest &); // Not defined + // Default assignment operator valid + + // virtual + ~LLViewerAssetRequest() + { + recordMetrics(); + } protected: - void recordMetrics() - { - if (mMetricsStartTime.value()) - { - // Okay, it appears this request was used for useful things. Record - // the expected dequeue and duration of request processing. - LLViewerAssetStatsFF::record_dequeue(mType, false, false); - LLViewerAssetStatsFF::record_response(mType, false, false, - (LLViewerAssetStatsFF::get_timestamp() - - mMetricsStartTime)); - mMetricsStartTime = (U32Seconds)0; - } - } - + void recordMetrics() + { + if (mMetricsStartTime.value()) + { + // Okay, it appears this request was used for useful things. Record + // the expected dequeue and duration of request processing. + LLViewerAssetStatsFF::record_dequeue(mType, mWithHTTP, false); + LLViewerAssetStatsFF::record_response(mType, mWithHTTP, false, + (LLViewerAssetStatsFF::get_timestamp() + - mMetricsStartTime), + mBytesFetched); + mMetricsStartTime = (U32Seconds)0; + } + } + public: - LLViewerAssetStats::duration_t mMetricsStartTime; + LLViewerAssetStats::duration_t mMetricsStartTime; + bool mWithHTTP; }; ///---------------------------------------------------------------------------- /// LLViewerAssetStorage ///---------------------------------------------------------------------------- +// Unused? LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, - LLVFS *vfs, LLVFS *static_vfs, - const LLHost &upstream_host) - : LLAssetStorage(msg, xfer, vfs, static_vfs, upstream_host) + LLVFS *vfs, LLVFS *static_vfs, + const LLHost &upstream_host) + : LLAssetStorage(msg, xfer, vfs, static_vfs, upstream_host), + mAssetCoroCount(0), + mCountRequests(0), + mCountStarted(0), + mCountCompleted(0), + mCountSucceeded(0), + mTotalBytesFetched(0) { } LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, - LLVFS *vfs, LLVFS *static_vfs) - : LLAssetStorage(msg, xfer, vfs, static_vfs) + LLVFS *vfs, LLVFS *static_vfs) + : LLAssetStorage(msg, xfer, vfs, static_vfs), + mAssetCoroCount(0), + mCountRequests(0), + mCountStarted(0), + mCountCompleted(0), + mCountSucceeded(0), + mTotalBytesFetched(0) { } // virtual void LLViewerAssetStorage::storeAssetData( - const LLTransactionID& tid, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file, - bool is_priority, - bool store_local, - bool user_waiting, - F64Seconds timeout) + const LLTransactionID& tid, + LLAssetType::EType asset_type, + LLStoreAssetCallback callback, + void* user_data, + bool temp_file, + bool is_priority, + bool store_local, + bool user_waiting, + F64Seconds timeout) { - LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - LL_DEBUGS("AssetStorage") << "LLViewerAssetStorage::storeAssetData (legacy) " << tid << ":" << LLAssetType::lookup(asset_type) - << " ASSET_ID: " << asset_id << LL_ENDL; - - if (mUpstreamHost.isOk()) - { - if (mVFS->getExists(asset_id, asset_type)) - { - // Pack data into this packet if we can fit it. - U8 buffer[MTUBYTES]; - buffer[0] = 0; - - LLVFile vfile(mVFS, asset_id, asset_type, LLVFile::READ); - S32 asset_size = vfile.getSize(); - - LLAssetRequest *req = new LLAssetRequest(asset_id, asset_type); - req->mUpCallback = callback; - req->mUserData = user_data; - - if (asset_size < 1) - { - // This can happen if there's a bug in our code or if the VFS has been corrupted. - LL_WARNS() << "LLViewerAssetStorage::storeAssetData() Data _should_ already be in the VFS, but it's not! " << asset_id << LL_ENDL; - // LLAssetStorage metric: Zero size VFS - reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" ); - - delete req; - if (callback) - { - callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_VFS_CORRUPT); - } - return; - } - else - { - // LLAssetStorage metric: Successful Request - S32 size = mVFS->getSize(asset_id, asset_type); - const char *message = "Added to upload queue"; - reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, size, MR_OKAY, __FILE__, __LINE__, message ); - - if(is_priority) - { - mPendingUploads.push_front(req); - } - else - { - mPendingUploads.push_back(req); - } - } - - // Read the data from the VFS if it'll fit in this packet. - if (asset_size + 100 < MTUBYTES) - { - BOOL res = vfile.read(buffer, asset_size); /* Flawfinder: ignore */ - S32 bytes_read = res ? vfile.getLastBytesRead() : 0; - - if( bytes_read == asset_size ) - { - req->mDataSentInFirstPacket = TRUE; - //LL_INFOS() << "LLViewerAssetStorage::createAsset sending data in first packet" << LL_ENDL; - } - else - { - LL_WARNS() << "Probable corruption in VFS file, aborting store asset data" << LL_ENDL; - - // LLAssetStorage metric: VFS corrupt - bogus size - reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, asset_size, MR_VFS_CORRUPTION, __FILE__, __LINE__, "VFS corruption" ); - - if (callback) - { - callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_VFS_CORRUPT); - } - return; - } - } - else - { - // Too big, do an xfer - buffer[0] = 0; - asset_size = 0; - } - mMessageSys->newMessageFast(_PREHASH_AssetUploadRequest); - mMessageSys->nextBlockFast(_PREHASH_AssetBlock); - mMessageSys->addUUIDFast(_PREHASH_TransactionID, tid); - mMessageSys->addS8Fast(_PREHASH_Type, (S8)asset_type); - mMessageSys->addBOOLFast(_PREHASH_Tempfile, temp_file); - mMessageSys->addBOOLFast(_PREHASH_StoreLocal, store_local); - mMessageSys->addBinaryDataFast( _PREHASH_AssetData, buffer, asset_size ); - mMessageSys->sendReliable(mUpstreamHost); - } - else - { - LL_WARNS() << "AssetStorage: attempt to upload non-existent vfile " << asset_id << ":" << LLAssetType::lookup(asset_type) << LL_ENDL; - // LLAssetStorage metric: Zero size VFS - reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" ); - if (callback) - { - callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_NONEXISTENT_FILE); - } - } - } - else - { - LL_WARNS() << "Attempt to move asset store request upstream w/o valid upstream provider" << LL_ENDL; - // LLAssetStorage metric: Upstream provider dead - reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_NO_UPSTREAM, __FILE__, __LINE__, "No upstream provider" ); - if (callback) - { - callback(asset_id, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); - } - } + LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + LL_DEBUGS("AssetStorage") << "LLViewerAssetStorage::storeAssetData (legacy) " << tid << ":" << LLAssetType::lookup(asset_type) + << " ASSET_ID: " << asset_id << LL_ENDL; + + if (mUpstreamHost.isOk()) + { + if (mVFS->getExists(asset_id, asset_type)) + { + // Pack data into this packet if we can fit it. + U8 buffer[MTUBYTES]; + buffer[0] = 0; + + LLVFile vfile(mVFS, asset_id, asset_type, LLVFile::READ); + S32 asset_size = vfile.getSize(); + + LLAssetRequest *req = new LLAssetRequest(asset_id, asset_type); + req->mUpCallback = callback; + req->mUserData = user_data; + + if (asset_size < 1) + { + // This can happen if there's a bug in our code or if the VFS has been corrupted. + LL_WARNS("AssetStorage") << "LLViewerAssetStorage::storeAssetData() Data _should_ already be in the VFS, but it's not! " << asset_id << LL_ENDL; + // LLAssetStorage metric: Zero size VFS + reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" ); + + delete req; + if (callback) + { + callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_VFS_CORRUPT); + } + return; + } + else + { + // LLAssetStorage metric: Successful Request + S32 size = mVFS->getSize(asset_id, asset_type); + const char *message = "Added to upload queue"; + reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, size, MR_OKAY, __FILE__, __LINE__, message ); + + if(is_priority) + { + mPendingUploads.push_front(req); + } + else + { + mPendingUploads.push_back(req); + } + } + + // Read the data from the VFS if it'll fit in this packet. + if (asset_size + 100 < MTUBYTES) + { + BOOL res = vfile.read(buffer, asset_size); /* Flawfinder: ignore */ + S32 bytes_read = res ? vfile.getLastBytesRead() : 0; + + if( bytes_read == asset_size ) + { + req->mDataSentInFirstPacket = TRUE; + //LL_INFOS() << "LLViewerAssetStorage::createAsset sending data in first packet" << LL_ENDL; + } + else + { + LL_WARNS("AssetStorage") << "Probable corruption in VFS file, aborting store asset data" << LL_ENDL; + + // LLAssetStorage metric: VFS corrupt - bogus size + reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, asset_size, MR_VFS_CORRUPTION, __FILE__, __LINE__, "VFS corruption" ); + + if (callback) + { + callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_VFS_CORRUPT); + } + return; + } + } + else + { + // Too big, do an xfer + buffer[0] = 0; + asset_size = 0; + } + mMessageSys->newMessageFast(_PREHASH_AssetUploadRequest); + mMessageSys->nextBlockFast(_PREHASH_AssetBlock); + mMessageSys->addUUIDFast(_PREHASH_TransactionID, tid); + mMessageSys->addS8Fast(_PREHASH_Type, (S8)asset_type); + mMessageSys->addBOOLFast(_PREHASH_Tempfile, temp_file); + mMessageSys->addBOOLFast(_PREHASH_StoreLocal, store_local); + mMessageSys->addBinaryDataFast( _PREHASH_AssetData, buffer, asset_size ); + mMessageSys->sendReliable(mUpstreamHost); + } + else + { + LL_WARNS("AssetStorage") << "AssetStorage: attempt to upload non-existent vfile " << asset_id << ":" << LLAssetType::lookup(asset_type) << LL_ENDL; + // LLAssetStorage metric: Zero size VFS + reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" ); + if (callback) + { + callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_NONEXISTENT_FILE); + } + } + } + else + { + LL_WARNS("AssetStorage") << "Attempt to move asset store request upstream w/o valid upstream provider" << LL_ENDL; + // LLAssetStorage metric: Upstream provider dead + reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_NO_UPSTREAM, __FILE__, __LINE__, "No upstream provider" ); + if (callback) + { + callback(asset_id, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); + } + } } void LLViewerAssetStorage::storeAssetData( - const std::string& filename, - const LLTransactionID& tid, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file, - bool is_priority, - bool user_waiting, - F64Seconds timeout) + const std::string& filename, + const LLTransactionID& tid, + LLAssetType::EType asset_type, + LLStoreAssetCallback callback, + void* user_data, + bool temp_file, + bool is_priority, + bool user_waiting, + F64Seconds timeout) { - if(filename.empty()) - { - // LLAssetStorage metric: no filename - reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_VFS_CORRUPTION, __FILE__, __LINE__, "Filename missing" ); - LL_ERRS() << "No filename specified" << LL_ENDL; - return; - } - - LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - LL_DEBUGS("AssetStorage") << "LLViewerAssetStorage::storeAssetData (legacy)" << asset_id << ":" << LLAssetType::lookup(asset_type) << LL_ENDL; - - LL_DEBUGS("AssetStorage") << "ASSET_ID: " << asset_id << LL_ENDL; - - S32 size = 0; - LLFILE* fp = LLFile::fopen(filename, "rb"); - if (fp) - { - fseek(fp, 0, SEEK_END); - size = ftell(fp); - fseek(fp, 0, SEEK_SET); - } - if( size ) - { - LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest; - - legacy->mUpCallback = callback; - legacy->mUserData = user_data; - - LLVFile file(mVFS, asset_id, asset_type, LLVFile::WRITE); - - file.setMaxSize(size); - - const S32 buf_size = 65536; - U8 copy_buf[buf_size]; - while ((size = (S32)fread(copy_buf, 1, buf_size, fp))) - { - file.write(copy_buf, size); - } - fclose(fp); - - // if this upload fails, the caller needs to setup a new tempfile for us - if (temp_file) - { - LLFile::remove(filename); - } - - // LLAssetStorage metric: Success not needed; handled in the overloaded method here: - - LLViewerAssetStorage::storeAssetData( - tid, - asset_type, - legacyStoreDataCallback, - (void**)legacy, - temp_file, - is_priority); - } - else // size == 0 (but previous block changes size) - { - if( fp ) - { - // LLAssetStorage metric: Zero size - reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file was zero length" ); - } - else - { - // LLAssetStorage metric: Missing File - reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_FILE_NONEXIST, __FILE__, __LINE__, "The file didn't exist" ); - } - if (callback) - { - callback(asset_id, user_data, LL_ERR_CANNOT_OPEN_FILE, LL_EXSTAT_BLOCKED_FILE); - } - } + if(filename.empty()) + { + // LLAssetStorage metric: no filename + reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_VFS_CORRUPTION, __FILE__, __LINE__, "Filename missing" ); + LL_ERRS() << "No filename specified" << LL_ENDL; + return; + } + + LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + LL_DEBUGS("AssetStorage") << "LLViewerAssetStorage::storeAssetData (legacy)" << asset_id << ":" << LLAssetType::lookup(asset_type) << LL_ENDL; + + LL_DEBUGS("AssetStorage") << "ASSET_ID: " << asset_id << LL_ENDL; + + S32 size = 0; + LLFILE* fp = LLFile::fopen(filename, "rb"); + if (fp) + { + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + } + if( size ) + { + LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest; + + legacy->mUpCallback = callback; + legacy->mUserData = user_data; + + LLVFile file(mVFS, asset_id, asset_type, LLVFile::WRITE); + + file.setMaxSize(size); + + const S32 buf_size = 65536; + U8 copy_buf[buf_size]; + while ((size = (S32)fread(copy_buf, 1, buf_size, fp))) + { + file.write(copy_buf, size); + } + fclose(fp); + + // if this upload fails, the caller needs to setup a new tempfile for us + if (temp_file) + { + LLFile::remove(filename); + } + + // LLAssetStorage metric: Success not needed; handled in the overloaded method here: + + LLViewerAssetStorage::storeAssetData( + tid, + asset_type, + legacyStoreDataCallback, + (void**)legacy, + temp_file, + is_priority); + } + else // size == 0 (but previous block changes size) + { + if( fp ) + { + // LLAssetStorage metric: Zero size + reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file was zero length" ); + } + else + { + // LLAssetStorage metric: Missing File + reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_FILE_NONEXIST, __FILE__, __LINE__, "The file didn't exist" ); + } + if (callback) + { + callback(asset_id, user_data, LL_ERR_CANNOT_OPEN_FILE, LL_EXSTAT_BLOCKED_FILE); + } + } } @@ -334,56 +358,218 @@ void LLViewerAssetStorage::storeAssetData( // virtual void LLViewerAssetStorage::_queueDataRequest( - const LLUUID& uuid, - LLAssetType::EType atype, - LLGetAssetCallback callback, - void *user_data, - BOOL duplicate, - BOOL is_priority) + const LLUUID& uuid, + LLAssetType::EType atype, + LLGetAssetCallback callback, + void *user_data, + BOOL duplicate, + BOOL is_priority) +{ + mCountRequests++; + queueRequestHttp(uuid, atype, callback, user_data, duplicate, is_priority); +} + +void LLViewerAssetStorage::queueRequestHttp( + const LLUUID& uuid, + LLAssetType::EType atype, + LLGetAssetCallback callback, + void *user_data, + BOOL duplicate, + BOOL is_priority) { - if (mUpstreamHost.isOk()) - { - // stash the callback info so we can find it after we get the response message - LLViewerAssetRequest *req = new LLViewerAssetRequest(uuid, atype); - req->mDownCallback = callback; - req->mUserData = user_data; - req->mIsPriority = is_priority; - if (!duplicate) - { - // Only collect metrics for non-duplicate requests. Others - // are piggy-backing and will artificially lower averages. - req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); - } - - mPendingDownloads.push_back(req); - - if (!duplicate) - { - // send request message to our upstream data provider - // Create a new asset transfer. - LLTransferSourceParamsAsset spa; - spa.setAsset(uuid, atype); - - // Set our destination file, and the completion callback. - LLTransferTargetParamsVFile tpvf; - tpvf.setAsset(uuid, atype); - tpvf.setCallback(downloadCompleteCallback, *req); - - LL_DEBUGS("AssetStorage") << "Starting transfer for " << uuid << LL_ENDL; - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET); - ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f)); - - LLViewerAssetStatsFF::record_enqueue(atype, false, false); - } - } - else - { - // uh-oh, we shouldn't have gotten here - LL_WARNS() << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; - if (callback) - { - callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); - } - } + LL_DEBUGS("ViewerAsset") << "Request asset via HTTP " << uuid << " type " << LLAssetType::lookup(atype) << LL_ENDL; + + bool with_http = true; + LLViewerAssetRequest *req = new LLViewerAssetRequest(uuid, atype, with_http); + req->mDownCallback = callback; + req->mUserData = user_data; + req->mIsPriority = is_priority; + if (!duplicate) + { + // Only collect metrics for non-duplicate requests. Others + // are piggy-backing and will artificially lower averages. + req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); + } + mPendingDownloads.push_back(req); + + // This is the same as the current UDP logic - don't re-request a duplicate. + if (!duplicate) + { + bool with_http = true; + bool is_temp = false; + LLViewerAssetStatsFF::record_enqueue(atype, with_http, is_temp); + + LLCoprocedureManager::instance().enqueueCoprocedure("AssetStorage","LLViewerAssetStorage::assetRequestCoro", + boost::bind(&LLViewerAssetStorage::assetRequestCoro, this, req, uuid, atype, callback, user_data)); + } } +void LLViewerAssetStorage::capsRecvForRegion(const LLUUID& region_id, std::string pumpname) +{ + LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(region_id); + if (!regionp) + { + LL_WARNS("ViewerAsset") << "region not found for region_id " << region_id << LL_ENDL; + } + else + { + mViewerAssetUrl = regionp->getViewerAssetUrl(); + } + + LLEventPumps::instance().obtain(pumpname).post(LLSD()); +} + +struct LLScopedIncrement +{ + LLScopedIncrement(S32& counter): + mCounter(counter) + { + ++mCounter; + } + ~LLScopedIncrement() + { + --mCounter; + } + S32& mCounter; +}; + +void LLViewerAssetStorage::assetRequestCoro( + LLViewerAssetRequest *req, + const LLUUID uuid, + LLAssetType::EType atype, + LLGetAssetCallback callback, + void *user_data) +{ + LLScopedIncrement coro_count_boost(mAssetCoroCount); + mCountStarted++; + + S32 result_code = LL_ERR_NOERR; + LLExtStat ext_status = LL_EXSTAT_NONE; + + if (!gAgent.getRegion()) + { + LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: no region set" << LL_ENDL; + result_code = LL_ERR_ASSET_REQUEST_FAILED; + ext_status = LL_EXSTAT_NONE; + removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status); + return; + } + else if (!gAgent.getRegion()->capabilitiesReceived()) + { + LL_WARNS_ONCE("ViewerAsset") << "Waiting for capabilities" << LL_ENDL; + + LLEventStream capsRecv("waitForCaps", true); + + gAgent.getRegion()->setCapabilitiesReceivedCallback( + boost::bind(&LLViewerAssetStorage::capsRecvForRegion, this, _1, capsRecv.getName())); + + llcoro::suspendUntilEventOn(capsRecv); + LL_WARNS_ONCE("ViewerAsset") << "capsRecv got event" << LL_ENDL; + LL_WARNS_ONCE("ViewerAsset") << "region " << gAgent.getRegion() << " mViewerAssetUrl " << mViewerAssetUrl << LL_ENDL; + } + if (mViewerAssetUrl.empty() && gAgent.getRegion()) + { + mViewerAssetUrl = gAgent.getRegion()->getViewerAssetUrl(); + } + if (mViewerAssetUrl.empty()) + { + LL_WARNS_ONCE("ViewerAsset") << "asset request fails: caps received but no viewer asset cap found" << LL_ENDL; + result_code = LL_ERR_ASSET_REQUEST_FAILED; + ext_status = LL_EXSTAT_NONE; + removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status); + return; + } + std::string url = getAssetURL(mViewerAssetUrl, uuid,atype); + LL_DEBUGS("ViewerAsset") << "request url: " << url << LL_ENDL; + + LLCore::HttpRequest::policy_t httpPolicy(LLAppCoreHttp::AP_TEXTURE); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("assetRequestCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + + LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts); + + if (LLApp::isQuitting()) + { + // Bail out if result arrives after shutdown has been started. + return; + } + + mCountCompleted++; + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status) + { + LL_DEBUGS("ViewerAsset") << "request failed, status " << status.toTerseString() << LL_ENDL; + result_code = LL_ERR_ASSET_REQUEST_FAILED; + ext_status = LL_EXSTAT_NONE; + } + else + { + LL_DEBUGS("ViewerAsset") << "request succeeded, url " << url << LL_ENDL; + + const LLSD::Binary &raw = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary(); + + S32 size = raw.size(); + if (size > 0) + { + mTotalBytesFetched += size; + + // This create-then-rename flow is modeled on + // LLTransferTargetVFile, which is what was used in the UDP + // case. + LLUUID temp_id; + temp_id.generate(); + LLVFile vf(gAssetStorage->mVFS, temp_id, atype, LLVFile::WRITE); + vf.setMaxSize(size); + req->mBytesFetched = size; + if (!vf.write(raw.data(),size)) + { + // TODO asset-http: handle error + LL_WARNS("ViewerAsset") << "Failure in vf.write()" << LL_ENDL; + result_code = LL_ERR_ASSET_REQUEST_FAILED; + ext_status = LL_EXSTAT_VFS_CORRUPT; + } + else if (!vf.rename(uuid, atype)) + { + LL_WARNS("ViewerAsset") << "rename failed" << LL_ENDL; + result_code = LL_ERR_ASSET_REQUEST_FAILED; + ext_status = LL_EXSTAT_VFS_CORRUPT; + } + else + { + mCountSucceeded++; + } + } + else + { + // TODO asset-http: handle invalid size case + LL_WARNS("ViewerAsset") << "bad size" << LL_ENDL; + result_code = LL_ERR_ASSET_REQUEST_FAILED; + ext_status = LL_EXSTAT_NONE; + } + } + + // Clean up pending downloads and trigger callbacks + removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status); +} + +std::string LLViewerAssetStorage::getAssetURL(const std::string& cap_url, const LLUUID& uuid, LLAssetType::EType atype) +{ + std::string type_name = LLAssetType::lookup(atype); + std::string url = cap_url + "/?" + type_name + "_id=" + uuid.asString(); + return url; +} + +void LLViewerAssetStorage::logAssetStorageInfo() +{ + LLMemory::logMemoryInfo(true); + LL_INFOS("AssetStorage") << "Active coros " << mAssetCoroCount << LL_ENDL; + LL_INFOS("AssetStorage") << "mPendingDownloads size " << mPendingDownloads.size() << LL_ENDL; + LL_INFOS("AssetStorage") << "mCountStarted " << mCountStarted << LL_ENDL; + LL_INFOS("AssetStorage") << "mCountCompleted " << mCountCompleted << LL_ENDL; + LL_INFOS("AssetStorage") << "mCountSucceeded " << mCountSucceeded << LL_ENDL; + LL_INFOS("AssetStorage") << "mTotalBytesFetched " << mTotalBytesFetched << LL_ENDL; +} diff --git a/indra/newview/llviewerassetstorage.h b/indra/newview/llviewerassetstorage.h index 6baec647e6..50131682e7 100644 --- a/indra/newview/llviewerassetstorage.h +++ b/indra/newview/llviewerassetstorage.h @@ -28,10 +28,12 @@ #define LLVIEWERASSETSTORAGE_H #include "llassetstorage.h" -//#include "curl/curl.h" +#include "llcorehttputil.h" class LLVFile; +class LLViewerAssetRequest; + class LLViewerAssetStorage : public LLAssetStorage { public: @@ -41,7 +43,6 @@ public: LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, LLVFS *static_vfs); - using LLAssetStorage::storeAssetData; virtual void storeAssetData( const LLTransactionID& tid, LLAssetType::EType atype, @@ -65,8 +66,6 @@ public: F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT); protected: - using LLAssetStorage::_queueDataRequest; - // virtual void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type, @@ -74,6 +73,33 @@ protected: void *user_data, BOOL duplicate, BOOL is_priority); + + void queueRequestHttp(const LLUUID& uuid, + LLAssetType::EType type, + void (*callback) (LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), + void *user_data, + BOOL duplicate, + BOOL is_priority); + + void capsRecvForRegion(const LLUUID& region_id, std::string pumpname); + + void assetRequestCoro(LLViewerAssetRequest *req, + const LLUUID uuid, + LLAssetType::EType atype, + void (*callback) (LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), + void *user_data); + + std::string getAssetURL(const std::string& cap_url, const LLUUID& uuid, LLAssetType::EType atype); + + void logAssetStorageInfo(); + + std::string mViewerAssetUrl; + S32 mAssetCoroCount; + S32 mCountRequests; + S32 mCountStarted; + S32 mCountCompleted; + S32 mCountSucceeded; + S64 mTotalBytesFetched; }; #endif diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 960a36a251..e53db403e1 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -106,6 +106,7 @@ const F32 TELEPORT_EXPIRY_PER_ATTACHMENT = 3.f; U32 gRecentFrameCount = 0; // number of 'recent' frames LLFrameTimer gRecentFPSTime; LLFrameTimer gRecentMemoryTime; +LLFrameTimer gAssetStorageLogTime; // Rendering stuff void pre_show_depth_buffer(); @@ -226,6 +227,12 @@ void display_stats() LLMemory::logMemoryInfo(TRUE) ; gRecentMemoryTime.reset(); } + F32 asset_storage_log_freq = gSavedSettings.getF32("AssetStorageLogFrequency"); + if (asset_storage_log_freq > 0.f && gAssetStorageLogTime.getElapsedTimeF32() >= asset_storage_log_freq) + { + gAssetStorageLogTime.reset(); + gAssetStorage->logAssetStorageInfo(); + } } static LLTrace::BlockTimerStatHandle FTM_PICK("Picking"); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 899ab3a371..eb37613c95 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -521,7 +521,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, mColoName("unknown"), mProductSKU("unknown"), mProductName("unknown"), - mHttpUrl(""), + mViewerAssetUrl(""), mCacheLoaded(FALSE), mCacheDirty(FALSE), mReleaseNotesRequested(FALSE), @@ -2843,12 +2843,9 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("IsExperienceAdmin"); capabilityNames.append("IsExperienceContributor"); capabilityNames.append("RegionExperiences"); - capabilityNames.append("GetMesh"); - capabilityNames.append("GetMesh2"); capabilityNames.append("GetMetadata"); capabilityNames.append("GetObjectCost"); capabilityNames.append("GetObjectPhysicsData"); - capabilityNames.append("GetTexture"); capabilityNames.append("GroupAPIv1"); capabilityNames.append("GroupMemberData"); capabilityNames.append("GroupProposalBallot"); @@ -2895,6 +2892,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("UpdateScriptAgent"); capabilityNames.append("UpdateScriptTask"); capabilityNames.append("UploadBakedTexture"); + capabilityNames.append("ViewerAsset"); capabilityNames.append("ViewerMetrics"); capabilityNames.append("ViewerStartAuction"); capabilityNames.append("ViewerStats"); @@ -2961,9 +2959,9 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u else { mImpl->mCapabilities[name] = url; - if(name == "GetTexture") + if(name == "ViewerAsset") { - mHttpUrl = url ; + mViewerAssetUrl = url; } } } @@ -2974,9 +2972,9 @@ void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::stri if ( ! ( name == "EventQueueGet" || name == "UntrustedSimulatorMessage" || name == "SimulatorFeatures" ) ) { mImpl->mSecondCapabilitiesTracker[name] = url; - if(name == "GetTexture") + if(name == "ViewerAsset") { - mHttpUrl = url ; + mViewerAssetUrl = url; } } } diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index a7bb546d2c..61ce5b454d 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -354,7 +354,7 @@ public: friend std::ostream& operator<<(std::ostream &s, const LLViewerRegion ®ion); /// implements LLCapabilityProvider virtual std::string getDescription() const; - std::string getHttpUrl() const { return mHttpUrl ;} + std::string getViewerAssetUrl() const { return mViewerAssetUrl; } U32 getNumOfVisibleGroups() const; U32 getNumOfActiveCachedObjects() const; @@ -506,7 +506,7 @@ private: std::string mColoName; std::string mProductSKU; std::string mProductName; - std::string mHttpUrl ; + std::string mViewerAssetUrl ; // Maps local ids to cache entries. // Regions can have order 10,000 objects, so assume diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 3968266c27..80c6805ead 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -9387,6 +9387,3 @@ BOOL LLVOAvatar::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, // non-self avatars don't have wearables return FALSE; } - - - diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp index a08e32cb49..e2e7f09c3b 100644 --- a/indra/newview/tests/llviewerassetstats_test.cpp +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -71,25 +71,33 @@ static const char * all_keys[] = { "duration", "fps", - "get_other", + "get_other_http", + "get_other_udp", "get_texture_temp_http", "get_texture_temp_udp", "get_texture_non_temp_http", "get_texture_non_temp_udp", + "get_wearable_http", "get_wearable_udp", + "get_sound_http", "get_sound_udp", + "get_gesture_http", "get_gesture_udp" }; static const char * resp_keys[] = { - "get_other", + "get_other_http", + "get_other_udp", "get_texture_temp_http", "get_texture_temp_udp", "get_texture_non_temp_http", "get_texture_non_temp_udp", + "get_wearable_http", "get_wearable_udp", + "get_sound_http", "get_sound_udp", + "get_gesture_http", "get_gesture_udp" }; @@ -540,11 +548,17 @@ namespace tut ensure("sd[get_gesture_udp][enqueued] is 0", (0 == sd["get_gesture_udp"]["enqueued"].asInteger())); ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); - ensure("sd[get_wearable_udp][enqueued] is 4", (4 == sd["get_wearable_udp"]["enqueued"].asInteger())); - ensure("sd[get_wearable_udp][dequeued] is 4", (4 == sd["get_wearable_udp"]["dequeued"].asInteger())); + ensure("sd[get_wearable_http][enqueued] is 2", (2 == sd["get_wearable_http"]["enqueued"].asInteger())); + ensure("sd[get_wearable_http][dequeued] is 2", (2 == sd["get_wearable_http"]["dequeued"].asInteger())); - ensure("sd[get_other][enqueued] is 4", (4 == sd["get_other"]["enqueued"].asInteger())); - ensure("sd[get_other][dequeued] is 0", (0 == sd["get_other"]["dequeued"].asInteger())); + ensure("sd[get_wearable_udp][enqueued] is 2", (2 == sd["get_wearable_udp"]["enqueued"].asInteger())); + ensure("sd[get_wearable_udp][dequeued] is 2", (2 == sd["get_wearable_udp"]["dequeued"].asInteger())); + + ensure("sd[get_other_http][enqueued] is 2", (2 == sd["get_other_http"]["enqueued"].asInteger())); + ensure("sd[get_other_http][dequeued] is 0", (0 == sd["get_other_http"]["dequeued"].asInteger())); + + ensure("sd[get_other_udp][enqueued] is 2", (2 == sd["get_other_udp"]["enqueued"].asInteger())); + ensure("sd[get_other_udp][dequeued] is 0", (0 == sd["get_other_udp"]["dequeued"].asInteger())); // Reset and check zeros... // Reset leaves current region in place diff --git a/indra/test/test.cpp b/indra/test/test.cpp index e42374d56b..630af2b73b 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -34,6 +34,7 @@ * */ + #include "linden_common.h" #include "llerrorcontrol.h" #include "lltut.h" @@ -684,4 +685,5 @@ int main(int argc, char **argv) return retval; //delete mycallback; + } diff --git a/scripts/metrics/viewer_asset_logs.py b/scripts/metrics/viewer_asset_logs.py new file mode 100644 index 0000000000..e48286f696 --- /dev/null +++ b/scripts/metrics/viewer_asset_logs.py @@ -0,0 +1,102 @@ +#!runpy.sh + +"""\ + +This module contains tools for analyzing viewer asset metrics logs produced by the viewer. + +$LicenseInfo:firstyear=2016&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2016, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" + +import argparse +from lxml import etree +from llbase import llsd + +def get_metrics_record(infiles): + for filename in args.infiles: + f = open(filename) + # get an iterable + context = etree.iterparse(f, events=("start", "end")) + + # turn it into an iterator + context = iter(context) + + # get the root element + event, root = context.next() + try: + for event, elem in context: + if event == "end" and elem.tag == "llsd": + xmlstr = etree.tostring(elem, encoding="utf8", method="xml") + sd = llsd.parse_xml(xmlstr) + yield sd + except etree.XMLSyntaxError: + print "Fell off end of document" + + f.close() + +def update_stats(stats,rec): + for region in rec["regions"]: + region_key = (region["grid_x"],region["grid_y"]) + #print "region",region_key + for field, val in region.iteritems(): + if field in ["duration","grid_x","grid_y"]: + continue + if field == "fps": + # handle fps record as special case + pass + else: + #print "field",field + stats.setdefault(field,{}) + type_stats = stats.get(field) + newcount = val["resp_count"] + #print "field",field,"add count",newcount + type_stats["count"] = type_stats.get("count",0) + val["resp_count"] + #print "field",field,"count",type_stats["count"] + if (newcount>0): + type_stats["sum"] = type_stats.get("sum",0) + val["resp_count"] * val["resp_mean"] + type_stats["sum_bytes"] = type_stats.get("sum_bytes",0) + val["resp_count"] * val.get("resp_mean_bytes",0) + type_stats["enqueued"] = type_stats.get("enqueued",0) + val["enqueued"] + type_stats["dequeued"] = type_stats.get("dequeued",0) + val["dequeued"] + + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description="process metric xml files for viewer asset fetching") + parser.add_argument("--verbose", action="store_true",help="verbose flag") + parser.add_argument("infiles", nargs="+", help="name of .xml files to process") + args = parser.parse_args() + + #print "process files:",args.infiles + + stats = {} + for rec in get_metrics_record(args.infiles): + #print "record",rec + + update_stats(stats,rec) + + for key in sorted(stats.keys()): + val = stats[key] + if val["count"] > 0: + print key,"count",val["count"],"mean_time",val["sum"]/val["count"],"mean_bytes",val["sum_bytes"]/val["count"],"net bytes/sec",val["sum_bytes"]/val["sum"],"enqueued",val["enqueued"],"dequeued",val["dequeued"] + else: + print key,"count",val["count"],"enqueued",val["enqueued"],"dequeued",val["dequeued"] + |