Closed Bug 1468104 Opened 2 years ago Closed Last year

Existence of tag on a bookmark prevents deletion of associated keyword


(Toolkit :: Places, defect, P1)




Tracking Status
firefox62 --- verified


(Reporter: rob, Assigned: rob)



(Whiteboard: [fxsearch])


(1 file, 4 obsolete files)

Attached patch test.patch (obsolete) — Splinter Review
User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Build ID: 20180607202626

Steps to reproduce:

1. Create a fresh profile
2. Load
3. Add a bookmark for with the tag "stop"
4. Open the bookmark manager (Ctrl-Shift-O)
5. Add keyword "stop" for
6. Delete bookmark for

Actual results:

The keyword remained in the moz_keywords table (confirmed via running ".dump moz_keywords" on places.sqlite), which causes typing "stop" in the search bar to suggest at the top of the suggestions.  This doesn't happen if I don't tag the bookmark.

Expected results:

The keyword should have been removed from moz_keywords, causing to show up further down the search suggestions list from the search bar
I should mention that I reproduced this with a Firefox built from Mercurial (revision = 6ecc24376875).

I've attached a patch to add a test to reproduce this issue; please let me know if the test looks ok!
Component: Untriaged → Bookmarks & History
Oh, interesting, thanks for digging into this! I think the query in needs to be a bit smarter. Tags are stored as bookmarks under the hood, so `removeFromURLsIfNotBookmarked` still thinks the URL is bookmarked.
Blocks: 1435354
Component: Bookmarks & History → Places
Ever confirmed: true
Product: Firefox → Toolkit
Priority: -- → P1
Whiteboard: [fxsearch]
I just attached a patch to fix the issue (well, the test I wrote, anyway) - how does that look?
Comment on attachment 8984756 [details] [diff] [review]

Review of attachment 8984756 [details] [diff] [review]:

Hi Rob, thank you for the patches.

I've left a few comments about the test below. I've not looked at the SQL part, as I don't know enough about that particular bit to know how the performance is.

Could you update your patch with my comments, then combine the two patches into one, and post a single new patch? When you post, request review from Marco (set the reviewer flag to `::mak`) as he'll be best to look at the SQL part of this.

::: toolkit/components/places/tests/unit/test_keywords.js
@@ +493,5 @@
>  });
> +
> +add_task(async function test_tagDoesntPreventKeywordRemoval() {
> +  var tagssvc = Cc[";1"].
> +                createInstance().QueryInterface(Ci.nsITaggingService);

You can just use `PlacesUtils.tagging` instead of `tagsvc`.

@@ +498,5 @@
> +  await check_keyword(false, "", "example");
> +  let fc = await foreign_count("");
> +
> +  let httpBookmark = await PlacesUtils.bookmarks.insert({ url: "",
> +                                                      parentGuid: PlacesUtils.bookmarks.unfiledGuid });

Normally we like to wrap these like this:

let httpBookmark = await PlacesUtils.bookmarks.insert({
  url: "",
  parentGuid: PlacesUtils.bookmarks.unfiledGuid

@@ +513,5 @@
> +  await PlacesUtils.bookmarks.remove(httpBookmark);
> +
> +  // the notification is synchronous but the removal process is async.
> +  // Unfortunately there's nothing explicit we can wait for.
> +  while(await PlacesUtils.bookmarks.fetch({ url: ""}));

This looks like it should be waiting for the foreign_count to have been updated.

It would also be better to use TestUtils.waitForCondition() as well now (the code you copied this from is probably from before that was created).
Thanks for the feedback, Mark! I'll apply your fixes and send a new patch later today.
Attachment #8984756 - Attachment is obsolete: true
Attachment #8984894 - Attachment is obsolete: true
I've added a new patch, and I ran the previous and my revised query on my own places.sqlite as a thumb-to-the-wind benchmark:

[9:23:25] rob@eridanus /tmp $ sqlite3 /home/rob/.mozilla/firefox/*.default/places.sqlite '.read before.sql'
-- Loading resources from /home/rob/.sqliterc                                                                    
Run Time: real 0.002 user 0.001933 sys 0.000000
[9:23:30] rob@eridanus /tmp $ sqlite3 /home/rob/.mozilla/firefox/*.default/places.sqlite '.read after.sql' 
-- Loading resources from /home/rob/.sqliterc
Run Time: real 0.008 user 0.006696 sys 0.002061

So my new query is definitely slower - whether it's too slow to include is up to you all!
I suppose an alternative could be to make bookmarks inserted for tagging purposes not count against a place's foreign_count, but as I'm a newbie who's unfamiliar with the codebase as a whole that might cause issues I haven't forseen.  Also, it would require running a query to fix up existing users' places.sqlite files upon upgrade, which could be dicey.
Attachment #8985613 - Flags: review?(mak77)
Assignee: nobody → rob
This happens because tags are removed when the bookmarks API notifies onItemRemoved, that happens AFTER it asks keywords to cleanup themselves. So basically we try to cleanup keywords before tags. It makes sense to do that because we are in a transaction, and the problem will naturally disappear once we change the tags implementation in Bug 424160.
Comment on attachment 8985613 [details] [diff] [review]
Patch with test and fix incorporating Mark's feedback

Review of attachment 8985613 [details] [diff] [review]:

::: toolkit/components/places/PlacesUtils.jsm
@@ +2496,5 @@
> +              UNION
> +              SELECT fst.* FROM moz_bookmarks AS fst
> +                INNER JOIN untagged_bookmarks AS snd
> +                ON fst.parent =
> +                WHERE <> ${PlacesUtils.tagsFolderId} )

This is pretty much selecting all the bookmarks, that in a small profile is likely quick, but in a profile with some thousands bookmarks is not the best option.

I'd rather do the opposite, count tagged bookmarks for the given id, sum that to the number of keywords, and you can tell whether there are only keywords and tags.
Something like this should work:

SELECT, h.url
FROM moz_places h	
JOIN moz_keywords k ON k.place_id =	
HAVING h.foreign_count = count(*) +
  (SELECT count(*)
   FROM moz_bookmarks b
   JOIN moz_bookmarks p ON b.parent =
   WHERE p.parent = :tags_root AND =

Also, please use a binded param, don't build SQL strings manually
Attachment #8985613 - Flags: review?(mak77) → review-
Attachment #8985613 - Attachment is obsolete: true
Thanks for the review, Marcos!  I uploaded a new patch with your recommendations.
Attachment #8985737 - Flags: review?(mak77)
Comment on attachment 8985737 [details] [diff] [review]
Patch incorporating SQL performance and safety feedback from Marco

Review of attachment 8985737 [details] [diff] [review]:

Thanks, it looks great, I just ran the test locally to confirm it.

This kind of problems will go away naturally when we move tags away from the bookmarks table.
Attachment #8985737 - Flags: review?(mak77) → review+
Comment on attachment 8986198 [details]
Bug 1468104 - Existence of tag on a bookmark prevents deletion of associated keyword.
Attachment #8986198 - Flags: review?(mak77) → review+
Comment on attachment 8985737 [details] [diff] [review]
Patch incorporating SQL performance and safety feedback from Marco

Converted the patch to mozreview to simplify landing.
Attachment #8985737 - Attachment is obsolete: true
Pushed by
Existence of tag on a bookmark prevents deletion of associated keyword. r=mak
Closed: Last year
Resolution: --- → FIXED
Target Milestone: --- → mozilla62
Flags: qe-verify+
I’ve reproduced this issue on Firefox 62.0a1 (20180610100220) under Ubuntu 16.04 x64.
This behavior no longer occurs on Firefox 62.0b7 (20180709172241) under Ubuntu 16.04 x64, Windows 10 x64 and macOS 10.13.
Flags: qe-verify+
You need to log in before you can comment on or make changes to this bug.