Skip to content
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

Optimization for very slow processing after downloading folder content #5150

Open
wants to merge 26 commits into
base: master
Choose a base branch
from

Conversation

JorisBodin
Copy link
Member

@JorisBodin JorisBodin commented Jan 10, 2020

Hello,

Fixes #5086

My tests were performed with a folder of 1044 files and Galaxy S8

Benchmark
On master:
Insert (first download):
50 seconds.

Update (refresh):
20 seconds

With this pull request:
Insert:
20 seconds

Update:
6 seconds

There are still 2 things to improve
First, the doubleCheck in FileContentProvider:
image

This check is here because saveFolder (in FileDataStorageManager) is sometimes called twice for an insert.
I've found two cases where that happens, one of which is simple to fix.
The first time the application is started, the WRITE_EXTERNAL_STORAGE permission is requested. When the user accepts, syncAndUpdateFolder is called in onResume and in onRequestPermissionsResult.
Delete syncAndUpdateFolder in onRequestPermissionsResult is solution.

Also the first time the application is started, if refreshing the folder, syncAndUpdateFolder is called twice

The solution would be to block the simultaneous call of saveFolder.

Benchmark
If doubleCheck is removed:
Insert (first download):
13 seconds.

Update (refresh):
6 seconds

The other thing to improve is this check #4647
(It is discussed in #5086)
I haven't found an optimization solution for this case. 😞

Benchmark
But if we remove it
Insert (first download):
1 seconds.

Update (refresh):
5 seconds

I also took the time to refactor the FileDataStorageManager class, I have removed the inconsistencies and duplications that have accumulated since the beginning. 2298 lines to 1887 lines
It allowed me to better understand the code and better optimize it.

Next week, we're thinking of coming to hackweek in Berlin. Will you be there?

Signed-off-by: Joris Bodin <[email protected]>
Signed-off-by: Joris Bodin <[email protected]>
Signed-off-by: Joris Bodin <[email protected]>
avg 15s to 0.2s for 900 new files !
Remove unnecessary double check and very old method not used (since 2015)

Signed-off-by: Joris Bodin <[email protected]>
Before avg 6s (for avg new 1000 files) now 0.2s with applyBatch

Signed-off-by: Joris Bodin <[email protected]>
And readd localFile = mStorageManager.getFileByPath(updatedFile.getRemotePath());
And optimize insert virtualFile

Signed-off-by: Joris Bodin <[email protected]>
Rename file to ocFile for OCFile object to avoid ambiguity with the objects of type File
Remove unUsed variable != null (i check method caller)
Add != null is necessary
Rename to camelCase
Consistency in the code

Signed-off-by: Joris Bodin <[email protected]>
Signed-off-by: Joris Bodin <[email protected]>
Signed-off-by: Joris Bodin <[email protected]>
Signed-off-by: Joris Bodin <[email protected]>
Signed-off-by: Joris Bodin <[email protected]>
Signed-off-by: Joris Bodin <[email protected]>
@codecov
Copy link

codecov bot commented Jan 10, 2020

Codecov Report

❗ No coverage uploaded for pull request base (master@2a01aca). Click here to learn what that means.
The diff coverage is n/a.

@@            Coverage Diff            @@
##             master    #5150   +/-   ##
=========================================
  Coverage          ?   18.71%           
  Complexity        ?        3           
=========================================
  Files             ?      392           
  Lines             ?    34273           
  Branches          ?     5011           
=========================================
  Hits              ?     6414           
  Misses            ?    26863           
  Partials          ?      996

@nextcloud-android-bot
Copy link
Collaborator

Codacy Here is an overview of what got changed by this pull request:

Issues
======
+ Solved 15
- Added 28
           

Complexity decreasing per file
==============================
+ src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java  -3
         

See the complete overview on Codacy

ProviderTableMeta.FILE_CONTENT_TYPE + " != 'DIR' AND " +
ProviderTableMeta.FILE_ACCOUNT_OWNER + AND +
ProviderTableMeta.FILE_PATH + " LIKE ?";
selectionArgs = new String[]{account.name, parentPath + "%"};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


List<OCFile> files = getFolderContent(folder, false);
ArrayList<String> selectionArgsList = new ArrayList<>();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ArrayList<String> selectionArgsList = new ArrayList<>();
selectionArgsList.add(account.name);
selectionArgsList.addAll(listPathString);
String[] selectionArgs = selectionArgsList.toArray(new String[0]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (cursor != null) {
if (cursor.moveToFirst()) {
do {
OCFile ocFile = new OCFile(cursor.getString(cursor.getColumnIndex(ProviderTableMeta.FILE_PATH)));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

} else {
file = null;
ocFile = null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saveFile(newFile);
} else {
throw new IllegalArgumentException("Saving a new file in an unexisting folder");
private boolean isFileExists(ArrayList<OCFile> filesExists, OCFile ocFile) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return contentProviderResults;
}

private ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
where = ProviderTableMeta.FILE_ACCOUNT_OWNER + AND +
ProviderTableMeta.FILE_PATH + " = ?";
selectionArgs = new String[]{account.name, parentPath};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*
* @param folder
* @param updatedFiles
* @param filesToRemove
*/
public void saveFolder(OCFile folder, Collection<OCFile> updatedFiles, Collection<OCFile> filesToRemove) {
public void saveFolder(OCFile folder, ArrayList<OCFile> updatedFiles, Collection<OCFile> filesToRemove) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && operation.isInsert()) {
ContentValues contentValues = operation.resolveValueBackReferences(results, i);
Uri newUri = insert(database, operation.getUri(), contentValues);
results[i] = new ContentProviderResult(newUri);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


ArrayList<String> listPathString = new ArrayList<>();

int totalSize, processSize, loopSize;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (new File(path).delete() && MimeTypeUtil.isMedia(file.getMimeType())) {
if (ocFile.isDown()) {
String path = ocFile.getStoragePath();
if (new File(path).delete() && MimeTypeUtil.isMedia(ocFile.getMimeType())) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loopSize = Math.min((totalSize - processSize), 998);

listPathString.clear();
StringBuilder inList = new StringBuilder(folderContent.size() * 2);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return deleted;
}

private int deleteFiles(Uri uri, String where, String[] whereArgs) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (i > 0) {
inList.append(",");
}
inList.append("?");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ContentValues contentValues;
// prepare operations to insert or update files to save in the given folder
for (OCShare share : shares) {
contentValues = new ContentValues();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return executeQuery(uri, null, selection, selectionArgs, null, errorMessage);
}

private ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations, String errorMessage) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nextcloud-android-bot
Copy link
Collaborator

APK file: https://www.kaminsky.me/nc-dev/android-artifacts/12302.apk

qrcode

To test this change/fix you can simply download above APK file and install and test it in parallel to your existing Nextcloud app.

@nextcloud-android-bot
Copy link
Collaborator

Codacy

340

Lint

TypemasterPR
Warnings7676
Errors00

SpotBugs (new)

Warning TypeNumber
Bad practice Warnings26
Correctness Warnings69
Internationalization Warnings13
Malicious code vulnerability Warnings5
Multithreaded correctness Warnings9
Performance Warnings113
Security Warnings44
Dodgy code Warnings138
Total417

SpotBugs (master)

Warning TypeNumber
Bad practice Warnings26
Correctness Warnings71
Internationalization Warnings13
Malicious code vulnerability Warnings5
Multithreaded correctness Warnings9
Performance Warnings107
Security Warnings44
Dodgy code Warnings138
Total413

SpotBugs increased!

private static final String AND = "=? AND ";
private static final String FAILED_TO_INSERT_MSG = "Fail to insert insert file to database ";
private static final String AND = " = ? AND ";
private static final String FAILED_TO_UPDATE_MSG = "Fail to update file to database ";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that it same String is used for insert and update.
Changing this to "update" is as wrong as using only "insert".

So either, we use both and change it accordingly, or we generify the error message and us "failed to insert/update file to…"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With my refactor, I've removed a lot of code duplication. So FAILED_TO_INSERT_MSG was used more than once.
However, for update, it is used in 2 places. So I changed that message to this.
We can use "insert/update", but it will be less exact.
"Fail to insert" is used in the insertFile method, if you want to merge this :D

This was referenced Jan 28, 2020
tobiasKaminsky pushed a commit that referenced this pull request May 27, 2020
Signed-off-by: tobiasKaminsky <[email protected]>
tobiasKaminsky pushed a commit that referenced this pull request Jun 5, 2020
Signed-off-by: tobiasKaminsky <[email protected]>
tobiasKaminsky pushed a commit that referenced this pull request Jun 5, 2020
Signed-off-by: tobiasKaminsky <[email protected]>
tobiasKaminsky pushed a commit that referenced this pull request Jun 10, 2020
Signed-off-by: tobiasKaminsky <[email protected]>
tobiasKaminsky pushed a commit that referenced this pull request Jun 16, 2020
Signed-off-by: tobiasKaminsky <[email protected]>
tobiasKaminsky pushed a commit that referenced this pull request Jun 16, 2020
Signed-off-by: tobiasKaminsky <[email protected]>
tobiasKaminsky added a commit that referenced this pull request Jun 17, 2020
remove non needed exceptions
Split off of #5150
Update translations
Update Nextcloud Android library
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Very slow processing when first download lot of file in folder
4 participants