33#include " defaults.h"
44#include " localstore_p.h"
55#include " defaults_p.h"
6+ #include " remoteconnector_p.h"
67
78#include < QtCore/QThreadPool>
89#include < QtCore/QStandardPaths>
@@ -60,7 +61,8 @@ MigrationRunnable::MigrationRunnable(const Defaults &defaults, MigrationHelper *
6061#define QTDATASYNC_LOG _logger
6162
6263#define cleanDb () do { \
63- db.close (); \
64+ if (_flags.testFlag (MigrationHelper::MigrateData)) \
65+ db.close (); \
6466 db = QSqlDatabase (); \
6567 QSqlDatabase::removeDatabase (dbName); \
6668} while (false )
@@ -105,20 +107,45 @@ void MigrationRunnable::run()
105107 << storageDir.absolutePath ();
106108
107109 // open the database
108- auto dbName = QStringLiteral (" database_migration_" ) + _defaults.setupName ();
109- auto db = QSqlDatabase::addDatabase (QStringLiteral (" SQLITE" ), dbName);
110- db.setDatabaseName (storageDir.absoluteFilePath (QStringLiteral (" store.db" )));
111- if (!db.open ())
112- dbError (db);
110+ QString dbName = QStringLiteral (" database_migration_" ) + _defaults.setupName ();
111+ auto db = QSqlDatabase::addDatabase (QStringLiteral (" QSQLITE" ), dbName);
112+ if (_flags.testFlag (MigrationHelper::MigrateData)) {
113+ db.setDatabaseName (storageDir.absoluteFilePath (QStringLiteral (" store.db" )));
114+ if (!db.open ())
115+ dbError (db);
116+ else {
117+ if (!db.tables ().contains (QStringLiteral (" DataIndex" )) ||
118+ !db.tables ().contains (QStringLiteral (" SyncState" ))) {
119+ logWarning () << " Missing tables in database. Either DataIndex or SyncState could not be found" ;
120+ cleanDb ();
121+ migrationDone (false );
122+ return ;
123+ } else
124+ logDebug () << " Successfully opened database" ;
125+ }
126+ }
113127
114128 // count the number of things to migrate
115- QSqlQuery countQuery (db);
116- countQuery.prepare (QStringLiteral (" SELECT Count(*) FROM DataIndex" ));
117- if (!countQuery.exec ())
118- dbError (countQuery);
119- if (!countQuery.first ())
120- dbError (countQuery);
121- auto migrationCount = countQuery.value (0 ).toInt ();
129+ int migrationCount = 0 ;
130+ if (_flags.testFlag (MigrationHelper::MigrateData)) {
131+ QSqlQuery countQuery (db);
132+ if (!countQuery.exec (QStringLiteral (" SELECT Count(*) FROM ("
133+ " SELECT i.Type AS Type, i.Key AS Key "
134+ " FROM DataIndex i "
135+ " LEFT JOIN SyncState s "
136+ " ON i.Type = s.Type AND i.Key = s.Key "
137+ " UNION "
138+ " SELECT s.Type AS Type, s.Key AS Key "
139+ " FROM SyncState s "
140+ " LEFT JOIN DataIndex i "
141+ " ON s.Type = i.Type AND s.Key = i.Key "
142+ " WHERE i.Type IS NULL "
143+ " )" )))
144+ dbError (countQuery);
145+ if (!countQuery.first ())
146+ dbError (countQuery);
147+ migrationCount = countQuery.value (0 ).toInt ();
148+ }
122149 if (_flags.testFlag (MigrationHelper::MigrateRemoteConfig))
123150 migrationCount++;
124151 if (migrationCount == 0 ) {
@@ -139,20 +166,20 @@ void MigrationRunnable::run()
139166
140167 // migrate key by key
141168 copyConf (oldSettings, QStringLiteral (" RemoteConnector/remoteEnabled" ),
142- currentSettings, QStringLiteral (" connector/enabled " ) );
169+ currentSettings, QStringLiteral (" connector/" ) + RemoteConnector::keyRemoteEnabled );
143170 copyConf (oldSettings, QStringLiteral (" RemoteConnector/remoteUrl" ),
144- currentSettings, QStringLiteral (" connector/remote/url " ) );
171+ currentSettings, QStringLiteral (" connector/" ) + RemoteConnector::keyRemoteUrl );
145172// copyConf(oldSettings, QStringLiteral("RemoteConnector/verifyPeer"),
146173// currentSettings, QStringLiteral("connector/remote/verifyPeer")); //TODO add?
147174 copyConf (oldSettings, QStringLiteral (" RemoteConnector/sharedSecret" ),
148- currentSettings, QStringLiteral (" connector/remote/accessKey " ) );
175+ currentSettings, QStringLiteral (" connector/" ) + RemoteConnector::keyRemoteAccessKey );
149176
150177 copyConf (oldSettings, QStringLiteral (" NetworkExchange/name" ),
151- currentSettings, QStringLiteral (" connector/remote/accessKey " ) );
178+ currentSettings, QStringLiteral (" connector/" ) + RemoteConnector::keyDeviceName );
152179
153180 // special: copy headers
154181 oldSettings->beginGroup (QStringLiteral (" RemoteConnector/headers" ));
155- currentSettings->beginGroup (QStringLiteral (" connector/deviceName " ) );
182+ currentSettings->beginGroup (QStringLiteral (" connector/" ) + RemoteConnector::keyRemoteHeaders );
156183 foreach (auto key, oldSettings->childKeys ()) {
157184 copyConf (oldSettings, key,
158185 currentSettings, key);
@@ -165,103 +192,120 @@ void MigrationRunnable::run()
165192 }
166193
167194 // next: migrate all the data step by step
168- LocalStore store (_defaults, &scope);
169- for (auto offset = 0 ; true ; offset += 1000 ) {
170- QSqlQuery entryQuery (db);
171- entryQuery.prepare (QStringLiteral (" SELECT DataIndex.Type, DataIndex.Key, File, Changed, SyncState.Type, SyncState.Key "
172- " FROM DataIndex "
173- " FULL OUTER JOIN SyncState "
174- " ON DataIndex.Type = SyncState.Type AND DataIndex.Key = SyncState.Key "
175- " ORDER BY DataIndex.Type, DataIndex.Key, SyncState.Type, SyncState.Key"
176- " LIMIT 1000 OFFSET ?" ));
177- entryQuery.addBindValue (offset);
178- if (!entryQuery.exec ())
179- dbError (entryQuery);
180-
181- if (!entryQuery.first ())
182- break ;
183- do {
184- // extract data
185- auto type = entryQuery.value (0 ).toByteArray ();
186- QString key = entryQuery.value (1 ).toString ();
187- if (type.isEmpty ()) {
188- type = entryQuery.value (4 ).toByteArray ();
189- key = entryQuery.value (5 ).toString ();
190- }
191- auto file = entryQuery.value (2 ).toString ();
192- auto state = entryQuery.value (3 ).toInt ();
193-
194- ObjectKey objKey (type, key);
195- switch (state) {
196- case 0 : // unchanged
197- if (!_flags.testFlag (MigrationHelper::MigrateChanged)) // when not migrating changes assume changed
198- state = 1 ;
199- Q_FALLTHROUGH ();
200- case 1 : // changed
201- {
202- // find the storage directory
203- auto tName = QString::fromUtf8 (" store/_" + QByteArray (type).toHex ());
204- auto mDir = storageDir;
205- if (!mDir .cd (tName)) {
206- logWarning () << " Failed to find file of stored data. Skipping"
207- << objKey;
208- continue ; // scope is the do-while loop
209- }
195+ if (_flags.testFlag (MigrationHelper::MigrateData)) {
196+ LocalStore store (_defaults, &scope);
197+ for (auto offset = 0 ; true ; offset += 100 ) {
198+ QSqlQuery entryQuery (db);
199+ if (!entryQuery.prepare (QStringLiteral (" SELECT Type, Key, File, Changed FROM ( "
200+ " SELECT i.Type AS Type, i.Key AS Key, i.File AS File, s.Changed AS Changed "
201+ " FROM DataIndex i "
202+ " LEFT JOIN SyncState s "
203+ " ON i.Type = s.Type AND i.Key = s.Key "
204+ " UNION "
205+ " SELECT s.Type AS Type, s.Key AS Key, i.File AS File, s.Changed AS Changed "
206+ " FROM SyncState s "
207+ " LEFT JOIN DataIndex i "
208+ " ON s.Type = i.Type AND s.Key = i.Key "
209+ " WHERE i.Type IS NULL "
210+ " ) ORDER BY Type, Key "
211+ " LIMIT 100 OFFSET ?" )))
212+ dbError (entryQuery);
213+ entryQuery.addBindValue (offset);
214+ if (!entryQuery.exec ())
215+ dbError (entryQuery);
216+
217+ if (!entryQuery.first ())
218+ break ;
219+ do {
220+ // extract data
221+ ObjectKey key {
222+ entryQuery.value (0 ).toByteArray (),
223+ entryQuery.value (1 ).toString ()
224+ };
225+ QString file = entryQuery.value (2 ).toString () + QStringLiteral (" .dat" );
226+ auto state = entryQuery.value (3 ).toInt ();
227+
228+ switch (state) {
229+ case 0 : // unchanged
230+ if (!_flags.testFlag (MigrationHelper::MigrateChanged)) // when not migrating changes assume changed
231+ state = 1 ;
232+ Q_FALLTHROUGH ();
233+ case 1 : // changed
234+ {
235+ // find the storage directory
236+ auto tName = QString::fromUtf8 (" store/_" + key.typeName .toHex ());
237+ auto mDir = storageDir;
238+ if (!mDir .cd (tName)) {
239+ logWarning () << " Failed to find file of stored data. Skipping"
240+ << key << " with missing path:" << tName;
241+ migrationProgress ();
242+ continue ; // scope is the do-while loop
243+ }
210244
211- // read the data file as json
212- QFile inFile (mDir .absoluteFilePath (file));
213- if (!inFile.open (QIODevice::ReadOnly)) {
214- logWarning ().noquote () << " Failed to open file of stored data. Skipping"
215- << objKey << " with file error:"
216- << inFile.errorString ();
217- continue ; // scope is the do-while loop
218- }
219- auto data = QJsonDocument::fromBinaryData (inFile.readAll ()).object ();
220- inFile.close ();
221- if (data.isEmpty ()) {
222- logWarning () << " Failed read file of stored data. Skipping"
223- << objKey;
224- continue ; // scope is the do-while loop
225- }
245+ // read the data file as json
246+ QFile inFile (mDir .absoluteFilePath (file));
247+ if (!inFile.exists ()) {
248+ logWarning () << " Failed to find file of stored data. Skipping"
249+ << key << " with missing path:" << inFile.fileName ();
250+ migrationProgress ();
251+ continue ; // scope is the do-while loop
252+ }
253+ if (!inFile.open (QIODevice::ReadOnly)) {
254+ logWarning ().noquote () << " Failed to open file of stored data. Skipping"
255+ << key << " with file error:"
256+ << inFile.errorString ();
257+ migrationProgress ();
258+ continue ; // scope is the do-while loop
259+ }
260+ auto data = QJsonDocument::fromBinaryData (inFile.readAll ()).object ();
261+ inFile.close ();
262+ if (data.isEmpty ()) {
263+ logWarning () << " Failed read file of stored data. Skipping"
264+ << key;
265+ migrationProgress ();
266+ continue ; // scope is the do-while loop
267+ }
226268
227- // store in the store...
228- auto scope = store.startSync (objKey);
229- LocalStore::ChangeType type;
230- quint64 version;
231- QString fileName;
232- tie (type, version, fileName, std::ignore) = store.loadChangeInfo (scope);
233- if (type != LocalStore::NoExists && !_flags.testFlag (MigrationHelper::MigrateOverwriteData)) {
234- logDebug () << " Skipping" << objKey << " as it would overwrite existing data" ;
235- continue ;
236- }
237- store.storeChanged (scope, version + 1 , fileName, data, state == 1 , type);
238- store.commitSync (scope);
239- logDebug () << " Migrated dataset" << objKey << " from the old store to the new one" ;
240- break ;
241- }
242- case 2 : // deleted
243- if (_flags.testFlag (MigrationHelper::MigrateChanged)) {
244- // only when migrating changes, store the delete change
245- auto scope = store.startSync (objKey);
269+ // store in the store...
270+ auto scope = store.startSync (key);
246271 LocalStore::ChangeType type;
247272 quint64 version;
248- tie (type, version, std::ignore, std::ignore) = store.loadChangeInfo (scope);
273+ QString fileName;
274+ tie (type, version, fileName, std::ignore) = store.loadChangeInfo (scope);
249275 if (type != LocalStore::NoExists && !_flags.testFlag (MigrationHelper::MigrateOverwriteData)) {
250- logDebug () << " Skipping" << objKey << " as it would overwrite existing data" ;
276+ logDebug () << " Skipping" << key << " as it would overwrite existing data" ;
277+ migrationProgress ();
251278 continue ;
252279 }
253- store.storeDeleted (scope, version, true , type);
280+ store.storeChanged (scope, version + 1 , fileName, data, state == 1 , type);
254281 store.commitSync (scope);
255- logDebug () << " Migrated deleted dataset" << objKey << " from the old store to the new one" ;
282+ logDebug () << " Migrated dataset" << key << " from the old store to the new one" ;
283+ migrationProgress ();
256284 break ;
257285 }
258- break ;
259- default :
260- Q_UNREACHABLE ();
261- }
262-
263- migrationProgress ();
264- } while (entryQuery.next ());
286+ case 2 : // deleted
287+ if (_flags.testFlag (MigrationHelper::MigrateChanged)) {
288+ // only when migrating changes, store the delete change
289+ auto scope = store.startSync (key);
290+ LocalStore::ChangeType type;
291+ quint64 version;
292+ tie (type, version, std::ignore, std::ignore) = store.loadChangeInfo (scope);
293+ if (type != LocalStore::NoExists && !_flags.testFlag (MigrationHelper::MigrateOverwriteData)) {
294+ logDebug () << " Skipping" << key << " as it would overwrite existing data" ;
295+ migrationProgress ();
296+ continue ;
297+ }
298+ store.storeDeleted (scope, version + 1 , true , type);
299+ store.commitSync (scope);
300+ logDebug () << " Migrated deleted dataset" << key << " from the old store to the new one" ;
301+ }
302+ migrationProgress ();
303+ break ;
304+ default :
305+ Q_UNREACHABLE ();
306+ }
307+ } while (entryQuery.next ());
308+ }
265309 }
266310
267311 // cleanup merge
@@ -304,5 +348,8 @@ void MigrationRunnable::copyConf(QSettings *old, const QString &oldKey, QSetting
304348 current->setValue (newKey, old->value (oldKey));
305349 logDebug ().noquote () << " Migrated old settings" << QString (old->group () + QLatin1Char (' /' ) + oldKey)
306350 << " to new settings as" << QString (current->group () + QLatin1Char (' /' ) + newKey);
351+ } else {
352+ logDebug ().noquote () << " Skipping migration of key" << QString (old->group () + QLatin1Char (' /' ) + oldKey)
353+ << " to new settings as" << QString (current->group () + QLatin1Char (' /' ) + newKey);
307354 }
308355}
0 commit comments