changeset 216:7f8ffe65d453

* Fixes to FFT server lifecycle management
author Chris Cannam
date Mon, 22 Jan 2007 13:20:54 +0000
parents a051929fef3b
children b3dfc3714006
files data/fft/FFTDataServer.cpp data/fft/FFTDataServer.h
diffstat 2 files changed, 139 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/data/fft/FFTDataServer.cpp	Fri Jan 19 14:38:57 2007 +0000
+++ b/data/fft/FFTDataServer.cpp	Mon Jan 22 13:20:54 2007 +0000
@@ -187,7 +187,7 @@
                 if (server->getFillCompletion() < 50) distance += 100;
 
 #ifdef DEBUG_FFT_SERVER
-                std::cerr << "Distance " << distance << ", best is " << bestdist << std::endl;
+                std::cerr << "FFTDataServer::getFuzzyInstance: Distance for server " << server << " is " << distance << ", best is " << bestdist << std::endl;
 #endif
                 
                 if (bestdist == -1 || distance < bestdist) {
@@ -198,8 +198,12 @@
         }
 
         if (bestdist >= 0) {
-            ++best->second.second;
-            return best->second.first;
+            FFTDataServer *server = best->second.first;
+#ifdef DEBUG_FFT_SERVER
+            std::cerr << "FFTDataServer::getFuzzyInstance: We like server " << server << " (with distance " << bestdist << ")" << std::endl;
+#endif
+            claimInstance(server, false);
+            return server;
         }
     }
 
@@ -218,32 +222,66 @@
 FFTDataServer *
 FFTDataServer::findServer(QString n)
 {    
+#ifdef DEBUG_FFT_SERVER
+    std::cerr << "FFTDataServer::findServer(\"" << n.toStdString() << "\")" << std::endl;
+#endif
+
     if (m_servers.find(n) != m_servers.end()) {
-        ++m_servers[n].second;
-        return m_servers[n].first;
+
+        FFTDataServer *server = m_servers[n].first;
+
+#ifdef DEBUG_FFT_SERVER
+        std::cerr << "FFTDataServer::findServer(\"" << n.toStdString() << "\"): found " << server << std::endl;
+#endif
+
+        claimInstance(server, false);
+
+        return server;
     }
 
+#ifdef DEBUG_FFT_SERVER
+        std::cerr << "FFTDataServer::findServer(\"" << n.toStdString() << "\"): not found" << std::endl;
+#endif
+
     return 0;
 }
 
 void
 FFTDataServer::claimInstance(FFTDataServer *server)
 {
-    
-    QMutexLocker locker(&m_serverMapMutex);
+    claimInstance(server, true);
+}
+
+void
+FFTDataServer::claimInstance(FFTDataServer *server, bool needLock)
+{
+    QMutexLocker locker(needLock ? &m_serverMapMutex : 0);
+
+#ifdef DEBUG_FFT_SERVER
+    std::cerr << "FFTDataServer::claimInstance(" << server << ")" << std::endl;
+#endif
 
     for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) {
         if (i->second.first == server) {
 
             for (ServerQueue::iterator j = m_releasedServers.begin();
                  j != m_releasedServers.end(); ++j) {
+
                 if (*j == server) {
+#ifdef DEBUG_FFT_SERVER
+    std::cerr << "FFTDataServer::claimInstance: found in released server list, removing from it" << std::endl;
+#endif
                     m_releasedServers.erase(j);
                     break;
                 }
             }
 
             ++i->second.second;
+
+#ifdef DEBUG_FFT_SERVER
+            std::cerr << "FFTDataServer::claimInstance: new refcount is " << i->second.second << std::endl;
+#endif
+
             return;
         }
     }
@@ -255,12 +293,18 @@
 void
 FFTDataServer::releaseInstance(FFTDataServer *server)
 {
+    releaseInstance(server, true);
+}
+
+void
+FFTDataServer::releaseInstance(FFTDataServer *server, bool needLock)
+{    
+    QMutexLocker locker(needLock ? &m_serverMapMutex : 0);
+
 #ifdef DEBUG_FFT_SERVER
     std::cerr << "FFTDataServer::releaseInstance(" << server << ")" << std::endl;
 #endif
 
-    QMutexLocker locker(&m_serverMapMutex);
-
     // -- if ref count > 0, decrement and return
     // -- if the instance hasn't been used at all, delete it immediately 
     // -- if fewer than N instances (N = e.g. 3) remain with zero refcounts,
@@ -279,13 +323,39 @@
                           << server << "): instance not allocated" << std::endl;
             } else if (--i->second.second == 0) {
                 if (server->m_lastUsedCache == -1) { // never used
+#ifdef DEBUG_FFT_SERVER
+                    std::cerr << "FFTDataServer::releaseInstance: instance "
+                              << server << " has never been used, erasing"
+                              << std::endl;
+#endif
                     delete server;
                     m_servers.erase(i);
                 } else {
-                    m_releasedServers.push_back(server);
+#ifdef DEBUG_FFT_SERVER
+                    std::cerr << "FFTDataServer::releaseInstance: instance "
+                              << server << " no longer in use, marking for possible collection"
+                              << std::endl;
+#endif
+                    bool found = false;
+                    for (ServerQueue::iterator j = m_releasedServers.begin();
+                         j != m_releasedServers.end(); ++j) {
+                        if (*j == server) {
+                            std::cerr << "ERROR: FFTDataServer::releaseInstance("
+                                      << server << "): server is already in "
+                                      << "released servers list" << std::endl;
+                            found = true;
+                        }
+                    }
+                    if (!found) m_releasedServers.push_back(server);
                     server->suspend();
                     purgeLimbo();
                 }
+            } else {
+#ifdef DEBUG_FFT_SERVER
+                    std::cerr << "FFTDataServer::releaseInstance: instance "
+                              << server << " now has refcount " << i->second.second
+                              << std::endl;
+#endif
             }
             return;
         }
@@ -298,12 +368,22 @@
 void
 FFTDataServer::purgeLimbo(int maxSize)
 {
+#ifdef DEBUG_FFT_SERVER
+    std::cerr << "FFTDataServer::purgeLimbo(" << maxSize << "): "
+              << m_releasedServers.size() << " candidates" << std::endl;
+#endif
+
     while (m_releasedServers.size() > maxSize) {
 
         FFTDataServer *server = *m_releasedServers.begin();
 
         bool found = false;
 
+#ifdef DEBUG_FFT_SERVER
+        std::cerr << "FFTDataServer::purgeLimbo: considering candidate "
+                  << server << std::endl;
+#endif
+
         for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) {
 
             if (i->second.first == server) {
@@ -315,6 +395,11 @@
                     // ... so don't delete it
                     break;
                 }
+#ifdef DEBUG_FFT_SERVER
+                std::cerr << "FFTDataServer::purgeLimbo: looks OK, erasing it"
+                          << std::endl;
+#endif
+
                 m_servers.erase(i);
                 delete server;
                 break;
@@ -330,6 +415,12 @@
 
         m_releasedServers.pop_front();
     }
+
+#ifdef DEBUG_FFT_SERVER
+    std::cerr << "FFTDataServer::purgeLimbo(" << maxSize << "): "
+              << m_releasedServers.size() << " remain" << std::endl;
+#endif
+
 }
 
 void
@@ -337,21 +428,38 @@
 {
     QMutexLocker locker(&m_serverMapMutex);
 
+#ifdef DEBUG_FFT_SERVER
+    std::cerr << "FFTDataServer::modelAboutToBeDeleted(" << model << ")"
+              << std::endl;
+#endif
+
     for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) {
         
         FFTDataServer *server = i->second.first;
 
         if (server->getModel() == model) {
+
+#ifdef DEBUG_FFT_SERVER
+            std::cerr << "FFTDataServer::modelAboutToBeDeleted: server is "
+                      << server << std::endl;
+#endif
+
             if (i->second.second > 0) {
                 std::cerr << "ERROR: FFTDataServer::modelAboutToBeDeleted: Model " << model << " (\"" << model->objectName().toStdString() << "\") is about to be deleted, but is still being referred to by FFT server " << server << " with non-zero refcount " << i->second.second << std::endl;
             }
             for (ServerQueue::iterator j = m_releasedServers.begin();
                  j != m_releasedServers.end(); ++j) {
                 if (*j == server) {
+#ifdef DEBUG_FFT_SERVER
+                    std::cerr << "FFTDataServer::modelAboutToBeDeleted: erasing from released servers" << std::endl;
+#endif
                     m_releasedServers.erase(j);
                     break;
                 }
             }
+#ifdef DEBUG_FFT_SERVER
+            std::cerr << "FFTDataServer::modelAboutToBeDeleted: erasing server" << std::endl;
+#endif
             m_servers.erase(i);
             delete server;
             return;
@@ -397,6 +505,11 @@
     m_width = (end - start) / m_windowIncrement + 1;
     m_height = m_fftSize / 2 + 1; // DC == 0, Nyquist == fftsize/2
 
+#ifdef DEBUG_FFT_SERVER 
+    std::cerr << "FFTDataServer(" << this << "): dimensions are "
+              << m_width << "x" << m_height << std::endl;
+#endif
+
     size_t maxCacheSize = 20 * 1024 * 1024;
     size_t columnSize = m_height * sizeof(fftsample) * 2 + sizeof(fftsample);
     if (m_width * columnSize < maxCacheSize * 2) m_cacheWidth = m_width;
@@ -783,9 +896,20 @@
 {
     Profiler profiler("FFTDataServer::getValuesAt", false);
 
+    if (x >= m_width || y >= m_height) {
+        real = 0;
+        imaginary = 0;
+        return;
+    }
+
     size_t col;
     FFTCache *cache = getCache(x, col);
-    if (!cache) { real = 0; imaginary = 0; return; }
+
+    if (!cache) {
+        real = 0;
+        imaginary = 0;
+        return;
+    }
 
     if (!cache->haveSetColumnAt(col)) {
 #ifdef DEBUG_FFT_SERVER
--- a/data/fft/FFTDataServer.h	Fri Jan 19 14:38:57 2007 +0000
+++ b/data/fft/FFTDataServer.h	Mon Jan 22 13:20:54 2007 +0000
@@ -206,6 +206,10 @@
     static QMutex m_serverMapMutex;
     static FFTDataServer *findServer(QString); // call with serverMapMutex held
     static void purgeLimbo(int maxSize = 3); // call with serverMapMutex held
+
+    static void claimInstance(FFTDataServer *, bool needLock);
+    static void releaseInstance(FFTDataServer *, bool needLock);
+
 };
 
 #endif