Use fileMigrationDB for verifying if file needs update

This commit is contained in:
Neeraj Gupta 2022-08-05 16:39:56 +05:30
parent dfa761ae42
commit 4d0059df29
No known key found for this signature in database
GPG key ID: 3C5A1684DC1729E1
4 changed files with 101 additions and 47 deletions

View file

@ -107,15 +107,20 @@ class FilesMigrationDB {
}
Future<int> deleteByLocalIDs(List<String> localIDs) async {
if (localIDs.isEmpty) {
return -1;
}
String inParam = "";
for (final localID in localIDs) {
inParam += "'" + localID + "',";
}
inParam = inParam.substring(0, inParam.length - 1);
final db = await instance.database;
return await db.delete(
tableName,
where: '$_columnLocalID IN (${localIDs.join(', ')})',
db.rawQuery(
'''
DELETE FROM $tableName
WHERE $_columnLocalID IN ($inParam);
''',
);
}
@ -124,9 +129,9 @@ class FilesMigrationDB {
String reason,
) async {
final db = await instance.database;
String whereClause = '$_columnReason = $reason';
if (_columnReason == missingLocation) {
whereClause = '($_columnReason = $reason OR $_columnReason IS NULL';
String whereClause = '$_columnReason = "$reason"';
if (reason == missingLocation) {
whereClause = '($_columnReason = "$reason" OR $_columnReason IS NULL)';
}
final rows = await db.query(
tableName,

View file

@ -6,6 +6,7 @@ import 'package:logging/logging.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:photos/db/file_migration_db.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/utils/file_uploader_util.dart';
import 'package:shared_preferences/shared_preferences.dart';
// LocalFileUpdateService tracks all the potential local file IDs which have
@ -52,6 +53,7 @@ class LocalFileUpdateService {
_logger.info("start migration for missing location");
await _runMigrationForFilesWithMissingLocation();
}
await _markFilesWhichAreActuallyUpdated();
_existingMigration.complete();
_existingMigration = null;
} catch (e, s) {
@ -61,6 +63,82 @@ class LocalFileUpdateService {
}
}
// This method analyses all of local files for which the file
// modification/update time was changed. It checks if the existing fileHash
// is different from the hash of uploaded file. If fileHash are different,
// then it marks the file for file update.
Future<void> _markFilesWhichAreActuallyUpdated() async {
final sTime = DateTime.now().microsecondsSinceEpoch;
bool hasData = true;
const int limitInBatch = 100;
while (hasData) {
var localIDsToProcess =
await _filesMigrationDB.getLocalIDsForPotentialReUpload(
limitInBatch,
FilesMigrationDB.modificationTimeUpdated,
);
if (localIDsToProcess.isEmpty) {
hasData = false;
} else {
await _checkAndMarkFilesWithDifferentHashForFileUpdate(
localIDsToProcess,
);
}
}
final eTime = DateTime.now().microsecondsSinceEpoch;
final d = Duration(microseconds: eTime - sTime);
_logger.info(
'_markFilesWhichAreActuallyUpdated migration completed in ${d.inSeconds.toString()} seconds',
);
}
Future<void> _checkAndMarkFilesWithDifferentHashForFileUpdate(
List<String> localIDsToProcess,
) async {
_logger.info("files to process ${localIDsToProcess.length}");
var localFiles = await FilesDB.instance.getLocalFiles(localIDsToProcess);
Set<String> processedIDs = {};
for (var file in localFiles) {
if (processedIDs.contains(file.localID)) {
continue;
}
MediaUploadData uploadData;
try {
uploadData = await getUploadDataFromEnteFile(file);
if (file.hash != null ||
(file.hash == uploadData.fileHash ||
file.hash == uploadData.zipHash)) {
_logger.info("Skip file update as hash matched ${file.tag()}");
} else {
_logger.info(
"Marking for file update as hash did not match ${file.tag()}",
);
await FilesDB.instance.updateUploadedFile(
file.localID,
file.title,
file.location,
file.creationTime,
file.modificationTime,
null,
);
}
processedIDs.add(file.localID);
} catch (e) {
_logger.severe("Failed to get file uploadData", e);
} finally {
// delete the file from app's internal cache if it was copied to app
// for upload. Shared Media should only be cleared when the upload
// succeeds.
if (Platform.isIOS &&
uploadData != null &&
uploadData.sourceFile != null) {
await uploadData.sourceFile.delete();
}
}
}
await _filesMigrationDB.deleteByLocalIDs(processedIDs.toList());
}
Future<void> _runMigrationForFilesWithMissingLocation() async {
if (!Platform.isAndroid) {
return;
@ -82,7 +160,7 @@ class LocalFileUpdateService {
if (localIDsToProcess.isEmpty) {
hasData = false;
} else {
await _checkAndMarkFilesForReUpload(localIDsToProcess);
await _checkAndMarkFilesWithLocationForReUpload(localIDsToProcess);
}
}
final eTime = DateTime.now().microsecondsSinceEpoch;
@ -94,7 +172,7 @@ class LocalFileUpdateService {
await _markLocationMigrationAsCompleted();
}
Future<void> _checkAndMarkFilesForReUpload(
Future<void> _checkAndMarkFilesWithLocationForReUpload(
List<String> localIDsToProcess,
) async {
_logger.info("files to process ${localIDsToProcess.length}");

View file

@ -6,6 +6,7 @@ import 'package:logging/logging.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/db/file_migration_db.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/events/local_photos_updated_event.dart';
import 'package:photos/events/sync_status_update_event.dart';
@ -244,17 +245,15 @@ class LocalSyncService {
updatedFiles.length.toString() + " local files were updated.",
);
}
List<String> updatedLocalIDs = [];
for (final file in updatedFiles) {
await captureUpdateLogs(file);
await _db.updateUploadedFile(
file.localID,
file.title,
file.location,
file.creationTime,
file.modificationTime,
null,
);
if (file.localID != null) {
updatedLocalIDs.add(file.localID);
}
}
FilesMigrationDB.instance.insertMultiple(updatedLocalIDs,
reason: FilesMigrationDB.modificationTimeUpdated);
final List<File> allFiles = [];
allFiles.addAll(files);
files.removeWhere((file) => existingLocalFileIDs.contains(file.localID));
@ -266,32 +265,6 @@ class LocalSyncService {
await _prefs.setInt(kDbUpdationTimeKey, toTime);
}
// _captureUpdateLogs is a helper method to log details
// about the file which is being marked for re-upload
Future<void> captureUpdateLogs(File file) async {
_logger.info(
're-upload locally updated file ${file.toString()}',
);
try {
if (Platform.isIOS) {
var assetEntity = await AssetEntity.fromId(file.localID);
if (assetEntity != null) {
var isLocallyAvailable =
await assetEntity.isLocallyAvailable(isOrigin: true);
_logger.info(
're-upload asset ${file.toString()} with localAvailableFlag '
'$isLocallyAvailable and fav ${assetEntity.isFavorite}',
);
} else {
_logger
.info('re-upload failed to fetch assetInfo ${file.toString()}');
}
}
} catch (ignore) {
//ignore
}
}
void _updatePathsToBackup(List<File> files) {
if (Configuration.instance.hasSelectedAllFoldersForBackup()) {
final pathsToBackup = Configuration.instance.getPathsToBackUp();

View file

@ -16,7 +16,6 @@ import 'package:photos/models/file.dart';
import 'package:photos/models/file_type.dart';
import 'package:photos/services/app_lifecycle_service.dart';
import 'package:photos/services/collections_service.dart';
import 'package:photos/services/feature_flag_service.dart';
import 'package:photos/services/ignored_files_service.dart';
import 'package:photos/services/local_file_update_service.dart';
import 'package:photos/services/local_sync_service.dart';
@ -134,9 +133,8 @@ class RemoteSyncService {
if (!_hasReSynced()) {
await _markReSyncAsDone();
}
if (FeatureFlagService.instance.enableMissingLocationMigration()) {
_localFileUpdateService.markUpdatedFilesForReUpload();
}
unawaited(_localFileUpdateService.markUpdatedFilesForReUpload());
}
Future<void> _syncUpdatedCollections(bool silently) async {