llcachename.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:23k
源码类别:

游戏引擎

开发平台:

C++ Builder

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