SL-11657 Separated expected from current inventory serial for better sync and to fix partial loads

master
andreykproductengine 2019-07-31 19:10:03 +03:00
parent af011f9241
commit 301c5ae4e2
2 changed files with 103 additions and 69 deletions

View File

@ -269,6 +269,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
mPixelArea(1024.f),
mInventory(NULL),
mInventorySerialNum(0),
mExpectedInventorySerialNum(0),
mInvRequestState(INVENTORY_REQUEST_STOPPED),
mInvRequestXFerId(0),
mInventoryDirty(FALSE),
@ -2802,13 +2803,13 @@ void LLViewerObject::doUpdateInventory(
{
// best guess.
perm.setOwnerAndGroup(LLUUID::null, gAgent.getID(), item->getPermissions().getGroup(), is_atomic);
--mInventorySerialNum;
--mExpectedInventorySerialNum;
}
else
{
// dummy it up.
perm.setOwnerAndGroup(LLUUID::null, LLUUID::null, LLUUID::null, is_atomic);
--mInventorySerialNum;
--mExpectedInventorySerialNum;
}
}
LLViewerInventoryItem* oldItem = item;
@ -2816,7 +2817,11 @@ void LLViewerObject::doUpdateInventory(
new_item->setPermissions(perm);
mInventory->push_front(new_item);
doInventoryCallback();
++mInventorySerialNum;
++mExpectedInventorySerialNum;
}
else if (is_new)
{
++mExpectedInventorySerialNum;
}
}
@ -2883,7 +2888,7 @@ void LLViewerObject::moveInventory(const LLUUID& folder_id,
if(!item->getPermissions().allowCopyBy(gAgent.getID()))
{
deleteInventoryItem(item_id);
++mInventorySerialNum;
++mExpectedInventorySerialNum;
}
}
}
@ -3146,74 +3151,95 @@ S32 LLFilenameAndTask::sCount = 0;
// static
void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)
{
LLUUID task_id;
msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id);
LLViewerObject* object = gObjectList.findObject(task_id);
if(!object)
{
LL_WARNS() << "LLViewerObject::processTaskInv object "
<< task_id << " does not exist." << LL_ENDL;
return;
}
LLUUID task_id;
msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id);
LLViewerObject* object = gObjectList.findObject(task_id);
if (!object)
{
LL_WARNS() << "LLViewerObject::processTaskInv object "
<< task_id << " does not exist." << LL_ENDL;
return;
}
LLFilenameAndTask* ft = new LLFilenameAndTask;
ft->mTaskID = task_id;
// we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update
msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial);
LLFilenameAndTask* ft = new LLFilenameAndTask;
ft->mTaskID = task_id;
// we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update
msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial);
if (ft->mSerial < object->mInventorySerialNum)
{
// viewer did some changes to inventory that were not saved yet.
LL_DEBUGS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client serial: " << object->mInventorySerialNum << LL_ENDL;
object->mInventorySerialNum = ft->mSerial;
}
if (ft->mSerial == object->mInventorySerialNum)
{
// Loop Protection.
// We received same serial twice.
// Viewer did some changes to inventory that couldn't be saved server side
// or something went wrong to cause serial to be out of sync
LL_WARNS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client expected serial: " << object->mExpectedInventorySerialNum << LL_ENDL;
object->mExpectedInventorySerialNum = ft->mSerial;
}
std::string unclean_filename;
msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename);
ft->mFilename = LLDir::getScrubbedFileName(unclean_filename);
if (ft->mSerial < object->mExpectedInventorySerialNum)
{
// out of date message, record to current serial for loop protection, but do not load it
// just drop xfer to restart on idle
if (ft->mSerial < object->mInventorySerialNum)
{
LL_WARNS() << "Somehow task serial decreased, out of order packet?" << LL_ENDL;
}
object->mInventorySerialNum = ft->mSerial;
object->mInvRequestXFerId = 0;
object->mInvRequestState = INVENTORY_REQUEST_STOPPED;
}
else if (ft->mSerial >= object->mExpectedInventorySerialNum)
{
object->mInventorySerialNum = ft->mSerial;
object->mExpectedInventorySerialNum = ft->mSerial;
if(ft->mFilename.empty())
{
LL_DEBUGS() << "Task has no inventory" << LL_ENDL;
// mock up some inventory to make a drop target.
if(object->mInventory)
{
object->mInventory->clear(); // will deref and delete it
}
else
{
object->mInventory = new LLInventoryObject::object_list_t();
}
LLPointer<LLInventoryObject> obj;
obj = new LLInventoryObject(object->mID, LLUUID::null,
LLAssetType::AT_CATEGORY,
"Contents");
object->mInventory->push_front(obj);
object->doInventoryCallback();
delete ft;
return;
}
U64 new_id = gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename),
ft->mFilename, LL_PATH_CACHE,
object->mRegionp->getHost(),
TRUE,
&LLViewerObject::processTaskInvFile,
(void**)ft,
LLXferManager::HIGH_PRIORITY);
if (object->mInvRequestState == INVENTORY_XFER)
{
if (new_id > 0 && new_id != object->mInvRequestXFerId)
{
// we started new download.
gXferManager->abortRequestById(object->mInvRequestXFerId, -1);
object->mInvRequestXFerId = new_id;
}
}
else
{
object->mInvRequestState = INVENTORY_XFER;
object->mInvRequestXFerId = new_id;
}
std::string unclean_filename;
msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename);
ft->mFilename = LLDir::getScrubbedFileName(unclean_filename);
if (ft->mFilename.empty())
{
LL_DEBUGS() << "Task has no inventory" << LL_ENDL;
// mock up some inventory to make a drop target.
if (object->mInventory)
{
object->mInventory->clear(); // will deref and delete it
}
else
{
object->mInventory = new LLInventoryObject::object_list_t();
}
LLPointer<LLInventoryObject> obj;
obj = new LLInventoryObject(object->mID, LLUUID::null,
LLAssetType::AT_CATEGORY,
"Contents");
object->mInventory->push_front(obj);
object->doInventoryCallback();
delete ft;
return;
}
U64 new_id = gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename),
ft->mFilename, LL_PATH_CACHE,
object->mRegionp->getHost(),
TRUE,
&LLViewerObject::processTaskInvFile,
(void**)ft,
LLXferManager::HIGH_PRIORITY);
if (object->mInvRequestState == INVENTORY_XFER)
{
if (new_id > 0 && new_id != object->mInvRequestXFerId)
{
// we started new download.
gXferManager->abortRequestById(object->mInvRequestXFerId, -1);
object->mInvRequestXFerId = new_id;
}
}
else
{
object->mInvRequestState = INVENTORY_XFER;
object->mInvRequestXFerId = new_id;
}
}
}
void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status)
@ -3227,6 +3253,13 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS
&& ft->mSerial >= object->mInventorySerialNum)
{
object->mInventorySerialNum = ft->mSerial;
LL_DEBUGS() << "Receiving inventory task file for serial " << object->mInventorySerialNum << " taskid: " << ft->mTaskID << LL_ENDL;
if (ft->mSerial < object->mExpectedInventorySerialNum)
{
// User managed to change something while inventory was loading
LL_DEBUGS() << "Processing file that is potentially out of date for task: " << ft->mTaskID << LL_ENDL;
}
if (object->loadTaskInvFile(ft->mFilename))
{
@ -3376,7 +3409,7 @@ void LLViewerObject::removeInventory(const LLUUID& item_id)
msg->addUUIDFast(_PREHASH_ItemID, item_id);
msg->sendReliable(mRegionp->getHost());
deleteInventoryItem(item_id);
++mInventorySerialNum;
++mExpectedInventorySerialNum;
}
bool LLViewerObject::isTextureInInventory(LLViewerInventoryItem* item)

View File

@ -802,6 +802,7 @@ protected:
typedef std::list<LLInventoryCallbackInfo*> callback_list_t;
callback_list_t mInventoryCallbacks;
S16 mInventorySerialNum;
S16 mExpectedInventorySerialNum;
enum EInventoryRequestState
{