summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorDon Kjer <don@lindenlab.com>2012-12-06 22:56:21 +0000
committerDon Kjer <don@lindenlab.com>2012-12-06 22:56:21 +0000
commit23d77d3a34e48de6e9c69d60cdbd1d70766ad16c (patch)
tree84c2878deeb7ba8f4e408365ca53c3d119a15cb1 /indra
parent07d05c2967fb1013a3f21c1c055ad068b2be9995 (diff)
parent97adf6422ac61148a3334d67b4c59a5f5437af2c (diff)
Automated merge
Diffstat (limited to 'indra')
-rw-r--r--indra/cmake/Python.cmake2
-rw-r--r--indra/llcommon/tests/bitpack_test.cpp1
-rw-r--r--indra/llvfs/llvfile.cpp7
-rw-r--r--indra/llwindow/llwindowsdl.cpp3
-rwxr-xr-xindra/newview/CMakeLists.txt9
-rwxr-xr-xindra/newview/app_settings/settings.xml11
-rwxr-xr-xindra/newview/llappearancemgr.cpp356
-rw-r--r--indra/newview/tests/llviewertexture_stub.cpp32
8 files changed, 360 insertions, 61 deletions
diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake
index 748c8c2bec..a81c9307fc 100644
--- a/indra/cmake/Python.cmake
+++ b/indra/cmake/Python.cmake
@@ -23,7 +23,7 @@ if (WINDOWS)
elseif (EXISTS /etc/debian_version)
# On Debian and Ubuntu, avoid Python 2.4 if possible.
- find_program(PYTHON_EXECUTABLE python2.5 python2.3 python PATHS /usr/bin)
+ find_program(PYTHON_EXECUTABLE python PATHS /usr/bin)
if (PYTHON_EXECUTABLE)
set(PYTHONINTERP_FOUND ON)
diff --git a/indra/llcommon/tests/bitpack_test.cpp b/indra/llcommon/tests/bitpack_test.cpp
index 7bca20c30a..afc0c18cd0 100644
--- a/indra/llcommon/tests/bitpack_test.cpp
+++ b/indra/llcommon/tests/bitpack_test.cpp
@@ -94,7 +94,6 @@ namespace tut
ensure("bitPack: individual unpack: 5", unpackbuffer[0] == (U8) str[5]);
bitunpack.bitUnpack(unpackbuffer, 8*4); // Life
ensure_memory_matches("bitPack: 4 bytes unpack:", unpackbuffer, 4, str+6, 4);
- //ensure("keep compiler quiet", unpack_bufsize == unpack_bufsize);
}
// U32 packing
diff --git a/indra/llvfs/llvfile.cpp b/indra/llvfs/llvfile.cpp
index ca749c5eaf..03d2cc25e3 100644
--- a/indra/llvfs/llvfile.cpp
+++ b/indra/llvfs/llvfile.cpp
@@ -32,6 +32,7 @@
#include "llthread.h"
#include "llstat.h"
#include "llvfs.h"
+#include "llmemory.h"
const S32 LLVFile::READ = 0x00000001;
const S32 LLVFile::WRITE = 0x00000002;
@@ -134,13 +135,13 @@ U8* LLVFile::readFile(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, S
data = NULL;
}
else
- {
- data = new U8[file_size];
+ {
+ data = (U8*) ll_aligned_malloc_16(file_size);
file.read(data, file_size); /* Flawfinder: ignore */
if (file.getLastBytesRead() != (S32)file_size)
{
- delete[] data;
+ ll_aligned_free(data);
data = NULL;
file_size = 0;
}
diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp
index c7b141d7c1..9ea76df479 100644
--- a/indra/llwindow/llwindowsdl.cpp
+++ b/indra/llwindow/llwindowsdl.cpp
@@ -2645,8 +2645,9 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()
if (sortpat)
{
// Sort the list of system fonts from most-to-least-desirable.
+ FcResult result;
fs = FcFontSort(NULL, sortpat, elide_unicode_coverage,
- NULL, NULL);
+ NULL, &result);
FcPatternDestroy(sortpat);
}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index f85060a140..e64697982f 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -2061,6 +2061,15 @@ if (LL_TESTS)
)
set_source_files_properties(
+ llworldmap.cpp
+ llworldmipmap.cpp
+ PROPERTIES
+ LL_TEST_ADDITIONAL_SOURCE_FILES
+ tests/llviewertexture_stub.cpp
+ #llviewertexturelist.cpp
+ )
+
+ set_source_files_properties(
lltranslate.cpp
PROPERTIES
LL_TEST_ADDITIONAL_LIBRARIES "${JSONCPP_LIBRARIES}"
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index efb1ccc1cc..4a69e5b356 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -4315,6 +4315,17 @@
<key>Value</key>
<real>1.0</real>
</map>
+ <key>InventoryDebugSimulateOpFailureRate</key>
+ <map>
+ <key>Comment</key>
+ <string>Rate at which we simulate failures of copy/link requests in some operations</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
<key>InventoryDisplayInbox</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 315811d709..98a8097a1e 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -155,55 +155,298 @@ LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string
}
}
-class LLWearInventoryCategoryCallback : public LLInventoryCallback
+// Shim between inventory callback and boost function
+typedef boost::function<void(const LLUUID&)> inventory_func_type;
+
+class LLBoostFuncInventoryCallback: public LLInventoryCallback
{
public:
- LLWearInventoryCategoryCallback(const LLUUID& cat_id, bool append)
- {
- mCatID = cat_id;
- mAppend = append;
- LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL;
-
- selfStartPhase("wear_inventory_category_callback");
+ LLBoostFuncInventoryCallback(const inventory_func_type& func):
+ mFunc(func)
+ {
}
+
void fire(const LLUUID& item_id)
{
- /*
- * Do nothing. We only care about the destructor
- *
- * The reason for this is that this callback is used in a hack where the
- * same callback is given to dozens of items, and the destructor is called
- * after the last item has fired the event and dereferenced it -- if all
- * the events actually fire!
- */
- LL_DEBUGS("Avatar") << self_av_string() << " fired on copied item, id " << item_id << LL_ENDL;
+ mFunc(item_id);
}
-protected:
- ~LLWearInventoryCategoryCallback()
+private:
+ inventory_func_type mFunc;
+};
+
+LLPointer<LLInventoryCallback> make_inventory_func_callback(const inventory_func_type& func)
+{
+ return new LLBoostFuncInventoryCallback(func);
+}
+
+void report_fire(const LLUUID& item_id)
+{
+ llinfos << item_id << llendl;
+}
+
+void no_op() {}
+
+class LLCallAfterInventoryBatchMgr: public LLEventTimer
+{
+public:
+ LLCallAfterInventoryBatchMgr(const LLUUID& dst_cat_id,
+ const std::string& phase_name,
+ nullary_func_t on_completion_func,
+ nullary_func_t on_failure_func = no_op,
+ F32 check_period = 5.0,
+ F32 retry_after = 10.0,
+ S32 max_retries = 2
+ ):
+ mDstCatID(dst_cat_id),
+ mTrackingPhase(phase_name),
+ mOnCompletionFunc(on_completion_func),
+ mOnFailureFunc(on_failure_func),
+ mRetryAfter(retry_after),
+ mMaxRetries(max_retries),
+ mPendingRequests(0),
+ mFailCount(0),
+ mCompletionOrFailureCalled(false),
+ mRetryCount(0),
+ LLEventTimer(check_period)
+ {
+ if (!mTrackingPhase.empty())
+ {
+ selfStartPhase(mTrackingPhase);
+ }
+ }
+
+ void addItems(LLInventoryModel::item_array_t& src_items)
{
- LL_INFOS("Avatar") << self_av_string() << "done all inventory callbacks" << LL_ENDL;
+ for (LLInventoryModel::item_array_t::const_iterator it = src_items.begin();
+ it != src_items.end();
+ ++it)
+ {
+ LLViewerInventoryItem* item = *it;
+ llassert(item);
+ addItem(item);
+ }
+ }
+
+ // Request or re-request operation for specified item.
+ void addItem(LLViewerInventoryItem *item)
+ {
+ const LLUUID& item_id = item->getUUID();
+ if (!item)
+ {
+ llwarns << "item not found for " << item_id << llendl;
+ return;
+ }
+ mPendingRequests++;
+ // On a re-request, this will reset the timer.
+ mWaitTimes[item_id] = LLTimer();
+ if (mRetryCounts.find(item_id) == mRetryCounts.end())
+ {
+ mRetryCounts[item_id] = 0;
+ }
+ else
+ {
+ mRetryCounts[item_id]++;
+ }
+
+ if (ll_frand()<gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate"))
+ {
+ // simulate server failure by not sending the request.
+ return;
+ }
- selfStopPhase("wear_inventory_category_callback");
+ requestOperation(item);
+ }
+
+ virtual void requestOperation(LLViewerInventoryItem *item) = 0;
- // Is the destructor called by ordinary dereference, or because the app's shutting down?
- // If the inventory callback manager goes away, we're shutting down, no longer want the callback.
- if( LLInventoryCallbackManager::is_instantiated() )
+ void onOp(const LLUUID& src_id, const LLUUID& dst_id)
+ {
+ LL_DEBUGS("Avatar") << "op done, src_id " << src_id << " dst_id " << dst_id << " after " << mWaitTimes[src_id].getElapsedTimeF32() << " seconds" << llendl;
+ mPendingRequests--;
+ F32 wait_time = mWaitTimes[src_id].getElapsedTimeF32();
+ mTimeStats.push(wait_time);
+ mWaitTimes.erase(src_id);
+ if (mCompletionOrFailureCalled)
{
- LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(gInventory.getCategory(mCatID), mAppend);
+ llinfos << "late-completing operation, src_id " << src_id << "dst_id " << dst_id << llendl;
+ }
+ if (mWaitTimes.empty() && !mCompletionOrFailureCalled)
+ {
+ onCompletionOrFailure();
+ }
+ }
+
+ void onCompletionOrFailure()
+ {
+ assert (!mCompletionOrFailureCalled);
+ mCompletionOrFailureCalled = true;
+
+ // Will never call onCompletion() if any item has been flagged as
+ // a failure - otherwise could wind up with corrupted
+ // outfit, involuntary nudity, etc.
+ reportStats();
+ if (!mTrackingPhase.empty())
+ {
+ selfStopPhase(mTrackingPhase);
+ }
+ if (!mFailCount)
+ {
+ onCompletion();
}
else
{
- llwarns << self_av_string() << "Dropping unhandled LLWearInventoryCategoryCallback" << llendl;
+ onFailure();
}
}
-private:
- LLUUID mCatID;
- bool mAppend;
+ void onFailure()
+ {
+ llinfos << "failed" << llendl;
+ mOnFailureFunc();
+ }
+
+ void onCompletion()
+ {
+ llinfos << "done" << llendl;
+ mOnCompletionFunc();
+ }
+
+ // virtual
+ // Will be deleted after returning true - only safe to do this if all callbacks have fired.
+ BOOL tick()
+ {
+ // mPendingRequests will be zero if all requests have been
+ // responded to. mWaitTimes.empty() will be true if we have
+ // received at least one reply for each UUID. If requests
+ // have been dropped and retried, these will not necessarily
+ // be the same. Only safe to return true if all requests have
+ // been serviced, since it will result in this object being
+ // deleted.
+ bool all_done = (mPendingRequests==0);
+
+ if (!mWaitTimes.empty())
+ {
+ llwarns << "still waiting on " << mWaitTimes.size() << " items" << llendl;
+ for (std::map<LLUUID,LLTimer>::iterator it = mWaitTimes.begin();
+ it != mWaitTimes.end();)
+ {
+ // Use a copy of iterator because it may be erased/invalidated.
+ std::map<LLUUID,LLTimer>::iterator curr_it = it;
+ ++it;
+
+ F32 time_waited = curr_it->second.getElapsedTimeF32();
+ S32 retries = mRetryCounts[curr_it->first];
+ if (time_waited > mRetryAfter)
+ {
+ if (retries < mMaxRetries)
+ {
+ LL_DEBUGS("Avatar") << "Waited " << time_waited <<
+ " for " << curr_it->first << ", retrying" << llendl;
+ mRetryCount++;
+ addItem(gInventory.getItem(curr_it->first));
+ }
+ else
+ {
+ llwarns << "Giving up on " << curr_it->first << " after too many retries" << llendl;
+ mWaitTimes.erase(curr_it);
+ mFailCount++;
+ }
+ }
+ if (mWaitTimes.empty())
+ {
+ onCompletionOrFailure();
+ }
+
+ }
+ }
+ return all_done;
+ }
+
+ void reportStats()
+ {
+ LL_DEBUGS("Avatar") << "Phase: " << mTrackingPhase << llendl;
+ LL_DEBUGS("Avatar") << "mFailCount: " << mFailCount << llendl;
+ LL_DEBUGS("Avatar") << "mRetryCount: " << mRetryCount << llendl;
+ LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << llendl;
+ LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << llendl;
+ }
+
+ virtual ~LLCallAfterInventoryBatchMgr()
+ {
+ LL_DEBUGS("Avatar") << "deleting" << llendl;
+ }
+
+protected:
+ std::string mTrackingPhase;
+ std::map<LLUUID,LLTimer> mWaitTimes;
+ std::map<LLUUID,S32> mRetryCounts;
+ LLUUID mDstCatID;
+ nullary_func_t mOnCompletionFunc;
+ nullary_func_t mOnFailureFunc;
+ F32 mRetryAfter;
+ S32 mMaxRetries;
+ S32 mPendingRequests;
+ S32 mFailCount;
+ S32 mRetryCount;
+ bool mCompletionOrFailureCalled;
+ LLViewerStats::StatsAccumulator mTimeStats;
+};
+
+class LLCallAfterInventoryCopyMgr: public LLCallAfterInventoryBatchMgr
+{
+public:
+ LLCallAfterInventoryCopyMgr(LLInventoryModel::item_array_t& src_items,
+ const LLUUID& dst_cat_id,
+ const std::string& phase_name,
+ nullary_func_t on_completion_func,
+ nullary_func_t on_failure_func = no_op
+ ):
+ LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func)
+ {
+ addItems(src_items);
+ }
+
+ virtual void requestOperation(LLViewerInventoryItem *item)
+ {
+ copy_inventory_item(
+ gAgent.getID(),
+ item->getPermissions().getOwner(),
+ item->getUUID(),
+ mDstCatID,
+ std::string(),
+ make_inventory_func_callback(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item->getUUID(),_1))
+ );
+ }
};
+class LLCallAfterInventoryLinkMgr: public LLCallAfterInventoryBatchMgr
+{
+public:
+ LLCallAfterInventoryLinkMgr(LLInventoryModel::item_array_t& src_items,
+ const LLUUID& dst_cat_id,
+ const std::string& phase_name,
+ nullary_func_t on_completion_func,
+ nullary_func_t on_failure_func = no_op
+ ):
+ LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func)
+ {
+ addItems(src_items);
+ }
+
+ virtual void requestOperation(LLViewerInventoryItem *item)
+ {
+ link_inventory_item(gAgent.getID(),
+ item->getLinkedUUID(),
+ mDstCatID,
+ item->getName(),
+ item->LLInventoryItem::getDescription(),
+ LLAssetType::AT_LINK,
+ make_inventory_func_callback(
+ boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item->getUUID(),_1)));
+ }
+};
//Inventory callback updating "dirty" state when destroyed
class LLUpdateDirtyState: public LLInventoryCallback
@@ -1527,34 +1770,38 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
purgeCategory(cof, keep_outfit_links);
gInventory.notifyObservers();
- // Create links to new COF contents.
- LL_DEBUGS("Avatar") << self_av_string() << "creating LLUpdateAppearanceOnDestroy" << LL_ENDL;
- LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(!append);
-
#ifndef LL_RELEASE_FOR_DOWNLOAD
LL_DEBUGS("Avatar") << self_av_string() << "Linking body items" << LL_ENDL;
#endif
- linkAll(cof, body_items, link_waiter);
+
+ // Create links to new COF contents.
+ LL_DEBUGS("Avatar") << self_av_string() << "creating LLCallAfterInventoryLinkMgr" << LL_ENDL;
+ bool update_base_outfit_ordering = !append;
+ LLCallAfterInventoryLinkMgr *link_waiter =
+ new LLCallAfterInventoryLinkMgr(body_items,cof,"update_appearance_on_destroy",
+ boost::bind(&LLAppearanceMgr::updateAppearanceFromCOF,
+ LLAppearanceMgr::getInstance(),
+ update_base_outfit_ordering));
#ifndef LL_RELEASE_FOR_DOWNLOAD
LL_DEBUGS("Avatar") << self_av_string() << "Linking wear items" << LL_ENDL;
#endif
- linkAll(cof, wear_items, link_waiter);
+ link_waiter->addItems(wear_items);
#ifndef LL_RELEASE_FOR_DOWNLOAD
LL_DEBUGS("Avatar") << self_av_string() << "Linking obj items" << LL_ENDL;
#endif
- linkAll(cof, obj_items, link_waiter);
+ link_waiter->addItems(obj_items);
#ifndef LL_RELEASE_FOR_DOWNLOAD
LL_DEBUGS("Avatar") << self_av_string() << "Linking gesture items" << LL_ENDL;
#endif
- linkAll(cof, gest_items, link_waiter);
+ link_waiter->addItems(gest_items);
// Add link to outfit if category is an outfit.
if (!append)
{
- createBaseOutfitLink(category, link_waiter);
+ createBaseOutfitLink(category, NULL);
}
LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL;
}
@@ -1980,22 +2227,15 @@ void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool ap
pid,
LLFolderType::FT_NONE,
name);
- LLPointer<LLInventoryCallback> cb = new LLWearInventoryCategoryCallback(new_cat_id, append);
- it = items->begin();
- for(; it < end; ++it)
- {
- item = *it;
- if(item)
- {
- copy_inventory_item(
- gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- new_cat_id,
- std::string(),
- cb);
- }
- }
+
+ // Create a CopyMgr that will copy items, manage its own destruction
+ new LLCallAfterInventoryCopyMgr(
+ *items, new_cat_id, std::string("wear_inventory_category_callback"),
+ boost::bind(&LLAppearanceMgr::wearInventoryCategoryOnAvatar,
+ LLAppearanceMgr::getInstance(),
+ gInventory.getCategory(new_cat_id),
+ append));
+
// BAP fixes a lag in display of created dir.
gInventory.notifyObservers();
}
@@ -2012,7 +2252,13 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego
// Avoid unintentionally overwriting old wearables. We have to do
// this up front to avoid having to deal with the case of multiple
// wearables being dirty.
- if(!category) return;
+ if (!category) return;
+
+ if ( !LLInventoryCallbackManager::is_instantiated() )
+ {
+ // shutting down, ignore.
+ return;
+ }
LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategoryOnAvatar '" << category->getName()
<< "'" << LL_ENDL;
diff --git a/indra/newview/tests/llviewertexture_stub.cpp b/indra/newview/tests/llviewertexture_stub.cpp
new file mode 100644
index 0000000000..90e76a8f83
--- /dev/null
+++ b/indra/newview/tests/llviewertexture_stub.cpp
@@ -0,0 +1,32 @@
+/**
+ * @file llviewertexture_stub.cpp
+ * @brief stub class to allow unit testing
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "../llviewertexture.h"
+
+void LLViewerTexture::setBoostLevel(int level)
+{
+}