// 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; }
// static void LLAssetStorage::uploadCompleteCallback(const LLUUID& uuid, void *user_data, S32 result, LLExtStat ext_status) // StoreAssetData callback (fixed) { if (!gAssetStorage) { llwarns << "LLAssetStorage::uploadCompleteCallback has no gAssetStorage!" << llendl; return; } LLAssetRequest *req = (LLAssetRequest *)user_data; BOOL success = TRUE; if (result) { llwarns << "LLAssetStorage::uploadCompleteCallback " << result << ":" << getErrorString(result) << " trying to upload file to upstream provider" << llendl; 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::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 llinfos << "Discarding duplicate request for UUID " << uuid << llendl; return; } } LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest; legacy->mDownCallback = callback; legacy->mUserData = user_data; getAssetData(uuid, type, legacyGetDataCallback, (void **)legacy, is_priority); }
void LLHTTPAssetStorage::bumpTimedOutUploads() { // No point bumping currently running uploads if there are no others in line. if (!(mPendingUploads.size() > mRunningUploads.size())) { return; } F64 mt_secs = LLMessageSystem::getMessageTimeSeconds(); // deletePendingRequest will modify the mRunningUploads list so we don't want to iterate over it. request_list_t temp_running = mRunningUploads; request_list_t::iterator it = temp_running.begin(); request_list_t::iterator end = temp_running.end(); for ( ; it != end; ++it) { //request_list_t::iterator curiter = iter++; LLAssetRequest* req = *it; if ( LL_ASSET_STORAGE_TIMEOUT < (mt_secs - req->mTime) ) { llwarns << "Asset upload request timed out for " << req->getUUID() << "." << LLAssetType::lookup(req->getType()) << ", bumping to the back of the line!" << llendl; deletePendingRequest(RT_UPLOAD, req->getType(), req->getUUID()); } } }
// internal requester, used by getAssetData in superclass void LLHTTPAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType type, void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32), void *user_data, BOOL duplicate, BOOL is_priority) { // stash the callback info so we can find it after we get the response message LLAssetRequest *req = new LLAssetRequest(uuid, type); req->mDownCallback = callback; req->mUserData = user_data; req->mIsPriority = is_priority; // this will get picked up and downloaded in checkForTimeouts // // HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACK! Asset requests were taking too long and timing out. // Since texture requests are the LEAST sensitive (on the simulator) to being delayed, add // non-texture requests to the front, and add texture requests to the back. The theory is // that we always want them first, even if they're out of order. // if (req->getType() == LLAssetType::AT_TEXTURE) { mPendingDownloads.push_back(req); } else { mPendingDownloads.push_front(req); } }
void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) { F64 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))) { llwarns << "Asset " << getRequestName((ERequestType)rt) << " request " << (all ? "aborted" : "timed out") << " for " << tmp->getUUID() << "." << LLAssetType::lookup(tmp->getType()) << llendl; 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; } }
// 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) { 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 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; }
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; } }
void LLAssetStorage::downloadCompleteCallback( S32 result, const LLUUID& file_id, LLAssetType::EType file_type, void* user_data, LLExtStat ext_status) { lldebugs << "LLAssetStorage::downloadCompleteCallback() for " << file_id << "," << LLAssetType::lookup(file_type) << llendl; LLAssetRequest* req = (LLAssetRequest*)user_data; if(!req) { llwarns << "LLAssetStorage::downloadCompleteCallback called without" "a valid request." << llendl; return; } if (!gAssetStorage) { llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl; return; } // 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 the LLAssetRequest doesn't exist in the downloads queue, then it either has already been deleted // by _cleanupRequests, or it's a transfer. if (download_iter != gAssetStorage->mPendingDownloads.end()) { 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) { llwarns << "downloadCompleteCallback has non-existent or zero-size asset " << req->getUUID() << llendl; 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) { tmp->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), tmp->mUserData, result, ext_status); } delete tmp; } }
// IW - uuid is passed by value to avoid side effects, please don't re-add & void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), void *user_data, BOOL is_priority) { lldebugs << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << llendl; if (mShutDown) { return; // don't get the asset or do any callbacks, we are shutting down } if (uuid.isNull()) { // Special case early out for NULL uuid if (callback) { callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); } return; } /* <edit> */ if(std::find(mBlackListedAsset.begin(),mBlackListedAsset.end(),uuid) != mBlackListedAsset.end()) { llinfos << "Blacklisted asset " << uuid.asString() << " was trying to be accessed!!!!!!" << llendl; if (callback) { callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); } return; } /* </edit> */ BOOL exists = mVFS->getExists(uuid, type); LLVFile file(mVFS, uuid, type); U32 size = exists ? file.getSize() : 0; if (size < 1) { if (exists) { llwarns << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << llendl; 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 llwarns << "Discarding duplicate request for asset " << uuid << "." << LLAssetType::lookup(type) << llendl; return; } // this is a duplicate request // queue the request, but don't actually ask for it again duplicate = TRUE; } } if (duplicate) { llinfos << "Adding additional non-duplicate request for asset " << uuid << "." << LLAssetType::lookup(type) << llendl; } // This can be overridden by subclasses _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority); } else { // 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); } } }
// overloaded to additionally move data to/from the webserver void LLHTTPAssetStorage::checkForTimeouts() { CURLMcode mcode; LLAssetRequest *req; while ( (req = findNextRequest(mPendingDownloads, mRunningDownloads)) ) { // Setup this curl download request // We need to generate a new request here // since the one in the list could go away char tmp_url[MAX_STRING]; /*Flawfinder: ignore*/ char uuid_str[UUID_STR_LENGTH]; /*Flawfinder: ignore*/ req->getUUID().toString(uuid_str); std::string base_url = getBaseURL(req->getUUID(), req->getType()); snprintf(tmp_url, sizeof(tmp_url), "%s/%36s.%s", base_url.c_str() , uuid_str, LLAssetType::lookup(req->getType())); /* Flawfinder: ignore */ LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(), req->getType(), RT_DOWNLOAD, tmp_url, mCurlMultiHandle); new_req->mTmpUUID.generate(); // Sets pending download flag internally new_req->setupCurlHandle(); curl_easy_setopt(new_req->mCurlHandle, CURLOPT_FOLLOWLOCATION, TRUE); curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &curlDownCallback); curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEDATA, new_req->mCurlHandle); mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle); if (mcode > CURLM_OK) { // Failure. Deleting the pending request will remove it from the running // queue, and push it to the end of the pending queue. new_req->cleanupCurlHandle(); deletePendingRequest(RT_DOWNLOAD, new_req->getType(), new_req->getUUID()); break; } else { llinfos << "Requesting " << new_req->mURLBuffer << llendl; } } while ( (req = findNextRequest(mPendingUploads, mRunningUploads)) ) { // setup this curl upload request bool do_compress = req->getType() == LLAssetType::AT_OBJECT; char tmp_url[MAX_STRING];/*Flawfinder: ignore*/ char uuid_str[UUID_STR_LENGTH];/*Flawfinder: ignore*/ req->getUUID().toString(uuid_str); snprintf(tmp_url, sizeof(tmp_url), /* Flawfinder: ignore */ do_compress ? "%s/%s.%s.gz" : "%s/%s.%s", mBaseURL.c_str(), uuid_str, LLAssetType::lookup(req->getType())); LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(), req->getType(), RT_UPLOAD, tmp_url, mCurlMultiHandle); if (do_compress) { new_req->prepareCompressedUpload(); } // Sets pending upload flag internally new_req->setupCurlHandle(); curl_easy_setopt(new_req->mCurlHandle, CURLOPT_UPLOAD, 1); curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &nullOutputCallback); if (do_compress) { curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION, &LLHTTPAssetRequest::curlCompressedUploadCallback); } else { LLVFile file(mVFS, req->getUUID(), req->getType()); curl_easy_setopt(new_req->mCurlHandle, CURLOPT_INFILESIZE, file.getSize()); curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION, &curlUpCallback); } curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle); mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle); if (mcode > CURLM_OK) { // Failure. Deleting the pending request will remove it from the running // queue, and push it to the end of the pending queue. new_req->cleanupCurlHandle(); deletePendingRequest(RT_UPLOAD, new_req->getType(), new_req->getUUID()); break; } else { llinfos << "Requesting PUT " << new_req->mURLBuffer << llendl; } // Pending upload will have been flagged by the request } while ( (req = findNextRequest(mPendingLocalUploads, mRunningLocalUploads)) ) { // setup this curl upload request LLVFile file(mVFS, req->getUUID(), req->getType()); char tmp_url[MAX_STRING]; /*Flawfinder: ignore*/ char uuid_str[UUID_STR_LENGTH]; /*Flawfinder: ignore*/ req->getUUID().toString(uuid_str); // KLW - All temporary uploads are saved locally "http://localhost:12041/asset" snprintf(tmp_url, sizeof(tmp_url), "%s/%36s.%s", mLocalBaseURL.c_str(), uuid_str, LLAssetType::lookup(req->getType())); /* Flawfinder: ignore */ LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(), req->getType(), RT_LOCALUPLOAD, tmp_url, mCurlMultiHandle); new_req->mRequestingAgentID = req->mRequestingAgentID; // Sets pending upload flag internally new_req->setupCurlHandle(); curl_easy_setopt(new_req->mCurlHandle, CURLOPT_PUT, 1); curl_easy_setopt(new_req->mCurlHandle, CURLOPT_INFILESIZE, file.getSize()); curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &nullOutputCallback); curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION, &curlUpCallback); curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle); mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle); if (mcode > CURLM_OK) { // Failure. Deleting the pending request will remove it from the running // queue, and push it to the end of the pending queue. new_req->cleanupCurlHandle(); deletePendingRequest(RT_LOCALUPLOAD, new_req->getType(), new_req->getUUID()); break; } else { llinfos << "TAT: LLHTTPAssetStorage::checkForTimeouts() : pending local!" << " Requesting PUT " << new_req->mURLBuffer << llendl; } // Pending upload will have been flagged by the request } S32 count = 0; int queue_length; do { mcode = curl_multi_perform(mCurlMultiHandle, &queue_length); count++; } while (mcode == CURLM_CALL_MULTI_PERFORM && (count < 5)); CURLMsg *curl_msg; do { curl_msg = curl_multi_info_read(mCurlMultiHandle, &queue_length); if (curl_msg && curl_msg->msg == CURLMSG_DONE) { long curl_result = 0; S32 xfer_result = 0; LLHTTPAssetRequest *req = NULL; curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_PRIVATE, &req); curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_HTTP_CODE, &curl_result); if (RT_UPLOAD == req->mRequestType || RT_LOCALUPLOAD == req->mRequestType) { if (curl_msg->data.result == CURLE_OK && ( curl_result == HTTP_OK || curl_result == HTTP_PUT_OK || curl_result == HTTP_NO_CONTENT)) { llinfos << "Success uploading " << req->getUUID() << " to " << req->mURLBuffer << llendl; if (RT_LOCALUPLOAD == req->mRequestType) { addTempAssetData(req->getUUID(), req->mRequestingAgentID, mHostName); } } else if (curl_msg->data.result == CURLE_COULDNT_CONNECT || curl_msg->data.result == CURLE_OPERATION_TIMEOUTED || curl_result == HTTP_SERVER_BAD_GATEWAY || curl_result == HTTP_SERVER_TEMP_UNAVAILABLE) { llwarns << "Re-requesting upload for " << req->getUUID() << ". Received upload error to " << req->mURLBuffer << " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl; } else { llwarns << "Failure uploading " << req->getUUID() << " to " << req->mURLBuffer << " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl; xfer_result = LL_ERR_ASSET_REQUEST_FAILED; } if (!(curl_msg->data.result == CURLE_COULDNT_CONNECT || curl_msg->data.result == CURLE_OPERATION_TIMEOUTED || curl_result == HTTP_SERVER_BAD_GATEWAY || curl_result == HTTP_SERVER_TEMP_UNAVAILABLE)) { // shared upload finished callback // in the base class, this is called from processUploadComplete _callUploadCallbacks(req->getUUID(), req->getType(), (xfer_result == 0)); // Pending upload flag will get cleared when the request is deleted } } else if (RT_DOWNLOAD == req->mRequestType) { if (curl_result == HTTP_OK && curl_msg->data.result == CURLE_OK) { if (req->mVFile && req->mVFile->getSize() > 0) { llinfos << "Success downloading " << req->mURLBuffer << ", size " << req->mVFile->getSize() << llendl; req->mVFile->rename(req->getUUID(), req->getType()); } else { // *TODO: if this actually indicates a bad asset on the server // (not certain at this point), then delete it llwarns << "Found " << req->mURLBuffer << " to be zero size" << llendl; xfer_result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; } } else { // KLW - TAT See if an avatar owns this texture, and if so request re-upload. llwarns << "Failure downloading " << req->mURLBuffer << " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl; xfer_result = (curl_result == HTTP_MISSING) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED; if (req->mVFile) { req->mVFile->remove(); } } // call the static callback for transfer completion // this will cleanup all requests for this asset, including ours downloadCompleteCallback( xfer_result, req->getUUID(), req->getType(), (void *)req); // Pending download flag will get cleared when the request is deleted } else { // nothing, just axe this request // currently this can only mean an asset delete } // Deleting clears the pending upload/download flag if it's set and the request is transferring delete req; req = NULL; } } while (curl_msg && queue_length > 0); // Cleanup // We want to bump to the back of the line any running uploads that have timed out. bumpTimedOutUploads(); LLAssetStorage::checkForTimeouts(); }
// 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) { 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) { callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); } return; } if(std::find(mBlackListedAsset.begin(),mBlackListedAsset.end(),uuid) != mBlackListedAsset.end()) { LL_INFOS() << "Blacklisted asset " << uuid.asString() << " was trying to be accessed!!!!!!" << LL_ENDL; if (callback) { 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::downloadCompleteCallback( S32 result, const LLUUID& file_id, LLAssetType::EType file_type, void* user_data, LLExtStat ext_status) { lldebugs << "LLAssetStorage::downloadCompleteCallback() for " << file_id << "," << LLAssetType::lookup(file_type) << llendl; LLAssetRequest* req = (LLAssetRequest*)user_data; if(!req) { llwarns << "LLAssetStorage::downloadCompleteCallback called without" "a valid request." << llendl; return; } if (!gAssetStorage) { llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl; 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) { llwarns << "downloadCompleteCallback has non-existent or zero-size asset " << req->getUUID() << llendl; 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() == req->getUUID()) && (tmp->getType()== req->getType())) { 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) { tmp->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), tmp->mUserData, result, ext_status); } delete tmp; } }