changeset 215:a051929fef3b

* Attempt to improve management of FFT models that are not currently in use. I think these are some problems with this at the moment.
author Chris Cannam
date Fri, 19 Jan 2007 14:38:57 +0000
parents ce6f65ab3327
children 7f8ffe65d453
files data/fft/FFTDataServer.cpp data/fft/FFTDataServer.h
diffstat 2 files changed, 91 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/data/fft/FFTDataServer.cpp	Fri Jan 19 13:13:14 2007 +0000
+++ b/data/fft/FFTDataServer.cpp	Fri Jan 19 14:38:57 2007 +0000
@@ -40,6 +40,7 @@
 #endif
 
 FFTDataServer::ServerMap FFTDataServer::m_servers;
+FFTDataServer::ServerQueue FFTDataServer::m_releasedServers;
 QMutex FFTDataServer::m_serverMapMutex;
 
 FFTDataServer *
@@ -233,6 +234,15 @@
 
     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) {
+                    m_releasedServers.erase(j);
+                    break;
+                }
+            }
+
             ++i->second.second;
             return;
         }
@@ -251,8 +261,6 @@
 
     QMutexLocker locker(&m_serverMapMutex);
 
-    //!!! not a good strategy.  Want something like:
-
     // -- 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,
@@ -264,9 +272,6 @@
     // -- have an additional method to indicate that a model has been
     //    destroyed, so that we can delete all of its fft server instances
 
-    // also:
-    //
-
     for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) {
         if (i->second.first == server) {
             if (i->second.second == 0) {
@@ -277,6 +282,7 @@
                     delete server;
                     m_servers.erase(i);
                 } else {
+                    m_releasedServers.push_back(server);
                     server->suspend();
                     purgeLimbo();
                 }
@@ -292,19 +298,64 @@
 void
 FFTDataServer::purgeLimbo(int maxSize)
 {
-    ServerMap::iterator i = m_servers.end();
+    while (m_releasedServers.size() > maxSize) {
 
-    int count = 0;
+        FFTDataServer *server = *m_releasedServers.begin();
 
-    while (i != m_servers.begin()) {
-        --i;
-        if (i->second.second == 0) {
-            if (++count > maxSize) {
-                delete i->second.first;
+        bool found = false;
+
+        for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) {
+
+            if (i->second.first == server) {
+                found = true;
+                if (i->second.second > 0) {
+                    std::cerr << "ERROR: FFTDataServer::purgeLimbo: Server "
+                              << server << " is in released queue, but still has non-zero refcount "
+                              << i->second.second << std::endl;
+                    // ... so don't delete it
+                    break;
+                }
                 m_servers.erase(i);
-                return;
+                delete server;
+                break;
             }
         }
+
+        if (!found) {
+            std::cerr << "ERROR: FFTDataServer::purgeLimbo: Server "
+                      << server << " is in released queue, but not in server map!"
+                      << std::endl;
+            delete server;
+        }
+
+        m_releasedServers.pop_front();
+    }
+}
+
+void
+FFTDataServer::modelAboutToBeDeleted(Model *model)
+{
+    QMutexLocker locker(&m_serverMapMutex);
+
+    for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) {
+        
+        FFTDataServer *server = i->second.first;
+
+        if (server->getModel() == model) {
+            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) {
+                    m_releasedServers.erase(j);
+                    break;
+                }
+            }
+            m_servers.erase(i);
+            delete server;
+            return;
+        }
     }
 }
 
@@ -374,13 +425,29 @@
     int cells = m_width * m_height;
     int minimumSize = (cells / 1024) * sizeof(uint16_t); // kb
     int maximumSize = (cells / 1024) * sizeof(float); // kb
+    
+    StorageAdviser::Recommendation recommendation;
 
-    // This can throw InsufficientDiscSpace.  We don't catch it here -- we
-    // haven't allocated anything yet and can safely let the exception out.
-    // Caller needs to check for it.
-    
-    StorageAdviser::Recommendation recommendation = 
-        StorageAdviser::recommend(criteria, minimumSize, maximumSize);
+    try {
+
+        recommendation =
+            StorageAdviser::recommend(criteria, minimumSize, maximumSize);
+
+    } catch (InsufficientDiscSpace s) {
+
+        // Delete any unused servers we may have been leaving around
+        // in case we wanted them again
+
+        purgeLimbo(0);
+
+        // This time we don't catch InsufficientDiscSpace -- we
+        // haven't allocated anything yet and can safely let the
+        // exception out to indicate to the caller that we can't
+        // handle it.
+
+        recommendation =
+            StorageAdviser::recommend(criteria, minimumSize, maximumSize);
+    }
 
     std::cerr << "Recommendation was: " << recommendation << std::endl;
 
--- a/data/fft/FFTDataServer.h	Fri Jan 19 13:13:14 2007 +0000
+++ b/data/fft/FFTDataServer.h	Fri Jan 19 14:38:57 2007 +0000
@@ -29,6 +29,7 @@
 #include <deque>
 
 class DenseTimeValueModel;
+class Model;
 class FFTCache;
 
 class FFTDataServer
@@ -55,6 +56,8 @@
     static void claimInstance(FFTDataServer *);
     static void releaseInstance(FFTDataServer *);
 
+    static void modelAboutToBeDeleted(Model *);
+
     const DenseTimeValueModel *getModel() const { return m_model; }
     int        getChannel() const { return m_channel; }
     WindowType getWindowType() const { return m_windower.getType(); }
@@ -196,8 +199,10 @@
 
     typedef std::pair<FFTDataServer *, int> ServerCountPair;
     typedef std::map<QString, ServerCountPair> ServerMap;
+    typedef std::deque<FFTDataServer *> ServerQueue;
 
     static ServerMap m_servers;
+    static ServerQueue m_releasedServers; // these are still in m_servers as well, with zero refcount
     static QMutex m_serverMapMutex;
     static FFTDataServer *findServer(QString); // call with serverMapMutex held
     static void purgeLimbo(int maxSize = 3); // call with serverMapMutex held