From: Greg Burri Date: Sat, 4 Oct 2008 14:03:29 +0000 (+0000) Subject: MOD amélioration de la vitesse de euphorik_bd:messages (mais toujours en O(n)). Cette... X-Git-Tag: 1.1.3~23 X-Git-Url: https://git.euphorik.ch/?a=commitdiff_plain;h=e290f3af3f37ca377712b02460da8b3c4ce02d3d;p=euphorik.git MOD amélioration de la vitesse de euphorik_bd:messages (mais toujours en O(n)). Cette fonction est utililsée dans le module euphorik_test --- diff --git a/modules/Makefile b/modules/Makefile index 0a77892..859cc56 100755 --- a/modules/Makefile +++ b/modules/Makefile @@ -41,7 +41,7 @@ $(rep_ebin)/euphorik_bd.beam: $(rep_erl)/euphorik_bd.erl $(rep_include)/euphorik erlc $(erlc_params) # Module pour la mise à jour de la BD -$(rep_ebin)/euphorik_bd_admin.beam: $(rep_erl)/euphorik_bd_admin.erl $(rep_erl)/euphorik_bd.erl $(rep_include)/euphorik_bd.hrl $(rep_include)/euphorik_defines.hrl +$(rep_ebin)/euphorik_bd_admin.beam: $(rep_erl)/euphorik_bd_admin.erl $(rep_include)/euphorik_bd.hrl $(rep_include)/euphorik_defines.hrl erlc $(erlc_params) # Module permettant l'extraction des conversations du minichat @@ -61,7 +61,7 @@ $(rep_ebin)/euphorik_protocole.beam: $(rep_erl)/euphorik_protocole.erl $(rep_inc # erlc $(erlc_params) # Module effectuant periodiquement certaines tâches -$(rep_ebin)/euphorik_daemon.beam: $(rep_erl)/euphorik_daemon.erl $(rep_include)/euphorik_defines.hrl $(rep_erl)/euphorik_bd_admin.erl +$(rep_ebin)/euphorik_daemon.beam: $(rep_erl)/euphorik_daemon.erl $(rep_include)/euphorik_defines.hrl erlc $(erlc_params) # Module avec plein de bordel dedant @@ -69,7 +69,7 @@ $(rep_ebin)/euphorik_common.beam: $(rep_erl)/euphorik_common.erl erlc $(erlc_params) # Module dédié au tests -$(rep_ebin)/euphorik_test.beam: $(rep_erl)/euphorik_test.erl $(rep_erl)/euphorik_bd.erl $(rep_include)/euphorik_bd.hrl +$(rep_ebin)/euphorik_test.beam: $(rep_erl)/euphorik_test.erl $(rep_include)/euphorik_bd.hrl erlc $(erlc_params) # Suppression des modules compilés diff --git a/modules/erl/euphorik_bd.erl b/modules/erl/euphorik_bd.erl index cfd0bfd..4fecb73 100755 --- a/modules/erl/euphorik_bd.erl +++ b/modules/erl/euphorik_bd.erl @@ -275,13 +275,16 @@ user_by_mess(Id) -> nouveau_message(Mess, Auteur_id, Repond_A_ids) -> % regarde si les id 'Repond_A' existent F = fun() -> - Repond_a = lists:map( - fun(Repond_a_id) -> - [M] = mnesia:read({minichat, Repond_a_id}), - M - end, + Repond_a = lists:foldr( + fun(Repond_a_id, Acc) -> + case mnesia:read({minichat, Repond_a_id}) of + [M] -> [M | Acc]; + _ -> Acc % le message n'est pas trouvé + end + end, + [], Repond_A_ids - ), + ), Racine_id = case Repond_a of [] -> undefined; [M | _] -> @@ -293,16 +296,16 @@ nouveau_message(Mess, Auteur_id, Repond_A_ids) -> _ -> {erreur, "Les messages ne font pas partie de la même conversation"} end - end, - case Racine_id of - {erreur, E} -> {erreur, E}; - _ -> - % est-ce que l'auteur existe ? - case mnesia:wread({user, Auteur_id}) of - [#user{profile = Profile} = Auteur] -> - if length(Repond_a) =/= length(Repond_A_ids) -> - {erreur, "Un ou plusieurs messages introuvable"}; - true -> + end, + if length(Repond_a) =/= length(Repond_A_ids) -> + {erreur, "Un ou plusieurs messages introuvable"}; + true -> + case Racine_id of + {erreur, E} -> {erreur, E}; + _ -> + % est-ce que l'auteur existe ? + case mnesia:wread({user, Auteur_id}) of + [#user{profile = Profile} = Auteur] -> % comparaison entre la date du dernier poste et maintenant (gestion du flood) Now = now(), Delta = euphorik_common:delta_date_ms(Auteur#user.date_derniere_connexion, Now), @@ -330,11 +333,11 @@ nouveau_message(Mess, Auteur_id, Repond_A_ids) -> racine_id = if Racine_id =:= undefined -> Id; true -> Racine_id end }), Id - end - end; - _ -> - {erreur, "L'auteur du message est introuvable"} - end + end; + _ -> + {erreur, "L'auteur du message est introuvable"} + end + end end end, resultat_transaction(mnesia:transaction(F)). @@ -365,26 +368,29 @@ messages(N) -> messages(N, 1). -% Renvoie N messages se trouvant sur la page P +% Renvoie N messages se trouvant sur la page P +% TODO FIXME : fonction en O(N * P) ! messages(N, P) -> - F = fun() -> - C = cursor( - qlc:keysort( - #minichat.id, - q([E#minichat{contenu = contenu_message(E)} || E <- mnesia:table(minichat)]), - [{order, descending}] - ), - [{tmpdir, ?KEY_SORT_TEMP_DIR}] - ), - if P > 1 -> qlc:next_answers(C, N * (P - 1)); - true -> ok - end, - R = qlc:next_answers(C, N), - qlc:delete_cursor(C), - R + F = fun() -> + % % #minichat{contenu = contenu_message(E)} + get_tuples_avant(minichat, reculer(minichat, mnesia:last(minichat), N * (P - 1)), N) end, - lists:reverse(resultat_transaction(mnesia:transaction(F))). - + resultat_transaction(mnesia:transaction(F)). + +get_tuples_avant(Table, Id, N) -> + get_tuples_avant(Table, Id, N, []). +get_tuples_avant(_, '$end_of_table', _, Tuples) -> Tuples; +get_tuples_avant(_, _, 0, Tuples) -> + Tuples; +get_tuples_avant(Table, Id, N, Tuples) -> + [T] = mnesia:read({Table, Id}), + get_tuples_avant(Table, mnesia:prev(Table, Id), N - 1, [T | Tuples]). + +reculer(_, '$end_of_table' = Fin, _) -> Fin; +reculer(_, Id, 0) -> Id; +reculer(Table, Id, N) -> + reculer(Table, mnesia:prev(Table, Id), N - 1). + % Renvoie les messages manquants pour la page P en sachant qu'il y a N message % par page et que le dernier message que l'on possède est Id diff --git a/modules/erl/euphorik_bd_admin.erl b/modules/erl/euphorik_bd_admin.erl index 64ea4ac..a5a69f1 100644 --- a/modules/erl/euphorik_bd_admin.erl +++ b/modules/erl/euphorik_bd_admin.erl @@ -84,6 +84,7 @@ create_tables() -> {disc_copies, [node()]} ]), mnesia:create_table(minichat, [ + {type, ordered_set}, {attributes, record_info(fields, minichat)}, {disc_copies, [node()]} ]), diff --git a/modules/erl/euphorik_test.erl b/modules/erl/euphorik_test.erl index c1bf49b..2cbc1ec 100644 --- a/modules/erl/euphorik_test.erl +++ b/modules/erl/euphorik_test.erl @@ -22,6 +22,7 @@ -module(euphorik_test). -export([ + bench_write_minichat/1, start/2, stop/1, bench_get_messages/0, @@ -34,6 +35,7 @@ -define(INTERVALLE_MIN, 2). -define(INTERVALLE_MAX, 5). + % N est le nombre d'utilisateur % M est le nombre de message que chaque utilisateur va poster start(N, M) -> @@ -55,7 +57,7 @@ start(N, M) -> stop(Pids) -> lists:foreach(fun(Pid) -> exit(Pid, kill) end, Pids). - +% des trucs qui trainent bench_get_messages() -> T = [ {page,"chat"}, @@ -67,8 +69,6 @@ bench_get_messages() -> {conversations,{array,[]}} ], moyenne_temps(euphorik_protocole, wait_event, [T], 20). - - bench_get_messages_avec_2_conversations() -> T = [ {page,"chat"}, @@ -91,8 +91,6 @@ bench_get_messages_avec_2_conversations() -> ]}} ], moyenne_temps(euphorik_protocole, wait_event, [T], 20). - - moyenne_temps(Module, Fun, Args, N) -> moyenne_temps(Module, Fun, Args, N, N, 0). moyenne_temps(_, _, _, 0, Total, Temps_acc) -> @@ -129,9 +127,9 @@ mot_rand(L, Mot) -> % Tire au hasard de 0 à 3 messages sur les 10 derniers postés, renvoie une liste de int() % répartition : % 0 : 0.1 -% 1 : 0.7 -% 2 : 0.15 -% 3 : 0.05 +% 1 : 0.95 +% 2 : 0.04 +% 3 : 0.01 messages_id_rand() -> R = random:uniform(), if R =< 0.1 -> @@ -139,9 +137,9 @@ messages_id_rand() -> true -> Messages = lists:map(fun(#minichat{id = Id}) -> Id end, euphorik_bd:messages(8)), if - R > 0.1 andalso R =< 0.8 -> + R > 0.1 andalso R =< 0.95 -> tire_element_rand(1, Messages); - R > 0.8 andalso R =< 0.95 -> + R > 0.95 andalso R =< 0.99 -> tire_element_rand(2, Messages); true -> tire_element_rand(3, Messages) @@ -170,9 +168,8 @@ loop(User_id, M) -> % attend un temp aléatoire compris entre INTERVALLE_MIN sec et INTERVALLE_MAX sec timer:sleep(1000 * (random:uniform(?INTERVALLE_MAX - ?INTERVALLE_MIN + 1) + ?INTERVALLE_MIN - 1)), % poste un message aléatoire par une personne aléatoire répondant à des messages aléatoires - {Message, Repond_a} = {message_rand(), messages_id_rand()}, - %{Message, Repond_a} = {"blablablablablabla", []}, - io:format("~p poste ~p et repond a ~w~n", [User_id, Message, Repond_a]), + {Message, Repond_a} = {message_rand(), messages_id_rand()}, + % io:format("~p poste ~p et repond a ~w~n", [User_id, Message, Repond_a]), case euphorik_bd:nouveau_message(Message, User_id, Repond_a) of {erreur, E} -> io:format("~p : erreur : ~p~n", [User_id, E]), @@ -181,4 +178,35 @@ loop(User_id, M) -> loop(User_id, M - 1) end. + +% Permet de tester la vitesse d'écriture en fonction de la +% taille de la BD +% voir : http://erlang.org/pipermail/erlang-questions/2008-October/038697.html +bench_write_minichat(Filename) -> + Times = bench_write_minichat(1, []), + {ok, File} = file:open(Filename, [write]), + lists:foreach( + fun({Id, Time}) -> + io:format(File, "~w ~w~n", [Id, Time]) + end, + Times + ), + file:close(File). +bench_write_minichat(100000, Temps) -> Temps; +bench_write_minichat(N, Temps) -> + {T, _} = timer:tc(mnesia, transaction, [fun() -> + Id = mnesia:dirty_update_counter(counter, minichat, 1), + mnesia:write(#minichat{ + id = Id, + auteur_id = random:uniform(10000), + date = now(), + pseudo = "Test", + contenu = "Blabla blabla bla.", + racine_id = random:uniform(10000) + }) + end]), + bench_write_minichat(N + 1, if N rem 500 =:= 0 -> [{N, T} | Temps]; true -> Temps end). + + + \ No newline at end of file diff --git a/modules/include/euphorik_bd.hrl b/modules/include/euphorik_bd.hrl index ae69459..dbca45b 100755 --- a/modules/include/euphorik_bd.hrl +++ b/modules/include/euphorik_bd.hrl @@ -1,3 +1,4 @@ +% coding: utf-8 % Copyright 2008 Grégory Burri % % This file is part of Euphorik. @@ -82,6 +83,8 @@ }). + + -record(user, { id, diff --git a/tools/start_yaws.sh b/tools/start_yaws.sh index 87e6e4e..29be884 100755 --- a/tools/start_yaws.sh +++ b/tools/start_yaws.sh @@ -1,3 +1,4 @@ -#!/bin/bash +#!/bin/bash # screen est utilisé par exemple pour lancé une version de preproduction et permettre de la faire tourner après un délog -screen -S yawspreprod yaws --conf ./yaws.conf --sname yaws_dev --mnesiadir "../var/BD/" -I debian_yaws_dev +#screen -S yawspreprod +yaws --conf ./yaws.conf --sname yaws_dev --mnesiadir "../BD/" -I debian_yaws_dev