llcachename.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 #include "llcachename.h"
00035 
00036 // linden library includes
00037 #include "message.h"
00038 #include "llrand.h"
00039 #include "lldbstrings.h"
00040 #include "llframetimer.h"
00041 #include "llhost.h"
00042 #include "lluuid.h"
00043 
00044 // Constants
00045 const char* CN_WAITING = "(waiting)";
00046 const char* CN_NOBODY = "(nobody)";
00047 const char* CN_NONE = "(none)";
00048 const char* CN_HIPPOS = "(hippos)";
00049 const F32 HIPPO_PROBABILITY = 0.01f;
00050 
00051 // We track name requests in flight for up to this long.
00052 // We won't re-request a name during this time
00053 const U32 PENDING_TIMEOUT_SECS = 5 * 60;
00054 
00055 // File version number
00056 const S32 CN_FILE_VERSION = 2;
00057 
00058 // Globals
00059 LLCacheName* gCacheName = NULL;
00060 
00064 
00065 class LLCacheNameEntry
00066 {
00067 public:
00068         LLCacheNameEntry();
00069 
00070 public:
00071         bool mIsGroup;
00072         U32 mCreateTime;        // unix time_t
00073         char mFirstName[DB_FIRST_NAME_BUF_SIZE]; /*Flawfinder: ignore*/
00074         char mLastName[DB_LAST_NAME_BUF_SIZE]; /*Flawfinder: ignore*/
00075         char mGroupName[DB_GROUP_NAME_BUF_SIZE]; /*Flawfinder: ignore*/
00076 };
00077 
00078 LLCacheNameEntry::LLCacheNameEntry()
00079 {
00080         mFirstName[0] = '\0';
00081         mLastName[0]  = '\0';
00082         mGroupName[0] = '\0';
00083 }
00084 
00085 
00086 class PendingReply
00087 {
00088 public:
00089         LLUUID                          mID;
00090         LLCacheNameCallback mCallback;
00091         LLHost                          mHost;
00092         void*                           mData;
00093         PendingReply(const LLUUID& id, LLCacheNameCallback callback, void* data = NULL)
00094                 : mID(id), mCallback(callback), mData(data)
00095         { }
00096 
00097         PendingReply(const LLUUID& id, const LLHost& host)
00098                 : mID(id), mCallback(0), mHost(host)
00099         { }
00100 
00101         void done()                     { mID.setNull(); }
00102         bool isDone() const     { return mID.isNull() != FALSE; }
00103 };
00104 
00105 class ReplySender
00106 {
00107 public:
00108         ReplySender(LLMessageSystem* msg);
00109         ~ReplySender();
00110 
00111         void send(const LLUUID& id,
00112                 const LLCacheNameEntry& entry, const LLHost& host);
00113 
00114 private:
00115         void flush();
00116 
00117         LLMessageSystem*        mMsg;
00118         bool                            mPending;
00119         bool                            mCurrIsGroup;
00120         LLHost                          mCurrHost;
00121 };
00122 
00123 ReplySender::ReplySender(LLMessageSystem* msg)
00124         : mMsg(msg), mPending(false)
00125 { }
00126 
00127 ReplySender::~ReplySender()
00128 {
00129         flush();
00130 }
00131 
00132 void ReplySender::send(const LLUUID& id,
00133         const LLCacheNameEntry& entry, const LLHost& host)
00134 {
00135         if (mPending)
00136         {
00137                 if (mCurrIsGroup != entry.mIsGroup
00138                 ||  mCurrHost != host)
00139                 {
00140                         flush();
00141                 }
00142         }
00143 
00144         if (!mPending)
00145         {
00146                 mPending = true;
00147                 mCurrIsGroup = entry.mIsGroup;
00148                 mCurrHost = host;
00149 
00150                 if(mCurrIsGroup)
00151                         mMsg->newMessageFast(_PREHASH_UUIDGroupNameReply);
00152                 else
00153                         mMsg->newMessageFast(_PREHASH_UUIDNameReply);
00154         }
00155 
00156         mMsg->nextBlockFast(_PREHASH_UUIDNameBlock);
00157         mMsg->addUUIDFast(_PREHASH_ID, id);
00158         if(mCurrIsGroup)
00159         {
00160                 mMsg->addStringFast(_PREHASH_GroupName, entry.mGroupName);
00161         }
00162         else
00163         {
00164                 mMsg->addStringFast(_PREHASH_FirstName, entry.mFirstName);
00165                 mMsg->addStringFast(_PREHASH_LastName, entry.mLastName);
00166         }
00167 
00168         if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock))
00169         {
00170                 flush();
00171         }
00172 }
00173 
00174 void ReplySender::flush()
00175 {
00176         if (mPending)
00177         {
00178                 mMsg->sendReliable(mCurrHost);
00179                 mPending = false;
00180         }
00181 }
00182 
00183 
00184 typedef std::set<LLUUID>                                        AskQueue;
00185 typedef std::vector<PendingReply>                       ReplyQueue;
00186 typedef std::map<LLUUID,U32>                            PendingQueue;
00187 typedef std::map<LLUUID, LLCacheNameEntry*> Cache;
00188 typedef std::vector<LLCacheNameCallback>        Observers;
00189 
00190 class LLCacheName::Impl
00191 {
00192 public:
00193         LLMessageSystem*        mMsg;
00194         LLHost                          mUpstreamHost;
00195 
00196         Cache                           mCache;
00197                 // the map of UUIDs to names
00198 
00199         AskQueue                        mAskNameQueue;
00200         AskQueue                        mAskGroupQueue;
00201                 // UUIDs to ask our upstream host about
00202         
00203         PendingQueue            mPendingQueue;
00204                 // UUIDs that have been requested but are not in cache yet.
00205 
00206         ReplyQueue                      mReplyQueue;
00207                 // requests awaiting replies from us
00208 
00209         Observers                       mObservers;
00210 
00211         LLFrameTimer            mProcessTimer;
00212 
00213         Impl(LLMessageSystem* msg);
00214         ~Impl();
00215 
00216         void processPendingAsks();
00217         void processPendingReplies();
00218         void sendRequest(const char* msg_name, const AskQueue& queue);
00219         bool isRequestPending(const LLUUID& id);
00220 
00221         // Message system callbacks.
00222         void processUUIDRequest(LLMessageSystem* msg, bool isGroup);
00223         void processUUIDReply(LLMessageSystem* msg, bool isGroup);
00224 
00225         static void handleUUIDNameRequest(LLMessageSystem* msg, void** userdata);
00226         static void handleUUIDNameReply(LLMessageSystem* msg, void** userdata);
00227         static void handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userdata);
00228         static void handleUUIDGroupNameReply(LLMessageSystem* msg, void** userdata);
00229 
00230         void notifyObservers(const LLUUID& id, const char* first, const char* last, BOOL group);
00231 };
00232 
00233 
00237 
00238 LLCacheName::LLCacheName(LLMessageSystem* msg)
00239         : impl(* new Impl(msg))
00240         { }
00241 
00242 LLCacheName::LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host)
00243         : impl(* new Impl(msg))
00244 {
00245         setUpstream(upstream_host);
00246 }
00247 
00248 LLCacheName::~LLCacheName()
00249 {
00250         delete &impl;
00251 }
00252 
00253 LLCacheName::Impl::Impl(LLMessageSystem* msg)
00254         : mMsg(msg), mUpstreamHost(LLHost::invalid)
00255 {
00256         mMsg->setHandlerFuncFast(
00257                 _PREHASH_UUIDNameRequest, handleUUIDNameRequest, (void**)this);
00258         mMsg->setHandlerFuncFast(
00259                 _PREHASH_UUIDNameReply, handleUUIDNameReply, (void**)this);
00260         mMsg->setHandlerFuncFast(
00261                 _PREHASH_UUIDGroupNameRequest, handleUUIDGroupNameRequest, (void**)this);
00262         mMsg->setHandlerFuncFast(
00263                 _PREHASH_UUIDGroupNameReply, handleUUIDGroupNameReply, (void**)this);
00264 }
00265 
00266 
00267 LLCacheName::Impl::~Impl()
00268 {
00269         for_each(mCache.begin(), mCache.end(), DeletePairedPointer());
00270 }
00271 
00272 
00273 void LLCacheName::setUpstream(const LLHost& upstream_host)
00274 {
00275         impl.mUpstreamHost = upstream_host;
00276 }
00277 
00278 void LLCacheName::addObserver(LLCacheNameCallback callback)
00279 {
00280         impl.mObservers.push_back(callback);
00281 }
00282 
00283 void LLCacheName::removeObserver(LLCacheNameCallback callback)
00284 {
00285         Observers::iterator it = impl.mObservers.begin();
00286         Observers::iterator end = impl.mObservers.end();
00287 
00288         for ( ; it != end; ++it)
00289         {
00290                 const LLCacheNameCallback& cb = (*it);
00291                 if (cb == callback)
00292                 {
00293                         impl.mObservers.erase(it);
00294                         return;
00295                 }
00296         }
00297 }
00298 
00299 void LLCacheName::cancelCallback(const LLUUID& id, LLCacheNameCallback callback, void* user_data)
00300 {
00301         ReplyQueue::iterator it = impl.mReplyQueue.begin();
00302         ReplyQueue::iterator end = impl.mReplyQueue.end();
00303         
00304         for(; it != end; ++it)
00305         {
00306                 const PendingReply& reply = (*it);
00307 
00308                 if ((callback == reply.mCallback)
00309                         && (id == reply.mID)
00310                         && (user_data == reply.mData) )
00311                 {
00312                         impl.mReplyQueue.erase(it);
00313                         return;
00314                 }
00315         }
00316 }
00317 
00318 void LLCacheName::importFile(FILE* fp)
00319 {
00320         S32 count = 0;
00321 
00322         const S32 BUFFER_SIZE = 1024;
00323         char buffer[BUFFER_SIZE];       /*Flawfinder: ignore*/
00324 
00325         // *NOTE: These buffer sizes are hardcoded into sscanf() below
00326         char id_string[MAX_STRING]; /*Flawfinder: ignore*/
00327         char firstname[MAX_STRING]; /*Flawfinder: ignore*/
00328         char lastname[MAX_STRING]; /*Flawfinder: ignore*/
00329         U32 create_time;
00330 
00331         // This is OK if the first line is actually a name.  We just don't load it.
00332         char* valid = fgets(buffer, BUFFER_SIZE, fp);
00333         if (!valid) return;
00334 
00335         // *NOTE: This buffer size is hardcoded into sscanf() below
00336         char version_string[BUFFER_SIZE]; /*Flawfinder: ignore*/
00337         S32 version = 0;
00338         S32 match = sscanf(     /* Flawfinder: ignore */
00339                 buffer,
00340                 "%1023s %d",
00341                 version_string, &version);
00342         if (   match != 2
00343                 || strcmp(version_string, "version")
00344                 || version != CN_FILE_VERSION)
00345         {
00346                 llwarns << "Ignoring old cache name file format" << llendl;
00347                 return;
00348         }
00349 
00350         // We'll expire entries more than a week old
00351         U32 now = (U32)time(NULL);
00352         const U32 SECS_PER_DAY = 60 * 60 * 24;
00353         U32 delete_before_time = now - (7 * SECS_PER_DAY);
00354 
00355         while(!feof(fp))
00356         {
00357                 valid = fgets(buffer, BUFFER_SIZE, fp);
00358                 if (!valid) break;
00359 
00360                 match = sscanf( /* Flawfinder: ignore */
00361                         buffer,
00362                         "%254s %u %254s %254s",
00363                         id_string, 
00364                         &create_time,
00365                         firstname, 
00366                         lastname);
00367                 if (4 != match) continue;
00368 
00369                 LLUUID id(id_string);
00370                 if (id.isNull()) continue;
00371 
00372                 // undo trivial XOR
00373                 S32 i;
00374                 for (i = 0; i < UUID_BYTES; i++)
00375                 {
00376                         id.mData[i] ^= 0x33;
00377                 }
00378 
00379                 // Don't load entries that are more than a week old
00380                 if (create_time < delete_before_time) continue;
00381 
00382                 LLCacheNameEntry* entry = new LLCacheNameEntry();
00383                 entry->mIsGroup = false;
00384                 entry->mCreateTime = create_time;
00385                 LLString::copy(entry->mFirstName, firstname, DB_FIRST_NAME_BUF_SIZE);
00386                 LLString::copy(entry->mLastName, lastname, DB_LAST_NAME_BUF_SIZE);
00387                 impl.mCache[id] = entry;
00388 
00389                 count++;
00390         }
00391 
00392         llinfos << "LLCacheName loaded " << count << " names" << llendl;
00393 }
00394 
00395 
00396 void LLCacheName::exportFile(FILE* fp)
00397 {
00398         fprintf(fp, "version\t%d\n", CN_FILE_VERSION);
00399 
00400         for (Cache::iterator iter = impl.mCache.begin(),
00401                          end = impl.mCache.end();
00402                  iter != end; iter++)
00403         {
00404                 LLCacheNameEntry* entry = iter->second;
00405                 // Only write entries for which we have valid data.
00406                 // HACK: Only write agent names.  This makes the reader easier.
00407                 if (   entry->mFirstName[0]
00408                         && entry->mLastName[0])
00409                 {
00410                         LLUUID id = iter->first;
00411 
00412                         // Trivial XOR encoding
00413                         S32 i;
00414                         for (i = 0; i < UUID_BYTES; i++)
00415                         {
00416                                 id.mData[i] ^= 0x33;
00417                         }
00418 
00419                         char id_string[UUID_STR_SIZE]; /*Flawfinder:ignore*/
00420                         id.toString(id_string);
00421 
00422                         // ...not a group name
00423                         fprintf(fp, "%s\t%u\t%s\t%s\n", 
00424                                         id_string, 
00425                                         entry->mCreateTime,
00426                                         entry->mFirstName, 
00427                                         entry->mLastName);
00428                 }
00429         }
00430 }
00431 
00432 
00433 BOOL LLCacheName::getName(const LLUUID& id, char* first, char* last)
00434 {
00435         if(id.isNull())
00436         {
00437                 // The function signature needs to change to pass in the
00438                 // length of first and last.
00439                 strcpy(first, CN_NOBODY);       /*Flawfinder: ignore*/
00440                 last[0] = '\0';
00441                 return FALSE;
00442         }
00443 
00444         LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id );
00445         if (entry)
00446         {
00447                 // The function signature needs to change to pass in the
00448                 // length of first and last.
00449                 strcpy(first, entry->mFirstName);       /*Flawfinder: ignore*/
00450                 strcpy(last,  entry->mLastName);        /*Flawfinder: ignore*/
00451                 return TRUE;
00452         }
00453         else
00454         {
00455                 //The function signature needs to change to pass in the
00456                 //length of first and last.
00457                 strcpy(first,(ll_frand() < HIPPO_PROBABILITY)
00458                                                 ? CN_HIPPOS 
00459                                                 : CN_WAITING);
00460                 strcpy(last, "");       /*Flawfinder: ignore*/
00461 
00462                 if (!impl.isRequestPending(id))
00463                 {
00464                         impl.mAskNameQueue.insert(id);
00465                 }       
00466                 return FALSE;
00467         }
00468 
00469 }
00470 
00471 
00472 
00473 BOOL LLCacheName::getGroupName(const LLUUID& id, char* group)
00474 {
00475         if(id.isNull())
00476         {
00477                 // The function signature needs to change to pass in the
00478                 // length of first and last.
00479                 strcpy(group, CN_NONE); /*Flawfinder: ignore*/
00480                 return FALSE;
00481         }
00482 
00483         LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache,id);
00484         if (entry && !entry->mGroupName[0])
00485         {
00486                 // COUNTER-HACK to combat James' HACK in exportFile()...
00487                 // this group name was loaded from a name cache that did not
00488                 // bother to save the group name ==> we must ask for it
00489                 lldebugs << "LLCacheName queuing HACK group request: " << id << llendl;
00490                 entry = NULL;
00491         }
00492 
00493         if (entry)
00494         {
00495                 // The function signature needs to change to pass in the length
00496                 // of group.
00497                 strcpy(group, entry->mGroupName);       /*Flawfinder: ignore*/
00498                 return TRUE;
00499         }
00500         else 
00501         {
00502                 // The function signature needs to change to pass in the length
00503                 // of first and last.
00504                 strcpy(group, CN_WAITING);      /*Flawfinder: ignore*/
00505                 if (!impl.isRequestPending(id))
00506                 {
00507                         impl.mAskGroupQueue.insert(id);
00508                 }
00509                 return FALSE;
00510         }
00511 }
00512 
00513 // TODO: Make the cache name callback take a SINGLE std::string,
00514 // not a separate first and last name.
00515 void LLCacheName::get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callback, void* user_data)
00516 {
00517         if(id.isNull())
00518         {
00519                 callback(id, CN_NOBODY, "", is_group, user_data);
00520         }
00521 
00522         LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id );
00523         if (entry)
00524         {
00525                 // id found in map therefore we can call the callback immediately.
00526                 if (entry->mIsGroup)
00527                 {
00528                         callback(id, entry->mGroupName, "", entry->mIsGroup, user_data);
00529                 }
00530                 else
00531                 {
00532                         callback(id, entry->mFirstName, entry->mLastName, entry->mIsGroup, user_data);
00533                 }
00534         }
00535         else
00536         {
00537                 // id not found in map so we must queue the callback call until available.
00538                 if (!impl.isRequestPending(id))
00539                 {
00540                         if (is_group)
00541                         {
00542                                 impl.mAskGroupQueue.insert(id);
00543                         }
00544                         else
00545                         {
00546                                 impl.mAskNameQueue.insert(id);
00547                         }
00548                 }
00549                 impl.mReplyQueue.push_back(PendingReply(id, callback, user_data));
00550         }
00551 }
00552 
00553 void LLCacheName::processPending()
00554 {
00555         const F32 SECS_BETWEEN_PROCESS = 0.1f;
00556         if(!impl.mProcessTimer.checkExpirationAndReset(SECS_BETWEEN_PROCESS))
00557         {
00558                 return;
00559         }
00560 
00561         if(!impl.mUpstreamHost.isOk())
00562         {
00563                 lldebugs << "LLCacheName::processPending() - bad upstream host."
00564                                  << llendl;
00565                 return;
00566         }
00567 
00568         impl.processPendingAsks();
00569         impl.processPendingReplies();
00570 }
00571 
00572 void LLCacheName::deleteEntriesOlderThan(S32 secs)
00573 {
00574         U32 now = (U32)time(NULL);
00575         U32 expire_time = now - secs;
00576         for(Cache::iterator iter = impl.mCache.begin(); iter != impl.mCache.end(); )
00577         {
00578                 Cache::iterator curiter = iter++;
00579                 LLCacheNameEntry* entry = curiter->second;
00580                 if (entry->mCreateTime < expire_time)
00581                 {
00582                         delete entry;
00583                         impl.mCache.erase(curiter);
00584                 }
00585         }
00586 
00587         // These are pending requests that we never heard back from.
00588         U32 pending_expire_time = now - PENDING_TIMEOUT_SECS;
00589         for(PendingQueue::iterator p_iter = impl.mPendingQueue.begin();
00590                 p_iter != impl.mPendingQueue.end(); )
00591         {
00592                 PendingQueue::iterator p_curitor = p_iter++;
00593  
00594                 if (p_curitor->second < pending_expire_time)
00595                 {
00596                         impl.mPendingQueue.erase(p_curitor);
00597                 }
00598         }
00599 }
00600 
00601 
00602 void LLCacheName::dump()
00603 {
00604         for (Cache::iterator iter = impl.mCache.begin(),
00605                          end = impl.mCache.end();
00606                  iter != end; iter++)
00607         {
00608                 LLCacheNameEntry* entry = iter->second;
00609                 if (entry->mIsGroup)
00610                 {
00611                         llinfos
00612                                 << iter->first << " = (group) "
00613                                 << entry->mGroupName
00614                                 << " @ " << entry->mCreateTime
00615                                 << llendl;
00616                 }
00617                 else
00618                 {
00619                         llinfos
00620                                 << iter->first << " = "
00621                                 << entry->mFirstName << " " << entry->mLastName
00622                                 << " @ " << entry->mCreateTime
00623                                 << llendl;
00624                 }
00625         }
00626 }
00627 
00628 void LLCacheName::dumpStats()
00629 {
00630         llinfos << "Queue sizes: "
00631                         << " Cache=" << impl.mCache.size()
00632                         << " AskName=" << impl.mAskNameQueue.size()
00633                         << " AskGroup=" << impl.mAskGroupQueue.size()
00634                         << " Pending=" << impl.mPendingQueue.size()
00635                         << " Reply=" << impl.mReplyQueue.size()
00636                         << " Observers=" << impl.mObservers.size()
00637                         << llendl;
00638 }
00639 
00640 //static 
00641 LLString LLCacheName::getDefaultName()
00642 {
00643         return LLString(CN_WAITING);
00644 }
00645 
00646 void LLCacheName::Impl::processPendingAsks()
00647 {
00648         sendRequest(_PREHASH_UUIDNameRequest, mAskNameQueue);
00649         sendRequest(_PREHASH_UUIDGroupNameRequest, mAskGroupQueue);
00650         mAskNameQueue.clear();
00651         mAskGroupQueue.clear();
00652 }
00653 
00654 void LLCacheName::Impl::processPendingReplies()
00655 {
00656         ReplyQueue::iterator it = mReplyQueue.begin();
00657         ReplyQueue::iterator end = mReplyQueue.end();
00658         
00659         // First call all the callbacks, because they might send messages.
00660         for(; it != end; ++it)
00661         {
00662                 LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID);
00663                 if(!entry) continue;
00664 
00665                 if (it->mCallback)
00666                 {
00667                         if (!entry->mIsGroup)
00668                         {
00669                                 (it->mCallback)(it->mID,
00670                                         entry->mFirstName, entry->mLastName,
00671                                         FALSE, it->mData);
00672                         }
00673                         else {
00674                                 (it->mCallback)(it->mID,
00675                                         entry->mGroupName, "",
00676                                         TRUE, it->mData);
00677                         }
00678                 }
00679         }
00680 
00681         // Forward on all replies, if needed.
00682         ReplySender sender(mMsg);
00683         for (it = mReplyQueue.begin(); it != end; ++it)
00684         {
00685                 LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID);
00686                 if(!entry) continue;
00687 
00688                 if (it->mHost.isOk())
00689                 {
00690                         sender.send(it->mID, *entry, it->mHost);
00691                 }
00692 
00693                 it->done();
00694         }
00695 
00696         mReplyQueue.erase(
00697                 remove_if(mReplyQueue.begin(), mReplyQueue.end(),
00698                         std::mem_fun_ref(&PendingReply::isDone)),
00699                 mReplyQueue.end());
00700 }
00701 
00702 
00703 void LLCacheName::Impl::sendRequest(
00704         const char* msg_name,
00705         const AskQueue& queue)
00706 {
00707         if(queue.empty())
00708         {
00709                 return;         
00710         }
00711 
00712         bool start_new_message = true;
00713         AskQueue::const_iterator it = queue.begin();
00714         AskQueue::const_iterator end = queue.end();
00715         for(; it != end; ++it)
00716         {
00717                 if(start_new_message)
00718                 {
00719                         start_new_message = false;
00720                         mMsg->newMessageFast(msg_name);
00721                 }
00722                 mMsg->nextBlockFast(_PREHASH_UUIDNameBlock);
00723                 mMsg->addUUIDFast(_PREHASH_ID, (*it));
00724 
00725                 if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock))
00726                 {
00727                         start_new_message = true;
00728                         mMsg->sendReliable(mUpstreamHost);
00729                 }
00730         }
00731         if(!start_new_message)
00732         {
00733                 mMsg->sendReliable(mUpstreamHost);
00734         }
00735 }
00736 
00737 void LLCacheName::Impl::notifyObservers(const LLUUID& id,
00738         const char* first, const char* last, BOOL is_group)
00739 {
00740         for (Observers::const_iterator i = mObservers.begin(),
00741                                                                    end = mObservers.end();
00742                 i != end;
00743                 ++i)
00744         {
00745                 (**i)(id, first, last, is_group, NULL);
00746         }
00747 }
00748 
00749 bool LLCacheName::Impl::isRequestPending(const LLUUID& id)
00750 {
00751         U32 now = (U32)time(NULL);
00752         U32 expire_time = now - PENDING_TIMEOUT_SECS;
00753 
00754         PendingQueue::iterator iter = mPendingQueue.find(id);
00755 
00756         if (iter == mPendingQueue.end()
00757                 || (iter->second < expire_time) )
00758         {
00759                 mPendingQueue[id] = now;
00760                 return false;
00761         }
00762 
00763         return true;
00764 }
00765         
00766 void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup)
00767 {
00768         // You should only get this message if the cache is at the simulator
00769         // level, hence having an upstream provider.
00770         if (!mUpstreamHost.isOk())
00771         {
00772                 llwarns << "LLCacheName - got UUID name/group request, but no upstream provider!" << llendl;
00773                 return;
00774         }
00775 
00776         LLHost fromHost = msg->getSender();
00777         ReplySender sender(msg);
00778 
00779         S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock);
00780         for(S32 i = 0; i < count; ++i)
00781         {
00782                 LLUUID id;
00783                 msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i);
00784                 LLCacheNameEntry* entry = get_ptr_in_map(mCache, id);
00785                 if(entry)
00786                 {
00787                         if (isGroup != entry->mIsGroup)
00788                         {
00789                                 llwarns << "LLCacheName - Asked for "
00790                                                 << (isGroup ? "group" : "user") << " name, "
00791                                                 << "but found "
00792                                                 << (entry->mIsGroup ? "group" : "user")
00793                                                 << ": " << id << llendl;
00794                         }
00795                         else
00796                         {
00797                                 // ...it's in the cache, so send it as the reply
00798                                 sender.send(id, *entry, fromHost);
00799                         }
00800                 }
00801                 else
00802                 {
00803                         if (!isRequestPending(id))
00804                         {
00805                                 if (isGroup)
00806                                 {
00807                                         mAskGroupQueue.insert(id);
00808                                 }
00809                                 else
00810                                 {
00811                                         mAskNameQueue.insert(id);
00812                                 }
00813                         }
00814                         
00815                         mReplyQueue.push_back(PendingReply(id, fromHost));
00816                 }
00817         }
00818 }
00819 
00820 
00821 
00822 void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup)
00823 {
00824         S32 count = msg->getNumberOfBlocksFast(_PREHASH_UUIDNameBlock);
00825         for(S32 i = 0; i < count; ++i)
00826         {
00827                 LLUUID id;
00828                 msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i);
00829                 LLCacheNameEntry* entry = get_ptr_in_map(mCache, id);
00830                 if (!entry)
00831                 {
00832                         entry = new LLCacheNameEntry;
00833                         mCache[id] = entry;
00834                 }
00835 
00836                 mPendingQueue.erase(id);
00837 
00838                 entry->mIsGroup = isGroup;
00839                 entry->mCreateTime = (U32)time(NULL);
00840                 if (!isGroup)
00841                 {
00842                         msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_FirstName, DB_FIRST_NAME_BUF_SIZE, entry->mFirstName, i);
00843                         msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_LastName,  DB_LAST_NAME_BUF_SIZE, entry->mLastName, i);
00844                 }
00845                 else
00846                 {
00847                         msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, DB_GROUP_NAME_BUF_SIZE, entry->mGroupName, i);
00848                 }
00849 
00850                 if (!isGroup)
00851                 {
00852                         notifyObservers(id,
00853                                                         entry->mFirstName, entry->mLastName,
00854                                                         FALSE);
00855                 }
00856                 else
00857                 {
00858                         notifyObservers(id, entry->mGroupName, "", TRUE);
00859                 }
00860         }
00861 }
00862 
00863 
00864 
00865 // static call back functions
00866 
00867 void LLCacheName::Impl::handleUUIDNameReply(LLMessageSystem* msg, void** userData)
00868 {
00869         ((LLCacheName::Impl*)userData)->processUUIDReply(msg, false);
00870 }
00871 
00872 void LLCacheName::Impl::handleUUIDNameRequest(LLMessageSystem* msg, void** userData)
00873 {
00874         ((LLCacheName::Impl*)userData)->processUUIDRequest(msg, false);
00875 }
00876 
00877 void LLCacheName::Impl::handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userData)
00878 {
00879         ((LLCacheName::Impl*)userData)->processUUIDRequest(msg, true);
00880 }
00881 
00882 void LLCacheName::Impl::handleUUIDGroupNameReply(LLMessageSystem* msg, void** userData)
00883 {
00884         ((LLCacheName::Impl*)userData)->processUUIDReply(msg, true);
00885 }
00886 
00887 
00888 
00889 

Generated on Thu Jul 1 06:08:20 2010 for Second Life Viewer by  doxygen 1.4.7