aRts audio server
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.

275 lines
4.8KB

  1. /*
  2. Copyright (C) 2000 Stefan Westerfeld
  3. stefan@space.twc.de
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License as published by the Free Software Foundation; either
  7. version 2 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public License
  13. along with this library; see the file COPYING.LIB. If not, write to
  14. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  15. Boston, MA 02110-1301, USA.
  16. */
  17. #include "cache.h"
  18. #include "debug.h"
  19. #include "iomanager.h"
  20. #include "dispatcher.h"
  21. #include <iostream>
  22. #include <assert.h>
  23. using namespace std;
  24. using namespace Arts;
  25. bool CachedObject::isValid()
  26. {
  27. return true;
  28. }
  29. void CachedObject::setKey(string key)
  30. {
  31. _object_key = key;
  32. }
  33. string CachedObject::getKey()
  34. {
  35. return _object_key;
  36. }
  37. void CachedObject::decRef()
  38. {
  39. _ref_cnt--;
  40. time(&_lastAccess);
  41. }
  42. void CachedObject::incRef()
  43. {
  44. _ref_cnt++;
  45. }
  46. int CachedObject::refCnt()
  47. {
  48. return _ref_cnt;
  49. }
  50. time_t CachedObject::lastAccess()
  51. {
  52. return(_lastAccess);
  53. }
  54. CachedObject::CachedObject(Cache *cache)
  55. {
  56. _ref_cnt = 1;
  57. cache->add(this);
  58. }
  59. CachedObject::~CachedObject()
  60. {
  61. assert(_ref_cnt == 0);
  62. }
  63. //------------------------- Cache implementation ---------------------------
  64. long Cache::memused = 0;
  65. CachedObject *Cache::get(string key)
  66. {
  67. list<CachedObject *>::iterator i;
  68. for(i=objects.begin();i != objects.end(); i++)
  69. {
  70. if((*i)->getKey() == key && (*i)->isValid())
  71. {
  72. (*i)->incRef();
  73. return(*i);
  74. }
  75. }
  76. return 0;
  77. }
  78. void Cache::add(CachedObject *object)
  79. {
  80. objects.push_back(object);
  81. }
  82. long Cache::cleanUp(long cacheLimit)
  83. {
  84. time_t lastAccess;
  85. list<CachedObject *>::iterator i;
  86. long memory = 0;
  87. // delete all invalid unused entries (invalid entries that are still
  88. // in use, e.g. cached wav files which have changed on disk but are
  89. // still played can't be deleted!)
  90. for(i=objects.begin();i != objects.end(); i++)
  91. {
  92. CachedObject *co = (*i);
  93. if(co->refCnt() == 0 && !co->isValid())
  94. {
  95. objects.remove(co);
  96. delete co;
  97. i = objects.begin();
  98. }
  99. }
  100. for(i=objects.begin();i != objects.end(); i++)
  101. {
  102. memory += (*i)->memoryUsage();
  103. }
  104. bool freeok = true;
  105. while(memory > cacheLimit && freeok)
  106. {
  107. CachedObject *freeme;
  108. freeok = false;
  109. // only start freeing objects which have not been accessed
  110. // in the last 5 seconds
  111. time(&lastAccess);
  112. lastAccess -= 5;
  113. for(i=objects.begin();!freeok && (i != objects.end()); i++)
  114. {
  115. CachedObject *co = (*i);
  116. assert(co->refCnt() >= 0);
  117. if(co->refCnt() == 0 && (co->lastAccess() < lastAccess))
  118. {
  119. lastAccess = co->lastAccess();
  120. freeme = co;
  121. freeok = true;
  122. }
  123. else
  124. {
  125. //artsdebug("%d => %ld\n",co->refCnt(),co->lastAccess());
  126. }
  127. }
  128. if(freeok)
  129. {
  130. memory -= freeme->memoryUsage();
  131. objects.remove(freeme);
  132. delete(freeme);
  133. }
  134. else
  135. {
  136. //artsdebug("cache problem: memory overused, but nothing there to free\n");
  137. }
  138. }
  139. memused = memory/1024;
  140. return(memory);
  141. }
  142. Cache *Cache::_instance = 0;
  143. Cache::Cache()
  144. {
  145. assert(!_instance);
  146. _instance = this;
  147. }
  148. Cache::~Cache()
  149. {
  150. list<CachedObject *>::iterator i;
  151. for(i=objects.begin(); i != objects.end(); i++)
  152. delete (*i);
  153. objects.clear();
  154. assert(_instance);
  155. _instance = 0;
  156. }
  157. Cache *Cache::the()
  158. {
  159. if(!_instance) _instance = new Cache();
  160. return _instance;
  161. }
  162. void Cache::shutdown()
  163. {
  164. if(_instance)
  165. {
  166. list<CachedObject *>::iterator i;
  167. long rcnt = 0;
  168. for(i=_instance->objects.begin(); i != _instance->objects.end(); i++)
  169. rcnt += (*i)->refCnt();
  170. if(rcnt == 0)
  171. {
  172. delete _instance;
  173. _instance = 0;
  174. }
  175. else
  176. {
  177. arts_warning("cache shutdown while still active objects in cache");
  178. }
  179. }
  180. }
  181. namespace Arts { // internal helpers
  182. // periodic cache clean
  183. class CacheClean : public TimeNotify {
  184. public:
  185. CacheClean();
  186. void notifyTime();
  187. virtual ~CacheClean();
  188. };
  189. // cache startup & shutdown
  190. class CacheStartup :public StartupClass
  191. {
  192. public:
  193. void startup();
  194. void shutdown();
  195. private:
  196. CacheClean *cacheClean;
  197. };
  198. }
  199. CacheClean::CacheClean()
  200. {
  201. Dispatcher::the()->ioManager()->addTimer(5000, this);
  202. }
  203. void CacheClean::notifyTime()
  204. {
  205. // TODO: make this configurable
  206. Cache::the()->cleanUp(8192*1024);
  207. }
  208. CacheClean::~CacheClean()
  209. {
  210. Dispatcher::the()->ioManager()->removeTimer(this);
  211. }
  212. void CacheStartup::startup()
  213. {
  214. cacheClean = new CacheClean;
  215. }
  216. void CacheStartup::shutdown()
  217. {
  218. delete cacheClean;
  219. Cache::shutdown();
  220. }
  221. static CacheStartup cacheStartup;