diff options
Diffstat (limited to 'indra/llmessage/llcachename.cpp')
-rw-r--r-- | indra/llmessage/llcachename.cpp | 355 |
1 files changed, 175 insertions, 180 deletions
diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 1ad5179455..379f390625 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -2,30 +2,25 @@ * @file llcachename.cpp * @brief A hierarchical cache of first and last names queried based on UUID. * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,12 +36,7 @@ #include "llsdserialize.h" #include "lluuid.h" #include "message.h" - -// Constants -// probably need a setUIString() call in the interface -const char* const CN_WAITING = "(Loading...)"; // *TODO: translate -const char* const CN_NOBODY = "(nobody)"; // *TODO: translate -const char* const CN_NONE = "(none)"; // *TODO: translate +#include "llmemtype.h" // llsd serialization constants static const std::string AGENTS("agents"); @@ -65,6 +55,7 @@ const S32 CN_FILE_VERSION = 2; // Globals LLCacheName* gCacheName = NULL; +std::map<std::string, std::string> LLCacheName::sCacheName; /// --------------------------------------------------------------------------- /// class LLCacheNameEntry @@ -78,16 +69,15 @@ public: public: bool mIsGroup; U32 mCreateTime; // unix time_t - char mFirstName[DB_FIRST_NAME_BUF_SIZE]; /*Flawfinder: ignore*/ - char mLastName[DB_LAST_NAME_BUF_SIZE]; /*Flawfinder: ignore*/ - char mGroupName[DB_GROUP_NAME_BUF_SIZE]; /*Flawfinder: ignore*/ + std::string mFirstName; + std::string mLastName; + std::string mGroupName; }; LLCacheNameEntry::LLCacheNameEntry() + : mIsGroup(false), + mCreateTime(0) { - mFirstName[0] = '\0'; - mLastName[0] = '\0'; - mGroupName[0] = '\0'; } @@ -95,17 +85,19 @@ class PendingReply { public: LLUUID mID; - LLCacheNameCallback mCallback; + LLCacheNameSignal mSignal; LLHost mHost; - void* mData; - PendingReply(const LLUUID& id, LLCacheNameCallback callback, void* data = NULL) - : mID(id), mCallback(callback), mData(data) - { } - + PendingReply(const LLUUID& id, const LLHost& host) - : mID(id), mCallback(0), mHost(host) - { } - + : mID(id), mHost(host) + { + } + + boost::signals2::connection setCallback(const LLCacheNameCallback& cb) + { + return mSignal.connect(cb); + } + void done() { mID.setNull(); } bool isDone() const { return mID.isNull() != FALSE; } }; @@ -129,7 +121,7 @@ private: }; ReplySender::ReplySender(LLMessageSystem* msg) - : mMsg(msg), mPending(false) + : mMsg(msg), mPending(false), mCurrIsGroup(false) { } ReplySender::~ReplySender() @@ -190,10 +182,10 @@ void ReplySender::flush() typedef std::set<LLUUID> AskQueue; -typedef std::vector<PendingReply> ReplyQueue; +typedef std::list<PendingReply*> ReplyQueue; typedef std::map<LLUUID,U32> PendingQueue; typedef std::map<LLUUID, LLCacheNameEntry*> Cache; -typedef std::vector<LLCacheNameCallback> Observers; +typedef std::map<std::string, LLUUID> ReverseCache; class LLCacheName::Impl { @@ -203,7 +195,9 @@ public: Cache mCache; // the map of UUIDs to names - + ReverseCache mReverseCache; + // map of names to UUIDs + AskQueue mAskNameQueue; AskQueue mAskGroupQueue; // UUIDs to ask our upstream host about @@ -214,13 +208,16 @@ public: ReplyQueue mReplyQueue; // requests awaiting replies from us - Observers mObservers; + LLCacheNameSignal mSignal; LLFrameTimer mProcessTimer; Impl(LLMessageSystem* msg); ~Impl(); - + + boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback); + void addPending(const LLUUID& id, const LLHost& host); + void processPendingAsks(); void processPendingReplies(); void sendRequest(const char* msg_name, const AskQueue& queue); @@ -234,8 +231,6 @@ public: static void handleUUIDNameReply(LLMessageSystem* msg, void** userdata); static void handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userdata); static void handleUUIDGroupNameReply(LLMessageSystem* msg, void** userdata); - - void notifyObservers(const LLUUID& id, const char* first, const char* last, BOOL group); }; @@ -250,6 +245,9 @@ LLCacheName::LLCacheName(LLMessageSystem* msg) LLCacheName::LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host) : impl(* new Impl(msg)) { + sCacheName["waiting"] = "(Loading...)"; + sCacheName["nobody"] = "(nobody)"; + sCacheName["none"] = "(none)"; setUpstream(upstream_host); } @@ -275,52 +273,31 @@ LLCacheName::Impl::Impl(LLMessageSystem* msg) LLCacheName::Impl::~Impl() { for_each(mCache.begin(), mCache.end(), DeletePairedPointer()); + for_each(mReplyQueue.begin(), mReplyQueue.end(), DeletePointer()); } - -void LLCacheName::setUpstream(const LLHost& upstream_host) +boost::signals2::connection LLCacheName::Impl::addPending(const LLUUID& id, const LLCacheNameCallback& callback) { - impl.mUpstreamHost = upstream_host; + PendingReply* reply = new PendingReply(id, LLHost()); + boost::signals2::connection res = reply->setCallback(callback); + mReplyQueue.push_back(reply); + return res; } -void LLCacheName::addObserver(LLCacheNameCallback callback) +void LLCacheName::Impl::addPending(const LLUUID& id, const LLHost& host) { - impl.mObservers.push_back(callback); + PendingReply* reply = new PendingReply(id, host); + mReplyQueue.push_back(reply); } -void LLCacheName::removeObserver(LLCacheNameCallback callback) +void LLCacheName::setUpstream(const LLHost& upstream_host) { - Observers::iterator it = impl.mObservers.begin(); - Observers::iterator end = impl.mObservers.end(); - - for ( ; it != end; ++it) - { - const LLCacheNameCallback& cb = (*it); - if (cb == callback) - { - impl.mObservers.erase(it); - return; - } - } + impl.mUpstreamHost = upstream_host; } -void LLCacheName::cancelCallback(const LLUUID& id, LLCacheNameCallback callback, void* user_data) +boost::signals2::connection LLCacheName::addObserver(const LLCacheNameCallback& callback) { - ReplyQueue::iterator it = impl.mReplyQueue.begin(); - ReplyQueue::iterator end = impl.mReplyQueue.end(); - - for(; it != end; ++it) - { - const PendingReply& reply = (*it); - - if ((callback == reply.mCallback) - && (id == reply.mID) - && (user_data == reply.mData) ) - { - impl.mReplyQueue.erase(it); - return; - } - } + return impl.mSignal.connect(callback); } void LLCacheName::importFile(LLFILE* fp) @@ -390,10 +367,12 @@ void LLCacheName::importFile(LLFILE* fp) LLCacheNameEntry* entry = new LLCacheNameEntry(); entry->mIsGroup = false; entry->mCreateTime = create_time; - LLString::copy(entry->mFirstName, firstname, DB_FIRST_NAME_BUF_SIZE); - LLString::copy(entry->mLastName, lastname, DB_LAST_NAME_BUF_SIZE); + entry->mFirstName = firstname; + entry->mLastName = lastname; impl.mCache[id] = entry; - + std::string fullname = entry->mFirstName + " " + entry->mLastName; + impl.mReverseCache[fullname] = id; + count++; } @@ -426,13 +405,12 @@ bool LLCacheName::importFile(std::istream& istr) LLCacheNameEntry* entry = new LLCacheNameEntry(); entry->mIsGroup = false; entry->mCreateTime = ctime; - std::string first = agent[FIRST].asString(); - first.copy(entry->mFirstName, DB_FIRST_NAME_BUF_SIZE, 0); - entry->mFirstName[llmin(first.size(),(std::string::size_type)DB_FIRST_NAME_BUF_SIZE-1)] = '\0'; - std::string last = agent[LAST].asString(); - last.copy(entry->mLastName, DB_LAST_NAME_BUF_SIZE, 0); - entry->mLastName[llmin(last.size(),(std::string::size_type)DB_LAST_NAME_BUF_SIZE-1)] = '\0'; + entry->mFirstName = agent[FIRST].asString(); + entry->mLastName = agent[LAST].asString(); impl.mCache[id] = entry; + std::string fullname = entry->mFirstName + " " + entry->mLastName; + impl.mReverseCache[fullname] = id; + ++count; } llinfos << "LLCacheName loaded " << count << " agent names" << llendl; @@ -451,10 +429,9 @@ bool LLCacheName::importFile(std::istream& istr) LLCacheNameEntry* entry = new LLCacheNameEntry(); entry->mIsGroup = true; entry->mCreateTime = ctime; - std::string name = group[NAME].asString(); - name.copy(entry->mGroupName, DB_GROUP_NAME_BUF_SIZE, 0); - entry->mGroupName[llmin(name.size(), (std::string::size_type)DB_GROUP_NAME_BUF_SIZE-1)] = '\0'; + entry->mGroupName = group[NAME].asString(); impl.mCache[id] = entry; + impl.mReverseCache[entry->mGroupName] = id; ++count; } llinfos << "LLCacheName loaded " << count << " group names" << llendl; @@ -471,8 +448,8 @@ void LLCacheName::exportFile(std::ostream& ostr) // Only write entries for which we have valid data. LLCacheNameEntry* entry = iter->second; if(!entry - || (NULL != strchr(entry->mFirstName, '?')) - || (NULL != strchr(entry->mGroupName, '?'))) + || (std::string::npos != entry->mFirstName.find('?')) + || (std::string::npos != entry->mGroupName.find('?'))) { continue; } @@ -480,13 +457,13 @@ void LLCacheName::exportFile(std::ostream& ostr) // store it LLUUID id = iter->first; std::string id_str = id.asString(); - if(entry->mFirstName[0] && entry->mLastName[0]) + if(!entry->mFirstName.empty() && !entry->mLastName.empty()) { data[AGENTS][id_str][FIRST] = entry->mFirstName; data[AGENTS][id_str][LAST] = entry->mLastName; data[AGENTS][id_str][CTIME] = (S32)entry->mCreateTime; } - else if(entry->mIsGroup && entry->mGroupName[0]) + else if(entry->mIsGroup && !entry->mGroupName.empty()) { data[GROUPS][id_str][NAME] = entry->mGroupName; data[GROUPS][id_str][CTIME] = (S32)entry->mCreateTime; @@ -501,9 +478,9 @@ BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& las { if(id.isNull()) { - first = CN_NOBODY; + first = sCacheName["nobody"]; last.clear(); - return FALSE; + return TRUE; } LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id ); @@ -515,7 +492,7 @@ BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& las } else { - first = CN_WAITING; + first = sCacheName["waiting"]; last.clear(); if (!impl.isRequestPending(id)) { @@ -525,22 +502,20 @@ BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& las } } - -BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname) +// static +void LLCacheName::LocalizeCacheName(std::string key, std::string value) { - std::string first_name, last_name; - BOOL res = getName(id, first_name, last_name); - fullname = first_name + " " + last_name; - return res; + if (key!="" && value!= "" ) + sCacheName[key]=value; + else + llwarns<< " Error localizing cache key " << key << " To "<< value<<llendl; } -// *TODO: Deprecate -BOOL LLCacheName::getName(const LLUUID& id, char* first, char* last) +BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname) { std::string first_name, last_name; BOOL res = getName(id, first_name, last_name); - strcpy(first, first_name.c_str()); - strcpy(last, last_name.c_str()); + fullname = first_name + " " + last_name; return res; } @@ -548,12 +523,12 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group) { if(id.isNull()) { - group = CN_NONE; - return FALSE; + group = sCacheName["none"]; + return TRUE; } LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache,id); - if (entry && !entry->mGroupName[0]) + if (entry && entry->mGroupName.empty()) { // COUNTER-HACK to combat James' HACK in exportFile()... // this group name was loaded from a name cache that did not @@ -569,7 +544,7 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group) } else { - group = CN_WAITING; + group = sCacheName["waiting"]; if (!impl.isRequestPending(id)) { impl.mAskGroupQueue.insert(id); @@ -578,36 +553,58 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group) } } -// *TODO: Deprecate -BOOL LLCacheName::getGroupName(const LLUUID& id, char* group) +BOOL LLCacheName::getUUID(const std::string& first, const std::string& last, LLUUID& id) { - std::string group_name; - BOOL res = getGroupName(id, group_name); - strcpy(group, group_name.c_str()); - return res; + std::string fullname = first + " " + last; + return getUUID(fullname, id); } +BOOL LLCacheName::getUUID(const std::string& fullname, LLUUID& id) +{ + ReverseCache::iterator iter = impl.mReverseCache.find(fullname); + if (iter != impl.mReverseCache.end()) + { + id = iter->second; + return TRUE; + } + else + { + return FALSE; + } +} -// TODO: Make the cache name callback take a SINGLE std::string, -// not a separate first and last name. -void LLCacheName::get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callback, void* user_data) +// This is a little bit kludgy. LLCacheNameCallback is a slot instead of a function pointer. +// The reason it is a slot is so that the legacy get() function below can bind an old callback +// and pass it as a slot. The reason it isn't a boost::function is so that trackable behavior +// doesn't get lost. As a result, we have to bind the slot to a signal to call it, even when +// we call it immediately. -Steve +// NOTE: Even though passing first and last name is a bit of extra overhead, it eliminates the +// potential need for any parsing should any code need to handle first and last name independently. +boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback) { + boost::signals2::connection res; + if(id.isNull()) { - callback(id, CN_NOBODY, "", is_group, user_data); + LLCacheNameSignal signal; + signal.connect(callback); + signal(id, sCacheName["nobody"], "", is_group); + return res; } LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id ); if (entry) { + LLCacheNameSignal signal; + signal.connect(callback); // id found in map therefore we can call the callback immediately. if (entry->mIsGroup) { - callback(id, entry->mGroupName, "", entry->mIsGroup, user_data); + signal(id, entry->mGroupName, "", entry->mIsGroup); } else { - callback(id, entry->mFirstName, entry->mLastName, entry->mIsGroup, user_data); + signal(id, entry->mFirstName, entry->mLastName, entry->mIsGroup); } } else @@ -624,12 +621,19 @@ void LLCacheName::get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callb impl.mAskNameQueue.insert(id); } } - impl.mReplyQueue.push_back(PendingReply(id, callback, user_data)); + res = impl.addPending(id, callback); } + return res; +} + +boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, old_callback_t callback, void* user_data) +{ + return get(id, is_group, boost::bind(callback, _1, _2, _3, _4, user_data)); } void LLCacheName::processPending() { + LLMemType mt_pp(LLMemType::MTYPE_CACHE_PROCESS_PENDING); const F32 SECS_BETWEEN_PROCESS = 0.1f; if(!impl.mProcessTimer.checkExpirationAndReset(SECS_BETWEEN_PROCESS)) { @@ -711,18 +715,19 @@ void LLCacheName::dumpStats() << " AskGroup=" << impl.mAskGroupQueue.size() << " Pending=" << impl.mPendingQueue.size() << " Reply=" << impl.mReplyQueue.size() - << " Observers=" << impl.mObservers.size() +// << " Observers=" << impl.mSignal.size() << llendl; } //static -LLString LLCacheName::getDefaultName() +std::string LLCacheName::getDefaultName() { - return LLString(CN_WAITING); + return sCacheName["waiting"]; } void LLCacheName::Impl::processPendingAsks() { + LLMemType mt_ppa(LLMemType::MTYPE_CACHE_PROCESS_PENDING_ASKS); sendRequest(_PREHASH_UUIDNameRequest, mAskNameQueue); sendRequest(_PREHASH_UUIDGroupNameRequest, mAskGroupQueue); mAskNameQueue.clear(); @@ -731,50 +736,50 @@ void LLCacheName::Impl::processPendingAsks() void LLCacheName::Impl::processPendingReplies() { - ReplyQueue::iterator it = mReplyQueue.begin(); - ReplyQueue::iterator end = mReplyQueue.end(); - + LLMemType mt_ppr(LLMemType::MTYPE_CACHE_PROCESS_PENDING_REPLIES); // First call all the callbacks, because they might send messages. - for(; it != end; ++it) + for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it) { - LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID); + PendingReply* reply = *it; + LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID); if(!entry) continue; - if (it->mCallback) + if (!entry->mIsGroup) { - if (!entry->mIsGroup) - { - (it->mCallback)(it->mID, - entry->mFirstName, entry->mLastName, - FALSE, it->mData); - } - else { - (it->mCallback)(it->mID, - entry->mGroupName, "", - TRUE, it->mData); - } + (reply->mSignal)(reply->mID, entry->mFirstName, entry->mLastName, FALSE); + } + else + { + (reply->mSignal)(reply->mID, entry->mGroupName, "", TRUE); } } // Forward on all replies, if needed. ReplySender sender(mMsg); - for (it = mReplyQueue.begin(); it != end; ++it) + for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it) { - LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID); + PendingReply* reply = *it; + LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID); if(!entry) continue; - if (it->mHost.isOk()) + if (reply->mHost.isOk()) { - sender.send(it->mID, *entry, it->mHost); + sender.send(reply->mID, *entry, reply->mHost); } - it->done(); + reply->done(); + } + + for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ) + { + ReplyQueue::iterator curit = it++; + PendingReply* reply = *curit; + if (reply->isDone()) + { + delete reply; + mReplyQueue.erase(curit); + } } - - mReplyQueue.erase( - remove_if(mReplyQueue.begin(), mReplyQueue.end(), - std::mem_fun_ref(&PendingReply::isDone)), - mReplyQueue.end()); } @@ -812,18 +817,6 @@ void LLCacheName::Impl::sendRequest( } } -void LLCacheName::Impl::notifyObservers(const LLUUID& id, - const char* first, const char* last, BOOL is_group) -{ - for (Observers::const_iterator i = mObservers.begin(), - end = mObservers.end(); - i != end; - ++i) - { - (**i)(id, first, last, is_group, NULL); - } -} - bool LLCacheName::Impl::isRequestPending(const LLUUID& id) { U32 now = (U32)time(NULL); @@ -890,7 +883,7 @@ void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup) } } - mReplyQueue.push_back(PendingReply(id, fromHost)); + addPending(id, fromHost); } } } @@ -917,23 +910,25 @@ void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup) entry->mCreateTime = (U32)time(NULL); if (!isGroup) { - msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_FirstName, DB_FIRST_NAME_BUF_SIZE, entry->mFirstName, i); - msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_LastName, DB_LAST_NAME_BUF_SIZE, entry->mLastName, i); + msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_FirstName, entry->mFirstName, i); + msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_LastName, entry->mLastName, i); } else - { - msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, DB_GROUP_NAME_BUF_SIZE, entry->mGroupName, i); + { // is group + msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, entry->mGroupName, i); + LLStringFn::replace_ascii_controlchars(entry->mGroupName, LL_UNKNOWN_CHAR); } if (!isGroup) { - notifyObservers(id, - entry->mFirstName, entry->mLastName, - FALSE); + mSignal(id, entry->mFirstName, entry->mLastName, FALSE); + std::string fullname = entry->mFirstName + " " + entry->mLastName; + mReverseCache[fullname] = id; } else { - notifyObservers(id, entry->mGroupName, "", TRUE); + mSignal(id, entry->mGroupName, "", TRUE); + mReverseCache[entry->mGroupName] = id; } } } |