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: users logged out after SDK upgrade due to different cache path #1168

Merged
merged 10 commits into from
May 26, 2022

Conversation

rommansabbir
Copy link
Member

ParsePlugins ::

  • getCacheDir(), getFilesDir() APIs now has support for backward compatibility before migration to v3.0.0

ParsePlugins ::
- `getCacheDir()`, `getFilesDir()` APIs now has support for backward compatibility before migration to v3.0.0
@parse-github-assistant
Copy link

parse-github-assistant bot commented May 15, 2022

Thanks for opening this pull request!

  • ❌ Please edit your post and use the provided template when creating a new pull request. This helps everyone to understand your post better and asks for essential information to quicker review the pull request.

@mtrezza mtrezza requested a review from a team May 15, 2022 12:43
@mtrezza mtrezza changed the title Fixed app cache dir changes issue (#1158) fix: users are logged out after SDK upgrade due to different cache path May 15, 2022
@mtrezza mtrezza changed the title fix: users are logged out after SDK upgrade due to different cache path fix: users logged out after SDK upgrade due to different cache path May 15, 2022
@codecov
Copy link

codecov bot commented May 15, 2022

Codecov Report

Merging #1168 (4e2c22c) into master (4842329) will increase coverage by 0.50%.
The diff coverage is 90.00%.

@@             Coverage Diff              @@
##             master    #1168      +/-   ##
============================================
+ Coverage     66.81%   67.31%   +0.50%     
- Complexity     2249     2285      +36     
============================================
  Files           121      122       +1     
  Lines          9892     9962      +70     
  Branches       1332     1343      +11     
============================================
+ Hits           6609     6706      +97     
+ Misses         2771     2735      -36     
- Partials        512      521       +9     
Impacted Files Coverage Δ
parse/src/main/java/com/parse/ParseFileUtils.java 45.78% <75.00%> (+9.07%) ⬆️
...in/java/com/parse/ParseCacheDirMigrationUtils.java 91.80% <91.80%> (ø)
parse/src/main/java/com/parse/Parse.java 65.58% <100.00%> (+3.89%) ⬆️
...rc/main/java/com/parse/ParseRESTObjectCommand.java 73.07% <0.00%> (-11.54%) ⬇️
parse/src/main/java/com/parse/ParseRequest.java 82.00% <0.00%> (+2.00%) ⬆️
parse/src/main/java/com/parse/ParsePlugins.java 50.00% <0.00%> (+18.75%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4842329...4e2c22c. Read the comment docs.

@mtrezza mtrezza linked an issue May 15, 2022 that may be closed by this pull request
4 tasks
parse/src/main/java/com/parse/ParsePlugins.java Outdated Show resolved Hide resolved
parse/src/main/java/com/parse/ParsePlugins.java Outdated Show resolved Hide resolved
@azlekov
Copy link
Contributor

azlekov commented May 16, 2022

Here you can see an migration logic about the push notifications, I have expected to see something similar but much more simple: 7d0faa3#diff-6cb14853da236c30db3f14e4005ea40c5c45cb8fcb9fc49541693186620de1dcR60

@mman
Copy link

mman commented May 17, 2022

@rommansabbir Thanks for the PR, but looking at the proposed fix I think it is not gonna work at all.

There are potentially multiple cached files stored in both, the cache dir and the files dir. Your code will probably allow to read them from the original location, and then you delete them when the app exists (assuming the delete on exit works, as it might not as @L3K0V explains).

The actually files we care about are never moved anywhere, and even if they will have been be re-saved by the app at some point, they would end up in the old location and then then get deleted.

Needs more work IMHO...

@mtrezza
Copy link
Member

mtrezza commented May 17, 2022

Hi everyone, just to emphasize it, this is a particularly important PR, because any release without this migration logic is for most people likely a useless release. So this PR currently blocks the release pipeline. The sooner we get this merged the better, considering we have another issue with Facebook Login that is waiting to get merged. Any helping hand here is greatly appreciated and we have a bounty on this issue as well.

@rommansabbir rommansabbir deleted the patch-1 branch May 18, 2022 09:18
@rommansabbir rommansabbir restored the patch-1 branch May 18, 2022 09:18
@rommansabbir
Copy link
Member Author

@mtrezza @mman @L3K0V First of all, sorry for messed up with the PR. This is my first contribution to a such big community of Parse.

About my logic for cache path migrations. Based on @mman migration thoughts (#1158 (comment))

I came up with this ::

  • First, looking for the all files (including sub directory) in the old "app_Parse" directory
  • If files exists, moving the all files to the directory "com.parse" by following the old sub directory name. After that delete the old file (already copied) silently.
  • For each file, migration will be failed if there is already a file exist in the new directory with the same file name or other known cases.

If the solution seems suitable for migration process, I will create a new PR (which will include changes in ParsePlugins.java and ParseFileUtils.java).

Let me know, Thanks.

@mman
Copy link

mman commented May 18, 2022

@rommansabbir Yes, this is the approach I would take, but please note that since 3.0.0 is already in the wild, and since it forced people to re-login, there will be cases where there will be fresh files in new location com.parse as well as files in old location, the app_Parse directory. In that case, the new files should be used, and old just deleted...

@rommansabbir
Copy link
Member Author

One things more, in the old version, I have seen that ParsePlugins.getParseDir() API return file for app_Parse and it's deprecated. But in new APIs ParsePlugins.getCacheDir() and ParsePlugins.getFilesDir() points to (eg.) */cache/com.parse and */files/com.parse, two different path.

So, when running migration, for a specific file, in which location I should point to move the spcific file, */cache/com.parse or */files/com.parse?.

@mman
Copy link

mman commented May 18, 2022

@rommansabbir That is exactly what I have not yet had a time to investigate properly and in detail (read: This PR is actually trickier then it may appear on a first look).

@rommansabbir
Copy link
Member Author

@mman I think we can find out from where the old API is accessed and which FILE_NAME (File name) was used, eg. File(ParsePlugins.get().getParseDir(), FILENAME_CURRENT_CONFIG). We can look for others Constants like FILENAME_CURRENT_CONFIG. So, when migration is ongoing, we can check for item name matches with our Constants list or not, if match - then move item to */files/com.parse/ else */cache/com.parse/

@mtrezza
Copy link
Member

mtrezza commented May 18, 2022

So, when running migration, for a specific file, in which location I should point to move the spcific file, */cache/com.parse or */files/com.parse?.

The two storages have a different purpose and are managed differently. That determines which file should go where.

  • The cache dir is authoritatively managed by the OS and only co-managed by the app. It must not be considered persistent, in other words, the data the app stores there can be deleted by the OS at any time. That also means that if the app doesn't properly delete files the OS will make sure the cache doesn't swell up too much.
  • The files dir is exclusively managed by the app. It is persistent and must be managed by the app. If the app doesn't delete outdated files there the files will stay and the app's footprint will swell up until the OS will report a storage issue to the user.

For example, the user session token would go into persistent storage.

I would just make a list of all the SDK's internal files from looking at the pre-3.x logic, post the list here and then we can determine whether it should be persistent or not. That wrapped into the logic I proposed earlier should do the trick. I don't think there is a lot more to it.

@rommansabbir
Copy link
Member Author

ParsePlugins::installationId(){File(getParseDir(), INSTALLATION_ID_LOCATION)}
ParseCorePlugins::getCurrentUserController() {File(Parse.getParseDir(), FILENAME_CURRENT_USER)}
ParseCorePlugins::getConfigController() {File(ParsePlugins.get().getParseDir(), FILENAME_CURRENT_CONFIG)}
ParseCorePlugins::getCurrentInstallationController() {File(ParsePlugins.get().getParseDir(), FILENAME_CURRENT_INSTALLATION)}
ParseCommandCache::getCacheDir(){File(Parse.getParseDir(), "CommandCache")}
LocalIdManager(Parse.getParseDir()){File(root, "LocalId")}
PushRouter::getInstance(){File(ParsePlugins.get().getParseDir(), LEGACY_STATE_LOCATION)}

from where ParsePlugins.get().getParseDir() API has been accessed. All of those files managed by SDK itself, so when migration is ongoing, we can look for those listed files and move files to */files/com.parse/ directory, then delete the old files from app_Parse by covering known cases.

After that, all other files that left in app_Parse directory should move to */cache/com.parse/ directory by covering known cases.

  • The files dir is exclusively managed by the app. It is persistent and must be managed by the app. If the app doesn't delete outdated files there the files will stay and the app's footprint will swell up until the OS will report a storage issue to the user.

Version: 2.0.6

ParseCorePlugins::getFileController(){
             ParseFileController(
                    ParsePlugins.get().restClient(), 
                    Parse.getParseCacheDir("files")
            ))
}

calling Parse.getParseCacheDir("files") API which point to */cache/com.parse/. In this case, all files (eg. when storing an ParseObject to LocalDataStore that contain an File itself call something.mp3) that are stored in the cache directory should point to */files/com.parse/ as something.mp3 is managed by SDK itself.

@mtrezza
Copy link
Member

mtrezza commented May 19, 2022

All of those files managed by SDK itself, so when migration is ongoing, we can look for those listed files and move files to */files/com.parse/ directory, then delete the old files from app_Parse by covering known cases.

Sounds good; how about the other modules like facebook, fcm, it is possible that they store anything in there as well?

After that, all other files that left in app_Parse directory should move to */cache/com.parse/ directory by covering known cases.

What are these other files?

Reopening this PR, as the issue conversation is happening here instead of in the issue. I guess this PR can just be extended with the modifications discussed above, instead of opening a new one.

@mtrezza mtrezza reopened this May 19, 2022
@rommansabbir
Copy link
Member Author

@mtrezza I found those usages in the mentioned list. If any other module deal with File, at the end they all point to the same API ParsePlugins.get().getParseDir() to retreive File object.

What are these other files?

I'm not sure about how many files (File) is accessed (CRUD) to old dir (app_Parse) by the SDK itself. So,

  • Files that matches with our lists, will be moved to */files/com.parse/ but what about others files in the old dir? (If exists)
  • We can assume those files should be moved to */cache/com.parse/ dir.

@mtrezza
Copy link
Member

mtrezza commented May 19, 2022

In general I agree with your strategy, but I wonder what these other files could be?

I assume it's only the Parse SDK itself that writes to that dir, so any write logic, even for temporary files should be identifiable in code. Have you seen that there are also other files, or is that just an assumption? Or is it that the OS uses the cache dir of a module automatically to store cache files that are opaque to us?

@rommansabbir
Copy link
Member Author

According to my exploration of the code, many controller and classes using new locations ( */files/com.parse/,*/cache/com.parse/), but some classes still accessing the old location app_Parse.

Regarding the migrations: I have checked the migration with mentioned files and some random data.
Screenshot_1
Screenshot_2

I'm not sure about how many files (File) is accessed (CRUD) to old dir (app_Parse) by the SDK itself. So,

* Files that matches with our lists, will be moved to `*/files/com.parse/` but what about others files in the old dir? (If exists)

* We can assume those files should be moved to `*/cache/com.parse/` dir.

@mtrezza
Copy link
Member

mtrezza commented May 19, 2022

OK, so I guess let's go with your suggested migration concept and then just test it out.

but some classes still accessing the old location app_Parse.

You mean pre 3.x or even with the latest version of the SDK?

Copy link
Member Author

@rommansabbir rommansabbir left a comment

Choose a reason for hiding this comment

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

fix: parse cache dir migration routine on SDK initialization (only once) (#1168)

Copy link
Contributor

@azlekov azlekov left a comment

Choose a reason for hiding this comment

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

LGTM, but it would be great if someone else take a look as well.

Copy link
Member Author

@rommansabbir rommansabbir left a comment

Choose a reason for hiding this comment

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

Fixed SpotlessJavaCheck Violations gradle build issue for PR (#1168)

@mtrezza
Copy link
Member

mtrezza commented May 21, 2022

@PLR2388 Since you originally reported the issue, do you think you could test out this fix to see whether the migration happens successfully?

Would be nice to have a pre-release branch to test things out easier, to consider for the future.

@rommansabbir
Copy link
Member Author

@mman @mtrezza Any update on this PR?

@mtrezza
Copy link
Member

mtrezza commented May 23, 2022

Given the severity of the issue, I would like to have someone test this out with an actual app before we merge it and recommend to developers that the release is safe to use. That means:

  1. use the 2.x SDK
  2. log in a user
  3. update the SDK using this PR, relaunch the app, confirm at least whether:
  • user is still logged in (verify on server side by making a request to the server)
  • installation is set correctly (verify on server side by making a request to the server)
  • data is transferred, old dir deleted, non-essential files in cache dir, etc (verify via device file explorer)

If @PLR2388, @qmetzler-luna or @mman could try that out, that would be fantastic.

@rommansabbir
Copy link
Member Author

rommansabbir commented May 23, 2022

If @PLR2388, @qmetzler-luna or @mman could try that out, that would be fantastic.

@mtrezza @mman I have tested the "patch-1" version to check the migrations status & users logged out issue. Migrations was successful & users stayed logged in after SDK version updates from 2.x to patch-1.

Step 1:

  • Install Parse SDK v2.0.5
  • Logged In as a user (Fresh Login)
  • Check app data folder on Device Explorer
    Screenshot_6

Step 2:

  • Install Parse SDK from branch patch-1
  • Check logged in user status
  • Fetch current user again from server
  • Save an ParseObject to the server
  • Check app data folder on Device Explorer
    Screenshot_1

The result is as we expected 😃

@mtrezza
Copy link
Member

mtrezza commented May 24, 2022

@rommansabbir Thanks for documenting it in such detail. I will try this out as well just to confirm before we merge.

Side note, since you already did a lot of investigation, do you know why the applicationId file is stored in cache and what the file is used for? The ID is set during SDK initialization and probably stored in memory as it's always required for SDK requests. So why is it written to a cache file that may be deleted by the OS anytime anyway.

@rommansabbir
Copy link
Member Author

rommansabbir commented May 24, 2022

@mtrezza I will review the codes and will update you.

@mman
Copy link

mman commented May 24, 2022

@rommansabbir I will try to test until the end of this week...

@rommansabbir
Copy link
Member Author

@mtrezza According to the code comments:

  • Make sure the data on disk for Parse is for the current application on Parse SDK Init.
  • Verifies that the data stored on disk for Parse was generated using the same application that is running now
  • Make sure the current version of the cache is for this application id else the applicationId file was malformed or something
  • The application id has changed, so everything on disk is invalid.

@mtrezza
Copy link
Member

mtrezza commented May 24, 2022

Thanks for investigating, so the applicationId there is essentially to validate that the cache belongs to the app. So if an app would allow to switch between different application IDs, the cache would get invalidated with every switch. That makes sense.

@mtrezza
Copy link
Member

mtrezza commented May 24, 2022

I can confirm that the migration works fine.

It moves from com.example.app/app_Parse/ to com.example.app/files/com.parse/:

  • currentConfig
  • currentInstallation
  • currentUser
  • installationId

It moves from com.example.app/app_Parse/ to com.example.app/cache/com.parse/:

  • CommandCache/

The following file locations are unchanged:

  • com.example.app/cache/com.parse/applicationId
  • com.example.app/files/com.parse/push

Everything as expected, installation update and user requests server side also work fine.

Great job, @rommansabbir! Would you be interested in joining the Parse Android SDK team? No commitment in terms of contribution, but it would be great if you could at times help out with things like PR reviews for example.

@mtrezza mtrezza changed the title fix: users logged out after SDK upgrade due to different cache path fix: users logged out after SDK upgrade due to different cache path; this fixes the bug that was introduced with release 3.0.0 which ignored SDK-internal data that is stored locally on the client side May 24, 2022
@mtrezza mtrezza changed the title fix: users logged out after SDK upgrade due to different cache path; this fixes the bug that was introduced with release 3.0.0 which ignored SDK-internal data that is stored locally on the client side fix: users logged out after SDK upgrade due to different cache path May 24, 2022
@mtrezza
Copy link
Member

mtrezza commented May 24, 2022

Changelog entry:

Fix

@mtrezza
Copy link
Member

mtrezza commented May 24, 2022

@mman If you want to test that would be great, then we'll wait until the end of the week with the release.

@rommansabbir
Copy link
Member Author

Great job, @rommansabbir! Would you be interested in joining the Parse Android SDK team? No commitment in terms of contribution, but it would be great if you could at times help out with things like PR reviews for example.

Yes, I would love to 😃

@mman
Copy link

mman commented May 25, 2022

@rommansabbir @mtrezza I'd love to double check, the code looks good. What's the easiest way to build my app against this branch. I have tried naive approach to depend directly on git branch, but that apparently does not work. What steps are needed? Sorry for my lame question.

@rommansabbir
Copy link
Member Author

rommansabbir commented May 25, 2022

What's the easiest way to build my app against this branch. I have tried naive approach to depend directly on git branch, but that apparently does not work. What steps are needed?

@mman

image

Add this branch dependency:

implementation 'com.github.rommansabbir:Parse-SDK-Android:patch-1-SNAPSHOT'

I was able to install by following this approach. Now, you can install the latest SDK from this branch.

@mtrezza
Copy link
Member

mtrezza commented May 25, 2022

You can also clone the repo, checkout the PR branch, build to local maven and reference the builds in your example app. I think that's a question many may have; maybe we should add a step-by-step instruction to the contribution guide.

@mman
Copy link

mman commented May 26, 2022

Thanks @rommansabbir, I was missing the -SNAPSHOT in the github reference.

implementation 'com.github.rommansabbir:Parse-SDK-Android:patch-1-SNAPSHOT'

I have now tried our apps and looks like this PR does correctly move all files around.

Thanks, LGTM 👍

@mtrezza
Copy link
Member

mtrezza commented May 26, 2022

Thanks confirming @mman. We now have 3 confirmations that this PR works, so I will go ahead and merge.

Great teamwork everyone and thanks especially to @rommansabbir for kicking it off with this PR!

@mtrezza mtrezza merged commit ec7bd03 into parse-community:master May 26, 2022
parseplatformorg pushed a commit that referenced this pull request May 26, 2022
## [3.0.1](3.0.0...3.0.1) (2022-05-26)

### Bug Fixes

* users logged out after SDK upgrade due to different cache path; this fixes the bug that was introduced with release 3.0.0 which ignores SDK-internal data that is stored locally on the client side ([#1168](#1168)) ([ec7bd03](ec7bd03))
@parseplatformorg
Copy link

🎉 This change has been released in version 3.0.1

@parseplatformorg parseplatformorg added the state:released Released as stable version label May 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
state:released Released as stable version
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Users are logged out after SDK upgrade
5 participants