xenial (7) elektra-error-handling.7.gz

Provided by: elektra-doc_0.8.14-5_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.

                                                  November 2015                        ELEKTRA-ERROR-HANDLING(7)