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

Fix crash when opening conflict dialog #2948

Merged
merged 2 commits into from
Mar 5, 2021
Merged

Conversation

FlexW
Copy link

@FlexW FlexW commented Feb 23, 2021

Note: This PR is a draft. It fixes the problem but probably needs some polishing. I first wanted to hear your thoughts about this problem, my findings and my proposed solution before I investigate further.

Now to the actual problem:

When the client runs and a conflict gets detected, the sync engine runs
two times.

On the first run, the sync engine detects the conflict, marks the
file as a conflict and propagates that to the GUI. This leads to an
error notification with the original filename in the main dialog.

The sync engine runs then a second time. On this second run, the file
that originally caused the conflict is not anymore a conflict
file. Instead, the sync engine detects the conflicted copy and
propagates that file as a conflict to the GUI.

When opening the conflict dialog with the original file name (not the
conflicted copy) a crash happens. Usually, the two sync runs are really
fast, so the user does not notice the first notification. However, a
problem can occur if a conflict gets created while the client is not
running. Since then, the client does not do two sync runs. It does only
run once.

Steps to reproduce the original Issue on master:

  • Stop the client
  • Modify a synced file on the server
  • Modify the same file on the local machine
  • Start the client
  • Wait that the conflict gets detected
  • Press on the conflict notification
  • Observe the crash

Signed-off-by: Felix Weilbach felix.weilbach@nextcloud.com

@FlexW FlexW force-pushed the bugfix/conflict-dialog-issue branch from 1313512 to d226f64 Compare February 23, 2021 18:29
@FlexW
Copy link
Author

FlexW commented Feb 24, 2021

Another solution to his problem as proposed by @allexzander would be to just run a second sync after a file conflict has been detected and don't propagate the first conflict error to the GUI.

@er-vin I ping you because your input on this could be valuable :)

src/common/utility.h Outdated Show resolved Hide resolved
src/common/utility.h Outdated Show resolved Hide resolved
@er-vin
Copy link
Member

er-vin commented Feb 25, 2021

Another solution to his problem as proposed by @allexzander would be to just run a second sync after a file conflict has been detected and don't propagate the first conflict error to the GUI.

This maybe a good idea as well. Maybe less invasive? I have a hard time to gauge this from the top of my head.

Comes to mind that maybe it's the call to the dialog which should be fixed instead? I wonder if the call from socket api (so doesn't go at all through activity model) suffers from the same or a similar issue.

@FlexW FlexW force-pushed the bugfix/conflict-dialog-issue branch from d226f64 to a5c4bae Compare March 4, 2021 14:35
@FlexW
Copy link
Author

FlexW commented Mar 4, 2021

I updated the pr to block the unnecessary activity and schedule a new sync after a conflicted copy gets created.
@er-vin @allexzander

src/gui/tray/UserModel.cpp Outdated Show resolved Hide resolved
src/gui/tray/UserModel.cpp Outdated Show resolved Hide resolved
src/gui/tray/UserModel.cpp Outdated Show resolved Hide resolved
src/gui/tray/UserModel.h Outdated Show resolved Hide resolved
src/gui/tray/UserModel.cpp Outdated Show resolved Hide resolved
@FlexW FlexW force-pushed the bugfix/conflict-dialog-issue branch from a5c4bae to b00eb28 Compare March 5, 2021 09:05
const auto isDifferentAccount = folder->accountState() != _account.data();
const auto isConflictFromOriginalFile = item->_status == SyncFileItem::Conflict && !Utility::isConflictFile(item->_file);

if (isDifferentAccount) {
Copy link
Contributor

@allexzander allexzander Mar 5, 2021

Choose a reason for hiding this comment

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

@FlexW

We still have too many lines of code IMHO.

bool User::isValueableActivity(const Folder *folder, const SyncFileItemPtr &item) const
{
    // activity for a different account - ignore it
    if (!folder->accountState() != _account.data()) {
        return false;
    }

    // first time conflict activity should be ignored until the next sync (fix conflict dialog crash issue)
    if (item->_status == SyncFileItem::Conflict && !Utility::isConflictFile(item->_file) {
        return false;
    }

    return true;
}

Copy link
Author

Choose a reason for hiding this comment

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

@allexzander I find it more descriptive with the variable names. Then it's even readable without the comments:) With you approach it's just one line less. However, I like your comments about the conditionals. I updated it and changed the wording a bit.

@FlexW
Copy link
Author

FlexW commented Mar 5, 2021

/rebase

Felix Weilbach added 2 commits March 5, 2021 11:32
When the client runs and a conflict gets detected, the sync engine runs
two times.

On the first run, the sync engine detects the conflict, marks the
file as a conflict and propagates that to the GUI. This leads to an
error notification with the original filename in the main dialog.

The sync engine runs then a second time. On this second run, the file
that originally caused the conflict is not anymore a conflict
file. Instead, the sync engine detects the conflicted copy and
propagates that file as a conflict to the GUI.

When opening the conflict dialog with the original file name (not the
conflicted copy) a crash happens. Usually, the two sync runs are really
fast, so the user does not notice the first notification. However, a
problem can occur if a conflict gets created while the client is not
running. Since then, the client does not do two sync runs. It does only
run once.

Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
@github-actions github-actions bot force-pushed the bugfix/conflict-dialog-issue branch from a6ca9d4 to 63dbb90 Compare March 5, 2021 11:32
@nextcloud-desktop-bot
Copy link

AppImage file: Nextcloud-PR-2948-63dbb90bbd96d3169b6186fb7a37edddf3f00d3e-x86_64.AppImage

To test this change/fix you can simply download above AppImage file and test it.

Please make sure to quit your existing Nextcloud app and backup your data.

@FlexW FlexW merged commit f17c52d into master Mar 5, 2021
@FlexW FlexW deleted the bugfix/conflict-dialog-issue branch March 5, 2021 13:32
void User::slotItemCompleted(const QString &folder, const SyncFileItemPtr &item)
{
auto folderInstance = FolderMan::instance()->folder(folder);

if (!folderInstance)
return;

// check if we are adding it to the right account and if it is useful information (protocol errors)
if (folderInstance->accountState() == _account.data()) {
if (isValueableActivity(folderInstance, item)) {
Copy link
Member

Choose a reason for hiding this comment

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

Ouch, this is subpar API naming, what is "valueable"? It will tell me nothing months from now. I think it was better not factoring this out in a method but instead store the result in two nicely named booleans and combine then in the if. Typically something like:

const auto isForUserAccount = folderInstance->accountState() == _account.data();
const auto isUnresolvableConflict = item->_status == SyncFileItem::Conflict && !Utility::isConflictFile(item->_file);
if (isForUserAccount && !isUnresolvableConflict) {

Copy link
Contributor

Choose a reason for hiding this comment

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

@FlexW I guess we still have time to create a PR with just these changes :) @er-vin Sorry, we had to make it move forward. I must confess, I am not that nitpicky reviewer :)

Copy link
Author

Choose a reason for hiding this comment

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

@er-vin @allexzander pr for that #2976

Copy link
Member

Choose a reason for hiding this comment

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

@er-vin Sorry, we had to make it move forward.

No worries, I'm less available that's how it is. :-)

I must confess, I am not that nitpicky reviewer :)

Well, I know I put quite some nitpicks too, but there it was really more of a code smell. If something is not clearly named for some reason and one can't find a proper name for it... well something is fishy. ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants