.TH "md_doc_help_elektra-error-handling" 3elektra "Sun May 29 2016" "Version 0.8.14" "Elektra" \" -*- nroff -*- .ad l .nh .SH NAME md_doc_help_elektra-error-handling \- elektra-error-handling(7) -- error handling in Elektra You might want to read \fBabout data structures first\fP\&. .PP 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 \fBerror information\fP and \fBwarning information\fP depending on the severity\&. .PP 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 \fBfaulty state\fP\&. 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 \fBerror code\fP\&. As a user expects from a library, Elektra never calls \fCexit()\fP or something similar, regardless of how fatal the error is\&. In this situation error information should be set\&. .PP 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 \fBwarning information\fP\&. 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\&. .PP When error or warning information is presented to the user, it is called \fIerror message\fP or \fIwarning message\fP\&. The user may reply to this message in which way to continue\&. .PP .SS "Error vs\&. Warning Information" .PP 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: .PP .IP "\(bu" 2 The main purpose of \fC\fBkdbClose()\fP\fP 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 \fC\fBkdbClose()\fP\fP, setting error information is prohibited\&. Warning information is, however, very useful to tell the user the circumstance that some actions during cleanup failed\&. .IP "\(bu" 2 Also in \fC\fBkdbOpen()\fP\fP, only adding warning information is allowed\&. If \fC\fBkdbOpen()\fP\fP 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 \fC\fBkdbOpen()\fP\fP fails to open the default backend\&. This situation will induce an faulty state\&. .IP "\(bu" 2 In \fC\fBkdbSet()\fP\fP, 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\&. .PP .PP 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\&. .PP .SS "Error Information" .PP .SS "Reporting Errors" .PP Reporting errors is a critical task\&. Users expect different aspects: .PP .IP "\(bu" 2 The {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\&. .IP "\(bu" 2 The {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\&. .IP "\(bu" 2 A {developer of the library}{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\&. .IP "\(bu" 2 Vast information is needed to support correct error handling in [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 \fClongjmp\fP in C\&. A plugin is free to add, for example, \fCjmp_buf\fP information to the error information\&. .PP .PP 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\&. .PP .SS "Metadata" .PP 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 \fCKDB\fP 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\&. .PP The error information is categorised in metadata as follows: .PP .IP "\(bu" 2 [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\&. .PP .PP Additional metakeys yield all the details\&. .PP .IP "\(bu" 2 [error/number] yields a unique number for every error\&. .IP "\(bu" 2 [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''\&. .IP "\(bu" 2 [error/reason] specifies the reason of the error\&. The human readable message is in the metavalue of \fCerror/reason\fP\&. It states why the error occurred\&. One example for it is ''no disc space available''\&. .IP "\(bu" 2 [error/ingroup] contains ''\fCkdb\fP'' if the error occurred inside the core\&. It contains ''\fCmodule\fP'' if the error happened while loading a module\&. The metavalue is ''\fCplugin\fP'' if the error information comes from a plugin\&. .IP "\(bu" 2 [error/module] indicates the name of the specific module or plugin\&. .IP "\(bu" 2 [error/file] yields the source file from where the error information comes\&. .IP "\(bu" 2 [error/line] represents the exact line of that source file\&. .PP .PP As we see, the system is powerful because any other text or information can be added in a flexible manner by using additional metakeys\&. .PP .SS "Error Specification" .PP 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''\&. .PP 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\&. .PP .SS "Sources of Errors" .PP \fCKey\fP and \fCKeySet\fP 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\&. .PP The most interesting error situations, however, all occur in \fCKDB\fP\&. The error system described here is dedicated to the four main \fCKDB\fP functions: \fC\fBkdbOpen()\fP\fP, \fC\fBkdbGet()\fP\fP, \fC\fBkdbSet()\fP\fP and \fC\fBkdbClose()\fP\fP\&. 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\&. .PP .SS "Exceptions" .PP 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\&. .PP .SS "Language Bindings" .PP 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\&. .PP 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\&. .PP 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\&. .PP 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\&. .PP 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\&. .PP .SS "Exception Safety" .PP We can learn from the way languages define the semantics for \fBexception safety\fP\&. Exception safety is a concept which ensures that all resources are freed regardless of the chosen return path\&. \fBBasic guarantees\fP make sure that some invariants remain on an object even in exceptional cases\&. On the other hand, \fBstrong guarantees\fP 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\&. \fC\fBkdbSet()\fP\fP written in C++ would look like: .PP .nf 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 .fi .PP .PP 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\&. .PP Continue reading \fBwith the algorithm\fP\&.