PageRenderTime 211ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmessage/llcachename.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1020 lines | 787 code | 145 blank | 88 comment | 107 complexity | f91a83bc69d6cbcdc78cddad70ab5864 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llcachename.cpp
  3. * @brief A hierarchical cache of first and last names queried based on UUID.
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "llcachename.h"
  28. // linden library includes
  29. #include "lldbstrings.h"
  30. #include "llframetimer.h"
  31. #include "llhost.h"
  32. #include "llrand.h"
  33. #include "llsdserialize.h"
  34. #include "lluuid.h"
  35. #include "message.h"
  36. #include "llmemtype.h"
  37. #include <boost/regex.hpp>
  38. // llsd serialization constants
  39. static const std::string AGENTS("agents");
  40. static const std::string GROUPS("groups");
  41. static const std::string CTIME("ctime");
  42. static const std::string FIRST("first");
  43. static const std::string LAST("last");
  44. static const std::string NAME("name");
  45. // We track name requests in flight for up to this long.
  46. // We won't re-request a name during this time
  47. const U32 PENDING_TIMEOUT_SECS = 5 * 60;
  48. // File version number
  49. const S32 CN_FILE_VERSION = 2;
  50. // Globals
  51. LLCacheName* gCacheName = NULL;
  52. std::map<std::string, std::string> LLCacheName::sCacheName;
  53. /// ---------------------------------------------------------------------------
  54. /// class LLCacheNameEntry
  55. /// ---------------------------------------------------------------------------
  56. class LLCacheNameEntry
  57. {
  58. public:
  59. LLCacheNameEntry();
  60. public:
  61. bool mIsGroup;
  62. U32 mCreateTime; // unix time_t
  63. // IDEVO TODO collapse names to one field, which will eliminate
  64. // many string compares on "Resident"
  65. std::string mFirstName;
  66. std::string mLastName;
  67. std::string mGroupName;
  68. };
  69. LLCacheNameEntry::LLCacheNameEntry()
  70. : mIsGroup(false),
  71. mCreateTime(0)
  72. {
  73. }
  74. class PendingReply
  75. {
  76. public:
  77. LLUUID mID;
  78. LLCacheNameSignal mSignal;
  79. LLHost mHost;
  80. PendingReply(const LLUUID& id, const LLHost& host)
  81. : mID(id), mHost(host)
  82. {
  83. }
  84. boost::signals2::connection setCallback(const LLCacheNameCallback& cb)
  85. {
  86. return mSignal.connect(cb);
  87. }
  88. void done() { mID.setNull(); }
  89. bool isDone() const { return mID.isNull() != FALSE; }
  90. };
  91. class ReplySender
  92. {
  93. public:
  94. ReplySender(LLMessageSystem* msg);
  95. ~ReplySender();
  96. void send(const LLUUID& id,
  97. const LLCacheNameEntry& entry, const LLHost& host);
  98. private:
  99. void flush();
  100. LLMessageSystem* mMsg;
  101. bool mPending;
  102. bool mCurrIsGroup;
  103. LLHost mCurrHost;
  104. };
  105. ReplySender::ReplySender(LLMessageSystem* msg)
  106. : mMsg(msg), mPending(false), mCurrIsGroup(false)
  107. { }
  108. ReplySender::~ReplySender()
  109. {
  110. flush();
  111. }
  112. void ReplySender::send(const LLUUID& id,
  113. const LLCacheNameEntry& entry, const LLHost& host)
  114. {
  115. if (mPending)
  116. {
  117. if (mCurrIsGroup != entry.mIsGroup
  118. || mCurrHost != host)
  119. {
  120. flush();
  121. }
  122. }
  123. if (!mPending)
  124. {
  125. mPending = true;
  126. mCurrIsGroup = entry.mIsGroup;
  127. mCurrHost = host;
  128. if(mCurrIsGroup)
  129. mMsg->newMessageFast(_PREHASH_UUIDGroupNameReply);
  130. else
  131. mMsg->newMessageFast(_PREHASH_UUIDNameReply);
  132. }
  133. mMsg->nextBlockFast(_PREHASH_UUIDNameBlock);
  134. mMsg->addUUIDFast(_PREHASH_ID, id);
  135. if(mCurrIsGroup)
  136. {
  137. mMsg->addStringFast(_PREHASH_GroupName, entry.mGroupName);
  138. }
  139. else
  140. {
  141. mMsg->addStringFast(_PREHASH_FirstName, entry.mFirstName);
  142. mMsg->addStringFast(_PREHASH_LastName, entry.mLastName);
  143. }
  144. if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock))
  145. {
  146. flush();
  147. }
  148. }
  149. void ReplySender::flush()
  150. {
  151. if (mPending)
  152. {
  153. mMsg->sendReliable(mCurrHost);
  154. mPending = false;
  155. }
  156. }
  157. typedef std::set<LLUUID> AskQueue;
  158. typedef std::list<PendingReply*> ReplyQueue;
  159. typedef std::map<LLUUID,U32> PendingQueue;
  160. typedef std::map<LLUUID, LLCacheNameEntry*> Cache;
  161. typedef std::map<std::string, LLUUID> ReverseCache;
  162. class LLCacheName::Impl
  163. {
  164. public:
  165. LLMessageSystem* mMsg;
  166. LLHost mUpstreamHost;
  167. Cache mCache;
  168. // the map of UUIDs to names
  169. ReverseCache mReverseCache;
  170. // map of names to UUIDs
  171. AskQueue mAskNameQueue;
  172. AskQueue mAskGroupQueue;
  173. // UUIDs to ask our upstream host about
  174. PendingQueue mPendingQueue;
  175. // UUIDs that have been requested but are not in cache yet.
  176. ReplyQueue mReplyQueue;
  177. // requests awaiting replies from us
  178. LLCacheNameSignal mSignal;
  179. LLFrameTimer mProcessTimer;
  180. Impl(LLMessageSystem* msg);
  181. ~Impl();
  182. BOOL getName(const LLUUID& id, std::string& first, std::string& last);
  183. boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback);
  184. void addPending(const LLUUID& id, const LLHost& host);
  185. void processPendingAsks();
  186. void processPendingReplies();
  187. void sendRequest(const char* msg_name, const AskQueue& queue);
  188. bool isRequestPending(const LLUUID& id);
  189. // Message system callbacks.
  190. void processUUIDRequest(LLMessageSystem* msg, bool isGroup);
  191. void processUUIDReply(LLMessageSystem* msg, bool isGroup);
  192. static void handleUUIDNameRequest(LLMessageSystem* msg, void** userdata);
  193. static void handleUUIDNameReply(LLMessageSystem* msg, void** userdata);
  194. static void handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userdata);
  195. static void handleUUIDGroupNameReply(LLMessageSystem* msg, void** userdata);
  196. };
  197. /// --------------------------------------------------------------------------
  198. /// class LLCacheName
  199. /// ---------------------------------------------------------------------------
  200. LLCacheName::LLCacheName(LLMessageSystem* msg)
  201. : impl(* new Impl(msg))
  202. { }
  203. LLCacheName::LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host)
  204. : impl(* new Impl(msg))
  205. {
  206. sCacheName["waiting"] = "(Loading...)";
  207. sCacheName["nobody"] = "(nobody)";
  208. sCacheName["none"] = "(none)";
  209. setUpstream(upstream_host);
  210. }
  211. LLCacheName::~LLCacheName()
  212. {
  213. delete &impl;
  214. }
  215. LLCacheName::Impl::Impl(LLMessageSystem* msg)
  216. : mMsg(msg), mUpstreamHost(LLHost::invalid)
  217. {
  218. mMsg->setHandlerFuncFast(
  219. _PREHASH_UUIDNameRequest, handleUUIDNameRequest, (void**)this);
  220. mMsg->setHandlerFuncFast(
  221. _PREHASH_UUIDNameReply, handleUUIDNameReply, (void**)this);
  222. mMsg->setHandlerFuncFast(
  223. _PREHASH_UUIDGroupNameRequest, handleUUIDGroupNameRequest, (void**)this);
  224. mMsg->setHandlerFuncFast(
  225. _PREHASH_UUIDGroupNameReply, handleUUIDGroupNameReply, (void**)this);
  226. }
  227. LLCacheName::Impl::~Impl()
  228. {
  229. for_each(mCache.begin(), mCache.end(), DeletePairedPointer());
  230. for_each(mReplyQueue.begin(), mReplyQueue.end(), DeletePointer());
  231. }
  232. boost::signals2::connection LLCacheName::Impl::addPending(const LLUUID& id, const LLCacheNameCallback& callback)
  233. {
  234. PendingReply* reply = new PendingReply(id, LLHost());
  235. boost::signals2::connection res = reply->setCallback(callback);
  236. mReplyQueue.push_back(reply);
  237. return res;
  238. }
  239. void LLCacheName::Impl::addPending(const LLUUID& id, const LLHost& host)
  240. {
  241. PendingReply* reply = new PendingReply(id, host);
  242. mReplyQueue.push_back(reply);
  243. }
  244. void LLCacheName::setUpstream(const LLHost& upstream_host)
  245. {
  246. impl.mUpstreamHost = upstream_host;
  247. }
  248. boost::signals2::connection LLCacheName::addObserver(const LLCacheNameCallback& callback)
  249. {
  250. return impl.mSignal.connect(callback);
  251. }
  252. bool LLCacheName::importFile(std::istream& istr)
  253. {
  254. LLSD data;
  255. if(LLSDSerialize::fromXMLDocument(data, istr) < 1)
  256. return false;
  257. // We'll expire entries more than a week old
  258. U32 now = (U32)time(NULL);
  259. const U32 SECS_PER_DAY = 60 * 60 * 24;
  260. U32 delete_before_time = now - (7 * SECS_PER_DAY);
  261. // iterate over the agents
  262. S32 count = 0;
  263. LLSD agents = data[AGENTS];
  264. LLSD::map_iterator iter = agents.beginMap();
  265. LLSD::map_iterator end = agents.endMap();
  266. for( ; iter != end; ++iter)
  267. {
  268. LLUUID id((*iter).first);
  269. LLSD agent = (*iter).second;
  270. U32 ctime = (U32)agent[CTIME].asInteger();
  271. if(ctime < delete_before_time) continue;
  272. LLCacheNameEntry* entry = new LLCacheNameEntry();
  273. entry->mIsGroup = false;
  274. entry->mCreateTime = ctime;
  275. entry->mFirstName = agent[FIRST].asString();
  276. entry->mLastName = agent[LAST].asString();
  277. impl.mCache[id] = entry;
  278. std::string fullname = buildFullName(entry->mFirstName, entry->mLastName);
  279. impl.mReverseCache[fullname] = id;
  280. ++count;
  281. }
  282. llinfos << "LLCacheName loaded " << count << " agent names" << llendl;
  283. count = 0;
  284. LLSD groups = data[GROUPS];
  285. iter = groups.beginMap();
  286. end = groups.endMap();
  287. for( ; iter != end; ++iter)
  288. {
  289. LLUUID id((*iter).first);
  290. LLSD group = (*iter).second;
  291. U32 ctime = (U32)group[CTIME].asInteger();
  292. if(ctime < delete_before_time) continue;
  293. LLCacheNameEntry* entry = new LLCacheNameEntry();
  294. entry->mIsGroup = true;
  295. entry->mCreateTime = ctime;
  296. entry->mGroupName = group[NAME].asString();
  297. impl.mCache[id] = entry;
  298. impl.mReverseCache[entry->mGroupName] = id;
  299. ++count;
  300. }
  301. llinfos << "LLCacheName loaded " << count << " group names" << llendl;
  302. return true;
  303. }
  304. void LLCacheName::exportFile(std::ostream& ostr)
  305. {
  306. LLSD data;
  307. Cache::iterator iter = impl.mCache.begin();
  308. Cache::iterator end = impl.mCache.end();
  309. for( ; iter != end; ++iter)
  310. {
  311. // Only write entries for which we have valid data.
  312. LLCacheNameEntry* entry = iter->second;
  313. if(!entry
  314. || (std::string::npos != entry->mFirstName.find('?'))
  315. || (std::string::npos != entry->mGroupName.find('?')))
  316. {
  317. continue;
  318. }
  319. // store it
  320. LLUUID id = iter->first;
  321. std::string id_str = id.asString();
  322. // IDEVO TODO: Should we store SLIDs with last name "Resident" or not?
  323. if(!entry->mFirstName.empty() && !entry->mLastName.empty())
  324. {
  325. data[AGENTS][id_str][FIRST] = entry->mFirstName;
  326. data[AGENTS][id_str][LAST] = entry->mLastName;
  327. data[AGENTS][id_str][CTIME] = (S32)entry->mCreateTime;
  328. }
  329. else if(entry->mIsGroup && !entry->mGroupName.empty())
  330. {
  331. data[GROUPS][id_str][NAME] = entry->mGroupName;
  332. data[GROUPS][id_str][CTIME] = (S32)entry->mCreateTime;
  333. }
  334. }
  335. LLSDSerialize::toPrettyXML(data, ostr);
  336. }
  337. BOOL LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last)
  338. {
  339. if(id.isNull())
  340. {
  341. first = sCacheName["nobody"];
  342. last.clear();
  343. return TRUE;
  344. }
  345. LLCacheNameEntry* entry = get_ptr_in_map(mCache, id );
  346. if (entry)
  347. {
  348. first = entry->mFirstName;
  349. last = entry->mLastName;
  350. return TRUE;
  351. }
  352. else
  353. {
  354. first = sCacheName["waiting"];
  355. last.clear();
  356. if (!isRequestPending(id))
  357. {
  358. mAskNameQueue.insert(id);
  359. }
  360. return FALSE;
  361. }
  362. }
  363. // static
  364. void LLCacheName::localizeCacheName(std::string key, std::string value)
  365. {
  366. if (key!="" && value!= "" )
  367. sCacheName[key]=value;
  368. else
  369. llwarns<< " Error localizing cache key " << key << " To "<< value<<llendl;
  370. }
  371. BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname)
  372. {
  373. std::string first_name, last_name;
  374. BOOL res = impl.getName(id, first_name, last_name);
  375. fullname = buildFullName(first_name, last_name);
  376. return res;
  377. }
  378. BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)
  379. {
  380. if(id.isNull())
  381. {
  382. group = sCacheName["none"];
  383. return TRUE;
  384. }
  385. LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache,id);
  386. if (entry && entry->mGroupName.empty())
  387. {
  388. // COUNTER-HACK to combat James' HACK in exportFile()...
  389. // this group name was loaded from a name cache that did not
  390. // bother to save the group name ==> we must ask for it
  391. lldebugs << "LLCacheName queuing HACK group request: " << id << llendl;
  392. entry = NULL;
  393. }
  394. if (entry)
  395. {
  396. group = entry->mGroupName;
  397. return TRUE;
  398. }
  399. else
  400. {
  401. group = sCacheName["waiting"];
  402. if (!impl.isRequestPending(id))
  403. {
  404. impl.mAskGroupQueue.insert(id);
  405. }
  406. return FALSE;
  407. }
  408. }
  409. BOOL LLCacheName::getUUID(const std::string& first, const std::string& last, LLUUID& id)
  410. {
  411. std::string full_name = buildFullName(first, last);
  412. return getUUID(full_name, id);
  413. }
  414. BOOL LLCacheName::getUUID(const std::string& full_name, LLUUID& id)
  415. {
  416. ReverseCache::iterator iter = impl.mReverseCache.find(full_name);
  417. if (iter != impl.mReverseCache.end())
  418. {
  419. id = iter->second;
  420. return TRUE;
  421. }
  422. else
  423. {
  424. return FALSE;
  425. }
  426. }
  427. //static
  428. std::string LLCacheName::buildFullName(const std::string& first, const std::string& last)
  429. {
  430. std::string fullname = first;
  431. if (!last.empty()
  432. && last != "Resident")
  433. {
  434. fullname += ' ';
  435. fullname += last;
  436. }
  437. return fullname;
  438. }
  439. //static
  440. std::string LLCacheName::cleanFullName(const std::string& full_name)
  441. {
  442. return full_name.substr(0, full_name.find(" Resident"));
  443. }
  444. //static
  445. std::string LLCacheName::buildUsername(const std::string& full_name)
  446. {
  447. // rare, but handle hard-coded error names returned from server
  448. if (full_name == "(\?\?\?) (\?\?\?)")
  449. {
  450. return "(\?\?\?)";
  451. }
  452. std::string::size_type index = full_name.find(' ');
  453. if (index != std::string::npos)
  454. {
  455. std::string username;
  456. username = full_name.substr(0, index);
  457. std::string lastname = full_name.substr(index+1);
  458. if (lastname != "Resident")
  459. {
  460. username = username + "." + lastname;
  461. }
  462. LLStringUtil::toLower(username);
  463. return username;
  464. }
  465. // if the input wasn't a correctly formatted legacy name just return it unchanged
  466. return full_name;
  467. }
  468. //static
  469. std::string LLCacheName::buildLegacyName(const std::string& complete_name)
  470. {
  471. //boost::regexp was showing up in the crashreporter, so doing
  472. //painfully manual parsing using substr. LF
  473. S32 open_paren = complete_name.rfind(" (");
  474. S32 close_paren = complete_name.rfind(')');
  475. if (open_paren != std::string::npos &&
  476. close_paren == complete_name.length()-1)
  477. {
  478. S32 length = close_paren - open_paren - 2;
  479. std::string legacy_name = complete_name.substr(open_paren+2, length);
  480. if (legacy_name.length() > 0)
  481. {
  482. std::string cap_letter = legacy_name.substr(0, 1);
  483. LLStringUtil::toUpper(cap_letter);
  484. legacy_name = cap_letter + legacy_name.substr(1);
  485. S32 separator = legacy_name.find('.');
  486. if (separator != std::string::npos)
  487. {
  488. std::string last_name = legacy_name.substr(separator+1);
  489. legacy_name = legacy_name.substr(0, separator);
  490. if (last_name.length() > 0)
  491. {
  492. cap_letter = last_name.substr(0, 1);
  493. LLStringUtil::toUpper(cap_letter);
  494. legacy_name = legacy_name + " " + cap_letter + last_name.substr(1);
  495. }
  496. }
  497. return legacy_name;
  498. }
  499. }
  500. return complete_name;
  501. }
  502. // This is a little bit kludgy. LLCacheNameCallback is a slot instead of a function pointer.
  503. // The reason it is a slot is so that the legacy get() function below can bind an old callback
  504. // and pass it as a slot. The reason it isn't a boost::function is so that trackable behavior
  505. // doesn't get lost. As a result, we have to bind the slot to a signal to call it, even when
  506. // we call it immediately. -Steve
  507. // NOTE: Even though passing first and last name is a bit of extra overhead, it eliminates the
  508. // potential need for any parsing should any code need to handle first and last name independently.
  509. boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback)
  510. {
  511. boost::signals2::connection res;
  512. if(id.isNull())
  513. {
  514. LLCacheNameSignal signal;
  515. signal.connect(callback);
  516. signal(id, sCacheName["nobody"], is_group);
  517. return res;
  518. }
  519. LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id );
  520. if (entry)
  521. {
  522. LLCacheNameSignal signal;
  523. signal.connect(callback);
  524. // id found in map therefore we can call the callback immediately.
  525. if (entry->mIsGroup)
  526. {
  527. signal(id, entry->mGroupName, entry->mIsGroup);
  528. }
  529. else
  530. {
  531. std::string fullname =
  532. buildFullName(entry->mFirstName, entry->mLastName);
  533. signal(id, fullname, entry->mIsGroup);
  534. }
  535. }
  536. else
  537. {
  538. // id not found in map so we must queue the callback call until available.
  539. if (!impl.isRequestPending(id))
  540. {
  541. if (is_group)
  542. {
  543. impl.mAskGroupQueue.insert(id);
  544. }
  545. else
  546. {
  547. impl.mAskNameQueue.insert(id);
  548. }
  549. }
  550. res = impl.addPending(id, callback);
  551. }
  552. return res;
  553. }
  554. boost::signals2::connection LLCacheName::getGroup(const LLUUID& group_id,
  555. const LLCacheNameCallback& callback)
  556. {
  557. return get(group_id, true, callback);
  558. }
  559. boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data)
  560. {
  561. return get(id, is_group, boost::bind(callback, _1, _2, _3, user_data));
  562. }
  563. void LLCacheName::processPending()
  564. {
  565. LLMemType mt_pp(LLMemType::MTYPE_CACHE_PROCESS_PENDING);
  566. const F32 SECS_BETWEEN_PROCESS = 0.1f;
  567. if(!impl.mProcessTimer.checkExpirationAndReset(SECS_BETWEEN_PROCESS))
  568. {
  569. return;
  570. }
  571. if(!impl.mUpstreamHost.isOk())
  572. {
  573. lldebugs << "LLCacheName::processPending() - bad upstream host."
  574. << llendl;
  575. return;
  576. }
  577. impl.processPendingAsks();
  578. impl.processPendingReplies();
  579. }
  580. void LLCacheName::deleteEntriesOlderThan(S32 secs)
  581. {
  582. U32 now = (U32)time(NULL);
  583. U32 expire_time = now - secs;
  584. for(Cache::iterator iter = impl.mCache.begin(); iter != impl.mCache.end(); )
  585. {
  586. Cache::iterator curiter = iter++;
  587. LLCacheNameEntry* entry = curiter->second;
  588. if (entry->mCreateTime < expire_time)
  589. {
  590. delete entry;
  591. impl.mCache.erase(curiter);
  592. }
  593. }
  594. // These are pending requests that we never heard back from.
  595. U32 pending_expire_time = now - PENDING_TIMEOUT_SECS;
  596. for(PendingQueue::iterator p_iter = impl.mPendingQueue.begin();
  597. p_iter != impl.mPendingQueue.end(); )
  598. {
  599. PendingQueue::iterator p_curitor = p_iter++;
  600. if (p_curitor->second < pending_expire_time)
  601. {
  602. impl.mPendingQueue.erase(p_curitor);
  603. }
  604. }
  605. }
  606. void LLCacheName::dump()
  607. {
  608. for (Cache::iterator iter = impl.mCache.begin(),
  609. end = impl.mCache.end();
  610. iter != end; iter++)
  611. {
  612. LLCacheNameEntry* entry = iter->second;
  613. if (entry->mIsGroup)
  614. {
  615. llinfos
  616. << iter->first << " = (group) "
  617. << entry->mGroupName
  618. << " @ " << entry->mCreateTime
  619. << llendl;
  620. }
  621. else
  622. {
  623. llinfos
  624. << iter->first << " = "
  625. << buildFullName(entry->mFirstName, entry->mLastName)
  626. << " @ " << entry->mCreateTime
  627. << llendl;
  628. }
  629. }
  630. }
  631. void LLCacheName::dumpStats()
  632. {
  633. llinfos << "Queue sizes: "
  634. << " Cache=" << impl.mCache.size()
  635. << " AskName=" << impl.mAskNameQueue.size()
  636. << " AskGroup=" << impl.mAskGroupQueue.size()
  637. << " Pending=" << impl.mPendingQueue.size()
  638. << " Reply=" << impl.mReplyQueue.size()
  639. // << " Observers=" << impl.mSignal.size()
  640. << llendl;
  641. }
  642. void LLCacheName::clear()
  643. {
  644. for_each(impl.mCache.begin(), impl.mCache.end(), DeletePairedPointer());
  645. impl.mCache.clear();
  646. }
  647. //static
  648. std::string LLCacheName::getDefaultName()
  649. {
  650. return sCacheName["waiting"];
  651. }
  652. //static
  653. std::string LLCacheName::getDefaultLastName()
  654. {
  655. return "Resident";
  656. }
  657. void LLCacheName::Impl::processPendingAsks()
  658. {
  659. LLMemType mt_ppa(LLMemType::MTYPE_CACHE_PROCESS_PENDING_ASKS);
  660. sendRequest(_PREHASH_UUIDNameRequest, mAskNameQueue);
  661. sendRequest(_PREHASH_UUIDGroupNameRequest, mAskGroupQueue);
  662. mAskNameQueue.clear();
  663. mAskGroupQueue.clear();
  664. }
  665. void LLCacheName::Impl::processPendingReplies()
  666. {
  667. LLMemType mt_ppr(LLMemType::MTYPE_CACHE_PROCESS_PENDING_REPLIES);
  668. // First call all the callbacks, because they might send messages.
  669. for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it)
  670. {
  671. PendingReply* reply = *it;
  672. LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID);
  673. if(!entry) continue;
  674. if (!entry->mIsGroup)
  675. {
  676. std::string fullname =
  677. LLCacheName::buildFullName(entry->mFirstName, entry->mLastName);
  678. (reply->mSignal)(reply->mID, fullname, false);
  679. }
  680. else
  681. {
  682. (reply->mSignal)(reply->mID, entry->mGroupName, true);
  683. }
  684. }
  685. // Forward on all replies, if needed.
  686. ReplySender sender(mMsg);
  687. for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it)
  688. {
  689. PendingReply* reply = *it;
  690. LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID);
  691. if(!entry) continue;
  692. if (reply->mHost.isOk())
  693. {
  694. sender.send(reply->mID, *entry, reply->mHost);
  695. }
  696. reply->done();
  697. }
  698. for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); )
  699. {
  700. ReplyQueue::iterator curit = it++;
  701. PendingReply* reply = *curit;
  702. if (reply->isDone())
  703. {
  704. delete reply;
  705. mReplyQueue.erase(curit);
  706. }
  707. }
  708. }
  709. void LLCacheName::Impl::sendRequest(
  710. const char* msg_name,
  711. const AskQueue& queue)
  712. {
  713. if(queue.empty())
  714. {
  715. return;
  716. }
  717. bool start_new_message = true;
  718. AskQueue::const_iterator it = queue.begin();
  719. AskQueue::const_iterator end = queue.end();
  720. for(; it != end; ++it)
  721. {
  722. if(start_new_message)
  723. {
  724. start_new_message = false;
  725. mMsg->newMessageFast(msg_name);
  726. }
  727. mMsg->nextBlockFast(_PREHASH_UUIDNameBlock);
  728. mMsg->addUUIDFast(_PREHASH_ID, (*it));
  729. if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock))
  730. {
  731. start_new_message = true;
  732. mMsg->sendReliable(mUpstreamHost);
  733. }
  734. }
  735. if(!start_new_message)
  736. {
  737. mMsg->sendReliable(mUpstreamHost);
  738. }
  739. }
  740. bool LLCacheName::Impl::isRequestPending(const LLUUID& id)
  741. {
  742. U32 now = (U32)time(NULL);
  743. U32 expire_time = now - PENDING_TIMEOUT_SECS;
  744. PendingQueue::iterator iter = mPendingQueue.find(id);
  745. if (iter == mPendingQueue.end()
  746. || (iter->second < expire_time) )
  747. {
  748. mPendingQueue[id] = now;
  749. return false;
  750. }
  751. return true;
  752. }
  753. void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup)
  754. {
  755. // You should only get this message if the cache is at the simulator
  756. // level, hence having an upstream provider.
  757. if (!mUpstreamHost.isOk())
  758. {
  759. llwarns << "LLCacheName - got UUID name/group request, but no upstream provider!" << llendl;
  760. return;
  761. }
  762. LLHost fromHost = msg->getSender();
  763. ReplySender sender(msg);
  764. S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock);
  765. for(S32 i = 0; i < count; ++i)
  766. {
  767. LLUUID id;
  768. msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i);
  769. LLCacheNameEntry* entry = get_ptr_in_map(mCache, id);
  770. if(entry)
  771. {
  772. if (isGroup != entry->mIsGroup)
  773. {
  774. llwarns << "LLCacheName - Asked for "
  775. << (isGroup ? "group" : "user") << " name, "
  776. << "but found "
  777. << (entry->mIsGroup ? "group" : "user")
  778. << ": " << id << llendl;
  779. }
  780. else
  781. {
  782. // ...it's in the cache, so send it as the reply
  783. sender.send(id, *entry, fromHost);
  784. }
  785. }
  786. else
  787. {
  788. if (!isRequestPending(id))
  789. {
  790. if (isGroup)
  791. {
  792. mAskGroupQueue.insert(id);
  793. }
  794. else
  795. {
  796. mAskNameQueue.insert(id);
  797. }
  798. }
  799. addPending(id, fromHost);
  800. }
  801. }
  802. }
  803. void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup)
  804. {
  805. S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock);
  806. for(S32 i = 0; i < count; ++i)
  807. {
  808. LLUUID id;
  809. msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i);
  810. LLCacheNameEntry* entry = get_ptr_in_map(mCache, id);
  811. if (!entry)
  812. {
  813. entry = new LLCacheNameEntry;
  814. mCache[id] = entry;
  815. }
  816. mPendingQueue.erase(id);
  817. entry->mIsGroup = isGroup;
  818. entry->mCreateTime = (U32)time(NULL);
  819. if (!isGroup)
  820. {
  821. msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_FirstName, entry->mFirstName, i);
  822. msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_LastName, entry->mLastName, i);
  823. }
  824. else
  825. { // is group
  826. msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, entry->mGroupName, i);
  827. LLStringFn::replace_ascii_controlchars(entry->mGroupName, LL_UNKNOWN_CHAR);
  828. }
  829. if (!isGroup)
  830. {
  831. // NOTE: Very occasionally the server sends down a full name
  832. // in the first name field with an empty last name, for example,
  833. // first = "Ladanie1 Resident", last = "".
  834. // I cannot reproduce this, nor can I find a bug in the server code.
  835. // Ensure "Resident" does not appear via cleanFullName, because
  836. // buildFullName only checks last name. JC
  837. std::string full_name;
  838. if (entry->mLastName.empty())
  839. {
  840. full_name = cleanFullName(entry->mFirstName);
  841. //fix what we are putting in the cache
  842. entry->mFirstName = full_name;
  843. entry->mLastName = "Resident";
  844. }
  845. else
  846. {
  847. full_name = LLCacheName::buildFullName(entry->mFirstName, entry->mLastName);
  848. }
  849. mSignal(id, full_name, false);
  850. mReverseCache[full_name] = id;
  851. }
  852. else
  853. {
  854. mSignal(id, entry->mGroupName, true);
  855. mReverseCache[entry->mGroupName] = id;
  856. }
  857. }
  858. }
  859. // static call back functions
  860. void LLCacheName::Impl::handleUUIDNameReply(LLMessageSystem* msg, void** userData)
  861. {
  862. ((LLCacheName::Impl*)userData)->processUUIDReply(msg, false);
  863. }
  864. void LLCacheName::Impl::handleUUIDNameRequest(LLMessageSystem* msg, void** userData)
  865. {
  866. ((LLCacheName::Impl*)userData)->processUUIDRequest(msg, false);
  867. }
  868. void LLCacheName::Impl::handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userData)
  869. {
  870. ((LLCacheName::Impl*)userData)->processUUIDRequest(msg, true);
  871. }
  872. void LLCacheName::Impl::handleUUIDGroupNameReply(LLMessageSystem* msg, void** userData)
  873. {
  874. ((LLCacheName::Impl*)userData)->processUUIDReply(msg, true);
  875. }