Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

397 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: A cache of a bunch of CSharedObjects
  4. //
  5. //=============================================================================
  6. #include "stdafx.h"
  7. #include <time.h>
  8. // memdbgon must be the last include file in a .cpp file!!!
  9. #include "tier0/memdbgon.h"
  10. namespace GCSDK
  11. {
  12. #ifdef GC
  13. static GCConVar add_object_clean_do_has_element( "add_object_clean_do_has_element", "0", 0, "Enables AddObjectClean() checking that the cache doesn't already have this pointer" );
  14. #endif
  15. //----------------------------------------------------------------------------
  16. // Purpose: Constructor
  17. //----------------------------------------------------------------------------
  18. CSharedObjectTypeCache::CSharedObjectTypeCache( int nTypeID )
  19. : m_nTypeID( nTypeID )
  20. {
  21. }
  22. //----------------------------------------------------------------------------
  23. // Purpose: Destructor
  24. //----------------------------------------------------------------------------
  25. CSharedObjectTypeCache::~CSharedObjectTypeCache()
  26. {
  27. for ( int i = 0; i < m_vecObjects.Count(); i++ )
  28. {
  29. // NULL the entry so that this SO isn't found during
  30. // cleanup assertion checking.
  31. CSharedObject *pObj = m_vecObjects[ i ];
  32. m_vecObjects[ i ] = NULL;
  33. #ifdef GC
  34. if ( pObj->BShouldDeleteByCache() )
  35. {
  36. #if ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA
  37. --pObj->m_nRefCount;
  38. AssertMsg1( pObj->m_nRefCount == 0, "Destroying shared object %s that's still in use!", pObj->GetDebugString().String() );
  39. #endif // ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA
  40. delete pObj;
  41. }
  42. #else
  43. delete pObj;
  44. #endif
  45. }
  46. m_vecObjects.Purge();
  47. }
  48. //----------------------------------------------------------------------------
  49. // Purpose: Common shared add-to-cache code shared between AddObject() and
  50. // AddObjectClean().
  51. //----------------------------------------------------------------------------
  52. void CSharedObjectTypeCache::AddObjectInternal( CSharedObject *pObject )
  53. {
  54. Assert( pObject );
  55. m_vecObjects.AddToTail( pObject );
  56. #ifdef GC
  57. #if ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA
  58. AssertMsg1( pObject->m_nRefCount >= 0, "AddObjectInternal(): Invalid ref count for shared object %s", pObject->GetDebugString().String() );
  59. ++pObject->m_nRefCount;
  60. #endif // ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA
  61. #endif
  62. }
  63. //----------------------------------------------------------------------------
  64. // Purpose: Adds a shared object of the appropriate type to this type cache.
  65. //----------------------------------------------------------------------------
  66. bool CSharedObjectTypeCache::AddObject( CSharedObject *pObject )
  67. {
  68. Assert( pObject );
  69. Assert( m_nTypeID == pObject->GetTypeID() );
  70. if( m_vecObjects.HasElement( pObject ) )
  71. return false;
  72. AddObjectInternal( pObject );
  73. return true;
  74. }
  75. //----------------------------------------------------------------------------
  76. // Purpose: Adds an object without dirtying. This is done when the object
  77. // is just being loaded from SQL or memcached, so it's safe not to do the
  78. // has element check.
  79. //----------------------------------------------------------------------------
  80. bool CSharedObjectTypeCache::AddObjectClean( CSharedObject *pObject )
  81. {
  82. Assert( m_nTypeID == pObject->GetTypeID() );
  83. #ifdef GC
  84. if ( add_object_clean_do_has_element.GetBool() )
  85. {
  86. Assert( !m_vecObjects.HasElement( pObject ) );
  87. if( m_vecObjects.HasElement( pObject ) )
  88. return false;
  89. }
  90. #endif
  91. AddObjectInternal( pObject );
  92. return true;
  93. }
  94. //----------------------------------------------------------------------------
  95. // Purpose: Destroys the object matching the one passed in. This could be the
  96. // same one or simply one with matching index fields.
  97. //----------------------------------------------------------------------------
  98. CSharedObject *CSharedObjectTypeCache::RemoveObject( const CSharedObject & soIndex )
  99. {
  100. Assert( m_nTypeID == soIndex.GetTypeID() ); // This is probably harmless, but it's most likely a bug
  101. int nIndex = FindSharedObjectIndex( soIndex );
  102. if( m_vecObjects.IsValidIndex( nIndex ) )
  103. {
  104. return RemoveObjectByIndex( nIndex );
  105. }
  106. else
  107. {
  108. return NULL;
  109. }
  110. }
  111. CSharedObject *CSharedObjectTypeCache::RemoveObjectByIndex( uint32 nObj )
  112. {
  113. CSharedObject *pObj = m_vecObjects[nObj];
  114. #ifdef GC
  115. #if ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA
  116. AssertMsg1( pObj->m_nRefCount > 0, "Invalid ref count for shared object %s", pObj->GetDebugString().String() );
  117. --pObj->m_nRefCount;
  118. #endif // ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA
  119. #endif // GC
  120. m_vecObjects.Remove( nObj );
  121. return pObj;
  122. }
  123. //----------------------------------------------------------------------------
  124. // Purpose: Empties the object lists and deletes all elements
  125. //----------------------------------------------------------------------------
  126. void CSharedObjectTypeCache::DestroyAllObjects()
  127. {
  128. for ( int i = 0; i < m_vecObjects.Count(); i++ )
  129. {
  130. #ifdef GC
  131. if ( m_vecObjects[i]->BShouldDeleteByCache() )
  132. {
  133. #if ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA
  134. --m_vecObjects[i]->m_nRefCount;
  135. AssertMsg1( m_vecObjects[i]->m_nRefCount == 0, "Destroying shared object %s that's still in use!", m_vecObjects[i]->GetDebugString().String() );
  136. #endif // ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA
  137. delete m_vecObjects[i];
  138. }
  139. #else
  140. delete m_vecObjects[i];
  141. #endif
  142. }
  143. m_vecObjects.Purge();
  144. }
  145. //----------------------------------------------------------------------------
  146. // Purpose: Empties the object lists but doesn't delete any of the objects
  147. //----------------------------------------------------------------------------
  148. void CSharedObjectTypeCache::RemoveAllObjectsWithoutDeleting()
  149. {
  150. m_vecObjects.RemoveAll();
  151. }
  152. //----------------------------------------------------------------------------
  153. // Purpose: Makes sure there's room in the object vector for the suggested
  154. // number of items
  155. //----------------------------------------------------------------------------
  156. void CSharedObjectTypeCache::EnsureCapacity( uint32 nItems )
  157. {
  158. m_vecObjects.EnsureCapacity( nItems );
  159. }
  160. //----------------------------------------------------------------------------
  161. // Purpose: Searches the object list for an object that matches the provided
  162. // object on its index fields.
  163. //----------------------------------------------------------------------------
  164. CSharedObject *CSharedObjectTypeCache::FindSharedObject( const CSharedObject & soIndex )
  165. {
  166. int nIndex = FindSharedObjectIndex( soIndex );
  167. if( m_vecObjects.IsValidIndex( nIndex ) )
  168. return m_vecObjects[nIndex];
  169. else
  170. return NULL;
  171. }
  172. //----------------------------------------------------------------------------
  173. // Purpose: Searches the object list for an object that matches the provided
  174. // object on its index fields.
  175. //----------------------------------------------------------------------------
  176. int CSharedObjectTypeCache::FindSharedObjectIndex( const CSharedObject & soIndex ) const
  177. {
  178. FOR_EACH_VEC( m_vecObjects, nObj )
  179. {
  180. if( m_vecObjects[nObj]->BIsKeyEqual( soIndex ) )
  181. return nObj;
  182. }
  183. return -1;
  184. }
  185. //----------------------------------------------------------------------------
  186. // Purpose: Dumps all the objects in the type cache
  187. //----------------------------------------------------------------------------
  188. void CSharedObjectTypeCache::Dump() const
  189. {
  190. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "\tTypeCache for %d (%d objects):\n", GetTypeID(), m_vecObjects.Count() );
  191. FOR_EACH_VEC( m_vecObjects, nObj )
  192. {
  193. m_vecObjects[nObj]->Dump();
  194. }
  195. }
  196. //----------------------------------------------------------------------------
  197. // Purpose: Claims all the memory for the cache and its objects
  198. //----------------------------------------------------------------------------
  199. #ifdef DBGFLAG_VALIDATE
  200. void CSharedObjectTypeCache::Validate( CValidator &validator, const char *pchName )
  201. {
  202. VALIDATE_SCOPE();
  203. ValidateObj( m_vecObjects );
  204. FOR_EACH_VEC( m_vecObjects, nIndex )
  205. {
  206. m_vecObjects[nIndex]->Validate( validator, "m_vecObjects[n]" );
  207. }
  208. }
  209. #endif
  210. //----------------------------------------------------------------------------
  211. // Purpose: Constructor
  212. //----------------------------------------------------------------------------
  213. CSharedObjectCache::CSharedObjectCache( )
  214. : m_mapObjects( DefLessFunc(int) )
  215. , m_ulVersion( 0 )
  216. {
  217. }
  218. //----------------------------------------------------------------------------
  219. // Purpose: Destructor
  220. //----------------------------------------------------------------------------
  221. CSharedObjectCache::~CSharedObjectCache()
  222. {
  223. FOR_EACH_MAP( m_mapObjects, nTypeIndex )
  224. {
  225. delete m_mapObjects[nTypeIndex];
  226. }
  227. m_mapObjects.Purge();
  228. }
  229. //----------------------------------------------------------------------------
  230. // Purpose: Returns the type cache for the specified type ID, returning NULL
  231. // if the cache didn't previously exist.
  232. //----------------------------------------------------------------------------
  233. CSharedObjectTypeCache *CSharedObjectCache::FindBaseTypeCache( int nClassID ) const
  234. {
  235. int nIndex = m_mapObjects.Find( nClassID );
  236. CSharedObjectTypeCache *pTypeCache = NULL;
  237. if( m_mapObjects.IsValidIndex( nIndex ) )
  238. {
  239. pTypeCache = m_mapObjects[nIndex];
  240. }
  241. return pTypeCache;
  242. }
  243. //----------------------------------------------------------------------------
  244. // Purpose: Returns the type cache for the specified type ID, creating a new
  245. // cache and returning it if one didn't previously exist. Never intended
  246. // to return NULL.
  247. //----------------------------------------------------------------------------
  248. CSharedObjectTypeCache *CSharedObjectCache::CreateBaseTypeCache( int nClassID )
  249. {
  250. //see if we already have an existing one
  251. CSharedObjectTypeCache *pCache = FindBaseTypeCache( nClassID );
  252. if( pCache )
  253. return pCache;
  254. //nope, need to create one
  255. CSharedObjectTypeCache* pTypeCache = AllocateTypeCache( nClassID );
  256. m_mapObjects.Insert( nClassID, pTypeCache );
  257. #if 0
  258. // Kyle says: this is the newer way of managing caches on Dota but we haven't
  259. // brought any of it over yet
  260. m_CacheObjects.AddToTail( pTypeCache );
  261. //sort this cache for faster access
  262. std::sort( m_CacheObjects.begin(), m_CacheObjects.end(), SortCacheByTypeID );
  263. #endif
  264. return pTypeCache;
  265. }
  266. //----------------------------------------------------------------------------
  267. // Purpose: Adds a shared object to the cache.
  268. //----------------------------------------------------------------------------
  269. bool CSharedObjectCache::AddObject( CSharedObject *pSharedObject )
  270. {
  271. CSharedObjectTypeCache *pTypeCache = CreateBaseTypeCache( pSharedObject->GetTypeID() );
  272. if ( !pTypeCache->AddObject( pSharedObject ) )
  273. return false;
  274. MarkDirty();
  275. return true;
  276. }
  277. //----------------------------------------------------------------------------
  278. // Purpose: Removes the object matching the one passed in from this cache,
  279. // without destroying the actual object.
  280. //----------------------------------------------------------------------------
  281. CSharedObject *CSharedObjectCache::RemoveObject( const CSharedObject & soIndex )
  282. {
  283. CSharedObjectTypeCache *pTypeCache = FindBaseTypeCache( soIndex.GetTypeID() );
  284. if( !pTypeCache )
  285. return NULL;
  286. MarkDirty();
  287. return pTypeCache->RemoveObject( soIndex );
  288. }
  289. //----------------------------------------------------------------------------
  290. // Purpose: Empties the object lists but doesn't delete any of the objects
  291. //----------------------------------------------------------------------------
  292. void CSharedObjectCache::RemoveAllObjectsWithoutDeleting()
  293. {
  294. FOR_EACH_MAP_FAST( m_mapObjects, nType )
  295. {
  296. m_mapObjects[nType]->RemoveAllObjectsWithoutDeleting();
  297. }
  298. MarkDirty();
  299. }
  300. //----------------------------------------------------------------------------
  301. // Purpose: Searches the object list for an object that matches the provided
  302. // object on its index fields.
  303. //----------------------------------------------------------------------------
  304. CSharedObject *CSharedObjectCache::FindSharedObject( const CSharedObject & soIndex )
  305. {
  306. CSharedObjectTypeCache *pTypeCache = FindBaseTypeCache( soIndex.GetTypeID() );
  307. if( pTypeCache )
  308. return pTypeCache->FindSharedObject( soIndex );
  309. else
  310. return NULL;
  311. }
  312. //----------------------------------------------------------------------------
  313. // Purpose: Dumps all the objects in the type cache
  314. //----------------------------------------------------------------------------
  315. void CSharedObjectCache::Dump() const
  316. {
  317. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "SharedObjectCache for %s (%d types):\n", GetOwner().Render(), m_mapObjects.Count() );
  318. FOR_EACH_MAP( m_mapObjects, nTypeIndex )
  319. {
  320. m_mapObjects[nTypeIndex]->Dump();
  321. }
  322. }
  323. //----------------------------------------------------------------------------
  324. // Purpose: Claims all the memory for the cache
  325. //----------------------------------------------------------------------------
  326. #ifdef DBGFLAG_VALIDATE
  327. void CSharedObjectCache::Validate( CValidator &validator, const char *pchName )
  328. {
  329. VALIDATE_SCOPE();
  330. ValidateObj( m_mapObjects );
  331. FOR_EACH_MAP( m_mapObjects, nTypeIndex )
  332. {
  333. m_mapObjects[nTypeIndex]->Validate( validator, "m_mapObjects[n]" );
  334. }
  335. }
  336. #endif
  337. } // namespace GCSDK