From eb697d7a3b7fc8b8af052b6f025610dd85eb176b Mon Sep 17 00:00:00 2001 From: Arno Date: Tue, 25 Jun 2013 20:02:41 +0200 Subject: Fix random crashes in ArchiveCollector This was a hard one, actually. Since we only returned a pointer from the ArchiveCollector, it worked _most_ of the time, but crashed at random when the view was reading the tree while the collector was updating it. So create a working copy constructor for SmRootItem and return a copy of the the tree when the collector is done. I bet that's also the reason for the random crashes in the filesystem view. --- archivemodel.cpp | 32 +++++++++++++++++++++++--------- archivemodel.h | 3 +-- smtreeitem.cpp | 40 +++++++++++++++++++++++++++++++--------- 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/archivemodel.cpp b/archivemodel.cpp index b0a6941..86a478e 100644 --- a/archivemodel.cpp +++ b/archivemodel.cpp @@ -5,8 +5,8 @@ 2 of the License, or (at your option) any later version. */ -#include #include +#include #include #include #include @@ -102,7 +102,9 @@ bool ArchiveModel::setData(const QModelIndex &idx, const QVariant &value, int ro QVariant id = item->data(GenericId); updateQuery.bindValue(":value", value); updateQuery.bindValue(":id", id); + mDb.transaction(); if(updateQuery.exec()){ + mDb.commit(); item->setData(Name, value); emit dataChanged(idx, idx); if(nodeType == SeriesNode){ @@ -110,8 +112,8 @@ bool ArchiveModel::setData(const QModelIndex &idx, const QVariant &value, int ro return true; } writeCache(mOrder, root()); - return true; }else{ + mDb.rollback(); emitDatabaseError(updateQuery.lastError()); } return false; @@ -226,22 +228,23 @@ void ArchiveModel::setOrder(const QString &order){ void ArchiveModel::refresh(){ emit message(tr("Reading archive data...")); foreach(ArchiveCollector *c, mCollectors){ - c->start(); + if(!c->isRunning()){ + c->start(); + } } } void ArchiveModel::collectorFinished(QObject *thread){ QMutexLocker l(&mDoneMx); ArchiveCollector *t = qobject_cast(thread); - Q_ASSERT(t); - SmTreeItem *item = t->rootItem(); + SmTreeItem *rootCopy = t->rootItem(); int sortOrder = t->sortOrder(); if(sortOrder == mOrder){ emit collectorAboutToBeDone(); - setRoot(item); + setRoot(rootCopy); emit collectorDone(); } - writeCache(sortOrder, item); + writeCache(sortOrder, rootCopy); QString sortOrderName = mAvailableOrders.key(sortOrder); QString msg = QString("Done reading %1").arg(sortOrderName); emit message(msg); @@ -353,14 +356,24 @@ const QString ArchiveModel::cacheFile(int o) const{ return cacheFile; } -ArchiveCollector::ArchiveCollector(int numFields, int order, QObject *parent) : QThread(parent), mNumFields(numFields), mSortOrder(order) { +ArchiveCollector::ArchiveCollector(int numFields, int order, QObject *parent) : QThread(parent), mRootItem(0), mNumFields(numFields), mSortOrder(order) { QString dbName = QString("%1").arg((qint64(this))); mDb = QSqlDatabase::cloneDatabase(QSqlDatabase::database("treedb"), dbName); mDb.open(); - mRootItem = new SmTreeItem(numFields); + //mRootItem = new SmTreeItem(numFields); +} + +SmTreeItem *ArchiveCollector::rootItem(){ + mAccessMx.lock(); + SmTreeItem *retval = new SmTreeItem(*mRootItem); + mAccessMx.unlock(); + return retval; } void ArchiveCollector::run(){ + mAccessMx.lock(); + delete mRootItem; + mRootItem = new SmTreeItem(mNumFields); switch (mSortOrder){ case ArchiveModel::SeriesName: populateBySeriesName(); @@ -374,6 +387,7 @@ void ArchiveCollector::run(){ default: return; } + mAccessMx.unlock(); } void ArchiveCollector::populateBySeriesName() { diff --git a/archivemodel.h b/archivemodel.h index e4cfc5a..be69346 100644 --- a/archivemodel.h +++ b/archivemodel.h @@ -8,7 +8,6 @@ #ifndef ARCHIVEMODEL_H #define ARCHIVEMODEL_H -#include #include #include #include @@ -71,7 +70,7 @@ class ArchiveCollector : public QThread { Q_OBJECT public: explicit ArchiveCollector(int numFields, int order, QObject *parent = 0); - SmTreeItem *rootItem() { return mRootItem; } + SmTreeItem *rootItem(); int sortOrder() const { return mSortOrder; } signals: diff --git a/smtreeitem.cpp b/smtreeitem.cpp index 77a75d5..4548655 100644 --- a/smtreeitem.cpp +++ b/smtreeitem.cpp @@ -5,6 +5,9 @@ 2 of the License, or (at your option) any later version. */ +#include +#include + #include "smtreeitem.h" SmTreeItem::SmTreeItem(const QList &data, SmTreeItem *parent) : mData(data), mParent(parent) {} @@ -16,15 +19,34 @@ SmTreeItem::SmTreeItem(int rows, SmTreeItem *parent) : mParent(parent){ } SmTreeItem::SmTreeItem(const SmTreeItem &other){ - mData = other.mData; - if(other.mParent){ - mParent = new SmTreeItem(*mParent); - }else{ - mParent = 0; - } - foreach(SmTreeItem *child, other.mChildren){ - mChildren << new SmTreeItem(*child); - } + mParent = 0; + mData = other.mData; + QVector remaining; + QHash parents; + parents.insert(&other, this); + const SmTreeItem *cur = &other; + for(int i = 0; i < cur->childCount(); ++i){ + remaining << cur->child(i); + } + while(cur){ + cur = remaining.last(); + remaining.pop_back(); + for(int i = 0; i < cur->childCount(); ++i){ + remaining << cur->child(i); + } + if(remaining.isEmpty()){ + break; + } + SmTreeItem *newItem = new SmTreeItem(mData.size()); + for(int i = 0; i < cur->columnCount(); ++i){ + newItem->setData(i, cur->data(i)); + } + SmTreeItem *newParent = parents.value(cur->parent()); + newParent->appendChild(newItem); + newItem->setParent(newParent); + parents.insert(cur, newItem); + + } } SmTreeItem::~SmTreeItem(){ -- cgit v1.2.3-70-g09d2