Tuesday, November 18, 2014

unimplemented callback

Erlang behaviour

Erlang provides mechanism of behaviours, which allows to guarantee API of certain module. If one of behaviour's callback is not implemented, compiler generates warning.

gen_server

Let's examine the importance of these warnings on example of gen_server. Of course, process can not be started and stopped correctly without implementing init/2 and terminate/2 callbacks. Then gen_server implements some payload: handle_info, handle_call or handle_cast.

Neglect of unexpected messages

If one of these callbacks is not needed, some people do some default implementation, for example, logging of unexpected message and proceeding of program execution. This approach allows to avoid compilation warnings, but may hide serious problem in system if careful log monitoring is not organised. Also function clause with the same logic, which matches on everything, is often appended to each callback.

Crash on unexpected message

Another option could be termination of the process via returning stop-tuple, which is sometimes much better. The only argument against is that it happens by default in OTP but via crashing.

Hot code upgrade

The last callback not covered is code_change. It does not require a dummy implementation. During hot code upgrade system uses the newest callback to update process's state.

gen_fsm

If problem of unused code in gen_server's callbacks does not look that serious comparing to possible advantages of handling all possible messages, let's analyse another standard OTP behaviour - gen_fsm. Besides handle_info, init, terminate and code_change, which have logic similar to gen_server, gen_fsm has a number of callbacks for handling different types of events.

All state events

All state events could be synchronous and asynchronous and are handled in handle_sync_event/4 and handle_event/3 correspondently. For handling of unexpected messages of that type both strategies from gen_server (ignoring and termination) are applicable with the same advantages and disadvantages.

Named events

"Named" events could be synchronous and asynchronous as well and are handled by StateName/3 and StateName/2 callbacks of gen_fsm behaviour, where StateName is the name of current state of FSM. Since names of these callbacks are dynamic, not implementing them does not lead to compilation warnings, but somebody could understand fault-tolerance as not-crashing in any circumstances including receiving of unexpected events.
One, who decides to achieve this, must be really tolerant, since he needs to accumulate state names from entire FSM, and implement StateName/3 and StateName/2 dummy function clauses for each of them. Also he needs to maintain such FSM with growing number of states.

Conclusion

It is recommended not to implement any behaviour's callback just for the sake of suppressing of compilation warnings or being pseudo-fault-tolerant to unexpected messages/situations. Each callback implementation needs to have business logic. It's better to spend time on system's test automation instead of trying to make system, which can survive (not crash) if something unexpected happens.

Tuesday, September 16, 2014

lower bound

Lower bound

Sometimes lower bound algorithm, which returns an ordered subset of container's elements which are greater or equal to given value, is required in development. Surprisingly there is no implementation of it in OTP.

OTP containers

In Erlang there is a number of key-value containers with efficient search operation:
  1. ETS;
  2. mnesia;
  3. gb_trees;
  4. dict;
  5. orddict.
Several implementations of sets: gb_sets, sets, ordsets, which are more or less the same as key-value container besides that only keys are present.
DETS - is a specialised file storage. Maps are not covered in this article since the appeared in Erlang 17.
Basically there are some alternatives to base lower bound algorithm implementation on.

dict, sets

In documentation it's stated that the representation of a dictionary is not defined. Thereby implementation of lower bound algorithm requires reverse engineering and would be based on data structure which might be changed in next version.

orddict, ordsets

Sorted lists from the first sight is one of the best data for lower bound implementation, but in fact lists in Erlang do not provide random access to it's elements with constant complexity (singly linked list). In ordict:find/2 source code one can see that it just traverses the entire list starting from the head. So binary search is not used, as a result not efficient lower bound implementation is possible.

ETS, mnesia

ETS and mnesia are based on native code of Erlang VM and should have the best performance. Both containers have iterators so that resulting subset of lower bound algorithm could be traversed without copying. Unfortunately in ets:match_object as well as in mnesia:match_object key must be bound for efficient search, otherwise the entire container is searched.
In order to find out if optimisation exists for range matching in ETS, test is created. Two functions are implemented: first just finds element in ETS and returns it's key (key can be used as iterator), second - returns key of first element of lower bound . Both functions are implemented based on ets:select/3 with limit 1. ETS is initialised with 20000000 elements. Each element is a tuple {Key, Value}, where Key = Value. Integers incremented from 1 to 20000000  are used as keys. In performance test both functions are called with different element to search for in the same ETS. Here are function execution times.

KeyBound key time, sRange key time,s
100000.0000.002
1000000.0000.015
10000000.0000.163
100000000.0001.332
200000000.0001.537
From provided values it's obvious that ets:select/3 makes full table scan if the key is not bound. It's important to notice that select function stops after first matching element is found because of limit argument set to one.
Although optimisation of key range matching may appear in next version of Erlang at least for some types (ordered_set), ETS and mnesia are not suitable for lower bound algorithm implementation at the moment.

gb_sets, gb_trees

gb_trees has documented representation, it's ordinary binary search tree. Iterators are also available for this container. Implementation of lower bound algorithm is very elegant with recursion, function returns iterator to the first element of subset.

Conclusion

Surprisingly none of OTP containers has an implementation lower bound algorithm, which is very common for set theory. Implementation based on ETS of type ordered_set turned out to be inefficient in terms of complexity without any obvious reasons. The most suitable container for lower bound implementation is gb_trees, where binary tree search can be used. 

Sunday, August 3, 2014

empty supervisor

Problem

Sometimes Erlang application consists only of utility functions without any processes spawning. In such cases usually supervisor child specification in supervisor:init/1 is an empty list. Supervisor's process, which does nothing, is likely something developers should not worry about, but this situation can be resolved in more elegant way.

Solution

If application's boilerplate code is generated from standard template (for example,
rebar create-app), it usually contains:

  1. <application>.app (<application>.app.src) with application specification;
  2. <application>_sup.erl, which implements supervisor behaviour;
  3. <application>_app.erl, which implements application behaviour.
If supervisor's module is removed, application crashes on start since application:start/2 callback must return a pid of supervisor. So <application>_app.erl should be removed as well. After that application can not be started again, because module with application behaviour implementation is specified in <application>.app (<application>.app.src) in mod section.

{mod, { <application>_app, []}}
So that should be deleted too. As a result two unnecessary files were deleted from the project. Example of described application could be found here.

Exceptions

In very rare applications "state" could be stored not in process' state but in public ETS or other "not pure functional" techniques might be used. For that cases application:start/2 callback should be implemented even with empty supervisor. For instance, public ETS could be created on start of application.
Sometimes processes are started not under top-level supervisor, illustration of this is Cowboy web server. In all examples empty supervisor is used and Cowboy is started in application:start/2 callback.

Friday, July 18, 2014

Misuse of environment variables

Application environment variables

Environment variables are the main configuration mechanism for Erlang applications. Configuration of Erlang node basically is a list of application names together with list of application's environment variables.
Usually variables are set once on start of application and can be read any time during application's execution and in any place in the code. It's also possible to set or update it in runtime.
Application usually uses only it's environment variables, but accessing of other application's environment is also possible.
With such a "freedom" this mechanism is often misused. Let's see an example.

Testing

In gen_server:handle_call callback environment variable is read:

handle_call(use, _From, State) ->
 {ok, Var2} = application:get_env(var2),
 {reply, Var2, State}.

It works fine until we start writing of unit tests and application:gen_env/1 returns undefined leading to process crash. Next attempt could be setting variable in fixture of test case.

basic_test_() ->
 {
 setup,
 fun() ->
   application:set_env(app_env_var, var2, 3),
   start_link()
 end,

If it's launched in gen_server's test suite without starting application it crashes again. It happens because code is executed in context of other application (application:get_application/0 returns undefined until application is started). The only reasonable fix in this case is specifying of application name on getting environment variable value.

{ok, Var2} = application:get_env(app_env_var, var2)

To conclude, getting application environment variables in low-level functions makes testing more difficult.

Another approach

In order to overcome difficulties in testing, variables could be used in a different way. All environment variables should be read in application:start/2 callback and passed further to supervisor and rest processes in the chain.

start(_StartType, _StartArgs) ->
 {ok, Var1} = application:get_env(var1),
 app_env_var_sup:start_link(Var1).

In testing variables setup is changed with passing appropriate value to start_link function of gen_server and saving in state.

basic_test_() ->
 {
 setup,
 fun() -> start_link(3) end,

This kind of environment variable usage implies additional code for passing values to the place where it is actually used. One more disadvantage is necessary restart of the node for changing variable's value.
Environment variable can be compared with global variable in languages like C++ or Java. It is accessible everywhere, what could be convenient for some task, but has all the disadvantages, which are well know. 

Performance

One more argument in favour of not using environment variables is performance. Two gen_servers, which access data from application environment variable and from it's state correspondingly , were compared. Here are results.

gs1 (value from state accessed)  : 291802
gs2 (environment variable)       : 325638

Time is specified in microseconds, results are provided for 100000 runs of the same code.

Conclusion

Code of all unit tests and benchmarking is provided in github repository.
Passing environment variables' values as arguments from application:start/2  callback results into some additional boilerplate code, requires application's restart on configuration change, but makes code much cleaner and easier to test comparing to direct reading of env variables. It is important to find balance between both approaches. 
For global functionality such as logging passing configuration to each call using additional arguments is a big overhead in terms of code readability. If configurations of some application changes often and/or it's restart is undesirable accessing env variables is preferred. In most of other cases suggested approach fits better.

Saturday, July 5, 2014

tuples vs records vs proplists

Data structures for business logic

When function is being designed, one of the most important questions is data structure to use. In Erlang there are several compound "types": lists, records, maps and tuples. ETS is separate type which has a specific usage, in most cases there is no confusion with other data structures. Maps appeared in Erlang 17 and not covered in this article even though they combine properties of both lists and tuples.
List contains variable number of elements. One of the popular "subtype" of it is proplist, which is a list of {Key, Value} tuples. It does not allow pattern matching on elements except on head.
Tuple's arity is fixed and client code in most cases should be aware of exact size. It provides intensive usage of pattern matching. With growing size usage of tuples becomes error-prone.
Records solve complexity of big tuples' usage by adding syntax sugar on compile time. In fact records are translated to tuples. Usage of records might require some additional compile dependencies.
Another alternative to tuples, records and proplists is complex function signature.
save_user(Name, Surname, Age)
where  each property is a separate argument. It's mostly equivalent to
save_user({Name, Surname, Age}).
except that if signature of function changes ofter it's much more work to adapt code comparing to single tuple argument.
In API design performance of operations on types of arguments and return values is not as crucial as simplicity of usage, protection from misuse and other criteria of "good code/design". That's why no benchmarks are provided.
Recipe of good design in this scope is quite straightforward: "Data structure shall be chosen based on it's characteristics and logic of code". It is easier to illustrate this rule with an example.

Example

Service with RESTful interface is being developed. User information is received in JSON format in POST request.
{
 "name": "Eddy",
 "surname": "Snow",
 "age": 28
}
There is a general purpose JSON object parsing function (arrays are not covered here for simplicity), it accepts binary as an argument. Data structure for return value is not that obvious.
First of all, client code needs to detect errors in parsing. Assuming that exceptions are not used, function should return tuple {ok, Result} on success or {error, Reason} on failure. Tuple for error handling here fits perfect, there is no need to introduce record since tuple size is two.
Next is data structure for Result. Since function parse_json_object is generic, it can parse any object and result  is dynamic. Proplist is suitable type for it.
-spec parse_json_object(JSON::binary()) ->
  {ok, Result::list()} | {error, Reason::term()}.

Once user information is correctly parsed, it might be needed to validate it and store in the database. So kind of internal user object is required. It could be tempting to continue using proplist, but record fits much better for it, because it applies number of compile-time checks.
-record(
  user,
  {
     name,
     surname,
     age
  }
).

Advantages and disadvantages of records

Elements of record are accessed by name and Erlang compiler verifies that only existing properties are "got/set". If tuple is used instead data could be accessed only by index of element, which is error-prone with big tuple's size.
Sometimes it's declared that records are not suitable for storing in riak in erlang binary format, because if record declaration is changed data in storage becomes invalid in terms of matching it to the new version. In fact it's worth to implement some serialisation layer for this task as versioning might also be required for proplist or tuple.
Another argument against records could be hot code upgrade because of the same problem with changing of record declaration. In that case law of "not using records as tuples" could be broken in code_change callback.

Conclusion

To sum up, general recommendation for choosing data structure are:

  1. Do not use tuples of size more than 3.
  2. Use proplists only if number of "object's" properties varies.
  3. Consider records as a main alternative to tuple of big size.

Monday, June 16, 2014

Monitoring of Erlang systems

Monitoring

One of advantages of Erlang over other languages is scalability, which implies executing tasks on multiple machines. With growing number of servers used, monitoring of system becomes more and more complicated.

Monitoring in Erlang

What is monitoring for functional language such as Erlang? It is collecting of some attributes of function. In my opinion two most important of them are time of execution and return value.
Return value may indicate success or failure of certain operation, for example knowing if http server returned 200 or 404 is nice to track, another example is status of payment transaction: successful or declined.
Monitoring of time is important for diagnosing of performance issues, it is very useful see how long certain SQL query takes.

Possible implementations

Logging

In most projects people start adding code for monitoring directly to functions.
Fist naive implementation could be just logging of metrics. It works more or less fine except fact extracting data from logs is a tedious task. Also in most cases we are interested in relative value rather than absolute one. For example, fact that some SQL query takes 2 seconds does not tell much about system without context.

Reporting

Context in that case is history of metric, the most convenient way of representation is plot. Once people realise it, they setup up plot building software like graphitezabbix or opsview,  and implement Erlang clients for reporting. One project which is worth mentioning here is folsom, which is Erlang application for collecting metrics of a system.
On stage of integration of code, which reports data to plot building service, developers realise that almost all tests are broken, because this functionality needs to be mocked. It could be done by ordinary mocking or implementing of "empty" reporter, which does nothing.
It also turns out that monitoring code is global, and it's hard to track which metrics are monitored.

Usage of tracing

Erlang provides a convenient way of tracing software - erlang:trace function, which is reused by higher-level applications such as dbgttb and redbug. It could be also used for monitoring of system. The idea behind that is very simple. In demo project elmon tracing is enabled for all new processes spawned using this line of code:
    erlang:trace(new, true, [call, timestamp])
call option enables tracing of function calls, timestamp is just added to trace information.
Next step is in specifying functions to trace.
    MatchSpec = dbg:fun2ms(fun(_)->exception_trace()     end),
    erlang:trace_pattern(MFA, MatchSpec, [global]).
MFA here is tuple {Module, Function, Arity}, global option is specified to trace only exported functions, match specification sets up tracing of exceptional returns from function as well as normal ones.
Tracing could also be enabled for local functions, but likely it's time to refactor code when you need it. Match specification could potentially be more advanced with unbind variables ('_') and etc, but it seems to be a refactoring required instead. trace_pattern returns a number of functions matched, it is considered to be one for the same reason.
Combination of these two functions enables tracing of specified function calls in all processes spawned after. Trace information is sent to process, which called erlang:trace, in messages. Each message contains timestamp of occurred event. Events are function call and returning from it.
The only thing left to do is to store timestamp of call and subtract it from appropriate timestamp of return message. Key {Pid, MFA} is unique in scope of one call even for recursive functions, since finish message is sent after a chain of tail recursive calls is ended.
In elmon calculated trace information is reported gen_event subscribers registered for it. Monitoring may be disabled simply by not starting the application.
Usually sysops are interested in some metrics of Erlang VM such as memory usage, number of processes, etc. A separate application is a nice place to put them in.

Conclusions

Of course using of tracing has a significant drawback comparing to injecting of monitoring code directly to functions. It is performance. I would not provide any measurements, because it can vary depending on process model of software and many other factors.
Clear separation of concerns, easy enabling/disabling make Erlang tracing one of variants to consider when choosing monitoring strategy. 

Wednesday, March 26, 2014

rebar and repository organisation

Introduction

In Erlang ecosystem the most popular build tool seems to be rebar. It is quite easy to start using. If you have an Erlang application with directory structure organised according to OTP requirements, you just launch rebar compile in the root directory of app and it compiles.
Whenever you need a dependency from another application which is not in OTP, you create a rebar.config file with following content
{deps, [
  {dep_name, dep_version, path_to_dep}
]}.
Most likely path_to_dep would be VCS url, for example,
  {git, "git://github.com/rebar/rebar.git"}.
But what shall we do when we need to create one more own Erlang application? Let's overview possible code organisation strategies.

Repository per application

The most popular repository organisation used with rebar is a separate repository for each application. It provides a nice separation of concerns, great support from rebar and it is quite easy.
A new repository is created, source code is placed. Then algorithms for 3rd-party dependencies is repeated - reference to the new application is set up in rebar.config of original application.
Not everything is so bright with this approach. Even if you have only 3rd-party dependencies you need to take care of versioning, because depending just only on branch (especially on one under active development) could bring instability into the system you are working on. To solve this problem people specify a release branch as dependency (in case of git it is 'tag'). Rebar supports it from the box, even erlang application's version from .app file is supported (see dep_version in rebar.config), but it is not extensively used as it is the second versioning mechanism to take care of.
During development of system which consists of multiple applications it is very common that changes are required in several components for one feature. So feature branch is created in each repository, and in order to keep consistency during development this branch is specified in rebar.config.
{deps, [
    {app1, ".*",
        {git, "git_url/app1.git",
            {branch, "feature12"}}},
    {app2, ".*",
        {git, "git_url/app2.git",
            {branch, "feature12"}}}
]}.
You need to take care of rebar.config before or after merging to the development branch. With growing number of repositories code management could start to be a pain, which could be reduced with automation of routine tasks.


Single repository

An alternative to writing scripts for VCS handling is keeping everything in a single repository. The idea is to place each Erlang application into separate directory in the repository. As a result directory structure looks like this:
repo_dir
|-app1
|-app2
|-app3
|-rebar.config
In each directory there is a standard OTP application structure. The only change required is putting
{deps_dir, ".."}.
into each app's rebar.config and
{deps_dir, "."}.
into rebar.config in root directory. Dependencies from the same repository are specified only by name:
{deps, [app2]}.
The entire project could be found here.
All rebar commands such as compile, eunit and clean could be launched in each application's directory separately or in root. It is convenient, for example, to launch unit tests in all apps once change is made with rebar eunit in top level directory.
Keeping things in a single repository allows to do an "atomic commit", when single merge adds feature into development or integration branch. You can create a release (tag in git) with a single command as well. In over words it allows to have a snapshot of entire system easily.
It is quite easy to move modules from one application to another.
Of course there is a drawback with single repository. It does not allow to manage access for developers in flexible way. For example, company decides to opensource one of applications, so that rest of them are still private. It could only be achieved by moving the code into a separate repository. The same problem occurs if access must be granted only to the part of system (not for all applications).

To SumUp

I would recommend to start with single repository for all Erlang applications and move some of them to separate repositories only for a good reason.