Provided by: elektra-doc_0.8.14-5.1ubuntu2_all bug

NAME

       elektra-error-handling - error handling in Elektra

       You might want to read about data structures first elektra-data-structures.md.

Terminology

       It is sometimes unavoidable that errors occur that ultimately have an impact for the user.
       Examples for such an error are that hard disc space is exhausted.  For  a  library  it  is
       necessary  to  pass  information about the facts and circumstances to the user because the
       user wants to  be  informed  why  a  requested  action  failed.  So  Elektra  gathers  all
       information  in these situations. We call this resulting information error information and
       warning information depending on the severity.

       If the occurred error is  critical  and  ultimately  causes  a  situation  that  the  post
       conditions  cannot  be  fulfilled  we  say  that Elektra comes into a faulty state. Such a
       faulty state will change the control flow inside Elektra completely. Elektra is unable  to
       resolve  the problem without assistance. After cleaning up resources, a faulty state leads
       to immediate return from the function with an  error  code.  As  a  user  expects  from  a
       library,  Elektra  never  calls  exit()  or something similar, regardless of how fatal the
       error is. In this situation error information should be set.

       On the other hand, for many  problems  the  work  can  go  on  with  reasonable  defaults.
       Nevertheless,  the  user  will  be  warned  that  a  problem  occurred  using  the warning
       information. These situations do not influence the  control  flow.  But  applications  can
       choose  to  react  differently  in  the  presence  of warning information. They may not be
       interested in any warning information at all. It is no problem if warning  information  is
       ignored  because  they  are  stored  and  remain  accessible  in  a  circular  buffer. The
       implementation prevents an overflow  of  the  buffer.  Instead  the  oldest  warnings  are
       overwritten.

       When  error or warning information is presented to the user, it is called error message or
       warning message. The user may reply to this message in which way to continue.

   Error vs. Warning Information
       When an error in an faulty state  occurs,  the  error  information  must  still  hold  the
       original  error  information.  So  even  in  problems  that  would  cause  a faulty state,
       otherwise, the error information must be omitted or transformed to a warning  information.
       In some places only the adding of warning information is possible:

       •   The  main  purpose  of  kdbClose()  is  to  free  the handle. This operation is always
           successful and is carried  out  even  if  some  of  the  resources  cannot  be  freed.
           Therefore, in kdbClose(), setting error information is prohibited. Warning information
           is, however, very useful to tell the user the circumstance that  some  actions  during
           cleanup failed.

       •   Also  in  kdbOpen(),  only  adding warning information is allowed. If kdbOpen() is not
           able to open a plugin, the affected backend will be dropped out. The user is certainly
           interested  why  that  happened.  But  it  was decided not to make it an faulty state,
           because the application might not even access the faulty part of the key hierarchy. An
           exception  to  this  rule  is  if  kdbOpen()  fails  to open the default backend. This
           situation will induce an faulty state.

       •   In kdbSet(), the cleaning up of resources involves calling plugins.  But  during  this
           process  Elektra  is  in  a  faulty  state,  so  only adding of warning information is
           allowed. This ensures that the original error information is passed unchanged  to  the
           user.

       On the other hand, any access to the key database can produce warning information. Plugins
       are allowed to yield warning information at any place and for any reason. For example, the
       storage  plugin  reading  a  configuration  file with an old syntax, is free to report the
       circumstance as warning information. Warning information is also useful when more than one
       fact needs to be reported.

Error Information

   Reporting Errors
       Reporting errors is a critical task. Users expect different aspects:

       •   The  \emph{user  of the application} does not want to see any error message at all. If
           it is inevitable, he or she wants little, but very concrete information, about what he
           or  she  needs  to do. The message should be short and concise. Some error information
           may already be captured by the application,  but  others  like  ´´no  more  free  disk
           space´´  have to be displayed. Conflicts should also be presented to the user. It is a
           good idea to ask how to proceed if a diversity of possible reactions exists.  In  case
           of conflicts, the user may have additional knowledge about the other program which has
           caused the problem. The user is more likely to decide correctly by which strategy  the
           configuration shall be restored.

       •   The  \emph{user  of  the  library}  wants more detailed information. Categories of how
           severe the error is can help to decide how to proceed.  Even  more  important  is  the
           information  if  it  makes  sense  to  try  the same action again. If, for example, an
           unreliable network connection or file system is used, the same action can  work  in  a
           second try.

       •   A  \emph{developer  of the library}\footnote{Library refers to both Elektra´s core and
           plugins.} wants full information about anything needed to be  able  to  reproduce  and
           locate  potential bugs. Ideally the error information should even mention the file and
           line where the error occurred. This can help developers to decide if there  is  a  bug
           inside Elektra or if the problem lies somewhere else.

       •   Vast  information  is  needed  to support correct error handling in \empha[programming
           language]{other programming languages}.  In  languages  supporting  exceptions,  class
           name,  inheritance  or  interface  information  may  be  necessary.  Language specific
           extensions are, however, not limited to exceptions. Other ways of handling errors  are
           continuations  or  longjmp  in  C.  A  plugin  is  free  to  add, for example, jmp_buf
           information to the error information.

       It is certainly not a good idea to put all this previously mentioned  information  into  a
       single string. Elektra chooses another way described in the next chapter.

   Metadata
       As  stated  above, a library always informs the user about what has happened, but does not
       print or log anything itself. One way to return an error information is to add a parameter
       containing  the  error  information. In the case of Elektra, all KDB methods have a key as
       parameter. This key is additionally passed to every plugin. The idea is to add  the  error
       and warning information as metadata to this key. This approach does not limit flexibility,
       because a key can hold a potentially unlimited number of metakeys.

       The error information is categorised in metadata as follows:

       •   [error] indicates that an faulty state is present. The value of the  metakey  contains
           the  name  of  all  the  subkeys  that  are used for error indication. Metakeys do not
           guarantee any particular order on  iteration.  Instead  the  user  can  find  out  the
           information by looking at this metavalue.

       Additional metakeys yield all the details.

       •   [error/number] yields a unique number for every error.

       •   [error/description]  is  a  description for the error to be displayed to the user. For
           example, the metavalue can hold the text ´´could not write to file´´.

       •   [error/reason] specifies the reason of the error. The human readable message is in the
           metavalue  of  error/reason.  It  states why the error occurred. One example for it is
           ´´no disc space available´´.

       •   [error/ingroup] contains ´´kdb´´ if the error occurred inside the  core.  It  contains
           ´´module´´  if  the error happened while loading a module. The metavalue is ´´plugin´´
           if the error information comes from a plugin.

       •   [error/module] indicates the name of the specific module or plugin.

       •   [error/file] yields the source file from where the error information comes.

       •   [error/line] represents the exact line of that source file.

       As we see, the system is powerful because any other text or information can be added in  a
       flexible manner by using additional metakeys.

   Error Specification
       The  error  specification in Elektra is written in simple colon-separated text files. Each
       entry has a unique identifier and all the information we already discussed above. No  part
       of Elektra ever reads this file directly. Instead it is used to generate source code which
       contains everything needed to add a particular error or  warning  information.  With  that
       file  we  achieved  a central place for error-related information. All other locations are
       automatically generated instead of having error-prone duplicated code. This  principle  is
       called ´´Don´t repeat yourself´´.

       In  Elektra´s core and plugins, C macros are responsible for setting the error information
       and adding warning information. In C only a macro is able to add the file  name  and  line
       number of the source code. In language bindings other code may be generated.

   Sources of Errors
       Key  and  KeySet  functions  cannot expose more error information than the error code they
       return. But, of course, errors are also possible in  these  functions.  Typically,  errors
       concern  invalid  key names or null pointers. These problems are mostly programming errors
       with only local effects.

       The most interesting error situations,  however,  all  occur  in  KDB.  The  error  system
       described  here is dedicated to the four main KDB functions: kdbOpen(), kdbGet(), kdbSet()
       and kdbClose(). The place where the configuration is checked and made  persistent  is  the
       source  of  most  error  information. At this specific place a large variety of errors can
       happen ranging from opening, locking up and saving the file. Sometimes in plugins,  nearly
       every line needs to deal with an error situation.

Exceptions

       Exceptions  are  a  mechanism  of  the  language  and  not  just an implementation detail.
       Exceptions are not intended to  force  the  user  to  do  something,  but  to  enrich  the
       possibilities.  In  this  section, we discuss two issues related to exceptions. On the one
       hand, we will see how Elektra supports programming languages that provide  exceptions.  On
       the  other  hand, we will see how the research in exceptions helps Elektra to provide more
       robustness.

   Language Bindings
       C does not know anything about exceptions. But Elektra was designed so that  both  plugins
       and  applications  can be written in languages that provide exceptions. One design goal of
       Elektra´s error system is to transport exception-related information in a language neutral
       way from the plugins to the applications. To do so, a language binding of the plugin needs
       to catch every exception and transform it into error information and return an error code.

       Elektra recognises the error code, stops the processing of plugins, switches to  a  faulty
       state  and  gives  all  the  plugins  a  chance  to  do  the necessary cleanups. The error
       information is passed to the application as usual. If the application is written in  C  or
       does  not  want  to  deal  with exceptions for another reason, we are finished because the
       application  gets  the  error  information  inside  metadata  as  expected.  But,  if  the
       application  is  written  in another language, the binding translates the error code to an
       exception and throws it. It is worth noting that the source and  target  language  do  not
       need to be the same.

       Such  a  system  needs a central specification of error information. We already introduced
       such a specification file in error specification. The exception classes and converters can
       be  generated  from  it.  An  exception  converter  is either a long sequence of try-catch
       statements that transforms every  known  exception  into  an  appropriate  metakeys.  Each
       exception  thrown by the plugin has to be caught. Alternatively, a converter can be a long
       switch statement for every error number.  In  every  case  the  appropriate  exception  is
       thrown.

       The  motivation for using exceptions is that in C every return value has to be checked. On
       the other hand, the C++ exception mechanism allows the programmer to throw an exception in
       any  place and catch it where it is needed. So in C++ the code is not cluttered with parts
       responsible for error handling. Instead, in a single place all exceptions of a plugin  can
       be  transformed  to Elektra´s error or warning information. The code for this place can be
       generated automatically using an exception converter.

       Applications not written in C can also benefit from an  exception  converter.  Instead  of
       using  the  metadata  mechanism,  the  error information can be converted to the exception
       mechanism already used for that application. We see that Elektra is minimally invasive  in
       this regard.

   Exception Safety
       We  can  learn from the way languages define the semantics for exception safety. Exception
       safety is a concept which ensures that all resources are freed regardless  of  the  chosen
       return  path.  Basic guarantees make sure that some invariants remain on an object even in
       exceptional cases. On the other hand,  strong  guarantees  assure  that  the  investigated
       operation  is successful or has no effect at all. Methods are said to be exception safe if
       the object remains in a valid state. The idea of exception safety is  to  ensure  that  no
       resource leaking is possible. kdbSet() written in C++ would look like:

           try {
               plugin[1].set(); // may throw plugin[2].set(); // may
               throw plugin[3].set(); // may throw ...

               plugin[PLUGIN_COMMIT].set(); // now all changes are
               committed
           } catch (...) {
               // error situation, roll back the changes
               plugin[1].error(); // does not throw plugin[2].error();
               // does not throw plugin[3].error(); // does not throw ...

               // now all changes are rolled back return -1;
           } // now do all actions on success after commit
           plugin[POSTCOMMIT].set(); // does not throw ...  return 1; //
           commit successful

       This  pseudo  code  is  much  clearer  than  the  corresponding C code. Let us explain the
       guarantee Elektra provides using this example. One  by  one  plugin  gets  its  chance  to
       process  the  configuration.  If any plugin fails, the semantics resemble that of a thrown
       exception. All other plugins will not be executed. Instead, the plugins get  a  chance  to
       recover  from  the  faulty state. In this catch part, the plugins are not allowed to yield
       any error information, but they are allowed to add warnings.

       Continue reading with the algorithm elektra-algorithm.md.

                                            July 2017                   ELEKTRA-ERROR-HANDLING(7)