svn merge -r 58433:58660 svn+ssh://svn/svn/linden/branches/upload-queue into release

master
Don Kjer 2007-03-15 00:54:39 +00:00
parent 00dbacb215
commit 0947e139ed
6 changed files with 717 additions and 142 deletions

View File

@ -184,6 +184,20 @@ const char* LLAssetType::lookupHumanReadable(LLAssetType::EType type)
}
}
// static
LLAssetType::EType LLAssetType::lookupHumanReadable( const char* name )
{
for( S32 i = 0; i < AT_COUNT; i++ )
{
if( 0 == strcmp(name, mAssetTypeHumanNames[i]) )
{
// match
return (EType)i;
}
}
return AT_NONE;
}
EDragAndDropType LLAssetType::lookupDragAndDropType( EType asset )
{
switch( asset )

View File

@ -126,6 +126,7 @@ public:
static const char* lookup(EType type);
// translation from a type to a human readable form.
static EType lookupHumanReadable( const char* name );
static const char* lookupHumanReadable(EType type);
static EDragAndDropType lookupDragAndDropType( EType );

View File

@ -155,10 +155,40 @@ LLAssetRequest::LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType type
mTime = LLMessageSystem::getMessageTimeSeconds(TRUE);
}
// virtual
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;
time_t timestamp = (time_t) mTime;
std::ostringstream time_string;
time_string << ctime(&timestamp);
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;
}
///----------------------------------------------------------------------------
/// LLInvItemRequest
@ -279,47 +309,41 @@ void LLAssetStorage::checkForTimeouts()
void LLAssetStorage::_cleanupRequests(BOOL all, S32 error)
{
const S32 NUM_QUEUES = 3;
F64 mt_secs = LLMessageSystem::getMessageTimeSeconds();
std::list<LLAssetRequest*>* requests[NUM_QUEUES];
requests[0] = &mPendingDownloads;
requests[1] = &mPendingUploads;
requests[2] = &mPendingLocalUploads;
static const char* REQUEST_TYPE[NUM_QUEUES] = { "download", "upload", "localuploads"};
std::list<LLAssetRequest*> timed_out;
for (S32 ii = 0; ii < NUM_QUEUES; ++ii)
request_list_t timed_out;
S32 rt;
for (rt = 0; rt < RT_COUNT; rt++)
{
for (std::list<LLAssetRequest*>::iterator iter = requests[ii]->begin();
iter != requests[ii]->end(); )
request_list_t* requests = getRequestList((ERequestType)rt);
for (request_list_t::iterator iter = requests->begin();
iter != requests->end(); )
{
std::list<LLAssetRequest*>::iterator curiter = iter++;
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
|| ((0 == ii)
|| ((RT_DOWNLOAD == rt)
&& LL_ASSET_STORAGE_TIMEOUT < (mt_secs - tmp->mTime)))
{
llwarns << "Asset " << REQUEST_TYPE[ii] << " request "
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[ii]->erase(curiter);
iter = requests->erase(curiter);
}
}
}
LLAssetInfo info;
for (std::list<LLAssetRequest*>::iterator iter = timed_out.begin();
for (request_list_t::iterator iter = timed_out.begin();
iter != timed_out.end(); )
{
std::list<LLAssetRequest*>::iterator curiter = iter++;
request_list_t::iterator curiter = iter++;
LLAssetRequest* tmp = *curiter;
if (tmp->mUpCallback)
{
@ -382,7 +406,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, vo
BOOL duplicate = FALSE;
// check to see if there's a pending download of this uuid already
for (std::list<LLAssetRequest*>::iterator iter = mPendingDownloads.begin();
for (request_list_t::iterator iter = mPendingDownloads.begin();
iter != mPendingDownloads.end(); ++iter )
{
LLAssetRequest *tmp = *iter;
@ -504,11 +528,11 @@ void LLAssetStorage::downloadCompleteCallback(
// 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.
std::list<LLAssetRequest*> requests;
for (std::list<LLAssetRequest*>::iterator iter = gAssetStorage->mPendingDownloads.begin();
request_list_t requests;
for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin();
iter != gAssetStorage->mPendingDownloads.end(); )
{
std::list<LLAssetRequest*>::iterator curiter = iter++;
request_list_t::iterator curiter = iter++;
LLAssetRequest* tmp = *curiter;
if ((tmp->getUUID() == req->getUUID()) && (tmp->getType()== req->getType()))
{
@ -516,10 +540,10 @@ void LLAssetStorage::downloadCompleteCallback(
iter = gAssetStorage->mPendingDownloads.erase(curiter);
}
}
for (std::list<LLAssetRequest*>::iterator iter = requests.begin();
for (request_list_t::iterator iter = requests.begin();
iter != requests.end(); )
{
std::list<LLAssetRequest*>::iterator curiter = iter++;
request_list_t::iterator curiter = iter++;
LLAssetRequest* tmp = *curiter;
if (tmp->mDownCallback)
{
@ -877,11 +901,11 @@ void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType
{
// 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.
std::list<LLAssetRequest*> requests;
for (std::list<LLAssetRequest*>::iterator iter = mPendingUploads.begin();
request_list_t requests;
for (request_list_t::iterator iter = mPendingUploads.begin();
iter != mPendingUploads.end(); )
{
std::list<LLAssetRequest*>::iterator curiter = iter++;
request_list_t::iterator curiter = iter++;
LLAssetRequest* req = *curiter;
if ((req->getUUID() == uuid) && (req->getType() == asset_type))
{
@ -889,10 +913,10 @@ void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType
iter = mPendingUploads.erase(curiter);
}
}
for (std::list<LLAssetRequest*>::iterator iter = mPendingLocalUploads.begin();
for (request_list_t::iterator iter = mPendingLocalUploads.begin();
iter != mPendingLocalUploads.end(); )
{
std::list<LLAssetRequest*>::iterator curiter = iter++;
request_list_t::iterator curiter = iter++;
LLAssetRequest* req = *curiter;
if ((req->getUUID() == uuid) && (req->getType() == asset_type))
{
@ -900,10 +924,10 @@ void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType
iter = mPendingLocalUploads.erase(curiter);
}
}
for (std::list<LLAssetRequest*>::iterator iter = requests.begin();
for (request_list_t::iterator iter = requests.begin();
iter != requests.end(); )
{
std::list<LLAssetRequest*>::iterator curiter = iter++;
request_list_t::iterator curiter = iter++;
LLAssetRequest* req = *curiter;
if (req->mUpCallback)
{
@ -913,45 +937,239 @@ void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType
}
}
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:
llwarns << "Unable to find request list for request type '" << rt << "'" << llendl;
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:
llwarns << "Unable to find request list for request type '" << rt << "'" << llendl;
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:
llwarns << "Unable to find request name for request type '" << rt << "'" << llendl;
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;
}
S32 LLAssetStorage::getNumPendingDownloads() const
{
return mPendingDownloads.size();
return getNumPending(RT_DOWNLOAD);
}
S32 LLAssetStorage::getNumPendingUploads() const
{
return mPendingUploads.size();
return getNumPending(RT_UPLOAD);
}
S32 LLAssetStorage::getNumPendingLocalUploads()
{
return mPendingLocalUploads.size();
return getNumPending(RT_LOCALUPLOAD);
}
LLSD LLAssetStorage::getPendingTypes(const std::list<LLAssetRequest*>& requests) const
// virtual
LLSD LLAssetStorage::getPendingDetails(LLAssetStorage::ERequestType rt,
LLAssetType::EType asset_type,
const std::string& detail_prefix) const
{
LLSD type_counts;
std::list<LLAssetRequest*>::const_iterator it = requests.begin();
std::list<LLAssetRequest*>::const_iterator end = requests.end();
const request_list_t* requests = getRequestList(rt);
LLSD sd;
sd["requests"] = getPendingDetails(requests, asset_type, detail_prefix);
return sd;
}
// virtual
LLSD LLAssetStorage::getPendingDetails(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;
const char* type_name = LLAssetType::lookupHumanReadable(req->getType());
type_counts[type_name] = type_counts[type_name].asInteger() + 1;
}
return type_counts;
}
LLSD LLAssetStorage::getPendingDownloadTypes() const
if ( (LLAssetType::AT_NONE == asset_type)
|| (req->getType() == asset_type) )
{
return getPendingTypes(mPendingDownloads);
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;
}
LLSD LLAssetStorage::getPendingUploadTypes() const
// static
const LLAssetRequest* LLAssetStorage::findRequest(const LLAssetStorage::request_list_t* requests,
LLAssetType::EType asset_type,
const LLUUID& asset_id)
{
return getPendingTypes(mPendingUploads);
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;
}
// virtual
LLSD LLAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id) const
{
const request_list_t* requests = getRequestList(rt);
return getPendingRequest(requests, asset_type, asset_id);
}
// virtual
LLSD LLAssetStorage::getPendingRequest(const LLAssetStorage::request_list_t* requests,
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;
}
// virtual
bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id)
{
request_list_t* requests = getRequestList(rt);
if (deletePendingRequest(requests, asset_type, asset_id))
{
llinfos << "Asset " << getRequestName(rt) << " request for "
<< asset_id << "." << LLAssetType::lookup(asset_type)
<< " removed from pending queue." << llendl;
return true;
}
return false;
}
// virtual
bool LLAssetStorage::deletePendingRequest(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);
}
if (req->mDownCallback)
{
req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error);
}
if (req->mInfoCallback)
{
LLAssetInfo info;
req->mInfoCallback(&info, req->mUserData, error);
}
delete req;
return true;
}
return false;
}
// static
@ -996,7 +1214,7 @@ const char* LLAssetStorage::getErrorString(S32 status)
void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32), void *user_data, BOOL is_priority)
{
// check for duplicates here, since we're about to fool the normal duplicate checker
for (std::list<LLAssetRequest*>::iterator iter = mPendingDownloads.begin();
for (request_list_t::iterator iter = mPendingDownloads.begin();
iter != mPendingDownloads.end(); )
{
LLAssetRequest* tmp = *iter++;

View File

@ -90,6 +90,19 @@ public:
BOOL mDataSentInFirstPacket;
BOOL mDataIsInVFS;
LLUUID mRequestingAgentID; // Only valid for uploads from an agent
virtual LLSD getTerseDetails() const;
virtual LLSD getFullDetails() const;
};
template <class T>
struct ll_asset_request_equal : public std::equal_to<T>
{
bool operator()(const T& x, const T& y) const
{
return ( x->getType() == y->getType()
&& x->getUUID() == y->getUUID() );
}
};
@ -165,6 +178,15 @@ public:
LLVFS *mVFS;
typedef void (*LLStoreAssetCallback)(const LLUUID &asset_id, void *user_data, S32 status);
enum ERequestType
{
RT_INVALID = -1,
RT_DOWNLOAD = 0,
RT_UPLOAD = 1,
RT_LOCALUPLOAD = 2,
RT_COUNT = 3
};
protected:
BOOL mShutDown;
LLHost mUpstreamHost;
@ -172,9 +194,11 @@ protected:
LLMessageSystem *mMessageSys;
LLXferManager *mXferManager;
std::list<LLAssetRequest*> mPendingDownloads;
std::list<LLAssetRequest*> mPendingUploads;
std::list<LLAssetRequest*> mPendingLocalUploads;
typedef std::list<LLAssetRequest*> request_list_t;
request_list_t mPendingDownloads;
request_list_t mPendingUploads;
request_list_t mPendingLocalUploads;
public:
LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
@ -239,14 +263,48 @@ public:
const LLUUID &asset_id, LLAssetType::EType atype,
LLGetAssetCallback cb, void *user_data, BOOL is_priority = FALSE); // Get a particular inventory item.
protected:
virtual LLSD getPendingDetails(const request_list_t* requests,
LLAssetType::EType asset_type,
const std::string& detail_prefix) const;
virtual LLSD getPendingRequest(const request_list_t* requests,
LLAssetType::EType asset_type,
const LLUUID& asset_id) const;
virtual bool deletePendingRequest(request_list_t* requests,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
public:
static const LLAssetRequest* findRequest(const request_list_t* requests,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
static LLAssetRequest* findRequest(request_list_t* requests,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
request_list_t* getRequestList(ERequestType rt);
const request_list_t* getRequestList(ERequestType rt) const;
static std::string getRequestName(ERequestType rt);
S32 getNumPendingDownloads() const;
S32 getNumPendingUploads() const;
S32 getNumPendingLocalUploads();
S32 getNumPending(ERequestType rt) const;
virtual 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;
virtual bool deletePendingRequest(ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
// Returns a map from type to num pending, eg 'texture' => 5, 'object' => 10
LLSD getPendingDownloadTypes() const;
LLSD getPendingUploadTypes() const;
// download process callbacks
static void downloadCompleteCallback(
@ -330,8 +388,6 @@ private:
LLXferManager *xfer,
LLVFS *vfs,
const LLHost &upstream_host);
LLSD getPendingTypes(const std::list<LLAssetRequest*>& requests) const;
};
////////////////////////////////////////////////////////////////////////

View File

@ -11,12 +11,15 @@
#include "llhttpassetstorage.h"
#include <sys/stat.h>
#include "indra_constants.h"
#include "llvfile.h"
#include "llvfs.h"
#include "zlib/zlib.h"
const U32 MAX_RUNNING_REQUESTS = 4;
const F32 MAX_PROCESSING_TIME = 0.005f;
const S32 CURL_XFER_BUFFER_SIZE = 65536;
// Try for 30 minutes for now.
@ -49,7 +52,9 @@ struct LLTempAssetData
class LLHTTPAssetRequest : public LLAssetRequest
{
public:
LLHTTPAssetRequest(LLHTTPAssetStorage *asp, const LLUUID &uuid, LLAssetType::EType type, const char *url, CURLM *curl_multi);
LLHTTPAssetRequest(LLHTTPAssetStorage *asp, const LLUUID &uuid,
LLAssetType::EType type, LLAssetStorage::ERequestType rt,
const char *url, CURLM *curl_multi);
virtual ~LLHTTPAssetRequest();
void setupCurlHandle();
@ -61,6 +66,9 @@ public:
static size_t curlCompressedUploadCallback(
void *data, size_t size, size_t nmemb, void *user_data);
virtual LLSD getTerseDetails() const;
virtual LLSD getFullDetails() const;
public:
LLHTTPAssetStorage *mAssetStoragep;
@ -70,9 +78,7 @@ public:
struct curl_slist *mHTTPHeaders;
LLVFile *mVFile;
LLUUID mTmpUUID;
BOOL mIsUpload;
BOOL mIsLocalUpload;
BOOL mIsDownload;
LLAssetStorage::ERequestType mRequestType;
bool mZInitialized;
z_stream mZStream;
@ -83,7 +89,12 @@ public:
};
LLHTTPAssetRequest::LLHTTPAssetRequest(LLHTTPAssetStorage *asp, const LLUUID &uuid, LLAssetType::EType type, const char *url, CURLM *curl_multi)
LLHTTPAssetRequest::LLHTTPAssetRequest(LLHTTPAssetStorage *asp,
const LLUUID &uuid,
LLAssetType::EType type,
LLAssetStorage::ERequestType rt,
const char *url,
CURLM *curl_multi)
: LLAssetRequest(uuid, type),
mZInitialized(false)
{
@ -91,10 +102,11 @@ LLHTTPAssetRequest::LLHTTPAssetRequest(LLHTTPAssetStorage *asp, const LLUUID &uu
mCurlHandle = NULL;
mCurlMultiHandle = curl_multi;
mVFile = NULL;
mIsUpload = FALSE;
mIsLocalUpload = FALSE;
mIsDownload = FALSE;
mRequestType = rt;
mHTTPHeaders = NULL;
mFP = NULL;
mZInputBuffer = NULL;
mZInputExhausted = false;
mURLBuffer = new char[strlen(url) + 1]; /*Flawfinder: ignore*/
if (mURLBuffer)
@ -113,22 +125,7 @@ LLHTTPAssetRequest::~LLHTTPAssetRequest()
if (mAssetStoragep)
{
// Terminating a request. Thus upload or download is no longer pending.
if (mIsUpload)
{
mAssetStoragep->clearPendingUpload();
}
else if (mIsLocalUpload)
{
mAssetStoragep->clearPendingLocalUpload();
}
else if (mIsDownload)
{
mAssetStoragep->clearPendingDownload();
}
else
{
llerrs << "LLHTTPAssetRequest::~LLHTTPAssetRequest - Destroyed request is not upload OR download, this is bad!" << llendl;
}
mAssetStoragep->removeRunningRequest(mRequestType, this);
}
else
{
@ -144,6 +141,82 @@ LLHTTPAssetRequest::~LLHTTPAssetRequest()
finishCompressedUpload();
}
// virtual
LLSD LLHTTPAssetRequest::getTerseDetails() const
{
LLSD sd = LLAssetRequest::getTerseDetails();
sd["url"] = mURLBuffer;
return sd;
}
// virtual
LLSD LLHTTPAssetRequest::getFullDetails() const
{
LLSD sd = LLAssetRequest::getFullDetails();
if (mCurlHandle)
{
long curl_response = -1;
long curl_connect = -1;
double curl_total_time = -1.0f;
double curl_size_upload = -1.0f;
double curl_size_download = -1.0f;
long curl_content_length_upload = -1;
long curl_content_length_download = -1;
long curl_request_size = -1;
const char* curl_content_type = NULL;
curl_easy_getinfo(mCurlHandle, CURLINFO_HTTP_CODE, &curl_response);
curl_easy_getinfo(mCurlHandle, CURLINFO_HTTP_CONNECTCODE, &curl_connect);
curl_easy_getinfo(mCurlHandle, CURLINFO_TOTAL_TIME, &curl_total_time);
curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_UPLOAD, &curl_size_upload);
curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_DOWNLOAD, &curl_size_download);
curl_easy_getinfo(mCurlHandle, CURLINFO_CONTENT_LENGTH_UPLOAD, &curl_content_length_upload);
curl_easy_getinfo(mCurlHandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &curl_content_length_download);
curl_easy_getinfo(mCurlHandle, CURLINFO_REQUEST_SIZE, &curl_request_size);
curl_easy_getinfo(mCurlHandle, CURLINFO_CONTENT_TYPE, &curl_content_type);
sd["curl_response_code"] = (int) curl_response;
sd["curl_http_connect_code"] = (int) curl_connect;
sd["curl_total_time"] = curl_total_time;
sd["curl_size_upload"] = curl_size_upload;
sd["curl_size_download"] = curl_size_download;
sd["curl_content_length_upload"] = (int) curl_content_length_upload;
sd["curl_content_length_download"] = (int) curl_content_length_download;
sd["curl_request_size"] = (int) curl_request_size;
if (curl_content_type)
{
sd["curl_content_type"] = curl_content_type;
}
else
{
sd["curl_content_type"] = "";
}
}
sd["temp_id"] = mTmpUUID;
sd["request_type"] = LLAssetStorage::getRequestName(mRequestType);
sd["z_initialized"] = mZInitialized;
sd["z_input_exhausted"] = mZInputExhausted;
S32 file_size = -1;
if (mFP)
{
struct stat file_stat;
int file_desc = fileno(mFP);
if ( fstat(file_desc, &file_stat) == 0)
{
file_size = file_stat.st_size;
}
}
sd["file_size"] = file_size;
return sd;
}
void LLHTTPAssetRequest::setupCurlHandle()
{
mCurlHandle = curl_easy_init();
@ -151,7 +224,7 @@ void LLHTTPAssetRequest::setupCurlHandle()
curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1);
curl_easy_setopt(mCurlHandle, CURLOPT_URL, mURLBuffer);
curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, this);
if (mIsDownload)
if (LLAssetStorage::RT_DOWNLOAD == mRequestType)
{
curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
// only do this on downloads, as uploads
@ -174,22 +247,7 @@ void LLHTTPAssetRequest::setupCurlHandle()
if (mAssetStoragep)
{
// Set the appropriate pending upload or download flag
if (mIsUpload)
{
mAssetStoragep->setPendingUpload();
}
else if (mIsLocalUpload)
{
mAssetStoragep->setPendingLocalUpload();
}
else if (mIsDownload)
{
mAssetStoragep->setPendingDownload();
}
else
{
llerrs << "LLHTTPAssetRequest::setupCurlHandle - Request is not upload OR download, this is bad!" << llendl;
}
mAssetStoragep->addRunningRequest(mRequestType, this);
}
else
{
@ -323,10 +381,6 @@ void LLHTTPAssetStorage::_init(const char *web_host, const char *local_web_host,
curl_global_init(CURL_GLOBAL_ALL);
mCurlMultiHandle = curl_multi_init();
mPendingDownload = FALSE;
mPendingUpload = FALSE;
mPendingLocalUpload = FALSE;
}
LLHTTPAssetStorage::~LLHTTPAssetStorage()
@ -438,6 +492,113 @@ void LLHTTPAssetStorage::storeAssetData(
}
}
// virtual
LLSD LLHTTPAssetStorage::getPendingDetails(LLAssetStorage::ERequestType rt,
LLAssetType::EType asset_type,
const std::string& detail_prefix) const
{
LLSD sd = LLAssetStorage::getPendingDetails(rt, asset_type, detail_prefix);
const request_list_t* running = getRunningList(rt);
if (running)
{
// Loop through the pending requests sd, and add extra info about its running status.
S32 num_pending = sd["requests"].size();
S32 i;
for (i = 0; i < num_pending; ++i)
{
LLSD& pending = sd["requests"][i];
// See if this pending request is running.
const LLAssetRequest* req = findRequest(running,
LLAssetType::lookup(pending["type"].asString().c_str()),
pending["asset_id"]);
if (req)
{
// Keep the detail_url so we don't have to rebuild it.
LLURI detail_url = pending["detail"];
pending = req->getTerseDetails();
pending["detail"] = detail_url;
pending["is_running"] = true;
}
else
{
pending["is_running"] = false;
}
}
}
return sd;
}
// virtual
LLSD LLHTTPAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id) const
{
// Look for this asset in the running list first.
const request_list_t* running = getRunningList(rt);
if (running)
{
LLSD sd = LLAssetStorage::getPendingRequest(running, asset_type, asset_id);
if (sd)
{
sd["is_running"] = true;
return sd;
}
}
LLSD sd = LLAssetStorage::getPendingRequest(rt, asset_type, asset_id);
if (sd)
{
sd["is_running"] = false;
}
return sd;
}
// virtual
bool LLHTTPAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id)
{
// Try removing this from the running list first.
request_list_t* running = getRunningList(rt);
if (running)
{
LLAssetRequest* req = findRequest(running, asset_type, asset_id);
if (req)
{
// Remove this request from the running list to get it out of curl.
running->remove(req);
// Find this request in the pending list, so we can move it to the end of the line.
request_list_t* pending = getRequestList(rt);
if (pending)
{
request_list_t::iterator result = std::find_if(pending->begin(), pending->end(),
std::bind2nd(ll_asset_request_equal<LLAssetRequest*>(), req));
if (pending->end() != result)
{
// This request was found in the pending list. Move it to the end!
LLAssetRequest* pending_req = *result;
pending->remove(pending_req);
pending->push_back(pending_req);
llinfos << "Asset " << getRequestName(rt) << " request for "
<< asset_id << "." << LLAssetType::lookup(asset_type)
<< " removed from curl and placed at the end of the pending queue."
<< llendl;
}
else
{
llwarns << "Unable to find pending " << getRequestName(rt) << " request for "
<< asset_id << "." << LLAssetType::lookup(asset_type) << llendl;
}
}
delete req;
return true;
}
}
return LLAssetStorage::deletePendingRequest(rt, asset_type, asset_id);
}
// 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),
@ -469,13 +630,41 @@ void LLHTTPAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::ETyp
}
}
LLAssetRequest* LLHTTPAssetStorage::findNextRequest(LLAssetStorage::request_list_t& pending,
LLAssetStorage::request_list_t& running)
{
// Early exit if the running list is full, or we don't have more pending than running.
if (running.size() >= MAX_RUNNING_REQUESTS
|| pending.size() <= running.size()) return NULL;
// Look for the first pending request that is not already running.
request_list_t::iterator running_begin = running.begin();
request_list_t::iterator running_end = running.end();
request_list_t::iterator pending_iter = pending.begin();
request_list_t::iterator pending_end = pending.end();
// Loop over all pending requests until we miss finding it in the running list.
for (; pending_iter != pending.end(); ++pending_iter)
{
LLAssetRequest* req = *pending_iter;
// Look for this pending request in the running list.
if (running_end == std::find_if(running_begin, running_end,
std::bind2nd(ll_asset_request_equal<LLAssetRequest*>(), req)))
{
// It isn't running! Return it.
return req;
}
}
return NULL;
}
// overloaded to additionally move data to/from the webserver
void LLHTTPAssetStorage::checkForTimeouts()
{
LLAssetRequest *req = NULL;
if (mPendingDownloads.size() > 0 && !mPendingDownload)
CURLMcode mcode;
LLAssetRequest *req;
while (req = findNextRequest(mPendingDownloads, mRunningDownloads))
{
req = mPendingDownloads.front();
// Setup this curl download request
// We need to generate a new request here
// since the one in the list could go away
@ -485,9 +674,9 @@ void LLHTTPAssetStorage::checkForTimeouts()
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(), tmp_url, mCurlMultiHandle);
LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(),
req->getType(), RT_DOWNLOAD, tmp_url, mCurlMultiHandle);
new_req->mTmpUUID.generate();
new_req->mIsDownload = TRUE;
// Sets pending download flag internally
new_req->setupCurlHandle();
@ -495,15 +684,22 @@ void LLHTTPAssetStorage::checkForTimeouts()
curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &curlDownCallback);
curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEDATA, new_req->mCurlHandle);
curl_multi_add_handle(mCurlMultiHandle, 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.
deletePendingRequest(RT_DOWNLOAD, req->getType(), req->getUUID());
break;
}
else
{
llinfos << "Requesting " << new_req->mURLBuffer << llendl;
}
}
if (mPendingUploads.size() > 0 && !mPendingUpload)
while (req = findNextRequest(mPendingUploads, mRunningUploads))
{
req = mPendingUploads.front();
// setup this curl upload request
bool do_compress = req->getType() == LLAssetType::AT_OBJECT;
@ -515,8 +711,8 @@ void LLHTTPAssetStorage::checkForTimeouts()
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(), tmp_url, mCurlMultiHandle);
new_req->mIsUpload = TRUE;
LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(),
req->getType(), RT_UPLOAD, tmp_url, mCurlMultiHandle);
if (do_compress)
{
new_req->prepareCompressedUpload();
@ -541,15 +737,23 @@ void LLHTTPAssetStorage::checkForTimeouts()
}
curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle);
curl_multi_add_handle(mCurlMultiHandle, 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.
deletePendingRequest(RT_UPLOAD, req->getType(), req->getUUID());
break;
}
else
{
llinfos << "Requesting PUT " << new_req->mURLBuffer << llendl;
}
// Pending upload will have been flagged by the request
}
if (mPendingLocalUploads.size() > 0 && !mPendingLocalUpload)
while (req = findNextRequest(mPendingLocalUploads, mRunningLocalUploads))
{
req = mPendingLocalUploads.front();
// setup this curl upload request
LLVFile file(mVFS, req->getUUID(), req->getType());
@ -560,8 +764,8 @@ void LLHTTPAssetStorage::checkForTimeouts()
// 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(), tmp_url, mCurlMultiHandle);
new_req->mIsLocalUpload = TRUE;
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
@ -572,13 +776,22 @@ void LLHTTPAssetStorage::checkForTimeouts()
curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION, &curlUpCallback);
curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle);
curl_multi_add_handle(mCurlMultiHandle, 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.
deletePendingRequest(RT_LOCALUPLOAD, req->getType(), 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;
CURLMcode mcode;
int queue_length;
do
{
@ -599,12 +812,15 @@ void LLHTTPAssetStorage::checkForTimeouts()
curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_PRIVATE, &req);
curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_HTTP_CODE, &curl_result);
if (req->mIsUpload || req->mIsLocalUpload)
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))
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 (req->mIsLocalUpload)
if (RT_LOCALUPLOAD == req->mRequestType)
{
addTempAssetData(req->getUUID(), req->mRequestingAgentID, mHostName);
}
@ -636,7 +852,7 @@ void LLHTTPAssetStorage::checkForTimeouts()
// Pending upload flag will get cleared when the request is deleted
}
}
else if (req->mIsDownload)
else if (RT_DOWNLOAD == req->mRequestType)
{
if (curl_result == HTTP_OK && curl_msg->data.result == CURLE_OK)
{
@ -648,7 +864,7 @@ void LLHTTPAssetStorage::checkForTimeouts()
}
else
{
// TODO: if this actually indicates a bad asset on the server
// *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;
@ -774,9 +990,8 @@ S32 LLHTTPAssetStorage::getURLToFile(const LLUUID& uuid, LLAssetType::EType asse
}
// make sure we use the normal curl setup, even though we don't really need a request object
LLHTTPAssetRequest req(this, uuid, asset_type, url.c_str(), mCurlMultiHandle);
LLHTTPAssetRequest req(this, uuid, asset_type, RT_DOWNLOAD, url.c_str(), mCurlMultiHandle);
req.mFP = fp;
req.mIsDownload = TRUE;
req.setupCurlHandle();
curl_easy_setopt(req.mCurlHandle, CURLOPT_FOLLOWLOCATION, TRUE);
@ -868,6 +1083,63 @@ size_t LLHTTPAssetStorage::curlFileDownCallback(void *data, size_t size, size_t
return fwrite(data, size, nmemb, req->mFP);
}
LLAssetStorage::request_list_t* LLHTTPAssetStorage::getRunningList(LLAssetStorage::ERequestType rt)
{
switch (rt)
{
case RT_DOWNLOAD:
return &mRunningDownloads;
case RT_UPLOAD:
return &mRunningUploads;
case RT_LOCALUPLOAD:
return &mRunningLocalUploads;
default:
return NULL;
}
}
const LLAssetStorage::request_list_t* LLHTTPAssetStorage::getRunningList(LLAssetStorage::ERequestType rt) const
{
switch (rt)
{
case RT_DOWNLOAD:
return &mRunningDownloads;
case RT_UPLOAD:
return &mRunningUploads;
case RT_LOCALUPLOAD:
return &mRunningLocalUploads;
default:
return NULL;
}
}
void LLHTTPAssetStorage::addRunningRequest(ERequestType rt, LLHTTPAssetRequest* request)
{
request_list_t* requests = getRunningList(rt);
if (requests)
{
requests->push_back(request);
}
else
{
llerrs << "LLHTTPAssetStorage::addRunningRequest - Request is not an upload OR download, this is bad!" << llendl;
}
}
void LLHTTPAssetStorage::removeRunningRequest(ERequestType rt, LLHTTPAssetRequest* request)
{
request_list_t* requests = getRunningList(rt);
if (requests)
{
requests->remove(request);
}
else
{
llerrs << "LLHTTPAssetStorage::removeRunningRequest - Destroyed request is not an upload OR download, this is bad!" << llendl;
}
}
// virtual
void LLHTTPAssetStorage::addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name)
{

View File

@ -13,6 +13,7 @@
#include "curl/curl.h"
class LLVFile;
class LLHTTPAssetRequest;
typedef void (*progress_callback)(void* userdata);
struct LLTempAssetData;
@ -56,11 +57,25 @@ public:
bool temp_file,
bool is_priority);
virtual 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;
virtual bool deletePendingRequest(ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
// Hack. One off curl download an URL to a file. Probably should be elsewhere.
// Only used by lldynamicstate. The API is broken, and should be replaced with
// a generic HTTP file fetch - Doug 9/25/06
S32 getURLToFile(const LLUUID& uuid, LLAssetType::EType asset_type, const LLString &url, const char *filename, progress_callback callback, void *userdata);
LLAssetRequest* findNextRequest(request_list_t& pending, request_list_t& running);
void checkForTimeouts();
static size_t curlDownCallback(void *data, size_t size, size_t nmemb, void *user_data);
@ -69,12 +84,11 @@ public:
static size_t nullOutputCallback(void *data, size_t size, size_t nmemb, void *user_data);
// Should only be used by the LLHTTPAssetRequest
void setPendingUpload() { mPendingUpload = TRUE; }
void setPendingLocalUpload() { mPendingLocalUpload = TRUE; }
void setPendingDownload() { mPendingDownload = TRUE; }
void clearPendingUpload() { mPendingUpload = FALSE; }
void clearPendingLocalUpload() { mPendingLocalUpload = FALSE; }
void clearPendingDownload() { mPendingDownload = FALSE; }
void addRunningRequest(ERequestType rt, LLHTTPAssetRequest* request);
void removeRunningRequest(ERequestType rt, LLHTTPAssetRequest* request);
request_list_t* getRunningList(ERequestType rt);
const request_list_t* getRunningList(ERequestType rt) const;
// Temp assets are stored on sim nodes, they have agent ID and location data associated with them.
virtual void addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name);
@ -106,9 +120,9 @@ protected:
CURLM *mCurlMultiHandle;
BOOL mPendingDownload;
BOOL mPendingUpload;
BOOL mPendingLocalUpload;
request_list_t mRunningDownloads;
request_list_t mRunningUploads;
request_list_t mRunningLocalUploads;
uuid_tempdata_map mTempAssets;
};