Pregunta

Estoy escribiendo registros en Mnesia que deben mantenerse allí solo por un tiempo permitido (24 horas).Después de 24 horas, antes de que un usuario modifique parte de ellos, el sistema debe eliminarlos automáticamente.por ejemplo, un usuario recibe tiempo de aire gratis (para llamadas de voz) que debe usar en un momento determinado.Si no lo usan, después de 24 horas, el sistema debe eliminar estas reservas de recursos del registro de usuarios.

Ahora, esto ha traído cronómetros.un ejemplo de estructura de registro es:

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

El objeto del temporizador en el registro es importante porque en caso de que el usuario finalmente utilice los recursos reservados antes de que sean programados (o si están corriendo el tiempo), el sistema puede llamar timer:cancel/1 para aliviar el servidor de temporizador de este objeto.Ahora el problema, tengo dos formas de manejar los temporizadores en estos registros:

Opción 1:temporizadores manejados dentro de la transacción

 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).

Sobre la opción anterior.

Los documentos de Mnesia dicen que las transacciones tal vez repetidas por el gerente de TM (por alguna razón) hasta que tengan éxito, y así cuando se pone el código que es io:format/2 O cualquier otro que no tenga nada que ver con las escrituras o lecturas, puede ejecutarse varias veces.Esta declaración me hizo hacer una pausa en este punto y pensar en una forma de manejar los temporizadores de la transacción que sí mismo, por lo que modifiqué el código de la siguiente manera:

Opcion 2:temporizadores manejados fuera de la transacción

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.

El código para gestionar el tiempo fuera de la reserva:

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).

Ahora pensé que en la opción 2, estoy más seguro al mantener el código de procesamiento del temporizador fuera, incluso cuando MNESia_tm vuelve a ejecutar la transacción debido a sus razones, este código no se ejecuta dos veces (evito tener varios objetos de temporizador contra la misma registro).

Pregunta 1: ¿Cuál de estas dos implementaciones es correcta?y/o mal?Dime (también) si ambos están equivocados

Pregunta 2: El temporizador del módulo, ¿es adecuado para manejar grandes cantidades de trabajos de temporizador en la producción?

Pregunta 3: En comparación con el de Sean Hinde temporizador_mn-1.1, que se ejecuta en la parte superior de Mnesia, ¿el módulo de temporizador (posiblemente se ejecuta en la parte superior de las tablas ETS) es menos capaz (para real) en la producción?(Estoy preguntando esto porque el uso de Timer_Mn de Sean Hinde en un sistema que está utilizando Mnesia parece ser un problema en términos de cambios de esquema, problemas de nodos, etc.)

Si alguien tiene otra forma de manejar problemas relacionados con el temporizador con la mnesia, actualice Thanx Guys ...

¿Fue útil?

Solución

Pregunta 1:

Manejar el temporizador fuera de la transacción.Cuando las transacciones chocan en Mnesia, simplemente se repiten.Eso le daría más de una referencia de temporizador y dos activadores del temporizador.No es un problema en sí, pero si espera hasta que la transacción sea exitosa antes de instalar el temporizador, puede evitar el problema.

La segunda solución es lo que yo haría.Si el TX está bien, puedes instalarle un temporizador.Si el temporizador se activa y no hay ninguna referencia al objeto, no importa.Sólo debe preocuparse si esta situación ocurre con frecuencia, ya que entonces tendría una gran cantidad de temporizadores perdidos.

Pregunta 2:

El módulo del temporizador está bien, pero la guía de rendimiento recomienda utilizar el erlang:start_timer BIF en su lugar, ver

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

Introduciría un proceso separado como gen_server que se encarga de las cosas de sincronización.Le envías un remove(timer:hours(24), RefNo) mensaje y luego inicia un temporizador, obtiene un TRef e instala un mapeo {TRef, RefNo, AuxData} ya sea en Mnesia o ETS.Cuando se activa el temporizador, el proceso puede generar un ayudante que elimine el RefNo Entrada desde la mesa principal.

En este punto, debes preguntarte acerca de los accidentes.La eliminación gen_server puede estrellarse.Además, todo el nodo puede fallar.Depende de usted cómo desea reinstalar los temporizadores en caso de que esto suceda, pero debe reflexionar sobre cómo sucederá para poder resolverlo.Supongamos que volvemos a aparecer y la información del temporizador se carga desde el disco.¿Cómo planeas reinstalar los temporizadores?

Una forma es tener AuxData contener información sobre el punto de tiempo de espera.Cada hora o 15 minutos, escaneas toda la mesa, eliminando a los que no deberían estar allí.De hecho, podrías optar por que esta sea la forma principal de eliminar estructuras de temporizador.Sí, le darás a las personas 15 minutos de tiempo extra en el peor de los casos, pero puede ser más fácil de manejar desde el punto de vista del código.Al menos maneja mejor el caso en el que el nodo (y por tanto los temporizadores) mueren.

Otra opción es hacer trampa y almacenar sólo los tiempos de forma aproximada en una estructura de datos, lo que hace que sea muy barato encontrarlos. todos los RefNo's vencidos en los últimos 5 minutos y luego ejecútelo cada 5 minutos.Hacer cosas en masa probablemente será más efectivo.Este tipo de manejo masivo lo utilizan mucho, por ejemplo, los núcleos de los sistemas operativos.

Pregunta 3

no sé nada sobre timer-tm, Lo siento :)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top