Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

batch synced site creation #7309

Merged
merged 2 commits into from
Feb 24, 2017
Merged

batch synced site creation #7309

merged 2 commits into from
Feb 24, 2017

Conversation

diracdeltas
Copy link
Member

@diracdeltas diracdeltas commented Feb 18, 2017

fix #7308

Auditors: @ayumi @alexwykoff

Test Plan:

  1. in about:preferences#sync, choose the 'i have an existing sync code' option. enter in the code words that Alex posted in #testers (starts with 'forsaken')
  2. open about:bookmarks and wait for 6000+ bookmarks to be synced. the browser should not freeze or use excessive memory during the sync.

@diracdeltas
Copy link
Member Author

looks like syncing bookmarks tests are failing so i need to fix those

@bridiver
Copy link
Collaborator

I think this is part of a more general issue with appstate performance and we want to batch all updates in the dispatcher to solve some other perf issues. Is there any reason this code can't run in the background page?

@diracdeltas
Copy link
Member Author

Is there any reason this code can't run in the background page?

it would be some effort to replace all the calls to AppStore.getState() and appActions with IPC between background page and browser. which part of this is most helpful to move to the background page?

@bridiver
Copy link
Collaborator

@diracdeltas the loop that calls the appActions. That part seems like it should be pretty straightforward to move and then I can handle the batching with the appDispatcher stuff I'm working on

Copy link
Contributor

@ayumi ayumi left a comment

Choose a reason for hiding this comment

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

i know we're discussing moving some of this code around, but i reviewed for the concept of batching.

for ~1k bookmarks it reduces memory consumption which is sweet!

however syncing bookmarks in folders doesn't work, and they end up folderless– comments inline 🎷

const parentFolderObjectId = siteProps.parentFolderObjectId
if (parentFolderObjectId && parentFolderObjectId.length > 0) {
siteProps.parentFolderId =
getFolderIdByObjectId(new Immutable.List(parentFolderObjectId))
Copy link
Contributor

Choose a reason for hiding this comment

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

for initial sync, if we apply all bookmarks and folders at once, this will always return null; so folders don't sync.

we could fix this by first applying folders and folderless bookmarks and folders (to ensure correct ordering); then applying foldered bookmarks. see below for more info

Copy link
Member Author

Choose a reason for hiding this comment

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

@ayumi i think there is a general race condition here even if we apply stuff in the right hierarchy order. see #7293 (comment)

@@ -194,10 +232,22 @@ module.exports.applySyncRecord = (record) => {
*/
module.exports.applySyncRecords = (records) => {
if (!records || records.length === 0) { return }
const siteRecords = []
const otherRecords = []
records.forEach((record) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

bookmark folders:

instead of applying all bookmarks, i think we should first apply all folderless bookmarks and folders, then apply foldered bookmarks. otherwise we won't be able to resolve bookmark.parentFolderObjectId -> parentFolderId, so bookmarks will end up folderless.

bonus points to recursively apply (top level folders/items, then second level, etc) to better ensure folders ids are available when we need them.

@diracdeltas
Copy link
Member Author

@bridiver i tried moving this code to the background script; it didn't beach-ball the browser but it did make the UI non-responsive indefinitely. i think the batching is necessary to solve the perf issue.

@bridiver
Copy link
Collaborator

bridiver commented Feb 23, 2017 via email

appActions.removeSite(siteDetail, tag, true)
}
})
}, 2000)
Copy link
Collaborator

Choose a reason for hiding this comment

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

if this has to happen after creation a timeout doesn't seem very safe, or is the timeout just an extra buffer? If so I don't think it's really necessary with the dispatcher changes

let existingObjectData

if (record.action !== writeActions.CREATE) {
// XXX: Is this necessary for CREATEs also?
Copy link
Member Author

Choose a reason for hiding this comment

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

omitting the existingObject search for CREATES reduces the sync lag significantly, from a minute or so to a couple seconds.

Copy link
Contributor

Choose a reason for hiding this comment

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

affirming that existing objects aren't needed – it would have been resolved upstream during get_existing_objects -> resolved_sync_records

@diracdeltas
Copy link
Member Author

updated PR so now it fixes the bookmark folder issue too

@ayumi
Copy link
Contributor

ayumi commented Feb 24, 2017

it worked really fast for the forsaken ... profile!

then i tested with my special user data which is mildly corrupted (for example some bookmarks include nonexistent parentFolderIds), and it crashed.

you can replicate this by editing session-store-1 to change a bookmark's parentFolderId to something bogus, then starting Brave and doing the initial sync upload. it doesn't crash, but it prevents records from being uploaded.

in sync.js should syncUtil.createSiteData(siteJS) be also sending appState? https://github.com/brave/browser-laptop/blob/feature/batch-sync/app/sync.js#L207

TypeError: Cannot read property 'getIn' of undefined
    at findOrCreateFolderObjectId (/Users/ayu/repos/github.com/brave/browser-laptop/js/state/syncUtil.js:366:26)
    at Object.module.exports.createSiteData (/Users/ayu/repos/github.com/brave/browser-laptop/js/state/syncUtil.js:403:31)
    at syncBookmark (/Users/ayu/repos/github.com/brave/browser-laptop/app/sync.js:207:29)
    at /Users/ayu/repos/github.com/brave/browser-laptop/node_modules/immutable/dist/immutable.js:2701:43
    at List.__iterate (/Users/ayu/repos/github.com/brave/browser-laptop/node_modules/immutable/dist/immutable.js:2208:13)
    at OrderedMap.__iterate (/Users/ayu/repos/github.com/brave/browser-laptop/node_modules/immutable/dist/immutable.js:2700:25)
    at OrderedMap.forEach (/Users/ayu/repos/github.com/brave/browser-laptop/node_modules/immutable/dist/immutable.js:4383:19)
    at module.exports.onSyncReady (/Users/ayu/repos/github.com/brave/browser-laptop/app/sync.js:218:6)
    at emitOne (events.js:96:13)
    at EventEmitter.emit (events.js:188:7)

@diracdeltas
Copy link
Member Author

@ayumi does that issue exist without this PR?

@ayumi
Copy link
Contributor

ayumi commented Feb 24, 2017

@diracdeltas no, it works on master as of d9234b5

@diracdeltas
Copy link
Member Author

@ayumi i think its fixed now

@ayumi
Copy link
Contributor

ayumi commented Feb 24, 2017

@diracdeltas sweet it works now!

@@ -485,6 +487,32 @@ const handleAppAction = (action) => {
case appConstants.APP_DATA_URL_COPIED:
nativeImage.copyDataURL(action.dataURL, action.html, action.text)
break
case appConstants.APP_APPLY_SITE_RECORDS:
Copy link
Collaborator

Choose a reason for hiding this comment

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

can we leave a comment here about refactoring this into a single action with APP_ADD_SITE? When we do that we should probably pull it out of appStore anyway and create a siteReducer

Copy link
Collaborator

Choose a reason for hiding this comment

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

or maybe the comment should go on the action. Either way is fine, just want to capture it in the code

Copy link
Member Author

Choose a reason for hiding this comment

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

will do

@alexwykoff
Copy link
Contributor

I ran bookmark tests on 7a18689 and found 4 failures

71 passing (3m)
4 failing

  1. about:bookmarks page content "before all" hook:
    WaitUntilTimeoutError: Promise was rejected with the following reason: Error: unknown error: Cannot read property 'appStoreRenderer' of undefined
    at execute() - brave.js:407:19

  2. Syncing bookmarks create bookmark in folder:
    Promise was rejected with the following reason: timeout
    Error

  3. Syncing bookmarks update bookmark, moving it into the folder:
    Promise was rejected with the following reason: Error: An element could not be located on the page using the given search parameters.
    Error

  4. Syncing bookmarks from an existing profile "before all" hook:
    WaitUntilTimeoutError: Promise was rejected with the following reason: timeout
    at windowHandles() - brave.js:208:32

@diracdeltas
Copy link
Member Author

@alexwykoff could you try on 9a2b535 ?

@alexwykoff
Copy link
Contributor

Sure!

Here's the latest:
3 failing

  1. about:bookmarks page content "before all" hook:
    WaitUntilTimeoutError: Promise was rejected with the following reason: Error: unknown error: Cannot read property 'appStoreRenderer' of undefined
    at execute() - brave.js:407:19

  2. bookmark tests bookmarks bookmark pdf check location:
    WaitUntilTimeoutError: Promise was rejected with the following reason: timeout
    at execute() - brave.js:413:19

  3. navigationBar tests auto open bookmarks toolbar for the first bookmark should remain hidden if user has bookmarks but has toolbar hidden:
    WaitUntilTimeoutError: element (#navigator .removeBookmarkButton) still not existing after 10000ms
    at isExisting("#navigator .removeBookmarkButton") - waitForExist.js:37:22

I don't think these are on you, they look like flakey timeouts.

@bridiver
Copy link
Collaborator

@alexwykoff I think some of those are fixed in #7353
the number of intermittent test failures is way down with those changes

fix #7308
fix #7293
fix #7307

Auditors: @ayumi @alexwykoff

Test Plan:
1. in about:preferences#sync, choose the 'i have an existing sync code' option. enter in the code words that Alex posted in #testers (starts with 'forsaken')
2. wait for 6000+ bookmarks to appear in the bookmarks toolbar. the browser should not freeze or use excessive memory during the sync. for me it takes about 5 seconds.
3. open about:bookmarks. you should see a bunch of folders with bookmarks, including subfolders.
let existingObjectData

if (record.action !== writeActions.CREATE) {
// XXX: Is this necessary for CREATEs also?
Copy link
Contributor

Choose a reason for hiding this comment

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

affirming that existing objects aren't needed – it would have been resolved upstream during get_existing_objects -> resolved_sync_records

@diracdeltas
Copy link
Member Author

syncing tests all fixed now!

@srirambv
Copy link
Collaborator

srirambv commented Mar 1, 2017

@diracdeltas There is a momentary spike in the CPU usage when bookmarks are sync'd. Brave process's CPU usage goes upto 30% and drops down. It took ~2mins to sync the bookmarks on my machine with a clean profile.

image

@bridiver
Copy link
Collaborator

bridiver commented Mar 1, 2017

@srirambv when you say it took ~2 mins, what exactly are you referring to? Did the spike last 2 min? Was it 2 min until they appeared on another device?

@srirambv
Copy link
Collaborator

srirambv commented Mar 1, 2017

@bridiver The total time to sync was around 2 mins for the bookmarks to shown up on the second device. The CPU spike was momentary around 10 secs (could hear the fan loud and clear), happened initially when the sync code was added and then right before the bookmarks showed up on the second device.

@diracdeltas
Copy link
Member Author

sync polls every 1 minute, so on average i would expect ~30s for a sync to occur

@bridiver
Copy link
Collaborator

bridiver commented Mar 1, 2017 via email

@bridiver
Copy link
Collaborator

bridiver commented Mar 1, 2017 via email

@diracdeltas
Copy link
Member Author

If the poll time is 1 minute the average should be closer to 1 minute to sync across devices.

it sends ~immediately after the state change but the receiver polls every 1min

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

Successfully merging this pull request may close these issues.

apply sync records in batches
6 participants