Closed Bug 1372496 Opened 7 years ago Closed 7 years ago

PlacesUtils.bookmarks.eraseEverything is very slow

Categories

(Toolkit :: Places, enhancement, P1)

enhancement

Tracking

()

RESOLVED FIXED
mozilla56
Tracking Status
firefox56 --- fixed

People

(Reporter: standard8, Assigned: standard8)

References

Details

(Keywords: perf, Whiteboard: [fxsearch])

Attachments

(2 files)

In working on bug 1095426, I have discovered that the async eraseEverything appears to be quite slow.

When erasing ~24k bookmarks, it takes approximately 4 to 5 minutes on my Macbook Pro (after extending the sqlite timeout).

I'm currently investigating the causes of this, though it mainly seems to be related to the updateFrecency calculations.
I've cut down the bookmarks size to about 6.6k, my analysis shows that the erasing takes about 7s, but the updateFrecency takes about 6.5s of that.

From the code it looks like the updateFrecency is intended to run in the background, there's no await for it. However, the withConnectionWrapper/db.executeTransaction wrapper in eraseEverything seems to be ensuring that the frecency update completes.

I'm not sure if that is intended or not.

Attempting to batch the update frecency algorithm actually slows it down, so that isn't an option ;-)
Keywords: perf
(In reply to Mark Banner (:standard8) from comment #1)
> From the code it looks like the updateFrecency is intended to run in the
> background, there's no await for it. However, the
> withConnectionWrapper/db.executeTransaction wrapper in eraseEverything seems
> to be ensuring that the frecency update completes.

Regardless, all the queries are serialized on a thread, it's possible the updateFrecency call still happens before our COMMIT and so we end up waiting for it. We could try delaying it, maybe we could even do it in the transaction .then handler? Unfortunately requestIdleCallback is not yet usable from non DOM contexts.
 
> I'm not sure if that is intended or not.

No, the frecency updates should be outside the transaction :(

Another thing you should try, is to wrap the frecency updates in a transaction but batch them. In a previous patch I noticed that doing thousands of updates in a single query was 0(n^2), when I chunked the changes into smaller pieces it took one tenth of the time.

To sum up:
1. we can enqueue the updateFrecency calls better so they won't run inside the main transaction (API will return faster)
2. we should make updateFrecency chunk (we could try with 1k at a time) and try with and without a transaction.
Also, for reference and working with real-world numbers, telemetry tells us the 95th percentile of users have less than 1.4k bookmarks. Testing with double that number should be safe enough for the foreseeable future.
Whiteboard: [fxsearch]
Depends on: 1372936
P1 as it is blocking another P1 with patches.
Priority: -- → P1
(In reply to Marco Bonardo [::mak] from comment #2)
> 2. we should make updateFrecency chunk (we could try with 1k at a time) and
> try with and without a transaction.

I've just been trying this and comparing it. With 2.8k bookmarks on my machine with just step 1, we're seeing the updateFrecency take ~ 1035ms. With various sized chunk and with/without transactions I'm seeing a range of about 1020 - 1080. So I don't think there's any real benefit there.
This is what I've been using to test the speed of the changes. It is a simple xpcshell-test, that inserts and then removes 2.8k bookmarks.

Without the patch I've put up for review, this would show that eraseEverything would take about 1152 milliseconds.

With the patch for review, eraseEverything takes 274 milliseconds. updateFrecencies happening in the background and takes about 1034 milliseconds.
Comment on attachment 8877963 [details]
Bug 1372496 - Speed up bookmarks.eraseEverything and bookmarks.remove APIs by handling updating of frencencies outside of the main transaction.

https://reviewboard.mozilla.org/r/149362/#review154026

::: toolkit/components/places/Bookmarks.jsm:1609
(Diff revision 1)
>      if (item.type == Bookmarks.TYPE_BOOKMARK && !isUntagging) {
>        // ...though we don't wait for the calculation.
>        updateFrecency(db, [item.url]).catch(Cu.reportError);
>      }
>  
> +    if (urls && urls.length) {

just for added safety, let's also check item.type == Bookmarks.TYPE_FOLDER
Attachment #8877963 - Flags: review?(mak77) → review+
Pushed by mbanner@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/8a4350c371bb
Speed up bookmarks.eraseEverything and bookmarks.remove APIs by handling updating of frencencies outside of the main transaction. r=mak
https://hg.mozilla.org/mozilla-central/rev/8a4350c371bb
Status: NEW → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla56
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: