Skip to content

Commit

Permalink
docs(error-utils): add error_utils documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Tonidotpy committed Oct 12, 2023
1 parent 5999a7d commit ed28dd0
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 0 deletions.
24 changes: 24 additions & 0 deletions docs/error-utils/data_structures/hash_table.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Hash table

One of the main problems with how the errors are defined is that their total number
cannot be set from inside the library and dynamic memory allocation should be avoided.

To solve this problems an **hash table** with **open addressing** is used.

!!! Info The hash function used by the library is the 32 bit version of the
**MurmurHash3** implementation, for details refer to [MurmurHash](https://en.wikipedia.org/wiki/MurmurHash)

When a new error is set its hash value is calculated based on the type and its
instance, then the calculated value is used as the index for the hash table. \
If a collision happens the next index is calculated using **quadratic probing**
as described by this formula: `next_index = (curr_index + (offset * offset)) % buffer_size`
where the `offset` is the number of collisions and the `buffer_size` variable
is the size of the hash table.

When an error is reset it's not removed completely from the hash table but can
be replaced with another when needed.

The advantages of the MurmurHash algorithm is that it takes as input a 32 bit
integer **seed** (which is the error type in our case) and a **stream of bytes**
(which is the error instance), and it is suitable for generic hash-based lookup
like in the case of this library.
23 changes: 23 additions & 0 deletions docs/error-utils/data_structures/heap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Heap

To handle the expiration mechanism of the errors it is needed to get the error
with the **minimum remaining amount of time** before it expire, keeping it possible
to do fast insertion and removal.

One possible solution would be to sort each error every time it is set or reset
but, in the worst case scenario, it could take a lot of time to do that.

To solve this problem a separate data structure containing pointer to the errors
is **partially sorted** keeping the minimum element at the first index of the structure;
this structure is a [min heap](https://it.wikipedia.org/wiki/Heap_(struttura_dati))
with a static array implementation.

When an error is set a reference to that error is pushed at the end of the heap
and than it is swapped with its parent until it restores the properties of the heap.

When an error is reset the referenced to that error is swapped with the last element
of the heap and removed, and then the properties of the heap are restored.

Every time the first element (the minimum) is updated the expire handler is also
updated as well, except for the case in which no errors are running where the
expire handler is stopped.
36 changes: 36 additions & 0 deletions docs/error-utils/error_utils.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Error utils

The main purpose of this library is to handle **critical errors** that should
expire after a given time from the moment they were set.

A critical error is defined as an abnormal situation that should be notified to
the system and can be uniquely identified by a **type**, defined by the user,
and an **instance** that should identify the cause of the error.

The error instance can be a constant string (useful to give meaning to the instance)
or an integer (useful to enumarate and iterate multiple instances).

There are three main operations that can be done with an error:
1. **Set**
2. **Reset**
3. **Expire**

If an error is set the current *timestamp* is saved and an expire handler (usually a timer)
is started or updated.
If a running error is reset it cannot expire anymore, in that case the expire handler
is updated or stopped if there are no running errors.
If an error expires the system is notified through a callback, the expired error
is reset and the expire handler is updated or stopped.

!!! Important The exipre handler has to be defined and handled by the user,
this library only defines a couple of interfaces and does not manage
the handler internally.

---

The internal structure of the error utils library takes advantage of **two data
structures** to achieve fast insertion, deletion and search:
1. [Hash table](data_structures/hash_table.md): to handle error insertion(*set*)
and deletion(*reset*)
2. [Min heap](data_structures/heap.md): to handle the expire mechanism and sort
the errors based on their expiration time

0 comments on commit ed28dd0

Please sign in to comment.