# HG changeset patch # User Chris Cannam # Date 1169217537 0 # Node ID a051929fef3b32d00260c1b637c058eac6395687 # Parent ce6f65ab3327081fd6ce5e6572a33762177ce405 * Attempt to improve management of FFT models that are not currently in use. I think these are some problems with this at the moment. diff -r ce6f65ab3327 -r a051929fef3b data/fft/FFTDataServer.cpp --- 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; diff -r ce6f65ab3327 -r a051929fef3b data/fft/FFTDataServer.h --- 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 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 ServerCountPair; typedef std::map ServerMap; + typedef std::deque 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