summaryrefslogtreecommitdiffstats
path: root/flow/cache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'flow/cache.cpp')
-rw-r--r--flow/cache.cpp274
1 files changed, 274 insertions, 0 deletions
diff --git a/flow/cache.cpp b/flow/cache.cpp
new file mode 100644
index 0000000..80f0349
--- /dev/null
+++ b/flow/cache.cpp
@@ -0,0 +1,274 @@
+ /*
+
+ Copyright (C) 2000 Stefan Westerfeld
+ stefan@space.twc.de
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ */
+
+#include "cache.h"
+#include "debug.h"
+#include "iomanager.h"
+#include "dispatcher.h"
+#include <iostream>
+#include <assert.h>
+
+using namespace std;
+using namespace Arts;
+
+bool CachedObject::isValid()
+{
+ return true;
+}
+
+void CachedObject::setKey(string key)
+{
+ _object_key = key;
+}
+
+string CachedObject::getKey()
+{
+ return _object_key;
+}
+
+void CachedObject::decRef()
+{
+ _ref_cnt--;
+ time(&_lastAccess);
+}
+
+void CachedObject::incRef()
+{
+ _ref_cnt++;
+}
+
+int CachedObject::refCnt()
+{
+ return _ref_cnt;
+}
+
+time_t CachedObject::lastAccess()
+{
+ return(_lastAccess);
+}
+
+CachedObject::CachedObject(Cache *cache)
+{
+ _ref_cnt = 1;
+ cache->add(this);
+}
+
+CachedObject::~CachedObject()
+{
+ assert(_ref_cnt == 0);
+}
+
+//------------------------- Cache implementation ---------------------------
+long Cache::memused = 0;
+
+CachedObject *Cache::get(string key)
+{
+ list<CachedObject *>::iterator i;
+
+ for(i=objects.begin();i != objects.end(); i++)
+ {
+ if((*i)->getKey() == key && (*i)->isValid())
+ {
+ (*i)->incRef();
+ return(*i);
+ }
+ }
+ return 0;
+}
+
+void Cache::add(CachedObject *object)
+{
+ objects.push_back(object);
+}
+
+long Cache::cleanUp(long cacheLimit)
+{
+ time_t lastAccess;
+
+ list<CachedObject *>::iterator i;
+ long memory = 0;
+
+ // delete all invalid unused entries (invalid entries that are still
+ // in use, e.g. cached wav files which have changed on disk but are
+ // still played can't be deleted!)
+
+ for(i=objects.begin();i != objects.end(); i++)
+ {
+ CachedObject *co = (*i);
+
+ if(co->refCnt() == 0 && !co->isValid())
+ {
+ objects.remove(co);
+ delete co;
+ i = objects.begin();
+ }
+ }
+
+ for(i=objects.begin();i != objects.end(); i++)
+ {
+ memory += (*i)->memoryUsage();
+ }
+
+ bool freeok = true;
+ while(memory > cacheLimit && freeok)
+ {
+ CachedObject *freeme;
+
+ freeok = false;
+
+ // only start freeing objects which have not been accessed
+ // in the last 5 seconds
+
+ time(&lastAccess);
+ lastAccess -= 5;
+
+
+ for(i=objects.begin();!freeok && (i != objects.end()); i++)
+ {
+ CachedObject *co = (*i);
+
+ assert(co->refCnt() >= 0);
+ if(co->refCnt() == 0 && (co->lastAccess() < lastAccess))
+ {
+ lastAccess = co->lastAccess();
+ freeme = co;
+ freeok = true;
+ }
+ else
+ {
+ //artsdebug("%d => %ld\n",co->refCnt(),co->lastAccess());
+ }
+ }
+
+ if(freeok)
+ {
+ memory -= freeme->memoryUsage();
+ objects.remove(freeme);
+ delete(freeme);
+ }
+ else
+ {
+ //artsdebug("cache problem: memory overused, but nothing there to free\n");
+ }
+ }
+
+ memused = memory/1024;
+ return(memory);
+}
+
+Cache *Cache::_instance = 0;
+
+Cache::Cache()
+{
+ assert(!_instance);
+ _instance = this;
+}
+
+Cache::~Cache()
+{
+ list<CachedObject *>::iterator i;
+ for(i=objects.begin(); i != objects.end(); i++)
+ delete (*i);
+ objects.clear();
+
+ assert(_instance);
+ _instance = 0;
+}
+
+
+Cache *Cache::the()
+{
+ if(!_instance) _instance = new Cache();
+ return _instance;
+}
+
+void Cache::shutdown()
+{
+ if(_instance)
+ {
+ list<CachedObject *>::iterator i;
+ long rcnt = 0;
+ for(i=_instance->objects.begin(); i != _instance->objects.end(); i++)
+ rcnt += (*i)->refCnt();
+
+ if(rcnt == 0)
+ {
+ delete _instance;
+ _instance = 0;
+ }
+ else
+ {
+ arts_warning("cache shutdown while still active objects in cache");
+ }
+ }
+}
+
+namespace Arts { // internal helpers
+
+// periodic cache clean
+class CacheClean : public TimeNotify {
+public:
+ CacheClean();
+ void notifyTime();
+ virtual ~CacheClean();
+};
+
+// cache startup & shutdown
+class CacheStartup :public StartupClass
+{
+public:
+ void startup();
+ void shutdown();
+private:
+ CacheClean *cacheClean;
+};
+
+}
+
+CacheClean::CacheClean()
+{
+ Dispatcher::the()->ioManager()->addTimer(5000, this);
+}
+
+void CacheClean::notifyTime()
+{
+ // TODO: make this configurable
+ Cache::the()->cleanUp(8192*1024);
+}
+
+CacheClean::~CacheClean()
+{
+ Dispatcher::the()->ioManager()->removeTimer(this);
+}
+
+void CacheStartup::startup()
+{
+ cacheClean = new CacheClean;
+}
+
+void CacheStartup::shutdown()
+{
+ delete cacheClean;
+ Cache::shutdown();
+}
+
+static CacheStartup cacheStartup;