use of com.ichi2.libanki.Collection.CheckDatabaseResult in project AnkiChinaAndroid by ankichinateam.
the class Collection method fixIntegrity.
/**
* Fix possible problems and rebuild caches.
*/
public CheckDatabaseResult fixIntegrity(CollectionTask.ProgressCallback progressCallback) {
File file = new File(mPath);
CheckDatabaseResult result = new CheckDatabaseResult(file.length());
final int[] currentTask = { 1 };
// a few fixes are in all-models loops, the rest are one-offs
int totalTasks = (getModels().all().size() * 4) + 27;
Runnable notifyProgress = progressCallback == null ? null : () -> fixIntegrityProgress(progressCallback, currentTask[0]++, totalTasks);
FunctionalInterfaces.Consumer<FunctionalInterfaces.FunctionThrowable<Runnable, List<String>, JSONException>> executeIntegrityTask = (FunctionalInterfaces.FunctionThrowable<Runnable, List<String>, JSONException> function) -> {
// DEFECT: notifyProgress will lag if an exception is thrown.
try {
mDb.getDatabase().beginTransaction();
if (notifyProgress != null)
result.addAll(function.apply(notifyProgress));
mDb.getDatabase().setTransactionSuccessful();
} catch (Exception e) {
Timber.e(e, "Failed to execute integrity check");
AnkiDroidApp.sendExceptionReport(e, "fixIntegrity");
} finally {
try {
mDb.getDatabase().endTransaction();
} catch (Exception e) {
Timber.e(e, "Failed to end integrity check transaction");
AnkiDroidApp.sendExceptionReport(e, "fixIntegrity - endTransaction");
}
}
};
try {
mDb.getDatabase().beginTransaction();
save();
notifyProgress.run();
if (!mDb.getDatabase().isDatabaseIntegrityOk()) {
return result.markAsFailed();
}
mDb.getDatabase().setTransactionSuccessful();
} catch (SQLiteDatabaseLockedException ex) {
Timber.e("doInBackgroundCheckDatabase - Database locked");
return result.markAsLocked();
} catch (RuntimeException e) {
Timber.e(e, "doInBackgroundCheckDatabase - RuntimeException on marking card");
AnkiDroidApp.sendExceptionReport(e, "doInBackgroundCheckDatabase");
return result.markAsFailed();
} finally {
// if the database was locked, we never got the transaction.
if (mDb.getDatabase().inTransaction()) {
mDb.getDatabase().endTransaction();
}
}
executeIntegrityTask.consume(this::deleteNotesWithMissingModel);
// for each model
for (JSONObject m : getModels().all()) {
executeIntegrityTask.consume((callback) -> deleteCardsWithInvalidModelOrdinals(callback, m));
executeIntegrityTask.consume((callback) -> deleteNotesWithWrongFieldCounts(callback, m));
}
executeIntegrityTask.consume(this::deleteNotesWithMissingCards);
executeIntegrityTask.consume(this::deleteCardsWithMissingNotes);
executeIntegrityTask.consume(this::removeOriginalDuePropertyWhereInvalid);
executeIntegrityTask.consume(this::removeDynamicPropertyFromNonDynamicDecks);
executeIntegrityTask.consume(this::removeDeckOptionsFromDynamicDecks);
executeIntegrityTask.consume(this::resetInvalidDeckOptions);
executeIntegrityTask.consume(this::rebuildTags);
executeIntegrityTask.consume(this::updateFieldCache);
executeIntegrityTask.consume(this::fixNewCardDuePositionOverflow);
executeIntegrityTask.consume(this::resetNewCardInsertionPosition);
executeIntegrityTask.consume(this::fixExcessiveReviewDueDates);
// v2 sched had a bug that could create decimal intervals
executeIntegrityTask.consume(this::fixDecimalCardsData);
executeIntegrityTask.consume(this::fixDecimalRevLogData);
executeIntegrityTask.consume(this::restoreMissingDatabaseIndices);
executeIntegrityTask.consume(this::ensureModelsAreNotEmpty);
executeIntegrityTask.consume((progressNotifier) -> this.ensureCardsHaveHomeDeck(progressNotifier, result));
// and finally, optimize (unable to be done inside transaction).
try {
optimize(notifyProgress);
} catch (Exception e) {
Timber.e(e, "optimize");
AnkiDroidApp.sendExceptionReport(e, "fixIntegrity - optimize");
}
file = new File(mPath);
long newSize = file.length();
result.setNewSize(newSize);
// if any problems were found, force a full sync
if (result.hasProblems()) {
modSchemaNoCheck();
}
logProblems(result.getProblems());
return result;
}
use of com.ichi2.libanki.Collection.CheckDatabaseResult in project Anki-Android by ankidroid.
the class DeckPickerCheckDatabaseListenerTest method validResultWithFailedDatabaseWillShowFailedDialog.
@Test
public void validResultWithFailedDatabaseWillShowFailedDialog() {
CheckDatabaseResult failedDb = failedDatabase();
Pair<Boolean, Collection.CheckDatabaseResult> result = validResultWithData(failedDb);
execute(result);
assertThat("Load Failed dialog should be shown if failed data is supplied", mImpl.didDisplayDialogLoadFailed());
assertThat("Locked Database dialog should be shown if Db was locked", !mImpl.didDisplayLockedDialog());
assertThat("Dialog should not be displayed", !mImpl.didDisplayMessage());
}
use of com.ichi2.libanki.Collection.CheckDatabaseResult in project Anki-Android by ankidroid.
the class DeckPickerCheckDatabaseListenerTest method failedResultWithEmptyDataWillDisplayFailedDialog.
@Test
public void failedResultWithEmptyDataWillDisplayFailedDialog() {
CheckDatabaseResult validData = validData();
Pair<Boolean, Collection.CheckDatabaseResult> result = failedResultWithData(validData);
execute(result);
assertThat("Load Failed dialog should be shown if empty data is supplied", mImpl.didDisplayDialogLoadFailed());
}
use of com.ichi2.libanki.Collection.CheckDatabaseResult in project Anki-Android by ankidroid.
the class Collection method fixIntegrity.
/**
* Fix possible problems and rebuild caches.
*/
public CheckDatabaseResult fixIntegrity(TaskManager.ProgressCallback<String> progressCallback) {
File file = new File(mPath);
CheckDatabaseResult result = new CheckDatabaseResult(file.length());
final int[] currentTask = { 1 };
// a few fixes are in all-models loops, the rest are one-offs
int totalTasks = (getModels().all().size() * 4) + 27;
Runnable notifyProgress = () -> fixIntegrityProgress(progressCallback, currentTask[0]++, totalTasks);
Consumer<FunctionalInterfaces.FunctionThrowable<Runnable, List<String>, JSONException>> executeIntegrityTask = function -> {
// DEFECT: notifyProgress will lag if an exception is thrown.
try {
mDb.getDatabase().beginTransaction();
result.addAll(function.apply(notifyProgress));
mDb.getDatabase().setTransactionSuccessful();
} catch (Exception e) {
Timber.e(e, "Failed to execute integrity check");
AnkiDroidApp.sendExceptionReport(e, "fixIntegrity");
} finally {
try {
mDb.getDatabase().endTransaction();
} catch (Exception e) {
Timber.e(e, "Failed to end integrity check transaction");
AnkiDroidApp.sendExceptionReport(e, "fixIntegrity - endTransaction");
}
}
};
try {
mDb.getDatabase().beginTransaction();
save();
notifyProgress.run();
if (!mDb.getDatabase().isDatabaseIntegrityOk()) {
return result.markAsFailed();
}
mDb.getDatabase().setTransactionSuccessful();
} catch (SQLiteDatabaseLockedException ex) {
Timber.w(ex, "doInBackgroundCheckDatabase - Database locked");
return result.markAsLocked();
} catch (RuntimeException e) {
Timber.e(e, "doInBackgroundCheckDatabase - RuntimeException on marking card");
AnkiDroidApp.sendExceptionReport(e, "doInBackgroundCheckDatabase");
return result.markAsFailed();
} finally {
// if the database was locked, we never got the transaction.
if (mDb.getDatabase().inTransaction()) {
mDb.getDatabase().endTransaction();
}
}
executeIntegrityTask.accept(this::deleteNotesWithMissingModel);
// for each model
for (Model m : getModels().all()) {
executeIntegrityTask.accept((callback) -> deleteCardsWithInvalidModelOrdinals(callback, m));
executeIntegrityTask.accept((callback) -> deleteNotesWithWrongFieldCounts(callback, m));
}
executeIntegrityTask.accept(this::deleteNotesWithMissingCards);
executeIntegrityTask.accept(this::deleteCardsWithMissingNotes);
executeIntegrityTask.accept(this::removeOriginalDuePropertyWhereInvalid);
executeIntegrityTask.accept(this::removeDynamicPropertyFromNonDynamicDecks);
executeIntegrityTask.accept(this::removeDeckOptionsFromDynamicDecks);
executeIntegrityTask.accept(this::resetInvalidDeckOptions);
executeIntegrityTask.accept(this::rebuildTags);
executeIntegrityTask.accept(this::updateFieldCache);
executeIntegrityTask.accept(this::fixNewCardDuePositionOverflow);
executeIntegrityTask.accept(this::resetNewCardInsertionPosition);
executeIntegrityTask.accept(this::fixExcessiveReviewDueDates);
// v2 sched had a bug that could create decimal intervals
executeIntegrityTask.accept(this::fixDecimalCardsData);
executeIntegrityTask.accept(this::fixDecimalRevLogData);
executeIntegrityTask.accept(this::restoreMissingDatabaseIndices);
executeIntegrityTask.accept(this::ensureModelsAreNotEmpty);
executeIntegrityTask.accept((progressNotifier) -> this.ensureCardsHaveHomeDeck(progressNotifier, result));
// and finally, optimize (unable to be done inside transaction).
try {
optimize(notifyProgress);
} catch (Exception e) {
Timber.e(e, "optimize");
AnkiDroidApp.sendExceptionReport(e, "fixIntegrity - optimize");
}
file = new File(mPath);
long newSize = file.length();
result.setNewSize(newSize);
// if any problems were found, force a full sync
if (result.hasProblems()) {
modSchemaNoCheck();
}
logProblems(result.getProblems());
return result;
}
Aggregations