util: document some tricky code 29/195729/2
authorMichal Bloch <m.bloch@samsung.com>
Mon, 17 Dec 2018 15:40:30 +0000 (16:40 +0100)
committerHyotaek Shim <hyotaek.shim@samsung.com>
Tue, 18 Dec 2018 01:20:54 +0000 (01:20 +0000)
Change-Id: I301c7bd877248201edb7ca27590ad348b18db06a
Signed-off-by: Michal Bloch <m.bloch@samsung.com>
src/logutil/sort_vector.c

index e857d75..d4fc089 100644 (file)
@@ -134,6 +134,47 @@ int sort_vector_push(struct sort_vector *logs, struct logger_entry *p, struct lo
                sort_vector_pop(logs);
        }
 
+       /* Insertion sort. Logs usually appear in order, so it makes a lot of sense to just iterate
+        * linearly from the end to try and find the correct index. The algorithm starts working
+        * from the empty slot behind the last index and populates it with the greater of the log
+        * in the last index and the one we're trying to insert, which usually ends up being the
+        * latter, but if the choice was the former, it decrements the index and repeats the process.
+        *
+        * In general, this means that during iteration some entries will be duplicated. This looks
+        * a bit like a memory leak (especially to static analysis tools) but is fine since the
+        * duplicated value is always in the spot we're currently replacing and it is never itself
+        * eligible to be placed there, ensuring that all values are unique and sorted afterward.
+        *
+        * Let's illustrate this with a visual example. Suppose `p` has value 6, and that in the
+        * table there are already four values at indices 0, 1, 2, and 3 (thus logs->end == 4) with
+        * values 2, 3, 7, and 9 respectively:
+        * ┌─┬─┬─┬─┐   ┌─┐
+        * │2│3│7│9│  p│6│
+        * └─┴─┴─┴─┘   └─┘
+        * After insertion, we'd like the table to look like this:
+        * ┌─┬─┬─┬─┬─┐
+        * │2│3│6│7│9│
+        * └─┴─┴─┴─┴─┘
+        * Initially, i = 4 (the empty spot, marked by 'v' in the graphic below) is
+        * due replacement and the two candidates (marked by '?') are 6 (from `p`)
+        * and 9 (from the slot at i-1, represented in the code by `e`):
+        * ┌─┬─┬─┬?┬v┐   ┌?┐
+        * │2│3│7│9│ │  p│6│
+        * └─┴─┴─┴─┴─┘   └─┘
+        * 9 > 6, so it gets picked:
+        * ┌─┬─┬?┬v┬─┐   ┌?┐
+        * │2│3│7│9│9│  p│6│
+        * └─┴─┴─┴─┴─┘   └─┘
+        * It looks as if this duplicated this value, but now i = 3, and one of them is due replacement
+        * with either 7 (the value from slot i-1) or 6 (from `p`). Again, the earlier slot gets picked:
+        * ┌─┬?┬v┬─┬─┐   ┌?┐
+        * │2│3│7│7│9│  p│6│
+        * └─┴─┴─┴─┴─┘   └─┘
+        * This time, at i = 2, the choice is won by the value from `p`, ending iteration:
+        * ┌─┬─┬─┬─┬─┐
+        * │2│3│6│7│9│
+        * └─┴─┴─┴─┴─┘
+        */
        for (i = logs->end; i > logs->begin || (logs->end < logs->begin && i <= logs->end); --i) {
                struct logger_entry *e = logs->data[(i ?: logs->size)-1];
                if (log_entry_is_earlier(logs->sort_by, e, p)) {