Message Routing Paradigms

Ulf Wiger <>
Sun Dec 15 16:27:01 CET 2002


On Sat, 14 Dec 2002, Eric Newhuis wrote:

>Wiger,
>
>Thank you; yes I saw those.  I think my problem is
>different, however.
>
>Rather than having a table of values that I want to match
>with a single search pattern, I have a table of search
>patterns that I want to match with a single value.
>
>In other words:
>
>Given [a,b,c], ['_',b,c], and [x,y,z] as patterns I want to
>find out if the value [a,b,c] matches anything.  I have a
>database of patterns.  I do not have a database of values.

Yes. My first thought was that you could try to turn it
around and basically do reversed pattern matching: based on
the value, define a match filter that extracts matching
patterns. After sending the mail, I thought about it some
more and decided that it's probably unwieldy.

The next wild idea is to simply create an abstract for out
of your patterns and compile it. Given Erlang's support for
dynamic module loading, you _can_ compile a module on the
fly without breaking already running code; processes that
have started in the old code will finish there, and new
calls will be diverted to the new code. The VM is quite good
at pattern matching, and the BEAM code is very compact. This
would also allow you to design arbitrarily complex patterns.
;)

I once wrote a small module to test the concept. It relies
on a key-value table in mnesia, and exports a function
set_value(Key, Value). This function writes the Key-Value
tuple to the table, then matches out all Key-Value
combinations from same table and compiles a module
sysGlobals.erl, such that sysGlobals:Key() -> Value.

A small test (1-2 values in the table), indicates that it
takes ca 9 msec to update the table and recompile/reload.
I'm sure there are a hundred ways to improve the concept.
I think the basic idea is one that should be developed one
of these days.

/Uffe
-- 
Ulf Wiger, Senior Specialist,
   / / /   Architecture & Design of Carrier-Class Software
  / / /    Strategic Product & System Management
 / / /     Ericsson Telecom AB, ATM Multiservice Networks
-------------- next part --------------
-module(keyval).

-export([compile/0,
	 set_value/2]).

-export([bootstrap/0]).


-define(MOD_NAME, sysGlobals).
-define(TAB_NAME, ?MOD_NAME).

-record(sysGlobals, {key, value}).

-include_lib("stdlib/include/ms_transform.hrl").

compile() ->
    Keys = keys(),
    Forms = 
	[{attribute, 1, module, ?MOD_NAME},
	 {attribute, 2, compile, export_all}|
	 compile_keys(Keys, 3, [])],
    do_compile(Forms).


set_value(Key, Value) when atom(Key) ->
    mnesia:dirty_write(#sysGlobals{key = Key, value = Value}),
    compile().


bootstrap() ->
    %% test function
    mnesia:create_schema([node()]),
    mnesia:start(),
    {atomic, ok} = mnesia:create_table(?TAB_NAME, [{disc_copies,[node()]}]).

keys() ->
    MS = ets:fun2ms(fun(#sysGlobals{key = K, value = V}) ->
			    {K, V}
		    end),
    ets:select(?TAB_NAME, MS).


compile_keys([{K,V}|T], N, Acc) when atom(K) ->
    Acc1 = [{function, N, K, 0, [{clause,N,[],[],[form(V, N)]}]}| Acc],
     compile_keys(T, N+1, Acc1);
compile_keys([], N, Acc) ->
    lists:reverse([{eof, N}|Acc]).


form(X, N) when integer(X) ->	{integer, N, X};
form(X, N) when atom(X) ->	{atom, N, X};
form(X, N) when list(X) ->	form_list(X,N);
form(X, N) when tuple(X) ->	
    {tuple, N, [form(E, N) || E <- tuple_to_list(X)]}.

form_list([X], N) ->	{cons, N, form(X, N), {nil, N}};
form_list([X|T], N) ->	{cons, N, form(X, N), form_list(T, N)};
form_list([], N) ->	{nil, N}.



do_compile(Forms) ->
    Src = [erl_pp:form(F) || F <- Forms],
    Dir = filename:join(["", "tmp"]),
    FileName = filename:join([Dir, ?MOD_NAME]),
    ok = file:write_file(FileName ++ ".erl", list_to_binary(Src)),
    {ok, _ModName, Binary} = compile:file(FileName, [binary]),
    code:load_binary(?MOD_NAME, FileName ++ ".beam", Binary).


More information about the erlang-questions mailing list