00001
00032 #include "linden_common.h"
00033
00034
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037
00038 #include "llassetstorage.h"
00039
00040
00041 #include "llmath.h"
00042 #include "llstring.h"
00043 #include "lldir.h"
00044 #include "llsd.h"
00045
00046
00047 #include "message.h"
00048 #include "llxfermanager.h"
00049 #include "llvfile.h"
00050 #include "llvfs.h"
00051 #include "lldbstrings.h"
00052
00053 #include "lltransfersourceasset.h"
00054 #include "lltransfertargetvfile.h"
00055
00056 #include "llmetrics.h"
00057
00058 LLAssetStorage *gAssetStorage = NULL;
00059 LLMetrics *LLAssetStorage::metric_recipient = NULL;
00060
00061 const LLUUID CATEGORIZE_LOST_AND_FOUND_ID("00000000-0000-0000-0000-000000000010");
00062
00066
00067 LLAssetInfo::LLAssetInfo( void )
00068 : mDescription(),
00069 mName(),
00070 mUuid(),
00071 mCreatorID(),
00072 mType( LLAssetType::AT_NONE )
00073 { }
00074
00075 LLAssetInfo::LLAssetInfo( const LLUUID& object_id, const LLUUID& creator_id,
00076 LLAssetType::EType type, const char* name,
00077 const char* desc )
00078 : mUuid( object_id ),
00079 mCreatorID( creator_id ),
00080 mType( type )
00081 {
00082 setName( name );
00083 setDescription( desc );
00084 }
00085
00086 LLAssetInfo::LLAssetInfo( const LLNameValue& nv )
00087 {
00088 setFromNameValue( nv );
00089 }
00090
00091
00092
00093 void LLAssetInfo::setName( const std::string& name )
00094 {
00095 if( !name.empty() )
00096 {
00097 mName.assign( name, 0, llmin((U32)name.size(), (U32)DB_INV_ITEM_NAME_STR_LEN) );
00098 mName.erase( std::remove(mName.begin(), mName.end(), '|'),
00099 mName.end() );
00100 }
00101 }
00102
00103
00104
00105 void LLAssetInfo::setDescription( const std::string& desc )
00106 {
00107 if( !desc.empty() )
00108 {
00109 mDescription.assign( desc, 0, llmin((U32)desc.size(),
00110 (U32)DB_INV_ITEM_DESC_STR_LEN) );
00111 mDescription.erase( std::remove(mDescription.begin(),
00112 mDescription.end(), '|'),
00113 mDescription.end() );
00114 }
00115 }
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 void LLAssetInfo::setFromNameValue( const LLNameValue& nv )
00126 {
00127 std::string str;
00128 std::string buf;
00129 std::string::size_type pos1;
00130 std::string::size_type pos2;
00131
00132
00133 str.assign( nv.mName );
00134 pos1 = str.find('|');
00135 buf.assign( str, 0, pos1++ );
00136 mType = LLAssetType::lookup( buf.c_str() );
00137 buf.assign( str, pos1, std::string::npos );
00138 mUuid.set( buf.c_str() );
00139
00140
00141 str.assign( nv.getAsset() );
00142 pos1 = str.find('|');
00143 buf.assign( str, 0, pos1++ );
00144 mCreatorID.set( buf.c_str() );
00145 pos2 = str.find( '|', pos1 );
00146 buf.assign( str, pos1, (pos2++) - pos1 );
00147 setName( buf.c_str() );
00148 buf.assign( str, pos2, std::string::npos );
00149 setDescription( buf.c_str() );
00150 llinfos << "uuid: " << mUuid << llendl;
00151 llinfos << "creator: " << mCreatorID << llendl;
00152 }
00153
00157
00158 LLAssetRequest::LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType type)
00159 : mUUID(uuid),
00160 mType(type),
00161 mDownCallback( NULL ),
00162 mUpCallback( NULL ),
00163 mInfoCallback( NULL ),
00164 mUserData( NULL ),
00165 mHost(),
00166 mIsTemp( FALSE ),
00167 mIsLocal(FALSE),
00168 mIsUserWaiting(FALSE),
00169 mTimeout(LL_ASSET_STORAGE_TIMEOUT),
00170 mIsPriority(FALSE),
00171 mDataSentInFirstPacket(FALSE),
00172 mDataIsInVFS( FALSE )
00173 {
00174
00175
00176 mTime = LLMessageSystem::getMessageTimeSeconds(TRUE);
00177 }
00178
00179
00180 LLAssetRequest::~LLAssetRequest()
00181 {
00182 }
00183
00184
00185 LLSD LLAssetRequest::getTerseDetails() const
00186 {
00187 LLSD sd;
00188 sd["asset_id"] = getUUID();
00189 sd["type_long"] = LLAssetType::lookupHumanReadable(getType());
00190 sd["type"] = LLAssetType::lookup(getType());
00191 sd["time"] = mTime;
00192 time_t timestamp = (time_t) mTime;
00193 std::ostringstream time_string;
00194 time_string << ctime(×tamp);
00195 sd["time_string"] = time_string.str();
00196 return sd;
00197 }
00198
00199
00200 LLSD LLAssetRequest::getFullDetails() const
00201 {
00202 LLSD sd = getTerseDetails();
00203 sd["host"] = mHost.getIPandPort();
00204 sd["requesting_agent"] = mRequestingAgentID;
00205 sd["is_temp"] = mIsTemp;
00206 sd["is_local"] = mIsLocal;
00207 sd["is_priority"] = mIsPriority;
00208 sd["data_send_in_first_packet"] = mDataSentInFirstPacket;
00209 sd["data_is_in_vfs"] = mDataIsInVFS;
00210
00211 return sd;
00212 }
00213
00217
00218 LLInvItemRequest::LLInvItemRequest(const LLUUID &uuid, const LLAssetType::EType type)
00219 : mUUID(uuid),
00220 mType(type),
00221 mDownCallback( NULL ),
00222 mUserData( NULL ),
00223 mHost(),
00224 mIsTemp( FALSE ),
00225 mIsPriority(FALSE),
00226 mDataSentInFirstPacket(FALSE),
00227 mDataIsInVFS( FALSE )
00228 {
00229
00230
00231 mTime = LLMessageSystem::getMessageTimeSeconds(TRUE);
00232 }
00233
00234 LLInvItemRequest::~LLInvItemRequest()
00235 {
00236 }
00237
00241
00242 LLEstateAssetRequest::LLEstateAssetRequest(const LLUUID &uuid, const LLAssetType::EType atype,
00243 EstateAssetType etype)
00244 : mUUID(uuid),
00245 mAType(atype),
00246 mEstateAssetType(etype),
00247 mDownCallback( NULL ),
00248 mUserData( NULL ),
00249 mHost(),
00250 mIsTemp( FALSE ),
00251 mIsPriority(FALSE),
00252 mDataSentInFirstPacket(FALSE),
00253 mDataIsInVFS( FALSE )
00254 {
00255
00256
00257 mTime = LLMessageSystem::getMessageTimeSeconds(TRUE);
00258 }
00259
00260 LLEstateAssetRequest::~LLEstateAssetRequest()
00261 {
00262 }
00263
00264
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, const LLHost &upstream_host)
00279 {
00280 _init(msg, xfer, vfs, upstream_host);
00281 }
00282
00283
00284 LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
00285 LLVFS *vfs)
00286 {
00287 _init(msg, xfer, vfs, LLHost::invalid);
00288 }
00289
00290
00291 void LLAssetStorage::_init(LLMessageSystem *msg,
00292 LLXferManager *xfer,
00293 LLVFS *vfs,
00294 const LLHost &upstream_host)
00295 {
00296 mShutDown = FALSE;
00297 mMessageSys = msg;
00298 mXferManager = xfer;
00299 mVFS = vfs;
00300
00301 setUpstream(upstream_host);
00302 msg->setHandlerFuncFast(_PREHASH_AssetUploadComplete, processUploadComplete, (void **)this);
00303 }
00304
00305 LLAssetStorage::~LLAssetStorage()
00306 {
00307 mShutDown = TRUE;
00308
00309 _cleanupRequests(TRUE, LL_ERR_CIRCUIT_GONE);
00310
00311 if (gMessageSystem)
00312 {
00313
00314
00315 gMessageSystem->setHandlerFuncFast(_PREHASH_AssetUploadComplete, NULL, NULL);
00316 }
00317 }
00318
00319 void LLAssetStorage::setUpstream(const LLHost &upstream_host)
00320 {
00321 LL_DEBUGS("AppInit") << "AssetStorage: Setting upstream provider to " << upstream_host << LL_ENDL;
00322
00323 mUpstreamHost = upstream_host;
00324 }
00325
00326 void LLAssetStorage::checkForTimeouts()
00327 {
00328 _cleanupRequests(FALSE, LL_ERR_TCP_TIMEOUT);
00329 }
00330
00331 void LLAssetStorage::_cleanupRequests(BOOL all, S32 error)
00332 {
00333 F64 mt_secs = LLMessageSystem::getMessageTimeSeconds();
00334
00335 request_list_t timed_out;
00336 S32 rt;
00337 for (rt = 0; rt < RT_COUNT; rt++)
00338 {
00339 request_list_t* requests = getRequestList((ERequestType)rt);
00340 for (request_list_t::iterator iter = requests->begin();
00341 iter != requests->end(); )
00342 {
00343 request_list_t::iterator curiter = iter++;
00344 LLAssetRequest* tmp = *curiter;
00345
00346
00347
00348 if (all
00349 || ((RT_DOWNLOAD == rt)
00350 && LL_ASSET_STORAGE_TIMEOUT < (mt_secs - tmp->mTime)))
00351 {
00352 llwarns << "Asset " << getRequestName((ERequestType)rt) << " request "
00353 << (all ? "aborted" : "timed out") << " for "
00354 << tmp->getUUID() << "."
00355 << LLAssetType::lookup(tmp->getType()) << llendl;
00356
00357 timed_out.push_front(tmp);
00358 iter = requests->erase(curiter);
00359 }
00360 }
00361 }
00362
00363 LLAssetInfo info;
00364 for (request_list_t::iterator iter = timed_out.begin();
00365 iter != timed_out.end(); )
00366 {
00367 request_list_t::iterator curiter = iter++;
00368 LLAssetRequest* tmp = *curiter;
00369 if (tmp->mUpCallback)
00370 {
00371 tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LL_EXSTAT_NONE);
00372 }
00373 if (tmp->mDownCallback)
00374 {
00375 tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LL_EXSTAT_NONE);
00376 }
00377 if (tmp->mInfoCallback)
00378 {
00379 tmp->mInfoCallback(&info, tmp->mUserData, error);
00380 }
00381 delete tmp;
00382 }
00383
00384 }
00385
00386 BOOL LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType type)
00387 {
00388 return mVFS->getExists(uuid, type);
00389 }
00390
00392
00394
00395
00396 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)
00397 {
00398 lldebugs << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << llendl;
00399
00400 if (mShutDown)
00401 {
00402 return;
00403 }
00404
00405 if (uuid.isNull())
00406 {
00407
00408 if (callback)
00409 {
00410 callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
00411 }
00412 return;
00413 }
00414
00415 BOOL exists = mVFS->getExists(uuid, type);
00416 LLVFile file(mVFS, uuid, type);
00417 U32 size = exists ? file.getSize() : 0;
00418
00419 if (size < 1)
00420 {
00421 if (exists)
00422 {
00423 llwarns << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << llendl;
00424 file.remove();
00425 }
00426
00427 BOOL duplicate = FALSE;
00428
00429
00430 for (request_list_t::iterator iter = mPendingDownloads.begin();
00431 iter != mPendingDownloads.end(); ++iter )
00432 {
00433 LLAssetRequest *tmp = *iter;
00434 if ((type == tmp->getType()) && (uuid == tmp->getUUID()))
00435 {
00436 if (callback == tmp->mDownCallback && user_data == tmp->mUserData)
00437 {
00438
00439 llwarns << "Discarding duplicate request for asset " << uuid
00440 << "." << LLAssetType::lookup(type) << llendl;
00441 return;
00442 }
00443
00444
00445
00446 duplicate = TRUE;
00447 }
00448 }
00449 if (duplicate)
00450 {
00451 llinfos << "Adding additional non-duplicate request for asset " << uuid
00452 << "." << LLAssetType::lookup(type) << llendl;
00453 }
00454
00455
00456 _queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority);
00457 }
00458 else
00459 {
00460
00461
00462
00463 if (callback)
00464 {
00465 callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
00466 }
00467 }
00468 }
00469
00470 void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType atype,
00471 LLGetAssetCallback callback,
00472 void *user_data, BOOL duplicate,
00473 BOOL is_priority)
00474 {
00475 if (mUpstreamHost.isOk())
00476 {
00477
00478 LLAssetRequest *req = new LLAssetRequest(uuid, atype);
00479 req->mDownCallback = callback;
00480 req->mUserData = user_data;
00481 req->mIsPriority = is_priority;
00482
00483 mPendingDownloads.push_back(req);
00484
00485 if (!duplicate)
00486 {
00487
00488
00489 LLTransferSourceParamsAsset spa;
00490 spa.setAsset(uuid, atype);
00491
00492
00493 LLTransferTargetParamsVFile tpvf;
00494 tpvf.setAsset(uuid, atype);
00495 tpvf.setCallback(downloadCompleteCallback, req);
00496
00497 llinfos << "Starting transfer for " << uuid << llendl;
00498 LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET);
00499 ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f));
00500 }
00501 }
00502 else
00503 {
00504
00505 llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
00506 if (callback)
00507 {
00508 callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
00509 }
00510 }
00511 }
00512
00513
00514 void LLAssetStorage::downloadCompleteCallback(
00515 S32 result,
00516 const LLUUID& file_id,
00517 LLAssetType::EType file_type,
00518 void* user_data, LLExtStat ext_status)
00519 {
00520 lldebugs << "LLAssetStorage::downloadCompleteCallback() for " << file_id
00521 << "," << LLAssetType::lookup(file_type) << llendl;
00522 LLAssetRequest* req = (LLAssetRequest*)user_data;
00523 if(!req)
00524 {
00525 llwarns << "LLAssetStorage::downloadCompleteCallback called without"
00526 "a valid request." << llendl;
00527 return;
00528 }
00529 if (!gAssetStorage)
00530 {
00531 llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl;
00532 return;
00533 }
00534
00535 req->setUUID(file_id);
00536 req->setType(file_type);
00537 if (LL_ERR_NOERR == result)
00538 {
00539
00540 LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType());
00541 if (vfile.getSize() <= 0)
00542 {
00543 llwarns << "downloadCompleteCallback has non-existent or zero-size asset " << req->getUUID() << llendl;
00544
00545 result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
00546 vfile.remove();
00547 }
00548 }
00549
00550
00551
00552
00553 request_list_t requests;
00554 for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin();
00555 iter != gAssetStorage->mPendingDownloads.end(); )
00556 {
00557 request_list_t::iterator curiter = iter++;
00558 LLAssetRequest* tmp = *curiter;
00559 if ((tmp->getUUID() == req->getUUID()) && (tmp->getType()== req->getType()))
00560 {
00561 requests.push_front(tmp);
00562 iter = gAssetStorage->mPendingDownloads.erase(curiter);
00563 }
00564 }
00565 for (request_list_t::iterator iter = requests.begin();
00566 iter != requests.end(); )
00567 {
00568 request_list_t::iterator curiter = iter++;
00569 LLAssetRequest* tmp = *curiter;
00570 if (tmp->mDownCallback)
00571 {
00572 tmp->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), tmp->mUserData, result, ext_status);
00573 }
00574 delete tmp;
00575 }
00576 }
00577
00578 void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id,
00579 const LLUUID &asset_id, LLAssetType::EType atype, EstateAssetType etype,
00580 LLGetAssetCallback callback, void *user_data, BOOL is_priority)
00581 {
00582 lldebugs << "LLAssetStorage::getEstateAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << ", estatetype " << etype << llendl;
00583
00584
00585
00586
00587 if (asset_id.isNull())
00588 {
00589
00590 if (callback)
00591 {
00592 callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
00593 }
00594 return;
00595 }
00596
00597 BOOL exists = mVFS->getExists(asset_id, atype);
00598 LLVFile file(mVFS, asset_id, atype);
00599 U32 size = exists ? file.getSize() : 0;
00600
00601 if (size < 1)
00602 {
00603 if (exists)
00604 {
00605 llwarns << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << llendl;
00606 file.remove();
00607 }
00608
00609
00610 LLHost source_host;
00611 if (object_sim.isOk())
00612 {
00613 source_host = object_sim;
00614 }
00615 else
00616 {
00617 source_host = mUpstreamHost;
00618 }
00619 if (source_host.isOk())
00620 {
00621
00622 LLEstateAssetRequest *req = new LLEstateAssetRequest(asset_id, atype, etype);
00623 req->mDownCallback = callback;
00624 req->mUserData = user_data;
00625 req->mIsPriority = is_priority;
00626
00627
00628
00629 LLTransferSourceParamsEstate spe;
00630 spe.setAgentSession(agent_id, session_id);
00631 spe.setEstateAssetType(etype);
00632
00633
00634 LLTransferTargetParamsVFile tpvf;
00635 tpvf.setAsset(asset_id, atype);
00636 tpvf.setCallback(downloadEstateAssetCompleteCallback, req);
00637
00638 llinfos << "Starting transfer for " << asset_id << llendl;
00639 LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET);
00640 ttcp->requestTransfer(spe, tpvf, 100.f + (is_priority ? 1.f : 0.f));
00641 }
00642 else
00643 {
00644
00645 llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
00646 if (callback)
00647 {
00648 callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
00649 }
00650 }
00651 }
00652 else
00653 {
00654
00655
00656
00657 if (callback)
00658 {
00659 callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
00660 }
00661 }
00662 }
00663
00664 void LLAssetStorage::downloadEstateAssetCompleteCallback(
00665 S32 result,
00666 const LLUUID& file_id,
00667 LLAssetType::EType file_type,
00668 void* user_data,
00669 LLExtStat ext_status)
00670 {
00671 LLEstateAssetRequest *req = (LLEstateAssetRequest*)user_data;
00672 if(!req)
00673 {
00674 llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called"
00675 " without a valid request." << llendl;
00676 return;
00677 }
00678 if (!gAssetStorage)
00679 {
00680 llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called"
00681 " without any asset system, aborting!" << llendl;
00682 return;
00683 }
00684
00685 req->setUUID(file_id);
00686 req->setType(file_type);
00687 if (LL_ERR_NOERR == result)
00688 {
00689
00690 LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getAType());
00691 if (vfile.getSize() <= 0)
00692 {
00693 llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl;
00694
00695 result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
00696 vfile.remove();
00697 }
00698 }
00699
00700 req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getAType(), req->mUserData, result, ext_status);
00701 }
00702
00703 void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id,
00704 const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id,
00705 const LLUUID &asset_id, LLAssetType::EType atype,
00706 LLGetAssetCallback callback, void *user_data, BOOL is_priority)
00707 {
00708 lldebugs << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << llendl;
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723 bool exists = false;
00724 U32 size = 0;
00725
00726 if(asset_id.notNull())
00727 {
00728 exists = mVFS->getExists(asset_id, atype);
00729 LLVFile file(mVFS, asset_id, atype);
00730 size = exists ? file.getSize() : 0;
00731 if(exists && size < 1)
00732 {
00733 llwarns << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << llendl;
00734 file.remove();
00735 }
00736
00737 }
00738
00739 if (size < 1)
00740 {
00741
00742
00743 LLHost source_host;
00744 if (object_sim.isOk())
00745 {
00746 source_host = object_sim;
00747 }
00748 else
00749 {
00750 source_host = mUpstreamHost;
00751 }
00752 if (source_host.isOk())
00753 {
00754
00755 LLInvItemRequest *req = new LLInvItemRequest(asset_id, atype);
00756 req->mDownCallback = callback;
00757 req->mUserData = user_data;
00758 req->mIsPriority = is_priority;
00759
00760
00761
00762 LLTransferSourceParamsInvItem spi;
00763 spi.setAgentSession(agent_id, session_id);
00764 spi.setInvItem(owner_id, task_id, item_id);
00765 spi.setAsset(asset_id, atype);
00766
00767
00768 LLTransferTargetParamsVFile tpvf;
00769 tpvf.setAsset(asset_id, atype);
00770 tpvf.setCallback(downloadInvItemCompleteCallback, req);
00771
00772 llinfos << "Starting transfer for inventory asset "
00773 << item_id << " owned by " << owner_id << "," << task_id
00774 << llendl;
00775 LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET);
00776 ttcp->requestTransfer(spi, tpvf, 100.f + (is_priority ? 1.f : 0.f));
00777 }
00778 else
00779 {
00780
00781 llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
00782 if (callback)
00783 {
00784 callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
00785 }
00786 }
00787 }
00788 else
00789 {
00790
00791
00792
00793 if (callback)
00794 {
00795 callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
00796 }
00797 }
00798 }
00799
00800
00801 void LLAssetStorage::downloadInvItemCompleteCallback(
00802 S32 result,
00803 const LLUUID& file_id,
00804 LLAssetType::EType file_type,
00805 void* user_data,
00806 LLExtStat ext_status)
00807 {
00808 LLInvItemRequest *req = (LLInvItemRequest*)user_data;
00809 if(!req)
00810 {
00811 llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called"
00812 " without a valid request." << llendl;
00813 return;
00814 }
00815 if (!gAssetStorage)
00816 {
00817 llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl;
00818 return;
00819 }
00820
00821 req->setUUID(file_id);
00822 req->setType(file_type);
00823 if (LL_ERR_NOERR == result)
00824 {
00825
00826 LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType());
00827 if (vfile.getSize() <= 0)
00828 {
00829 llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl;
00830
00831 result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
00832 vfile.remove();
00833 }
00834 }
00835
00836 req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), req->mUserData, result, ext_status);
00837 }
00838
00840
00842
00843
00844 void LLAssetStorage::uploadCompleteCallback(const LLUUID& uuid, void *user_data, S32 result, LLExtStat ext_status)
00845 {
00846 if (!gAssetStorage)
00847 {
00848 llwarns << "LLAssetStorage::uploadCompleteCallback has no gAssetStorage!" << llendl;
00849 return;
00850 }
00851 LLAssetRequest *req = (LLAssetRequest *)user_data;
00852 BOOL success = TRUE;
00853
00854 if (result)
00855 {
00856 llwarns << "LLAssetStorage::uploadCompleteCallback " << result << ":" << getErrorString(result) << " trying to upload file to upstream provider" << llendl;
00857 success = FALSE;
00858 }
00859
00860
00861 gAssetStorage->mMessageSys->newMessageFast(_PREHASH_AssetUploadComplete);
00862 gAssetStorage->mMessageSys->nextBlockFast(_PREHASH_AssetBlock);
00863 gAssetStorage->mMessageSys->addUUIDFast(_PREHASH_UUID, uuid);
00864 gAssetStorage->mMessageSys->addS8Fast(_PREHASH_Type, req->getType());
00865 gAssetStorage->mMessageSys->addBOOLFast(_PREHASH_Success, success);
00866 gAssetStorage->mMessageSys->sendReliable(req->mHost);
00867
00868 delete req;
00869 }
00870
00871 void LLAssetStorage::processUploadComplete(LLMessageSystem *msg, void **user_data)
00872 {
00873 LLAssetStorage *this_ptr = (LLAssetStorage *)user_data;
00874 LLUUID uuid;
00875 S8 asset_type_s8;
00876 LLAssetType::EType asset_type;
00877 BOOL success = FALSE;
00878
00879 msg->getUUIDFast(_PREHASH_AssetBlock, _PREHASH_UUID, uuid);
00880 msg->getS8Fast(_PREHASH_AssetBlock, _PREHASH_Type, asset_type_s8);
00881 msg->getBOOLFast(_PREHASH_AssetBlock, _PREHASH_Success, success);
00882
00883 asset_type = (LLAssetType::EType)asset_type_s8;
00884 this_ptr->_callUploadCallbacks(uuid, asset_type, success, LL_EXSTAT_NONE);
00885 }
00886
00887 void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status )
00888 {
00889
00890
00891 request_list_t requests;
00892 for (request_list_t::iterator iter = mPendingUploads.begin();
00893 iter != mPendingUploads.end(); )
00894 {
00895 request_list_t::iterator curiter = iter++;
00896 LLAssetRequest* req = *curiter;
00897 if ((req->getUUID() == uuid) && (req->getType() == asset_type))
00898 {
00899 requests.push_front(req);
00900 iter = mPendingUploads.erase(curiter);
00901 }
00902 }
00903 for (request_list_t::iterator iter = mPendingLocalUploads.begin();
00904 iter != mPendingLocalUploads.end(); )
00905 {
00906 request_list_t::iterator curiter = iter++;
00907 LLAssetRequest* req = *curiter;
00908 if ((req->getUUID() == uuid) && (req->getType() == asset_type))
00909 {
00910 requests.push_front(req);
00911 iter = mPendingLocalUploads.erase(curiter);
00912 }
00913 }
00914 for (request_list_t::iterator iter = requests.begin();
00915 iter != requests.end(); )
00916 {
00917 request_list_t::iterator curiter = iter++;
00918 LLAssetRequest* req = *curiter;
00919 if (req->mUpCallback)
00920 {
00921 req->mUpCallback(uuid, req->mUserData, (success ? LL_ERR_NOERR : LL_ERR_ASSET_REQUEST_FAILED ), ext_status );
00922 }
00923 delete req;
00924 }
00925 }
00926
00927 LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStorage::ERequestType rt)
00928 {
00929 switch (rt)
00930 {
00931 case RT_DOWNLOAD:
00932 return &mPendingDownloads;
00933 case RT_UPLOAD:
00934 return &mPendingUploads;
00935 case RT_LOCALUPLOAD:
00936 return &mPendingLocalUploads;
00937 default:
00938 llwarns << "Unable to find request list for request type '" << rt << "'" << llendl;
00939 return NULL;
00940 }
00941 }
00942
00943 const LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStorage::ERequestType rt) const
00944 {
00945 switch (rt)
00946 {
00947 case RT_DOWNLOAD:
00948 return &mPendingDownloads;
00949 case RT_UPLOAD:
00950 return &mPendingUploads;
00951 case RT_LOCALUPLOAD:
00952 return &mPendingLocalUploads;
00953 default:
00954 llwarns << "Unable to find request list for request type '" << rt << "'" << llendl;
00955 return NULL;
00956 }
00957 }
00958
00959
00960 std::string LLAssetStorage::getRequestName(LLAssetStorage::ERequestType rt)
00961 {
00962 switch (rt)
00963 {
00964 case RT_DOWNLOAD:
00965 return "download";
00966 case RT_UPLOAD:
00967 return "upload";
00968 case RT_LOCALUPLOAD:
00969 return "localupload";
00970 default:
00971 llwarns << "Unable to find request name for request type '" << rt << "'" << llendl;
00972 return "";
00973 }
00974 }
00975
00976 S32 LLAssetStorage::getNumPending(LLAssetStorage::ERequestType rt) const
00977 {
00978 const request_list_t* requests = getRequestList(rt);
00979 S32 num_pending = -1;
00980 if (requests)
00981 {
00982 num_pending = requests->size();
00983 }
00984 return num_pending;
00985 }
00986
00987 S32 LLAssetStorage::getNumPendingDownloads() const
00988 {
00989 return getNumPending(RT_DOWNLOAD);
00990 }
00991
00992 S32 LLAssetStorage::getNumPendingUploads() const
00993 {
00994 return getNumPending(RT_UPLOAD);
00995 }
00996
00997 S32 LLAssetStorage::getNumPendingLocalUploads()
00998 {
00999 return getNumPending(RT_LOCALUPLOAD);
01000 }
01001
01002
01003 LLSD LLAssetStorage::getPendingDetails(LLAssetStorage::ERequestType rt,
01004 LLAssetType::EType asset_type,
01005 const std::string& detail_prefix) const
01006 {
01007 const request_list_t* requests = getRequestList(rt);
01008 LLSD sd;
01009 sd["requests"] = getPendingDetails(requests, asset_type, detail_prefix);
01010 return sd;
01011 }
01012
01013
01014 LLSD LLAssetStorage::getPendingDetails(const LLAssetStorage::request_list_t* requests,
01015 LLAssetType::EType asset_type,
01016 const std::string& detail_prefix) const
01017 {
01018 LLSD details;
01019 if (requests)
01020 {
01021 request_list_t::const_iterator it = requests->begin();
01022 request_list_t::const_iterator end = requests->end();
01023 for ( ; it != end; ++it)
01024 {
01025 LLAssetRequest* req = *it;
01026 if ( (LLAssetType::AT_NONE == asset_type)
01027 || (req->getType() == asset_type) )
01028 {
01029 LLSD row = req->getTerseDetails();
01030
01031 std::ostringstream detail;
01032 detail << detail_prefix << "/" << LLAssetType::lookup(req->getType())
01033 << "/" << req->getUUID();
01034 row["detail"] = LLURI(detail.str());
01035
01036 details.append(row);
01037 }
01038 }
01039 }
01040 return details;
01041 }
01042
01043
01044
01045 const LLAssetRequest* LLAssetStorage::findRequest(const LLAssetStorage::request_list_t* requests,
01046 LLAssetType::EType asset_type,
01047 const LLUUID& asset_id)
01048 {
01049 if (requests)
01050 {
01051
01052 request_list_t::const_iterator iter = requests->begin();
01053 request_list_t::const_iterator end = requests->end();
01054 for (; iter != end; ++iter)
01055 {
01056 const LLAssetRequest* req = *iter;
01057 if (asset_type == req->getType() &&
01058 asset_id == req->getUUID() )
01059 {
01060 return req;
01061 }
01062 }
01063 }
01064 return NULL;
01065 }
01066
01067
01068 LLAssetRequest* LLAssetStorage::findRequest(LLAssetStorage::request_list_t* requests,
01069 LLAssetType::EType asset_type,
01070 const LLUUID& asset_id)
01071 {
01072 if (requests)
01073 {
01074
01075 request_list_t::iterator iter = requests->begin();
01076 request_list_t::iterator end = requests->end();
01077 for (; iter != end; ++iter)
01078 {
01079 LLAssetRequest* req = *iter;
01080 if (asset_type == req->getType() &&
01081 asset_id == req->getUUID() )
01082 {
01083 return req;
01084 }
01085 }
01086 }
01087 return NULL;
01088 }
01089
01090
01091
01092 LLSD LLAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt,
01093 LLAssetType::EType asset_type,
01094 const LLUUID& asset_id) const
01095 {
01096 const request_list_t* requests = getRequestList(rt);
01097 return getPendingRequest(requests, asset_type, asset_id);
01098 }
01099
01100
01101 LLSD LLAssetStorage::getPendingRequest(const LLAssetStorage::request_list_t* requests,
01102 LLAssetType::EType asset_type,
01103 const LLUUID& asset_id) const
01104 {
01105 LLSD sd;
01106 const LLAssetRequest* req = findRequest(requests, asset_type, asset_id);
01107 if (req)
01108 {
01109 sd = req->getFullDetails();
01110 }
01111 return sd;
01112 }
01113
01114
01115 bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt,
01116 LLAssetType::EType asset_type,
01117 const LLUUID& asset_id)
01118 {
01119 request_list_t* requests = getRequestList(rt);
01120 if (deletePendingRequest(requests, asset_type, asset_id))
01121 {
01122 llinfos << "Asset " << getRequestName(rt) << " request for "
01123 << asset_id << "." << LLAssetType::lookup(asset_type)
01124 << " removed from pending queue." << llendl;
01125 return true;
01126 }
01127 return false;
01128 }
01129
01130
01131 bool LLAssetStorage::deletePendingRequest(LLAssetStorage::request_list_t* requests,
01132 LLAssetType::EType asset_type,
01133 const LLUUID& asset_id)
01134 {
01135 LLAssetRequest* req = findRequest(requests, asset_type, asset_id);
01136 if (req)
01137 {
01138
01139 requests->remove(req);
01140 S32 error = LL_ERR_TCP_TIMEOUT;
01141
01142 if (req->mUpCallback)
01143 {
01144 req->mUpCallback(req->getUUID(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED);
01145 }
01146 if (req->mDownCallback)
01147 {
01148 req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED);
01149 }
01150 if (req->mInfoCallback)
01151 {
01152 LLAssetInfo info;
01153 req->mInfoCallback(&info, req->mUserData, error);
01154 }
01155 delete req;
01156 return true;
01157 }
01158
01159 return false;
01160 }
01161
01162
01163 const char* LLAssetStorage::getErrorString(S32 status)
01164 {
01165 switch( status )
01166 {
01167 case LL_ERR_NOERR:
01168 return "No error";
01169
01170 case LL_ERR_ASSET_REQUEST_FAILED:
01171 return "Asset request: failed";
01172
01173 case LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE:
01174 return "Asset request: non-existent file";
01175
01176 case LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE:
01177 return "Asset request: asset not found in database";
01178
01179 case LL_ERR_EOF:
01180 return "End of file";
01181
01182 case LL_ERR_CANNOT_OPEN_FILE:
01183 return "Cannot open file";
01184
01185 case LL_ERR_FILE_NOT_FOUND:
01186 return "File not found";
01187
01188 case LL_ERR_TCP_TIMEOUT:
01189 return "File transfer timeout";
01190
01191 case LL_ERR_CIRCUIT_GONE:
01192 return "Circuit gone";
01193
01194 default:
01195 return "Unknown status";
01196 }
01197 }
01198
01199
01200
01201 void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, BOOL is_priority)
01202 {
01203
01204 for (request_list_t::iterator iter = mPendingDownloads.begin();
01205 iter != mPendingDownloads.end(); )
01206 {
01207 LLAssetRequest* tmp = *iter++;
01208 if (type == tmp->getType() &&
01209 uuid == tmp->getUUID() &&
01210 legacyGetDataCallback == tmp->mDownCallback &&
01211 callback == ((LLLegacyAssetRequest *)tmp->mUserData)->mDownCallback &&
01212 user_data == ((LLLegacyAssetRequest *)tmp->mUserData)->mUserData)
01213 {
01214
01215 llinfos << "Discarding duplicate request for UUID " << uuid << llendl;
01216 return;
01217 }
01218 }
01219
01220
01221 LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest;
01222
01223 legacy->mDownCallback = callback;
01224 legacy->mUserData = user_data;
01225
01226 getAssetData(uuid, type, legacyGetDataCallback, (void **)legacy,
01227 is_priority);
01228 }
01229
01230
01231 void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 status, LLExtStat ext_status)
01232 {
01233 LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data;
01234 char filename[LL_MAX_PATH] = "";
01235
01236 if (! status)
01237 {
01238 LLVFile file(vfs, uuid, type);
01239
01240 char uuid_str[UUID_STR_LENGTH];
01241
01242 uuid.toString(uuid_str);
01243 snprintf(filename,sizeof(filename),"%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type));
01244
01245 LLFILE* fp = LLFile::fopen(filename, "wb");
01246 if (fp)
01247 {
01248 const S32 buf_size = 65536;
01249 U8 copy_buf[buf_size];
01250 while (file.read(copy_buf, buf_size))
01251 {
01252 if (fwrite(copy_buf, file.getLastBytesRead(), 1, fp) < 1)
01253 {
01254
01255 status = LL_ERR_CANNOT_OPEN_FILE;
01256 }
01257 }
01258
01259 fclose(fp);
01260 }
01261 else
01262 {
01263 status = LL_ERR_CANNOT_OPEN_FILE;
01264 }
01265 }
01266
01267 legacy->mDownCallback(filename, uuid, legacy->mUserData, status, ext_status);
01268 delete legacy;
01269 }
01270
01271
01272
01273 void LLAssetStorage::storeAssetData(
01274 const LLTransactionID& tid,
01275 LLAssetType::EType asset_type,
01276 LLStoreAssetCallback callback,
01277 void* user_data,
01278 bool temp_file,
01279 bool is_priority,
01280 bool store_local,
01281 bool user_waiting,
01282 F64 timeout)
01283 {
01284 llwarns << "storeAssetData: wrong version called" << llendl;
01285
01286 reportMetric( LLUUID::null, asset_type, NULL, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 1" );
01287 }
01288
01289
01290
01291 void LLAssetStorage::storeAssetData(
01292 const LLUUID& asset_id,
01293 LLAssetType::EType asset_type,
01294 LLStoreAssetCallback callback,
01295 void* user_data,
01296 bool temp_file ,
01297 bool is_priority,
01298 bool store_local,
01299 const LLUUID& requesting_agent_id,
01300 bool user_waiting,
01301 F64 timeout)
01302 {
01303 llwarns << "storeAssetData: wrong version called" << llendl;
01304
01305 reportMetric( asset_id, asset_type, NULL, requesting_agent_id, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 2" );
01306 }
01307
01308
01309
01310 void LLAssetStorage::storeAssetData(
01311 const char* filename,
01312 const LLUUID& asset_id,
01313 LLAssetType::EType asset_type,
01314 LLStoreAssetCallback callback,
01315 void* user_data,
01316 bool temp_file,
01317 bool is_priority,
01318 bool user_waiting,
01319 F64 timeout)
01320 {
01321 llwarns << "storeAssetData: wrong version called" << llendl;
01322
01323 reportMetric( asset_id, asset_type, NULL, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 3" );
01324 }
01325
01326
01327
01328 void LLAssetStorage::storeAssetData(
01329 const char* filename,
01330 const LLTransactionID &transactoin_id,
01331 LLAssetType::EType asset_type,
01332 LLStoreAssetCallback callback,
01333 void* user_data,
01334 bool temp_file,
01335 bool is_priority,
01336 bool user_waiting,
01337 F64 timeout)
01338 {
01339 llwarns << "storeAssetData: wrong version called" << llendl;
01340
01341 reportMetric( LLUUID::null, asset_type, NULL, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 4" );
01342 }
01343
01344
01345 void LLAssetStorage::legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status)
01346 {
01347 LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data;
01348 if (legacy && legacy->mUpCallback)
01349 {
01350 legacy->mUpCallback(uuid, legacy->mUserData, status, ext_status);
01351 }
01352 delete legacy;
01353 }
01354
01355
01356 void LLAssetStorage::addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name)
01357 { }
01358
01359
01360 BOOL LLAssetStorage::hasTempAssetData(const LLUUID& texture_id) const
01361 { return FALSE; }
01362
01363
01364 std::string LLAssetStorage::getTempAssetHostName(const LLUUID& texture_id) const
01365 { return std::string(); }
01366
01367
01368 LLUUID LLAssetStorage::getTempAssetAgentID(const LLUUID& texture_id) const
01369 { return LLUUID::null; }
01370
01371
01372 void LLAssetStorage::removeTempAssetData(const LLUUID& asset_id)
01373 { }
01374
01375
01376 void LLAssetStorage::removeTempAssetDataByAgentID(const LLUUID& agent_id)
01377 { }
01378
01379
01380 void LLAssetStorage::dumpTempAssetData(const LLUUID& avatar_id) const
01381 { }
01382
01383
01384 void LLAssetStorage::clearTempAssetData()
01385 { }
01386
01387
01388 void LLAssetStorage::reportMetric( const LLUUID& asset_id, const LLAssetType::EType asset_type, const char *filename,
01389 const LLUUID& agent_id, S32 asset_size, EMetricResult result,
01390 const char *file, const S32 line, const char *message )
01391 {
01392 if( !metric_recipient )
01393 {
01394 llinfos << "Couldn't store LLAssetStoreage::reportMetric - no metrics_recipient" << llendl;
01395 return;
01396 }
01397
01398 filename = filename ? filename : "";
01399 file = file ? file : "";
01400
01401
01402 std::string new_message;
01403 new_message = message;
01404 new_message += " :: ";
01405 new_message += filename;
01406 char line_string[16];
01407 sprintf( line_string, ":%d", line );
01408 new_message += line_string;
01409 message = new_message.c_str();
01410
01411
01412 static bool always_report = false;
01413 const char *metric_name = "LLAssetStorage::Metrics";
01414
01415 bool success = result == MR_OKAY;
01416
01417 if( (!success) || always_report )
01418 {
01419 LLSD stats;
01420 stats["asset_id"] = asset_id;
01421 stats["asset_type"] = asset_type;
01422 stats["filename"] = filename? filename : "";
01423 stats["agent_id"] = agent_id;
01424 stats["asset_size"] = (S32)asset_size;
01425 stats["result"] = (S32)result;
01426
01427 metric_recipient->recordEventDetails( metric_name, message, success, stats);
01428 }
01429 else
01430 {
01431 metric_recipient->recordEvent(metric_name, message, success);
01432 }
01433 }