MozillaZine.jp フォーラム https://forums.mozillazine.jp/ |
|
長時間使用してるとLocalStorage保存でエラー発生する https://forums.mozillazine.jp/viewtopic.php?f=2&t=15228 |
ページ 1 / 2 |
作成者: | 偶然的通行人 [ 2015年1月25日(日) 21:14 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
当方、ご提示のデバッガ画面を読み解く実力はありませんし、ご提示の拡張機能やそのスキンは使用していないため、それらのことでは助力できそうにありませんが、問題点切り分けの考え方についてコメントさせていただきます。 NS_ERROR_STORAGE_BUSY のエラーは、プロファイルに存在する *.sqlite のファイルで発生することがあるようです。 localStorage(Web Storage)は、webappsstore.sqlite に保管されているので、ご提示のエラーが出る対象にはなっていると思いますが、localStorage に限定して出るエラーではなさそうです。 文字通り、対象のストレージがビジー状態で反応しなくなっているといった意味だと思いますが、 EarlgreyTea さんが書きました: これはFirefoxの問題と考えてよいでしょうか。それとも拡張機能側で対処可能でしょうか。 を判断するためには、この状態を生み出す根本的な原因を探る必要があるのではと思います。現状で、推測できる原因の所在は3つあると思います。 (1)Firefox 本体に本質的な問題がある (2)特定の拡張機能に問題がある (3)(2)の拡張機能に連動する特定のスキンに問題がある 予備的には、次も念頭に置いておくほうがいいかもしれません。 (4)他のアドオンや Firefox の設定などの組み合わせが影響しているかもしれない 現状でお使いの Firefox 35.0 をベースに、拡張機能とスキンの組み合わせを変えて、問題が発生するか否かを点検してはいかがでしょうか。 テスト用に、それぞれの組み合わせごとに新しいプロファイルを追加し、そこに当該の拡張機能とスキンだけを入れてテストしてみると、他のアドオンの影響の有無も判断できるかもしれません。 (a)chaika 開発版 1.7.5pre + gray 2.7.5(ご質問の事案が発生している条件) (b)現時点での chaika 正規版 + gray 2.7.5 (c)chaika 開発版 1.7.5pre + 他のスキンまたはデフォルトスキン (d)現時点での chaika 正規版 + 他のスキンまたはデフォルトスキン ―― この4種の組み合わせで問題発生の有無を調べ、発生する/しないが分かれるなら、原因のありかを(ある程度)絞り込めるのではないでしょうか。 どの組み合わせでも発生する場合、現状の Firefox 35.0 側に原因があるのかもしれません。 「エラーが発生するようになり」ということは、以前は問題が起こらなかったという意味だと推測されます。 もしそうなら、問題が起こらなかった以前のバージョン(退役した34.0 以前、または現役の 31.x ESR 版)を一時的に使って、上記4つを適用しながら試してみると、Firefox のバージョンによる動作の違いが見えてくるかもしれません。 ただ、「長時間使用しているとエラーが発生する」とのことなので、確認作業には根気がいると思われます。 EarlgreyTea さんが書きました: Firefoxの履歴やキャッシュのクリアなどを行っても改善されず、 localStorage のデータに関していえば、履歴やキャッシュのクリアでは消去されません。 [履歴] -> [最近の履歴を消去] で開くダイアログで、[消去する履歴の期間] を [すべての履歴] にし、[消去する項目] では [Cookie] にチェックを入れて [今すぐ消去] を実行します。 オリジン単位での選択的な消去はできず、すべて消すことになります。 同時に Cookie もすべて消去されるため、残しておきたい Cookie があるなら、プロファイル内の cookies.sqlite をバックアップしたあと上記を実行し、その後に cookies.sqlite を書き戻すことで、localStorage の全データだけを消すことができると思います。 以上、直接的な解決策ではなく申し訳ありませんが、とりあえず気がついたことを書かせていただきました。 的外れな話だったらすみません。 |
作成者: | EarlgreyTea [ 2015年1月26日(月) 07:15 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
コメントありがとうございます。 偶然的通行人 さんが書きました: 当方、ご提示のデバッガ画面を読み解く実力はありませんし、ご提示の拡張機能やそのスキンは使用していないため、それらのことでは助力できそうにありませんが、問題点切り分けの考え方についてコメントさせていただきます。 既知の問題があるならととりあえず質問させていただいたのですが、やはり切り分け必要ですよね。 なにぶん長時間連続使用しないと現象が出ないため、切り分け検証をしようとすると通常使用に差し障ってくるもので躊躇しておりました。やるならば、通常使用のプロファイルではchaikaを使わないようにし、別途テスト用のプロファイルにchaikaを入れたFirefoxを起動する必要があるようです。 さて、私の質問文は説明を端折り過ぎたのか一部齟齬が生じてしまったようです。今一度、状況を補足して説明させていただきます。 私はFirefoxを割りと起動しっぱなし、PCも1週間くらいは起動しっぱなしにしています。問題のエラーはFirefoxを起動した最初は起こらないのですが、連続して使用していると突然発生し、一度そうなるとchaikaでスレッドを読み直したりgrayの設定や履歴を保存しようとする度に必ずエラーになります。しかし再起動するだけでその状態は解消します。 そこで、grayが出すエラーメッセージ(alert)の箇所を探してデバッガで停め、キャッチした例外の中身を見てみたのが質問に添付した画像になります。その結果、ローカルストレージへの保存処理で NS_ERROR_STORAGE_BUSY 例外が発生しているところまで突き止めたという次第です。 この現象ですが、実は何ヶ月も前から(具体的には思い出せませんが)気がついていたのですが、Firefoxを再起動さえすれば解消するので放置していました。ということで、Firefox 35.0や直近のバージョンに限った話ではありません。 発生頻度については、今は長時間使っていたら発生したような気がするとしか言えません。1日くらいでエラーが出たり、もっと早くエラーになったこともあった気がします。ちなみに、22日に質問してからはまだ一度もエラーになっていません。 ともかく、まずはテスト環境で現象を再現させることをやってみて整理したいと思います。 【2月1日追記】 経過報告です。 切り分け検証するには、まず現状環境での問題の再現状況を確認しておかないと始まらないのですが…1月22日以降、27日に35.0.1に更新し29日に1回エラーが発生したっきりという状況です。以前はもっと発生頻度高かったはずなんですけどね。 仮に1週間に1回程度の頻度だとしてもそれを見極めるだけであと2、3週間は確認する必要あるでしょうし、そこから環境をいろいろ変えてただ再現確認するというのは、根気のいる作業なだけでなく、果たしてそれで原因特定に到れるものやら不安なところです。 できればエラーが発生した際に調べられることは調べておきたいと思います。何かよいアドバイスはございませんでしょうか。 |
作成者: | 偶然的通行人 [ 2015年2月13日(金) 20:18 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
すみません。いままで「追記」に気がつきませんでした。 # 返信は「新着」として反映されるのですが、既存記事の編集による追記だと # フォーラムページやフィードに新着情報として反映されないため、見落とされやすくなります。 EarlgreyTea さんが書きました: 私はFirefoxを割りと起動しっぱなし、PCも1週間くらいは起動しっぱなしにしています。問題のエラーはFirefoxを起動した最初は起こらないのですが、連続して使用していると突然発生し、一度そうなるとchaikaでスレッドを読み直したりgrayの設定や履歴を保存しようとする度に必ずエラーになります。しかし再起動するだけでその状態は解消します。 背景事情はわかりました。 ぼく自身の用途においては、そのような連続稼働を必要としないこと、PC 全体の安定性を考慮するなら適宜再起動するほうが安心できることなどから、作業が終われば PC をシャットダウンします。長くても 72 時間程度、それ以上連続稼働することは稀です。Firefox などのアプリケーションも同様です。 なので、ぼくのところでは、EarlgreyTea さんと同様の条件での使用体験はなく、正直いって追試もおこない難いです。 EarlgreyTea さんが書きました: そこで、grayが出すエラーメッセージ(alert)の箇所を探してデバッガで停め、キャッチした例外の中身を見てみたのが質問に添付した画像になります。その結果、ローカルストレージへの保存処理で NS_ERROR_STORAGE_BUSY 例外が発生しているところまで突き止めたという次第です。 localStorage のキーワードで Bugzilla を検索してみると、参考になるものが見つかるかもしれません。 ただ、「ローカルストレージへの保存処理で NS_ERROR_STORAGE_BUSY 例外が発生」していたとしても、そのエラーを引き起こしている原因がどこにあるかは、きちんと見極めたほうがいいと思います。 「設定が保存できない」という現象が起こったとして、Firefox 本体の不具合やアドオンの影響のほかにも、システムの設定ミスなどで書き込みが制限されていたことが原因になっているケースもあります。 「Web ページが表示されない」という現象でも、その原因はひとつではなく、原因によって対処方法が異なるのはご存知のとおりです。 そういう観点からいうと、"Firefox の localStorage 処理" そのものに不具合がある可能性もありますが、Firefox の localStorage 処理を阻害している別の何かがある可能性を否定できていないのが現状ですから、冷静に原因を見極めていかないと、本当の意味での解決にはつながらないのではと思います。 EarlgreyTea さんが書きました: 仮に1週間に1回程度の頻度だとしてもそれを見極めるだけであと2、3週間は確認する必要あるでしょうし、そこから環境をいろいろ変えてただ再現確認するというのは、根気のいる作業なだけでなく、果たしてそれで原因特定に到れるものやら不安なところです。 できればエラーが発生した際に調べられることは調べておきたいと思います。何かよいアドバイスはございませんでしょうか。 "PC 自体および Firefox を長時間連続稼働させたまま" というのが、ひとつのキーワードみたいですね。 とくに本件は、特定のアドオンの使用に際して起こってる問題のようですから、まずはアドオンの影響の有無を切り分けることをお勧めしたのですが、おっしゃるように前便で紹介した方法では検証に時間がかかるのは避けられません。 現状で把握できていることから仮説を立てるなら、一般的に長時間連続稼働したときに起こりがちなのは、メモリリークの問題でしょうか。 問題が起こったとき、Firefox を「再起動するだけでその状態は解消」するとのことなので、その可能性は高いかもしれません。 以前に比べれば、長時間稼働時における Firefox 本体のメモリリークの問題は改善されていますが、使っているアドオンの動作が絡んできますし、以前はなかった新機能も追加されていますので、全体の稼働状況としてはメモリリークが起こらないわけではありません。 すでに確認されていることかもしれませんが、もしこのあたりに端を発している問題だとすると、ご質問のエラーが出たとき、OS のタスクマネージャーから、システム全体の中でその時点の Firefox がどのような状態になっているか、点検してみてはいかがでしょうか。 合わせて、Firefox の about:memory から Firefox 内部の各プロセスのメモリ使用状況を調べてみると、問題点が見えてくるかもしれません。 (参考)・Firefox のメモリ消費量が多い https://support.mozilla.org/ja/kb/firef ... memory-ram あまり役に立てない回答しかできず申し訳ないですが、以上です。 専門知識を持った方からアドバイスをいただけるとありがたいです。 |
作成者: | WADA [ 2015年2月15日(日) 16:33 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
EarlgreyTea さんが書きました: その結果、ローカルストレージへの保存処理で NS_ERROR_STORAGE_BUSY 例外が発生しているところまで突き止めたという次第です。 NS_ERROR_STORAGE_BUSY でググる Bug 671894 がこのエラーの例。 これを見ると、FirefoxではSQLite DBのオープンは同時には一人しかできないようにしていて、誰かがオープン中なのにオープンしようとしてでるエラーのようです。 このバグの場合は、アドオンマネージャーのシャットダウン中にアドオンがリクエストを投げてきて、それでダブルオープンが起こってしまった、ということみたいで、 悪さをしているのはアドオンなんだけど、リクエストをちゃんと処理できない状態にも関わらずリクエストを処理しようとしてしまうアドオンマネージャーもアホ、ということで、 アドオンマネージャー側で対応したようです。 パッチには「protect against invalid calls」と書いてありました。 特定のホゲホゲストレージに限った話ではありません。 EarlgreyTea さんが書きました: 問題のエラーはFirefoxを起動した最初は起こらないのですが、 連続して使用していると突然発生し、 一度そうなるとchaikaでスレッドを読み直したりgrayの設定や履歴を保存しようとする度に必ずエラーになります。 これ自体は、一度NS_ERROR_STORAGE_BUSYが起こると、ちゃんとエラー処理をしていないので、SQLite DBの更新が二度とできなくなってしまう、という、アドオン・スキンの問題でしょう。 そのアドオン・スキンを使いさえしなければ絶対に問題が起こらない、とう場合は、まずはそのアドオン・スキンを疑うのが普通でしょう。 多くのアドオンで起こる、というような場合には、Firefoxを先に疑いますけど。 通常は、誰かがオープン中なんだから、空くのを待つなり、オープンしている人に処理を依頼するなり、オープンのステップはスキップしてSQL文を実行するなり、適切な処理をすればいいだけの話。 オープン中の誰かさんが絶対に手放さないので、他の人は一切手出しできなくなってしまう、というのも、よくある話ですけど。 問題は、何故NS_ERROR_STORAGE_BUSYになってしまうかで、これは、アドオンマネージャーと同様に、Web Storage側で「protect against invalid calls」をしないといけない、ということになる可能性もあります。 参考までに。 |
作成者: | WADA [ 2015年2月15日(日) 16:52 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
アドオンだったら、大体はJavaScriptで書いてあるだろうから、アドオンの.xpiファイルを.ZIPにして適当なディレクトリーに解凍すれば、ソースを見られます。 エラーに関係しそうな箇所を見つけて、そこをtry/catchでくくり、 どこかにdevtools/Console.jsmのimport文をいれておいて、 var console = (Cu.import("resource://gre/modules/devtools/Console.jsm", {})).console; ctach(e)ブロックで、 var msg = event.currentTarget.id+" / "+event.currentTarget.label ; console.log(msg); console.log(e); とかやれば、Browser Consoleにデータを書き出せます。 あとは、このディレクトリーの中身を全て一つの.ZIPファイルにし、.xpiにしたいなら拡張子を.xpiに変えれば、自分用のアドオンのできあがり。 このあたりは、Custom Buttonsというアドオンをいれ、自前のボタンを作って、そのコードに以下の文貼り付けるだけで、簡単に確認できます。 var console = (Cu.import("resource://gre/modules/devtools/Console.jsm", {})).console; console.dir(console); 参考までに。 |
作成者: | WADA [ 2015年2月15日(日) 17:24 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
Web Storge(localStorage) に関しては、「MDN の docs/DOM/Storage 」を読んでください。 アドオンを解凍して、この文書に書いてあることから離れて特殊なことをしていないか、などを調べてみるといいでしょう。 基本的には、自分用のデータに、キー=値のセットを色々書いているだけだと思いますが、変なことをしている可能性もあります。 また、何かエラーが起こったらそれでお終い、というような、Thunderbirdが好きな書き方をしている可能性もあります(^^) |
作成者: | EarlgreyTea [ 2015年2月15日(日) 18:58 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
偶然的通行人さん、WADAさんコメントありがとうございます。 原因の切り分けに関してはこれといった進展がない状況です。現象の発生頻度も毎日のように起こっていた時もあったのですが、質問を投稿してからは1/22、1/29、2/3、2/4という発生状況です。 偶然的通行人 さんが書きました: "PC 自体および Firefox を長時間連続稼働させたまま" というのが、ひとつのキーワードみたいですね。 長時間もそうですが酷使しているのが発生確率を上げている要因になっているかもしれません。質問時には書いておりませんでしたが、オンラインゲーム用にChromiumを5つ起動しており、時にCPU使用率が100%の状態が続くこともあります。 偶然的通行人 さんが書きました: 合わせて、Firefox の about:memory から Firefox 内部の各プロセスのメモリ使用状況を調べてみると、問題点が見えてくるかもしれません。 そうですね。ご指摘を受けてときどきメモリリポートを保存するようにしました。今のところExplicit Allocationsが着実に増加していってるようです。 WADA さんが書きました: NS_ERROR_STORAGE_BUSY でググる Bug 671894 がこのエラーの例。 これを見ると、FirefoxではSQLite DBのオープンは同時には一人しかできないようにしていて、誰かがオープン中なのにオープンしようとしてでるエラーのようです。 なるほど、やはりそういう意味でしたか。クリーンなテスト環境では一度も起きていませんので、何者かによって WADA さんが書きました: オープン中の誰かさんが絶対に手放さないので、他の人は一切手出しできなくなってしまう という状況が発生しているのでしょうね。WADA さんが書きました: Web Storge(localStorage) に関しては、「MDN の docs/DOM/Storage 」を読んでください。 アドオンを解凍して、この文書に書いてあることから離れて特殊なことをしていないか、などを調べてみるといいでしょう。 基本的には、自分用のデータに、キー=値のセットを色々書いているだけだと思いますが、変なことをしている可能性もあります。 chaika用のgrayスキンはlocalStorage.setItem()で値を書いてエラー発生時はキャッチしてダイアログを出して処理を返しているだけなので、たまたま巻き込まれた側のような気がします。localStorageオブジェクトの中で何をやっているのかは気になるところですが。拡張機能でlocalStorageにアクセスしているものを調べてみるとして、そのほかにもWebアプリとかも開いてますので、今度エラーが起きた際にそういうものを閉じてみるとかも試してみたいと思います。 |
作成者: | WADA [ 2015年2月16日(月) 09:21 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
EarlgreyTea さんが書きました: chaika用のgrayスキンはlocalStorage.setItem()で値を書いてエラー発生時はキャッチしてダイアログを出して処理を返しているだけなので、たまたま巻き込まれた側のような気がします。 そこまで行っていれば、話しは早い。 try{localStorage.setItem("key","value");}catch(e){alert("...");} くらいしか書きようがない。 localStorageは、これ以上シンプルなものは無いくらいにシンプルなもので、以下の定義(SQLite Managerで簡単にわかる)。 CREATE TABLE webappsstore2 (scope TEXT, key TEXT, value TEXT, secure INTEGER, owner TEXT) scope, key, value, secure, owner という5つのカラムの至極単純な表で、 scopeがサイトのURIに対応していてアプリからは見えなくて、アプリは、key, valueのセットを自由に書けるというだけの話。 localStorageというオブジェクトのプロパティ経由での更新を考えると、XPCOMだのがでてきてややこしくなるけれど、 推奨のlocalStorage.setItem()/getItem()方式で考えると、setItem()/getItem()/clear()を呼んでSQLのリクエストをだしているだけ。 webappsstore2 というSQLのTableの管理は、おそらく「localStorage」の中で、mozStorage(SQLiへのインターフェース)を使ってやっているはずだが、 Table単位でのロック絡みだとすると、chaikaとかgray以外のアプリ・サイト以外もダメになるはずだから、 scope単位での「オープン」、「行のロック」、の話? クリーンなテスト環境では一度も起きていない、負荷が高い時のようである、長い時間使った後である、アプリ側はsetItem()/getItem()/clear()しか出せない、マルチタスクは当たり前でマルチCPUも当たり前、ということなどを考えると、 タイミングによって、localStorageの中でデッドロックが発生してしまう? と思いつつ、bugzillaをNS_ERROR_STORAGE_BUSYで検索してみたが、バグサマリーにNS_ERROR_STORAGE_BUSYがあるバグはたったの3つで、Bug 671894以外は役たたず。 ならば、と、ソースを検索したら、以下に遭遇。 ERROR_STORAGE_BUSYがあるソース SQLからSQLITE_BUSYが返ると、 convertResultCodeでNS_ERROR_STORAGE_BUSYを返していて、 BUSYだからBUSYでなくなるまでSleep、という、至極普通に思えるコードなのだが、 そこに、以下のコメントが... コード: 148 // TODO (Bug 1062823): from Sqlite 3.7.11 on, rollback won't ever return 149 // a busy error, so this handling can be removed. 150 nsresult rv = NS_OK; 151 do { 152 rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING("ROLLBACK")); 153 if (rv == NS_ERROR_STORAGE_BUSY) 154 (void)PR_Sleep(PR_INTERVAL_NO_WAIT); 155 } while (rv == NS_ERROR_STORAGE_BUSY); Bug 1062823 を見ると、 以前のSQLiteが、ROLLBACKの時にペンディングリクエストがあると、SQLITE_BUSYを返して、後で出直してね、と言ってくるので、それでBUSYでなくなるまで待つ、ということのようで、 それが、SQLite 3.7.11以降は、ROLLBACKが、ペンディングリクエストがあった時、 ペンディングリクエストに対してはSQLITE_ABORT か SQLITE_ABORT_ROLLBACK error. を返してROLLBACKを実行するようになったから、 もう、BUSYでなくなるまで待つ必要はない、ということのようです。 これはROLLBACKの時だけの話で、この場合は、SQLITE_BUSYが返らなくなるまでリトライするから、 ROLLBACKでアプリ側にNS_ERROR_STORAGE_BUSYが伝わるのは、タイムアウトでキャンセルした時くらいしかない。 アプリがlocalStorage.setItem()を出すところでタイムアウト検出してどうこう、は、ちょっと考えられないから、 やっぱり、行ロックをとれなかった、ということの可能性が高いですね。 行ロックをとれなかった後、アプリ側は、何かのイベントの時にまたsetItem()を出しているだけだろうから、 NS_ERROR_STORAGE_BUSYが一度返ると消えない、というのは、 おそらく、localStorage内で、このアプリ用のscopeの行に関してデッドロックが発生している、ということなのでしょう。 タイミングホールだけでなく、アプリ側がclear()を多用していると、ROLLBACKとROLLBACKが衝突、というようなこともあるかもしれません。 極一部のアプリだけ、というのは、アプリ側が、こっちではKey1を更新してからKey2を更新、なのに、 あっちでは、Key2を更新してからKey1を更新、というようなことを、随所で行っている、 というようなことが関係してくるかもしれません。 元々がクッキーの置き換え・拡張だから、普通は、あるscopeにおいて一人だけが更新、だが、 アプリによっては、同じscopeで、複数のタスクが同時に更新、ということが起こるのかも知れません。 もしこういったことならば、原因は、localStorageがデッドロックを考慮していない、ということになるんだと思います。 なお、localStorageの中身を見たりするには、Firebug + FireStorage Plus!が便利そうです。 firefox-addon-to-view-edit-create-localstorage-data [追記] 既に、Toool/Web Developer/Storage Inspector が標準装備されてますね。 Storage Inspectorは、今のサイトのscopeのものについて、Cookie, IndexedDB, localStorage, sessionStorage, を見やすくして表示してくれて、親切。 Firebug + FireStorage Plus! のアドバンテージは、全部のscopeについて、一括で見られること。 [/追記] |
作成者: | WADA [ 2015年2月17日(火) 07:53 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
ロックが、最終的なその行のExclusive Lock以外にも、行の範囲でのロックもあるので、同じ行の範囲に対する複数のリクエストの間のロックの競合はあり得るけれど、 localStorageは、clear()以外は、一回のSQLへのリクエストは一つの行の操作だけだから、「デッドロック」と言う状態は、ちょっと考えにくい。 「一回のSQLへのリクエストは一つの行の操作だけ」であっても、「一回のSQLへのリクエスト」は、デッドロックが起こらないように、何かエラーがあったらROLLBACKしてやり直し、と言う感じになるはず。 となると、scopeが同じであろうとなかろうと、複数のタスクによる同じ行の範囲の操作の間で競合がおこり得るから、 その時に、両方のタスクが同時にROLLBACKを出すことがあり得る。 そして、今のSQLiteの仕様+あのコードだと、両方とも、SQLITE_BUSYが返らなくなるまで、無限にROLLBACKを繰り返す。 すると、今のSQLiteは、ペンディングリクエストがあるのだから、両方のROLLBACKに対して、必ずSQLITE_BUSYを返す。 そうなると、無限のROLLBACKの繰り返し、から永久に抜け出せない。 PR_Sleep(PR_INTERVAL_NO_WAIT)と、NSPR_SleepをNO_WAITでやっているんだから、コードを見る限りは、そうなって当然。 その状態の時に、同じ行に対するリクエスト、あるいは、同じ行の範囲に対するリクエストがくれば、SQLITE_BUSYが必ず返る。 SQLiteのSQLite_busy_timeoutとかSQLite_busy_callbackとかのマニュアルとか説明書で言っている、やってはいけないこと、あるいは、やると無限ループとか永久ウェィトになるよ、という類のことが実際に行われている例、かもしれません(^^) しかも、PR_Sleep(PR_INTERVAL_NO_WAIT)と、NSPR_SleepをNO_WAITでやっている、というオマケ付きで。 昔は、NO_WAITにしないとなかなかスケジュールされなくて、NO_WAITでちょうど良かったんでしょう。 何のためのSleepだと思っているんでしょうかね。 SQLite_timeoutなどもちゃんとあるわけだし。 clear()だと、一回のSQLiteへのリクエストで複数の行の操作、になるので、そういった問題がおきやすいかもしれないけれど、clear()がそんなに頻繁に多くのタスクからだされるとは考えにくく、 localStorageの場合は、getItem()による読み込みと、setItem()/removeItem()による更新だけと言ってもいいはず。 もしこういった問題だとすると、chaikaとかgrayだと起こる、というのは、 chaikaとかgrayは、同じ行の範囲になる更新のリクエストを、多くのタスクから同時並行的に多数出す、ということもあるかもしれないですが、 try{localStorage.setItem("key","value");}catch(e){alert("...");}みたいな書き方をしているのはchaikaとかgrayだけなので、chaikaとかgrayしか問題を検出できない、ということかもしれません。 WebサイトのHTMLのスクリプトで簡単に使える非常にシンプルなものだし、setCookie()などよりも使い勝手はいいし、 localStorageのコールをわざわざtry/catchに入れる、というのは、ちょっと考えにくい。 エラーを検出したら、ツールバーボタンなりページに仕込んだボタンなりで、同じものに対して、 try{localStorage.setItem("key","value");}catch(e){alert(e);} とかをやってみるといいでしょう。 [追記とちょっと訂正] デバッガーの出力画像をみたら、prototypeでflash()を作ってあって、その中でclear()を出していた。 て、そこでのcatch(e)なんですね。 これで「chaikaとかgrayだと検出」は正しいと確信。 clear()で、全部の行に対してアクセスすれば、どこの行で起こった問題であっても引っかかるし、 chaikaとかgrayはちゃんとtry/catchをしているから、エラーも検出、と var msg=new Array(); for(var nn=0;nn<localStorage.length;nn++){ try{ var key=localStorage.key(nn) ; msg[msg.length]=nn + " / " + key + " = " + localStorage[key] ; } catch(e){ msg[msg.length]=e; } } alert( msg.join("¥n") ); // 円記号は全角になってます とでもすると、リードでもエラーになるかわかりますし、 setItem()かremoveItem()にすれば、どこでエラーになるかわかるかもしれません。 nnは、後で追加した方が小さくなるみたいなので、 for(var nn=localStorage.length-1;0<nn;nn--) も試してみるといいでしょう。 [/追記とちょっと訂正] |
作成者: | WADA [ 2015年2月17日(火) 18:35 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
Bug 1062823 に書いてあった、「SQLite (since version 3.7.11 circa 2012-03-20) 」で、ROLLBACKで返るリーズンコードの仕様がかわることがちょっと気になって、Bug 1062823 で聞いてみたところ、Firefoxでは既にSQLite 3.8.8.2に上げていました。 そうなると、新しい仕様の、SQLITE_ABORT_ROLLBACK と SQLITE_ABORT への対応はどうなっているか気になります。 で、ちょっと調べたら、案の定、SQLITE_ABORT_ROLLBACK については、全く対応していない(^^; あのコードの所で、ROLLBACKに対してエラーが返る時は、すでに、SQLITE_BUSYではなくて、SQLITE_ABORT_ROLLBACKに変っているから、あのままではROLLBACKに対してエラーが返ったときの処理がおかしくなる可能性がある。 もし、ROLLBACKに対してSQLITE_ABORT_ROLLBACKが返った場合は、Rollback()をコールしたルーチンに、一般的なエラーのNS_ERROR_FAILUREのエラーが返される。 その時、Rollback()をコールした側がちゃんとROLLBACKに失敗したとしてエラーリカバリーをしていればいいのだが、 Mozillaファミリーのコードは、エラーがあっても先に進んだり、エラーだと何もしない、ということが往々にしてあって、 どこかで、ROLLBACKが失敗したのにそれを無視、ということがあってもおかしくはない。 もしかすると、こういったことが原因で、どこかでデッドロックが起こってしまっているのかもしれません。 [蛇足] 今回初めてlocalStorageの仕様などを知ったので、setItem()とかremoveItem()とかを使ってみました。 JavaScriptの{ key1 : text1, key2 ; text1, key3 : text3, ...} というオブジェクトのイメージで、KeyもValueもテキストという制限があるものの、SQLiteのDBに保存できて、便利ですね。 getItem(),setItem(),removeItem(),clear()と、Enumeratorであるkey()しかない、というシンプルさも、使い勝手が良くて好感がもてる。 cookieの拡張とはいえ、setCookiie()みたいなややこしさはないし、ValueにJSONのデータを使えるから、JavaScriptの{ key1 : {obj1}, key2 : {obj2}, key3 : {obj3}, ...} のオブジェクトも、setItem()/getItem()だけでSQLite DBに保存できて、xxx.JSONとかいうファイルに書く手間もいらない。 webappsstore.sqliteの中に、PHP+SQLiteとかFirefox+SQLite Managerでデータを放り込んでおけば、ローカルファイルのデータの処理にHTML+JavaScriptを簡単に使える。 簡単SQLite DBのWrapper、と思って使えて、いいですね。 [/蛇足] |
作成者: | EarlgreyTea [ 2015年2月17日(火) 21:35 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
ちょっと見てない間にいきなり核心に迫っていて、さすがですWADAさん。すばらしい。 どうやら私がやたらと起動しっぱなしでFirefoxをいじめて、しかもエラーでアラート出すようにしていたために、デッドロックが表面化した、というところでしょうか。 私の方としてはこのまま使い続けて、また現象が発生したらもう少し調べてみたいと思います。 |
作成者: | WADA [ 2015年2月17日(火) 23:19 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
EarlgreyTea さんが書きました: どうやら私がやたらと起動しっぱなしでFirefoxをいじめて、しかもエラーでアラート出すようにしていたために、デッドロックが表面化した、というところでしょうか。 やっぱり、try/catchを入れたのはEarlgreyTeaさんでしたか。 あんなにシンプルでエラーが起こるなんてまずは考えられないlocalStorageのコールなのに、スキンの作者さんがtry/catchに入れるなんて...、 と、不思議に思ってました(^^) ただ、一言。 catch(e){ alert("storage eror"); }とかじゃなくて、catch(e){ alert(e); }とかしていれば、デバッガーを持ち出さずとも、SQLITE_BUSYだと一発でわかったはず。 あと、SQLITE_BUSYを検出したのはlocalStorage.clear()だったと、早く言ってくれれば... 一回のSQLリクエストで、あるscopeの全部の行に対してlocalStorage.removeItem()をだしているのと同じだから、どの行でSQLITE_BUSYが起こっても検出できるわけで... デバッガーの画像を見るまでは、検出自体も、運がいいと検出できる、あるいは運が悪いと検出できる、と思ってました(^^; 「やたらと起動しっぱなしでFirefoxをいじめ」たので、どこかでROLLBCKにSQLITE_ABORT_ROLLBACKが返ってしまい、その上に、mozStorageのコードがまともにエラー処理をしていなかった、というのが、やっぱり一番説得力がありますよね。 可能性としてはこういうことがある、と書きながらも、いつも、あんなにシンプルなlocalStorageで起こるはずが...、と思っていたのですが、これでスッキリしました(^^) |
作成者: | EarlgreyTea [ 2015年2月18日(水) 00:59 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
あ、変な書き方しちゃってごめんなさい。try/catch は元からなんです。なんで入っていたのかは作者さんに聞かないとわかりませんが、「データの保存に失敗しました。しおりや履歴を消去して再度試してください」というちゃんとしたメッセージを出していたところからすると、たびたび発生していたのかもしれません。ただ同じ状況だとすると「しおりや履歴の消去」自体ができないはずなので、昔のバージョンではサイズの制限?のエラーが出てた?のかな。 |
作成者: | WADA [ 2015年2月20日(金) 18:15 ] |
記事の件名: | Re: 長時間使用してるとLocalStorage保存でエラー発生する |
EarlgreyTea さんが書きました: try/catch は元からなんです。なんで入っていたのかは作者さんに聞かないとわかりませんが、 「データの保存に失敗しました。しおりや履歴を消去して再度試してください」というちゃんとしたメッセージを出していたところからすると、たびたび発生していたのかもしれません。 何故かエントリーが消えていないことに気づき、clear()をtry/catchにいれてみた。 ⇒ scope内のどの行で永久SQLITE_BUSYが起こっても、clear()だとエラーを検出するので、alert()が時々出る ⇒ それで、ちゃんとしたメッセージにした、 という気が... そして、clear()で頻繁にエラーを検出、ということは、clear()を多用していることの裏返しのはず。 ROLLBACKに対してSQLITE_ABORT_ROLLBACKが返って来た時に、 ちゃんとROLLBACKを再度ださないとロックが残ってしまうことが起こり得るのは、 一回のリクエストで複数の行に対して更新を行う、clear()だけ。 他のリクエストの場合は、一行だけに対するリクエストだから、 SQLITE_BUSYが返って来た時にはその行のロックをとれなかったことは保証されている。 従って、その後、たとえ、ROLLBACKでSQLITE_ABORT_ROLLBACKが返り、 その時にROLLBACKを再度ださない、ということが発生しても、ロックが残ってしまうことは起こり得ない。 そうなると、件のアプリケーションが頻繁にclear()を出すことが、件のアプリケーションで頻繁に永久SQLITE_BUSYを見られる理由である、と言えます。 clear()は、あるscope()==Webサイトのもの全部のremoveItemだから、普通は頻繁にだすことは考えにくい。 http://www.google.com.の直下の、foo-1.html, foo-2.html, ... , .foo-N.html,、の全員が、 同じscope=http://www.google.comを使うのだから、 通常のHTML内のスクリプトが、localStorage.clear()を頻繁にだすとは思えない。 普通は、手動で、Firefocのメニューから履歴のクリアーを行った時くらい。 そう考えると、clear()を頻繁にだすのでバグに遭遇してしまう、ということになります。 [追記] となると、現時点の回避策は、そのアプリの全てのlocalStorage.clear()を以下のように変えること、になってきます。 // keyの順番の後ろから try{ while(0<localStorage.length) loalStrage.removeItem( localStrage.key( localStorage.length-1 ) ) ; } catch(e) { var err=e; var ll_err=localStorage.length; var key_err = localStrage.key(localStorage.length-1) ; // keyの順番の前から try{ while(0<localStorage.length) loalStrage.removeItem( localStrage.key(0) ) ; } catch(e) {var err2=e: var ll_err2=localStorage.length; var key_err2 = localStrage.key(0) ; } alert( ll_err + ket_err + ll_err2 + key_err2 ) ; alert( err ); if(err2) alert( err2 ); } clear()は使わないでremoveItem()を使う、というだけ。 途中で行が他のリクエストと競合してSQLITE_BUSYが返っても、 それは、その行のremoveItem()の中で処理してリトライしてくれるから、 ロックを残してしまう「クリアー」が発生しない。 そして、何か異常があってremoveItem()でエラーがあっても、clear()の時と同様に、上記のコードで捉えられる。 [/追記] |
ページ 1 / 2 | All times are UTC + 9 hours |
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ |