reSIProcate/DialogUsageManager  9694
InMemorySyncRegDb.cxx
Go to the documentation of this file.
00001 #include "resip/dum/InMemorySyncRegDb.hxx"
00002 #include "rutil/Timer.hxx"
00003 #include "rutil/Logger.hxx"
00004 #include "rutil/WinLeakCheck.hxx"
00005 
00006 using namespace resip;
00007 
00008 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
00009 
00010 class RemoveIfRequired
00011 {
00012 protected:
00013     UInt64 mNow;
00014     unsigned int mRemoveLingerSecs;
00015 public:
00016     RemoveIfRequired(UInt64& now, unsigned int removeLingerSecs) :
00017        mNow(now),
00018        mRemoveLingerSecs(removeLingerSecs) {}
00019     bool operator () (const ContactInstanceRecord& rec)
00020     {
00021        return mustRemove(rec);
00022     }
00023     bool mustRemove(const ContactInstanceRecord& rec)
00024     {
00025        if((rec.mRegExpires <= mNow) && ((mNow - rec.mLastUpdated) > mRemoveLingerSecs)) 
00026        {
00027           DebugLog(<< "ContactInstanceRecord removed after linger: " << rec.mContact);
00028           return true;
00029        }
00030       return false;
00031     }
00032 };
00033 
00034 /* Solaris with libCstd seems to choke on the use of an
00035    object (such as RemoveIfRequired) as a predicate for remove_if.
00036    Therefore, this wrapper function implements a workaround,
00037    iterating the list explicitly and using erase(). */
00038 void
00039 contactsRemoveIfRequired(ContactList& contacts, UInt64& now,
00040    unsigned int removeLingerSecs)
00041 {
00042    RemoveIfRequired rei(now, removeLingerSecs);
00043 #ifdef __SUNPRO_CC
00044    for(ContactList::iterator i = contacts.begin(); i != contacts.end(); )
00045    {
00046       if(rei.mustRemove(*i))
00047          i = contacts.erase(i);
00048       else
00049          ++i;
00050    }
00051 #else
00052    contacts.remove_if(rei);
00053 #endif
00054 }
00055 
00056 InMemorySyncRegDb::InMemorySyncRegDb(unsigned int removeLingerSecs) : 
00057    mRemoveLingerSecs(removeLingerSecs),
00058    mHandler(0)
00059 {
00060 }
00061 
00062 InMemorySyncRegDb::~InMemorySyncRegDb()
00063 {
00064    for( database_map_t::const_iterator it = mDatabase.begin();
00065         it != mDatabase.end(); it++)
00066    {
00067       delete it->second;
00068    }
00069    mDatabase.clear();
00070 }
00071 
00072 void 
00073 InMemorySyncRegDb::initialSync(unsigned int connectionId)
00074 {
00075    Lock g(mDatabaseMutex);
00076    UInt64 now = Timer::getTimeSecs();
00077    for(database_map_t::iterator it = mDatabase.begin(); it != mDatabase.end(); it++)
00078    {
00079       if(it->second)
00080       {
00081          ContactList& contacts = *(it->second);
00082          if(mRemoveLingerSecs > 0) 
00083          {
00084             contactsRemoveIfRequired(contacts, now, mRemoveLingerSecs);
00085          }
00086          if(mHandler) mHandler->onInitialSyncAor(connectionId, it->first, contacts);        
00087       }
00088    }
00089 }
00090 
00091 void 
00092 InMemorySyncRegDb::addAor(const Uri& aor,
00093                           const ContactList& contacts)
00094 {
00095    Lock g(mDatabaseMutex);
00096    database_map_t::iterator it = mDatabase.find(aor);
00097    if(it != mDatabase.end())
00098    {
00099        if(it->second)
00100        {
00101            *(it->second) = contacts;
00102        }
00103        else
00104        {
00105            it->second = new ContactList(contacts);
00106        }
00107    }
00108    else
00109    {
00110        mDatabase[aor] = new ContactList(contacts);
00111    }
00112    if(mHandler) mHandler->onAorModified(aor, contacts);
00113 }
00114 
00115 void 
00116 InMemorySyncRegDb::removeAor(const Uri& aor)
00117 {
00118   database_map_t::iterator i;
00119 
00120   Lock g(mDatabaseMutex);
00121   i = mDatabase.find(aor);
00122   //DebugLog (<< "Removing registration bindings " << aor);
00123   if (i != mDatabase.end())
00124   {
00125      if (i->second)
00126      {
00127         if(mRemoveLingerSecs > 0)
00128         {
00129            ContactList& contacts = *(i->second);
00130            UInt64 now = Timer::getTimeSecs();
00131            for(ContactList::iterator it = contacts.begin(); it != contacts.end(); it++)
00132            {
00133               // Don't delete record - set expires to 0
00134               it->mRegExpires = 0;
00135               it->mLastUpdated = now;
00136            }
00137            if(mHandler) mHandler->onAorModified(aor, contacts);
00138         }
00139         else
00140         {
00141            delete i->second;
00142            // Setting this to 0 causes it to be removed when we unlock the AOR.
00143            i->second = 0;
00144            ContactList emptyList;
00145            if(mHandler) mHandler->onAorModified(aor, emptyList);
00146         }
00147      }
00148   }
00149 }
00150 
00151 void
00152 InMemorySyncRegDb::getAors(InMemorySyncRegDb::UriList& container)
00153 {
00154    container.clear();
00155    Lock g(mDatabaseMutex);
00156    for( database_map_t::const_iterator it = mDatabase.begin();
00157         it != mDatabase.end(); it++)
00158    {
00159       container.push_back(it->first);
00160    }
00161 }
00162 
00163 bool 
00164 InMemorySyncRegDb::aorIsRegistered(const Uri& aor)
00165 {
00166    Lock g(mDatabaseMutex);
00167    database_map_t::iterator i = mDatabase.find(aor);
00168    if (i != mDatabase.end() && i->second == 0)
00169    {
00170       if(mRemoveLingerSecs > 0)
00171       {
00172          ContactList& contacts = *(i->second);
00173          UInt64 now = Timer::getTimeSecs();
00174          for(ContactList::iterator it = contacts.begin(); it != contacts.end(); it++)
00175          {
00176             if(it->mRegExpires > now)
00177             {
00178                return true;
00179             }
00180          }
00181       }
00182       else
00183       {
00184           return true;
00185       }
00186    }
00187    return false;
00188 }
00189 
00190 void
00191 InMemorySyncRegDb::lockRecord(const Uri& aor)
00192 {
00193    Lock g2(mLockedRecordsMutex);
00194 
00195    DebugLog(<< "InMemorySyncRegDb::lockRecord:  aor=" << aor << " threadid=" << ThreadIf::selfId());
00196 
00197    {
00198       Lock g1(mDatabaseMutex);
00199       // This forces insertion if the record does not yet exist.
00200       mDatabase[aor];
00201    }
00202 
00203    while (mLockedRecords.count(aor))
00204    {
00205       mRecordUnlocked.wait(mLockedRecordsMutex);
00206    }
00207 
00208    mLockedRecords.insert(aor);
00209 }
00210 
00211 void
00212 InMemorySyncRegDb::unlockRecord(const Uri& aor)
00213 {
00214    Lock g2(mLockedRecordsMutex);
00215 
00216    DebugLog(<< "InMemorySyncRegDb::unlockRecord:  aor=" << aor << " threadid=" << ThreadIf::selfId());
00217 
00218    {
00219       Lock g1(mDatabaseMutex);
00220       // If the pointer is null, we remove the record from the map.
00221       database_map_t::iterator i = mDatabase.find(aor);
00222 
00223       // The record must have been inserted when we locked it in the first place
00224       assert (i != mDatabase.end());
00225 
00226       if (i->second == 0)
00227       {
00228          mDatabase.erase(i);
00229       }
00230    }
00231 
00232    mLockedRecords.erase(aor);
00233    mRecordUnlocked.broadcast();
00234 }
00235 
00236 RegistrationPersistenceManager::update_status_t 
00237 InMemorySyncRegDb::updateContact(const resip::Uri& aor, 
00238                                  const ContactInstanceRecord& rec) 
00239 {
00240    ContactList *contactList = 0;
00241 
00242    {
00243       Lock g(mDatabaseMutex);
00244 
00245       database_map_t::iterator i;
00246       i = mDatabase.find(aor);
00247       if (i == mDatabase.end() || i->second == 0)
00248       {
00249          contactList = new ContactList();
00250          mDatabase[aor] = contactList;
00251       }
00252       else
00253       {
00254          contactList = i->second;
00255       }
00256    }
00257    
00258    assert(contactList);
00259 
00260    ContactList::iterator j;
00261 
00262    // See if the contact is already present. We use URI matching rules here.
00263    for (j = contactList->begin(); j != contactList->end(); j++)
00264    {
00265       if (*j == rec)
00266       {
00267          *j=rec;
00268          if(mHandler && !rec.mSyncContact) mHandler->onAorModified(aor, *contactList);
00269          return CONTACT_UPDATED;
00270       }
00271    }
00272 
00273    // This is a new contact, so we add it to the list.
00274    contactList->push_back(rec);
00275    if(mHandler && !rec.mSyncContact) mHandler->onAorModified(aor, *contactList);
00276    return CONTACT_CREATED;
00277 }
00278 
00279 void 
00280 InMemorySyncRegDb::removeContact(const Uri& aor, 
00281                                  const ContactInstanceRecord& rec)
00282 {
00283    ContactList *contactList = 0;
00284 
00285    {
00286       Lock g(mDatabaseMutex);
00287 
00288       database_map_t::iterator i;
00289       i = mDatabase.find(aor);
00290       if (i == mDatabase.end() || i->second == 0)
00291       {
00292          return;
00293       }
00294       contactList = i->second;
00295    }
00296 
00297    ContactList::iterator j;
00298 
00299    // See if the contact is present. We use URI matching rules here.
00300    for (j = contactList->begin(); j != contactList->end(); j++)
00301    {
00302       if (*j == rec)
00303       {
00304          if(mRemoveLingerSecs > 0)
00305          {
00306             j->mRegExpires = 0;
00307             j->mLastUpdated = Timer::getTimeSecs();
00308             if(mHandler && !rec.mSyncContact) mHandler->onAorModified(aor, *contactList);
00309          }
00310          else
00311          {
00312             contactList->erase(j);
00313             if (contactList->empty())
00314             {
00315                removeAor(aor);
00316             }
00317             else
00318             {
00319                if(mHandler && !rec.mSyncContact) mHandler->onAorModified(aor, *contactList);
00320             }
00321          }
00322          return;
00323       }
00324    }
00325 }
00326 
00327 void
00328 InMemorySyncRegDb::getContacts(const Uri& aor, ContactList& container)
00329 {
00330    Lock g(mDatabaseMutex);
00331    database_map_t::iterator i = mDatabase.find(aor);
00332    if (i == mDatabase.end() || i->second == 0)
00333    {
00334       container.clear();
00335       return;
00336    }
00337    if(mRemoveLingerSecs > 0)
00338    {
00339       ContactList& contacts = *(i->second);
00340       UInt64 now = Timer::getTimeSecs();
00341       contactsRemoveIfRequired(contacts, now, mRemoveLingerSecs);
00342       container.clear();
00343       for(ContactList::iterator it = contacts.begin(); it != contacts.end(); it++)
00344       {
00345          if(it->mRegExpires > now)
00346          {
00347              container.push_back(*it);
00348          }
00349       }
00350    }
00351    else
00352    {
00353       container = *(i->second);
00354    }
00355 }
00356 
00357 void
00358 InMemorySyncRegDb::getContactsFull(const Uri& aor, ContactList& container)
00359 {
00360    Lock g(mDatabaseMutex);
00361    database_map_t::iterator i = mDatabase.find(aor);
00362    if (i == mDatabase.end() || i->second == 0)
00363    {
00364       container.clear();
00365       return;
00366    }
00367    ContactList& contacts = *(i->second);
00368    if(mRemoveLingerSecs > 0)
00369    {
00370       UInt64 now = Timer::getTimeSecs();
00371       contactsRemoveIfRequired(contacts, now, mRemoveLingerSecs);
00372    }
00373    container = contacts;
00374 }
00375 
00376 
00377 /* ====================================================================
00378  * The Vovida Software License, Version 1.0 
00379  * 
00380  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00381  * 
00382  * Redistribution and use in source and binary forms, with or without
00383  * modification, are permitted provided that the following conditions
00384  * are met:
00385  * 
00386  * 1. Redistributions of source code must retain the above copyright
00387  *    notice, this list of conditions and the following disclaimer.
00388  * 
00389  * 2. Redistributions in binary form must reproduce the above copyright
00390  *    notice, this list of conditions and the following disclaimer in
00391  *    the documentation and/or other materials provided with the
00392  *    distribution.
00393  * 
00394  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00395  *    and "Vovida Open Communication Application Library (VOCAL)" must
00396  *    not be used to endorse or promote products derived from this
00397  *    software without prior written permission. For written
00398  *    permission, please contact vocal@vovida.org.
00399  *
00400  * 4. Products derived from this software may not be called "VOCAL", nor
00401  *    may "VOCAL" appear in their name, without prior written
00402  *    permission of Vovida Networks, Inc.
00403  * 
00404  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00405  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00406  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00407  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00408  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00409  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00410  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00411  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00412  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00413  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00414  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00415  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00416  * DAMAGE.
00417  * 
00418  * ====================================================================
00419  * 
00420  * This software consists of voluntary contributions made by Vovida
00421  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00422  * Inc.  For more information on Vovida Networks, Inc., please see
00423  * <http://www.vovida.org/>.
00424  *
00425  */