2

ほとんどのアプリケーションでは、ユーザーが必要とする大量の情報を照会する必要性を回避するのは困難browse throughです。これが私をカーソルに導いたものです。mnesia では、カーソルはqlc:cursor/1 または qlc:cursor/2を使用して実装されます。彼らとしばらく一緒に仕事をして、何度もこの問題に直面した後、

11> qlc:next_answers(QC,3).
** 例外エラー: {qlc_cursor_pid_no_longer_exists,<0.59.0>}
     関数内 qlc:next_loop/3 (qlc.erl、1359行目)
12>
カーソル全体が 1 つの mnesia トランザクション内にある必要があることに気付きました。全体として 1 回実行されます。以下のように
E:\>erl
Eshell V5.9 (^G で中止)
1> mnesia:start()。
わかった
2> rd(obj,{キー,値})。
オブジェクト
3> mnesia:create_table(obj,[{attributes,record_info(fields,obj)}])。
{アトミック、わかりました}
4> Write = fun(Obj) -> mnesia:transaction(fun() -> mnesia:write(Obj) end) end.
#楽しい<erl_eval.6.111823515>
5> [書き込み (#obj{キー = N、値 = N * 2}) || N <-リスト:seq(1,100)]、わかりました。
わかった
6> mnesia:transaction(fun() ->
            QC = cursor_server:cursor(qlc:q([XX || XX <- mnesia:table(obj)])),
            Ans = qlc:next_answers(QC,3),
            io:format("\n\tAns: ~p~n",[Ans])
    終わり)。
        回答: [{obj,20,40},{obj,21,42},{obj,86,172}]
{アトミック、わかりました}
7>
qlc:next_answers/2mnesia トランザクションの外で say: を呼び出そうとすると、例外が発生します。トランザクションの外だけでなく、そのメソッドがカーソルを作成したプロセスとは異なるプロセスによって実行されたとしても、問題は必ず発生します。

もう 1 つの興味深い発見は、mnesia トランザクションから抜け出すとすぐに、mnesia カーソル (明らかに mnesia はバックグラウンドでプロセスを生成します) に関与するプロセスの 1 つが終了し、カーソルが無効になることです。以下を見てください。
-module(cursor_server)。
-compile(export_all)。
カーソル(Q)-> case mnesia:is_transaction() の 偽 -> F = fun(QH)-> qlc:cursor(QH,[]) end, mnesia:activity(transaction,F,[Q],mnesia_frag); true -> qlc:cursor(Q,[]) 終わり。
%% --- モジュールの終わり ------------------------------------------ -
次に、シェルでそのメソッドを使用します:
7> QC = cursor_server:cursor(qlc:q([XX || XX <- mnesia:table(obj)]))。
{qlc_cursor,{<0.59.0>,<0.30.0>}}
8> erlang:is_process_alive(list_to_pid("<0.59.0>"))。
間違い
9> erlang:is_process_alive(list_to_pid("<0.30.0>"))。
真実
10>自分()。
<0.30.0>
11> qlc:next_answers(QC,3).
** 例外エラー: {qlc_cursor_pid_no_longer_exists,<0.59.0>}
     関数内 qlc:next_loop/3 (qlc.erl、1359行目)
12>
したがって、これにより、ユーザーが特定の結果セットを参照する必要がある Web アプリケーションを構築することが非常に困難になります。たとえば、グループごとに、最初の 20 を与え、次に次の 20 を与えるなどです。これには、最初の結果を取得することが含まれます。 、それらをWebページに送信し、ユーザーがクリックするのを待ってから、次の20をNEXT要求します. qlc:cursor/2これらの操作は、mnesia トランザクション内でハングアップしている間は実行できません!!! 唯一可能な方法は、そこでハングするプロセスを生成し、次の回答をメッセージとして受信して送り返し、次のようなメッセージとして next_answers リクエストを受信することです。

-define(CURSOR_TIMEOUT,timer:hours(1))。

%% 最初のリクエストは以下で行われます
リクエスト(ページサイズ)->
    私=自分()、    
    CursorPid = spawn(?MODULE,cursor_pid,[Me,PageSize]),
    受け取る
        {initial_answers,Ans} ->
            %% Cursor Pid を非表示にする方法を見つける
            %% ページで、後続のリクエスト
            %% 一緒に来る
            {Ans,pid_to_list(CursorPid)}
    ?CURSOR_TIMEOUT後 -> タイムアウト
    終わり。

cursor_pid(ParentPid,PageSize)->
    F = fun(Pid,N)->
            QC = cursor_server:cursor(qlc:q([XX || XX <- mnesia:table(obj)])),
            Ans = qlc:next_answers(QC,N),
            ピッド!{initial_answers,Ans},
            受け取る
                {From,{next_answers,Num}} ->
                    から !{next_answers,qlc:next_answers(QC,Num)},
                    %% ここに問題があります! ループバックする方法
                    %% チェック: Erlang Y-Combinator
                削除 ->
                    %% すでに死んでいる可能性があるため、ここでは注意してください !
                    qlc:delete_cursor(QC) を試してください
                        _ -> わかりました
                    キャッチ
                        _:_ -> わかりました
                    終わり、
                    退出(通常)
            ?CURSOR_TIMEOUT後 -> 終了(通常)
            終わり
        終わり、
    mnesia:activity(transaction,F,[ParentPid,PageSize],mnesia_frag).

next_answers(CursorPid,PageSize)->
    list_to_pid(CursorPid) ! {self(),{next_answers,PageSize}},
    受け取る
        {next_answers,Ans} ->
            {Ans,pid_to_list(CursorPid)}
    ?CURSOR_TIMEOUT後 -> タイムアウト
    終わり。

これは、プロセス終了の管理、追跡/監視などのより複雑な問題を引き起こします。なぜ mnesia の実装者はこれを見なかったのでしょう!

さて、それで私の質問に移ります。私は解決策を求めてWebを歩き回っていますが、質問が発生するこれらのリンクをチェックしてください。1.文書化されているものとは異なる方法でmnesiaクエリカーソルを処理する方法について誰かが考えを持っていますか?共有する価値がありますか? 2. mnesia implemeters が単一のトランザクション内でカーソルを強制することを決定した理由は何ですか?



next_answers

3.私が提示した内容から、明確に理解できないものはありますか?

4. AMNESIA (上記のリンクのセクション 4.7) には、カーソルの適切な実装があります。これは、next_answers の後続の呼び出しが同じトランザクション内にある必要がなく、同じプロセスによる NOR である必要がないためです。これが原因で mnesia から amnesia に切り替えることを誰かにアドバイスしてもらえますか?また、このライブラリはまだサポートされていますか?

5. Ulf Wiger (多くの erlang ライブラリ、特に GPROC の作成者) は、mnesia:select/4. Web アプリケーションのカーソルの問題を解決するためにどのように使用しますか?

注: この特定の問題に mnesia を使用したいので、mnesia を離れて別のものを使用するようにアドバイスしないでください。この質問をすべて読んでいただきありがとうございます。

4

2 に答える 2

3

動機は、トランザクションが(あなたの場合)読み取りロックを取得することです。ロックは、トランザクションの外では保持できません。

必要に応じて、dirty_context で実行できますが、トランザクション プロパティが失われます。つまり、呼び出し間でテーブルが変わる可能性があります。

make_cursor() ->
    QD = qlc:sort(mnesia:table(person, [{traverse, select}])),
    mnesia:activity(async_dirty, fun() -> qlc:cursor(QD) end, mnesia_frag).

get_next(Cursor) ->
    Get = fun() -> qlc:next_answers(Cursor,5) end,
    mnesia:activity(async_dirty, Get, mnesia_frag).

del_cursor(Cursor) ->
    qlc:delete_cursor(Cursor).
于 2012-08-20T13:30:27.270 に答える