changeset 690:827a522a5da4 by-id

Re-implement Document::releaseModel
author Chris Cannam
date Fri, 12 Jul 2019 09:40:56 +0100
parents e56cc6fe7da2
children c8ba09756eff
files framework/Document.cpp
diffstat 1 files changed, 48 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/framework/Document.cpp	Sun Jul 07 16:43:16 2019 +0100
+++ b/framework/Document.cpp	Fri Jul 12 09:40:56 2019 +0100
@@ -746,103 +746,77 @@
 }
 
 void
-Document::releaseModel(ModelId modelId) // Will _not_ release main model!
+Document::releaseModel(ModelId modelId)
 {
-    //!!!
+    // This is called when a layer has been deleted or has replaced
+    // its model, in order to reclaim storage for the old model. It
+    // could be a no-op without making any functional difference, as
+    // all the models stored in the ById pool are released when the
+    // document is deleted. But models can sometimes be large, so if
+    // we know no other layer is using one, we should release it. If
+    // we happen to release one that is being used, the ModelById
+    // borrowed-pointer mechanism will at least prevent memory errors,
+    // although the other code will have to stop whatever it's doing.
 
-    SVCERR << "Document::releaseModel(" << modelId << "): STILL TO REVIEW" << endl;
-
-#ifdef NOT_DEFINED
+    SVCERR << "Document::releaseModel(" << modelId << ")" << endl;
     
     if (modelId.isNone()) {
         return;
     }
-
-    auto model = ModelById::get(modelId);
-    if (!model) {
-        return;
-    }
     
 #ifdef DEBUG_DOCUMENT
-    SVDEBUG << "Document::releaseModel(" << modelId << ", type "
-            << model->getTypeName() << ", name \""
-            << model->objectName() << "\")" << endl;
+    SVCERR << "Document::releaseModel(" << modelId << ")" << endl;
 #endif
-    
+
     if (modelId == m_mainModel) {
+#ifdef DEBUG_DOCUMENT
+        SVCERR << "Document::releaseModel: It's the main model, ignoring"
+               << endl;
+#endif
         return;
     }
 
-    bool toDelete = false;
-    bool isInModelList = false; // should become true for any "normal" model
-
-    if (m_models.find(modelId) != m_models.end()) {
-
-        if (mitr->refcount == 0) {
-            SVCERR << "WARNING: Document::releaseModel: model " << model
-                   << " reference count is zero already!" << endl;
-        } else {
+    if (m_models.find(modelId) == m_models.end()) {
+        // No point in releasing aggregate models and the like,
+        // they're not large
 #ifdef DEBUG_DOCUMENT
-            SVDEBUG << "Lowering refcount from " << mitr->refcount << endl;
+        SVCERR << "Document::releaseModel: It's not a regular layer model, ignoring" << endl;
 #endif
-            if (--mitr->refcount == 0) {
-                toDelete = true;
-            }
-        }
-        isInModelList = true;
-
-    } else if (m_aggregateModels.find(model) != m_aggregateModels.end()) {
-#ifdef DEBUG_DOCUMENT
-        SVDEBUG << "Document::releaseModel: is an aggregate model" << endl;
-#endif
-        toDelete = true;
-    } else { 
-        SVCERR << "WARNING: Document::releaseModel: Unfound model "
-               << model << endl;
-        toDelete = true;
+        return;
     }
 
-    if (toDelete) {
-
-        int sourceCount = 0;
-
-        for (auto &rec: m_models) {
-            if (rec.source == model) {
-                ++sourceCount;
-                rec.source = nullptr;
-            }
-        }
-
-        if (sourceCount > 0) {
-            SVDEBUG << "Document::releaseModel: Deleting model "
-                    << model << " even though it is source for "
-                    << sourceCount << " other derived model(s) -- resetting "
-                    << "their source fields appropriately" << endl;
-        }
-
-        if (isInModelList) {
-            deleteModelFromList(model);
-
+    for (auto layer: m_layers) {
+        if (layer->getModel() == modelId) {
 #ifdef DEBUG_DOCUMENT
-            SVDEBUG << "Document::releaseModel: Deleted model " << model << endl;
-            SVDEBUG << "Models now: ";
-            for (const auto &r: m_models) {
-                SVDEBUG << r.model << " ";
-            } 
-            SVDEBUG << endl;
+            SVCERR << "Document::releaseModel: It's still in use in at least one layer, ignoring" << endl;
 #endif
-        } else {
-            model->aboutToDelete();
-            emit modelAboutToBeDeleted(model);
-            delete model;
-
-#ifdef DEBUG_DOCUMENT
-            SVDEBUG << "Document::releaseModel: Deleted awkward model " << model << endl;
-#endif
+            return;
         }
     }
 
+#ifdef DEBUG_DOCUMENT
+    SVCERR << "Document::releaseModel: Seems to be OK to release this one"
+           << endl;
 #endif
+
+    int sourceCount = 0;
+
+    for (auto &m: m_models) {
+        if (m.second.source == modelId) {
+            ++sourceCount;
+            m.second.source = {};
+        }
+    }
+
+    if (sourceCount > 0) {
+        SVCERR << "Document::releaseModel: Request to release model "
+               << modelId << " even though it was source for "
+               << sourceCount << " other derived model(s) -- have cleared "
+               << "their source fields" << endl;
+    }
+
+    m_models.erase(modelId);
+    ModelById::release(modelId);
 }
 
 void