Domanda

Sto scrivendo record in Mnesia che dovrebbero essere tenuti lì solo per un tempo consentito (24 ore).Dopo 24 ore, prima che un utente ne modifichi una parte, il sistema dovrebbe rimuoverli automaticamente.ForeSample, a un utente viene concesso il tempo di trasmissione gratuito (per le chiamate vocali) che dovrebbero usare in un determinato momento.Se non lo usano, dopo 24 ore, il sistema dovrebbe rimuovere queste prenotazioni delle risorse dai registri degli utenti.

Ora, questo ha introdotto i timer.un esempio di struttura di record è:

 -record(free_airtime,
            {
                reference_no,
                timer_object,   %% value returned by timer:apply_after/4
                amount
            }).
 

L'oggetto timer nel record è importante perché nel caso in cui l'utente metta finalmente per utilizzare le risorse riservate prima di essere scattate (o se sono di tempo), il sistema può chiamare timer:cancel/1 in modo da alleviare il server timer da questo oggetto.Ora il problema, ho due modi per gestire i timer su questi record:

Opzione 1:timer gestiti all'interno della transazione

 reserve_resources(Reference_no,Amnt)->
    F = fun(Ref_no,Amount) -> 
            case mnesia:read({free_airtime,Ref_no}) of
                [] -> 
                    case mnesia:write(#free_airtime{reference_no = Ref_no,amount = Amount}) == ok of
                        true -> 
                            case timer:apply_after(timer:hours(24),?MODULE,reference_no_timed_out,[Ref_no]) of
                                {ok,Timer_obj} -> 
                                    [Obj] = mnesia:read({free_airtime,Ref_no}),
                                    mnesia:write(Obj#free_airtime{timer_object = Timer_obj});
                                _ -> mnesia:abort({error,failed_to_time_object})
                            end;
                        false -> mnesia:abort({error,write_failed})
                    end;
                [_] -> mnesia:abort({error,exists,Ref_no})
            end
        end,
    mnesia:activity(transaction,F,[Reference_no,Amnt],mnesia_frag).

Informazioni sull'opzione di cui sopra.

I documenti della Mnesia affermano che le transazioni potrebbero essere ripetute dal gestore della TM (per qualche motivo) fino a quando non hanno successo, e quindi quando si mette il codice che è io:format/2 o qualsiasi altro che non ha nulla a che fare con le scritture o le letture, potrebbe essere eseguito più volte.Questa affermazione mi ha fatto fermare a questo punto e pensare a un modo di gestire i timer fuori dalla transazione se stessi, quindi ho modificato il codice come segue:

Opzione 2:timer gestiti al di fuori della transazione

reserve_resources(Reference_no,Amnt)->
    F = fun(Ref_no,Amount) -> 
            case mnesia:read({free_airtime,Ref_no}) of
                [] -> 
                    P = #free_airtime{reference_no = Ref_no,amount = Amount},
                    ok = mnesia:write(P),
                    P;
                [_] -> mnesia:abort({error,exists,Ref_no})
            end
        end,    
    Result  =   try mnesia:activity(transaction,F,[Reference_no,Amnt],mnesia_frag) of
                    Any -> Any
                catch
                    exit:{aborted,{error,exists,XX}} -> {exists,XX}
                    E1:E2 -> {error,{E1,E2}}
                end,
    on_reservation(Result).

on_reservation(#free_airtime{reference_no = Some_Ref})-> 
    case timer:apply_after(timer:hours(24),?MODULE,reference_no_timed_out,[Some_Ref]) of
        {ok,Timer_obj} -> 
                [Obj] = mnesia:activity(transaction,fun(XX) -> mnesia:read({free_airtime,XX}) end,[Some_Ref],mnesia_frag),
                ok = mnesia:activity(transaction,fun(XX) -> mnesia:write(XX) end,[Obj#free_airtime{timer_object = Timer_obj}],mnesia_frag);
        _ -> 
            ok = mnesia:activity(transaction,fun(XX) -> mnesia:delete({free_airtime,XX}) end,[Some_Ref],mnesia_frag),
            {error,failed_to_time_object}
    end;
on_reservation(Any)-> Any.

Il codice per gestire il time out della prenotazione:

reference_no_timed_out(Ref_no)->
    do_somethings_here.....
    then later remove this reservation from the database....below..
    ok = mnesia:activity(transaction,fun(XX) -> mnesia:delete({free_airtime,XX}) end,[Ref_no],mnesia_frag).

Ora ho pensato che nell'opzione 2, sono più sicuro mantenendo il codice di elaborazione del timer, anche quando mnesia_tm riesetta la transazione per le sue ragioni, questo pezzo di codice non viene eseguito due volte (evito di avere diversi oggetti timer contro lo stesso documentazione).

Domanda 1: Quale di queste due implementazioni è corretta?e/o sbagliato?Dimmi (anche) se entrambi abbiano torto

Domanda 2: Il timer del modulo, è adatto a gestire un gran numero di lavori di timer in produzione?

Domanda 3: Rispetto a quello di Sean Hinde timer_mn-1.1, che funziona in cima alla Mnesia, il modulo timer (possibilmente in esecuzione su tabelle ETS) meno capace (per reale) in produzione?(Lo sto chiedendo perché usare il timer_mn di Sean Hinde su un sistema che a sua volta sta usando la Mnesia sembra essere un problema in termini di modifiche allo schema, problemi di nodo ecc.)

Se qualcuno ha un altro modo di gestire i problemi relativi al timer con la Mnesia, aggiornami grazie ragazzi ...

È stato utile?

Soluzione

Domanda 1:

Gestisci il timer al di fuori della transazione.Quando le transazioni si scontrano in Mnesia, si ripetono semplicemente.Ciò ti darebbe più di un riferimento al timer e due trigger del timer.Di per sé non è un problema, ma se aspetti il ​​successo della transazione prima di installare il timer, puoi evitare il problema.

La seconda soluzione è quella che farei io.Se il TX è a posto, puoi installarci un timer.Se il timer si attiva e non c'è alcun riferimento all'oggetto, non importa.Dovresti solo preoccuparti se questa situazione si verifica spesso poiché avresti un gran numero di timer vaganti.

Domanda 2:

Il modulo timer è pulito, ma la guida alle prestazioni consiglia di utilizzare il erlang:start_timer BIF invece, vedi

http://www.erlang.org/doc/efficiency_guide/commoncaveats.html#id58959

Vorrei introdurre un processo separato come a gen_server che gestisce le cose relative ai tempi.Lo invii a remove(timer:hours(24), RefNo) messaggio e poi avvia un timer, ottiene un file TRef e installa una mappatura {TRef, RefNo, AuxData} in Mnesia o ETS.Quando il timer si attiva, il processo può generare un aiutante che rimuove il file RefNo voce dalla tabella principale.

A questo punto, devi chiederti se si verificano arresti anomali.La rimozione gen_server potrebbe bloccarsi.Inoltre, l'intero nodo potrebbe bloccarsi.Il modo in cui desideri reinstallare i timer nel caso in cui ciò accada dipende da te, ma dovresti riflettere sul fatto che ciò accada in modo da poterlo risolvere.Supponiamo di tornare di nuovo e che le informazioni sul timer vengano caricate dal disco.Come pensi di reinstallare i timer?

Un modo è avere AuxData contengono informazioni sul punto di timeout.Ogni ora o 15 minuti, controlli tutto il tavolo, rimuovendo i ragazzi che non dovrebbero essere lì.In effetti, potresti optare per questo come il modo principale per rimuovere le strutture del timer.Sì, nel peggiore dei casi darai alle persone 15 minuti di tempo extra, ma potrebbe essere più semplice da gestire in termini di codice.Almeno gestisce meglio il caso in cui il nodo (e quindi i timer) muoiono.

Un'altra opzione ancora è quella di imbrogliare e memorizzare solo i tempi approssimativamente in una struttura dati che lo rende molto economico da trovare tutti i RefNo scaduti negli ultimi 5 minuti e poi eseguilo ogni 5 minuti.Fare cose in blocco sarà probabilmente più efficace.Questo tipo di gestione in blocco viene utilizzato molto, ad esempio, dai kernel del sistema operativo.

Domanda 3

Non ne so nulla timer-tm, Scusa :)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top