Firefoxのバグ、9分おきにフリーズする件について

何だか気になるので調査

リンクを辿って、

に行く。

何が気になるのか

  • どんな処理を行ったときにFirefoxがフリーズするほどの処理が走るのか
  • 対象ユーザはどんな人か
  • 何故9分おきなのか
  • 対応策のアドオンは何をやっているのか
    • 効果はあるのか

どんなバグか

nsNavHistory::AsyncExecuteLegacyQueriesメソッドがSQLステートメントを作るのに同期的なcreateStatementを使用しているのでメインスレッドがそこでブロックされる。替わりに、createAsyncStatementを使用すべき。』というもの。

どんな変更が入っている?

テストコードを除くと、主に2つファイル

  • nsCookieService.cpp
  • nsNavHistory.cpp

この2つのファイル内のdbConn-<CreateStatementdbConn-<CreaateAsyncStatementに変更されている。

変更箇所はどんな処理部分?

nsCookieService

こちらはCookieの管理を行うサービス

  1. nsCookieService::RemoveAll()
    • 保管されているCookieを全削除(DELETE FROM moz_cookies)
    • 全削除を呼び出すのは稀。今回の件とは別だけど、ついでにって感じだろう
  2. nsCookieService::Read()
    • baseDomainがNULLでないCookieデータを照会(SELECT .. FROM moz_cookies WHERE baseDomain NOTNULL)
    • baseDomainがNULLのデータ削除(DELETE FROM moz_cookies WHERE baseDomain ISNULL)
    • 全データを照会するので、頻度によってはボトルネックだが、一般的なhttp通信でCookieを取って設定するメソッドは別にあるので使用頻度は低いと思われる。
      • とりあえず、DBの初期化部分で呼び出しているのは発見した。他にもあるかもしれないが、そんな何度も呼び出すメソッドではないはず。
nsNavHistory

こちらはPlacesと呼ばれるブックマークと履歴の管理を行うサービス。

  1. nsNavHistory::AsyncExecuteLegacyQueries()
    • 複数のクエリを非同期実行するメソッドのはずだが...同期的実行になってしまっていた模様
    • 実行する頻度によってはボトルネックになりそう
  2. nsNavHistory::BindQueryClauseParameters()
  3. nsNavHistory::FixInvalidFrecencies()
    • frecencyとやらの値が0未満のデータに対して変更(UPDATE moz_places SET frecency = CALCULATE_FRECENCY(id) WHERE frecency > 0)
    • これも実行頻度によってはボトルネックになると思われる
小まとめ

問題は以下2点のメソッドと思われる。

  1. nsNavHistory::AsyncExecuteLegacyQueries
  2. nsNavHistory::FixInvalidFrecencies

nsNavHistory::AsyncExecuteLegacyQueries

これは何処から呼ばれているか。Mozilla Cross-Referenceで検索する。

テストコードとIDLを除くと、呼び出しているのは一つのみ

名前から察するに、Windows7のジャンプリストのことだろう、という予想通りWindows7でないと動かない仕組みになっている。

どの程度の頻度で呼び出されるか

WindowsJumpList.jsmを読むと、

  1. _updateTimerメソッドを実行して
  2. nsITimerにより定期的にnotifyメソッドを呼び出している
    • 頻度: browser.taskbar.lists.refreshInSeconds(デフォルト: 120) 秒
    • いくつか条件をクリア(Firefox起動中は大抵通りそうな条件)
    • _buildListメソッド呼び出し
      • browser.taskbar.lists.frequent.enabled(デフォルト: true)がtrueなら、--中略-- _getHistoryResults呼び出し
      • browser.taskbar.lists.recent.enabled(デフォルト: false)がtrueなら、--中略-- _getHistoryResults呼び出し

問題のasyncExecuteLegacyQueries_getHistoryResultsから呼び出されている。

まあだいたい120秒間隔で同期的SQLが実行されていることになるのだろう。

_getHistoryResults

PlacesQueryなるものを作成して履歴を照会している。
それぞれ、デフォルト値なら、

  • Frequent(よく行くページ): place:sort=8&redirectsMode=2&maxResults=7
  • Recent(最近行ったページ): place:sort=4&redirectsMode=2&maxResults=14

となる。(このコードをURLとしてブックマークすると特殊なフォルダとして使えるようになるよ)

どちらも訪問回数や訪問時刻でソートするし、訪問回数なら集約関数とかgroup byを使うことになるしで多少重たい処理かも。
まあ詳しくは本を買えw

Firefox 3 Hacks ―Mozillaテクノロジ徹底活用テクニック

Firefox 3 Hacks ―Mozillaテクノロジ徹底活用テクニック

小まとめ
  • Windows 7限定
  • それなりの頻度で定期的に実行され、その間メインスレッドがブロックされると思われる
    • デフォルト120秒間隔なので「9分間隔」で、という理由にはなっていない気がする
  • 本を買え

nsNavHistory::FixInvalidFrecencies

次、nsNavHistory::FixInvalidFrecencies
これが呼ばれるのは、結局のところ、オブザーバーのaTopicidle-dailyの場合になる。名前のとおり、少なくとも24時間毎の実行になるため、「9分毎」はあり得ないだろう。
ということで、実行頻度は低い。


対応策のアドオン

  1. 「Places Maintenance add-on」をインストール。
  2. 「Places Maintenance」のオプションダイアログを起動。
  3. 「Expire」を選択し「Execute」をクリック。
  4. 「Places Maintenance」アドオンをアンインストール。もちろん必要であればインストールしておいても問題ない。
Firefoxにバグ、9分おきにフリーズ | エンタープライズ | マイコミジャーナル

アドオンの中身を見てみると、結局のところ、PlacesDBUtils.expireを実行しているようだ。

PlacesDBUtils.expire
  1. 訪問7日間より前の履歴データを削除
  2. 履歴とブックマークのテーブルから参照されていないエントリを削除
  3. 参照されないアイコンデータの削除
  4. 参照されないアノテーションの削除
  5. 期限切れのアノテーションの削除
  6. 参照されない入力履歴の削除
  7. 各テーブルの統計情報を取得

と、要はデータの削除を行っている。

データ量が減って照会が速くなるぞ、ワーイってわけ。

エラーコンソールを起動して

Components.utils.import("resource://gre/modules/PlacesDBUtils.jsm").PlacesDBUtils.expire()

と実行すれば、アドオン入れなくてもOKかもw

Places DBのメンテ

コードを読んでいて気付いたのだが、DBのメンテナンスが通常だと、places.history.expiration.interval_seconds(設定されていない場合は 180) x 3秒、通常設定されていないので、9分間隔で動くのよね。

PlacesDBUtils.expireからと比べると量は少ないはずだけど、削除処理は走る。非同期処理のはずだけれどDBが大きい場合は馬鹿にならない処理となりそう。これ、結構怪しい。

と思いながら、Bugzillaの方を読み直すと(面倒臭がって初めは読んでなかった)、こちらの問題っぽいコメントが出ていた。予備知識をもって読むと理解度が全然違うね!

というわけで、

To fix the hangs we'll also need bug 690354 and bug 691509 though.

https://bugzilla.mozilla.org/show_bug.cgi?id=686025#c115

というコメントが付いているわけですね。

結論

  • 今回のBug 686025バグフィックスだけでは不十分
    • Windows 7ユーザは多少重たさが解消されるかも
  • places.sqlite 周りの定期メンテナンスが適切に行われないとフリーズする可能性はまだある
どんな処理を行った時に重たくなるか
  • 9分間隔くらいで動くplaces.sqliteのメンテナンス
    • 期限切れデータの削除
    • 統計情報取得
対象
  • たくさんのページを開く人
  • アイドル時間をあまり取らない人
  • places.sqliteのメンテをしない人
  • Windows7ユーザ
    • 今回ので多少解消されると思うが...
何故9分おきか
  • places.sqliteのメンテナンスが走る間隔だから
対応策のアドオンは何をやっているか
  • 強烈なメンテナンス(7日間より前のデータは全削除)
    • 効果はある(作った人、Marco Bonardo が今回のパッチを作っている)

って感じでしょうか。


ふぅ〜疲れた。おやすみ!

:wq