-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
BugFix - Track File Upload Index #14822
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt
Outdated
Show resolved
Hide resolved
9bab4d3 to
162560c
Compare
10d07bf to
2b18be9
Compare
2b18be9 to
9536f4a
Compare
|
During my recent testing, I found an issue with the use of Example scenario Consider a user with a folder structure where folder A contains 101 files, including a subfolder named inner_folder which also contains 101 files. If the user selects all files in folder A except the inner_folder and initiates an upload, the first Using an external counter to track the number of uploads does not resolve this issue as well, since the counter increments based on the inaccurate item count retrieved from the same function. Changes The The following tests need to be done
Please compare these changes against the master branch to identify which aspects are within the current scope and which are not. Demo: test_fuw.mp4 |
360799b to
bb9840b
Compare
| public OCUpload[] getCurrentUploadsForAccount(final @NonNull String accountName) { | ||
| return getUploads(ProviderTableMeta.UPLOADS_STATUS + EQUAL + UploadStatus.UPLOAD_IN_PROGRESS.value + AND + | ||
| ProviderTableMeta.UPLOADS_ACCOUNT_NAME + IS_EQUAL, accountName); | ||
| public long[] getCurrentUploadIds(final @NonNull String accountName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The OCUpload class is a wrapper around the UploadEntity data class and it is redundant. A similar redundancy exists between OCFile and FileEntity. These entity data classes can be used directly and can have helper methods.
The getCurrentUploadsForAccountPageAscById and getCurrentUploadsForAccount functions currently uses the ContentResolver to obtain a cursor, which is then mapped to OCUpload objects an unnecessary step. Instead, current uploads can be fetched directly from the Room database via DAO methods.
As a result, the getCurrentUploadsForAccountPageAscById and getCurrentUploadsForAccount functions become obsolete and should no longer be used.
Demo
faf9.mp4
| " ) AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + IS_EQUAL; | ||
| } | ||
|
|
||
| public int getTotalUploadSize(@Nullable String... selectionArgs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused function
55ebde7 to
963cfcb
Compare
f1673a1 to
36b391d
Compare
app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt
Outdated
Show resolved
Hide resolved
| val tag = startFileUploadJobTag(user) + Random.nextLong() | ||
| val dataBuilder = Data.Builder() | ||
| .putString(FileUploadWorker.ACCOUNT, user.accountName) | ||
| .putLongArray(FileUploadWorker.UPLOAD_IDS, uploadIds) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not passs uploadIs, but instead access data inside worker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In all cases, uploadIds are not directly accessible via the account name. For example:
FileUploadHelper.retryUploadsreceives afailedUploads: Array<OCUpload>parameter, where the failed uploads originate fromUploadsStorageManager.FileUploadHelper.uploadNewFilesmaps thelocalPathsparameter passed from eight different classes to createOCUploadinstances. Therefore, this process cannot be handled directly within the worker.FileUploadHelper.cancelFileUploadstakes auploads: List<OCUpload>argument, which is provided by various classes, making it unsuitable for direct handling inside the worker.FileUploadHelper.uploadUpdatedFileuses theexistingFilesparameter to generateOCUploadobjects through mapping, which similarly cannot be managed directly within the worker.
| Log_OC.d(TAG, "Total upload size: $totalUploadSize") | ||
|
|
||
| while (uploadsPerPage.isNotEmpty() && !isStopped) { | ||
| for ((index, upload) in uploads.withIndex()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inside loop check if upload still is pending in uploadsStorageManager
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UPLOAD_IN_PROGRESS (to see checkpublic enum UploadStatus description) represents both scheduled and currently uploading files, which makes it unsuitable for filtering within the loop without unintentionally skipping valid uploads. When I tried using the following SQL command, I wasn’t able to upload any files because it represents both scheduled and in-progress uploads.
@Query(
"SELECT EXISTS(" +
"SELECT 1 FROM " + ProviderTableMeta.UPLOADS_TABLE_NAME +
" WHERE " + ProviderTableMeta._ID + " = :id AND " +
ProviderTableMeta.UPLOADS_ACCOUNT_NAME + " = :accountName AND " +
ProviderTableMeta.UPLOADS_STATUS + " = :pendingStatus" +
")"
)
fun isPendingUpload(
id: Int,
accountName: String,
pendingStatus: Int = UploadStatus.UPLOAD_IN_PROGRESS.value
): Boolean
Solutions:
Introducing a new status (e.g., UPLOAD_PROCESSING_NOW) would require significant changes to the existing codebase, affecting multiple classes.
In-memory tracking (storing a set of upload IDs currently being processed to prevent re-processing them in the same run) is also unreliable because if the worker restarts unexpectedly (for example, due to system resource constraints or OS killing background tasks), this in-memory state is lost, leading to possible duplicate uploads.
Based on current testing, the worker executes uploads sequentially without any issues. If a user tries to upload the same files, no conflict resolve notification appears, just like in the master branch. If the file name is the same, but the content has changed, the conflict resolve notification appears, consistent with the master branch behavior.
I suggest addressing this in a separate PR.
Demo:
Screen.Recording.2025-06-27.at.11.50.48.mp4
tobiasKaminsky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see inline
36b391d to
5255e52
Compare
f363bcd to
595afb2
Compare
…ctivity.java Co-authored-by: Tom <70907959+ZetaTom@users.noreply.github.com> Signed-off-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
…oesnt picks folder or files manually Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
Signed-off-by: alperozturk <alper_ozturk@proton.me>
96f9380 to
0a35102
Compare
|
APK file: https://www.kaminsky.me/nc-dev/android-artifacts/14822.apk |
|
Ah, I was under the impression that percentage is about how many files, not file transfer of one file. |
| } | ||
| val user = userAccountManager.getUser(accountName) | ||
| if (!user.isPresent) { | ||
| uploadsStorageManager.removeUpload(upload.uploadId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this mean to remove uploads that are not for the currently active user? (see #15320)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, thanks for the message.
Get the account that wants to upload the file. If that user is not available, remove the upload that belongs to the same user from the queue, just like before.
What do you think? How does this change affect the issue you linked to, it is same as before?
Maybe we can find the root cause of the issue please share your thoughts, thanks.


Problem
Currently, the logic implemented in FileUploadWorker processes file uploads in discrete batches, which limits our ability to track the overall upload progress accurately and total upload index is wrong. We have outer while loop to update uploads and inner for loop for uploads.
For example, when a user attempts to upload 164 files:
How to reproduce?
Solution
Demo
ddd.mp4