Only cache a dir after its children are synced and cached

This commit is contained in:
Ming Ming 2022-12-08 00:54:47 +08:00
parent d5d69144de
commit a3d3c6c375
2 changed files with 77 additions and 16 deletions

View file

@ -568,6 +568,22 @@ class FileSqliteDbDataSource implements FileDataSource {
static final _log = Logger("entity.file.data_source.FileSqliteDbDataSource"); static final _log = Logger("entity.file.data_source.FileSqliteDbDataSource");
} }
class IntermediateSyncState {
const IntermediateSyncState({
required this.account,
required this.dir,
required this.remoteTouchEtag,
required this.files,
required this.shouldCache,
});
final Account account;
final File dir;
final String? remoteTouchEtag;
final List<File> files;
final bool shouldCache;
}
class FileCachedDataSource implements FileDataSource { class FileCachedDataSource implements FileDataSource {
FileCachedDataSource( FileCachedDataSource(
this._c, { this._c, {
@ -598,21 +614,29 @@ class FileCachedDataSource implements FileDataSource {
Account account, Account account,
File dir, { File dir, {
required String? remoteTouchEtag, required String? remoteTouchEtag,
}) async {
final state = await beginSync(
account,
dir,
remoteTouchEtag: remoteTouchEtag,
);
return concludeSync(state);
}
Future<IntermediateSyncState> beginSync(
Account account,
File dir, {
required String? remoteTouchEtag,
}) async { }) async {
try { try {
final remote = await _remoteSrc.list(account, dir); final remote = await _remoteSrc.list(account, dir);
await FileSqliteCacheUpdater(_c)(account, dir, remote: remote); return IntermediateSyncState(
if (shouldCheckCache) { account: account,
// update our local touch token to match the remote one dir: dir,
try { remoteTouchEtag: remoteTouchEtag,
_log.info("[list] Update outdated local etag: ${dir.path}"); files: remote,
await _c.touchManager.setLocalEtag(account, dir, remoteTouchEtag); shouldCache: true,
} catch (e, stacktrace) { );
_log.shout("[list] Failed while setLocalToken", e, stacktrace);
// ignore error
}
}
return remote;
} on ApiException catch (e) { } on ApiException catch (e) {
if (e.response.statusCode == 404) { if (e.response.statusCode == 404) {
_log.info("[list] File removed: $dir"); _log.info("[list] File removed: $dir");
@ -622,7 +646,13 @@ class FileCachedDataSource implements FileDataSource {
_log.warning( _log.warning(
"[list] Failed while remove from db, file not cached?", e); "[list] Failed while remove from db, file not cached?", e);
} }
return []; return IntermediateSyncState(
account: account,
dir: dir,
remoteTouchEtag: remoteTouchEtag,
files: [],
shouldCache: false,
);
} else if (e.response.statusCode == 403) { } else if (e.response.statusCode == 403) {
_log.info("[list] E2E encrypted dir: $dir"); _log.info("[list] E2E encrypted dir: $dir");
try { try {
@ -633,13 +663,40 @@ class FileCachedDataSource implements FileDataSource {
_log.warning( _log.warning(
"[list] Failed while emptying from db, file not cached?", e); "[list] Failed while emptying from db, file not cached?", e);
} }
return []; return IntermediateSyncState(
account: account,
dir: dir,
remoteTouchEtag: remoteTouchEtag,
files: [],
shouldCache: false,
);
} else { } else {
rethrow; rethrow;
} }
} }
} }
Future<List<File>> concludeSync(IntermediateSyncState state) async {
if (!state.shouldCache) {
return state.files;
}
await FileSqliteCacheUpdater(_c)(state.account, state.dir,
remote: state.files);
if (shouldCheckCache) {
// update our local touch token to match the remote one
try {
_log.info("[list] Update outdated local etag: ${state.dir.path}");
await _c.touchManager
.setLocalEtag(state.account, state.dir, state.remoteTouchEtag);
} catch (e, stacktrace) {
_log.shout("[list] Failed while setLocalToken", e, stacktrace);
// ignore error
}
}
return state.files;
}
@override @override
listSingle(Account account, File f) async { listSingle(Account account, File f) async {
final remote = await _remoteSrc.listSingle(account, f); final remote = await _remoteSrc.listSingle(account, f);

View file

@ -56,9 +56,12 @@ class SyncDir {
} }
_log.info("[_syncDir] Dir changed: ${remoteDir.path}"); _log.info("[_syncDir] Dir changed: ${remoteDir.path}");
final children = await FileCachedDataSource(_c, shouldCheckCache: true) final dataSrc = FileCachedDataSource(_c, shouldCheckCache: true);
.sync(account, remoteDir, remoteTouchEtag: status.item2); final syncState = await dataSrc.beginSync(account, remoteDir,
remoteTouchEtag: status.item2);
final children = syncState.files;
if (!isRecursive) { if (!isRecursive) {
await dataSrc.concludeSync(syncState);
return true; return true;
} }
final subDirs = children final subDirs = children
@ -88,6 +91,7 @@ class SyncDir {
} }
progress.next(); progress.next();
} }
await dataSrc.concludeSync(syncState);
return true; return true;
} }