gnucash master: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Sat May 9 17:43:44 EDT 2020


Updated	 via  https://github.com/Gnucash/gnucash/commit/5da3bf79 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/3e442a0e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/0403e490 (commit)
	from  https://github.com/Gnucash/gnucash/commit/f1ff7896 (commit)



commit 5da3bf79434df06735e2d2e4ba2fc54d4182a9bb
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Jan 22 21:29:24 2019 -0800

    [QofLog] Replace hashtable with tree of vectors.
    
    16x speedup.

diff --git a/libgnucash/backend/xml/test/CMakeLists.txt b/libgnucash/backend/xml/test/CMakeLists.txt
index 78effe61e..6612da309 100644
--- a/libgnucash/backend/xml/test/CMakeLists.txt
+++ b/libgnucash/backend/xml/test/CMakeLists.txt
@@ -18,7 +18,7 @@ set(XML_TEST_LIBS gnc-engine gnc-test-engine test-core ${LIBXML2_LDFLAGS} -lz)
 
 function(add_xml_test _TARGET _SOURCE_FILES)
   gnc_add_test(${_TARGET} "${_SOURCE_FILES}" XML_TEST_INCLUDE_DIRS XML_TEST_LIBS ${ARGN})
-  target_compile_options(${_TARGET} PRIVATE -DU_SHOW_CPLUSPLUS_API=0)
+  target_compile_options(${_TARGET} PRIVATE -DU_SHOW_CPLUSPLUS_API=0 -DG_LOG_DOMAIN=\"gnc.backend.xml\")
 endfunction()
 
 
diff --git a/libgnucash/engine/qoflog.cpp b/libgnucash/engine/qoflog.cpp
index f787e7602..ba3efac88 100644
--- a/libgnucash/engine/qoflog.cpp
+++ b/libgnucash/engine/qoflog.cpp
@@ -54,6 +54,9 @@ extern "C"
 
 #include "qof.h"
 #include "qoflog.h"
+#include <string>
+#include <vector>
+#include <memory>
 
 #define QOF_LOG_MAX_CHARS 50
 #define QOF_LOG_MAX_CHARS_WITH_ALLOWANCE 100
@@ -63,10 +66,45 @@ extern "C"
 static FILE *fout = NULL;
 static gchar* function_buffer = NULL;
 static gint qof_log_num_spaces = 0;
-static GHashTable *log_table = NULL;
 static GLogFunc previous_handler = NULL;
 static gchar* qof_logger_format = NULL;
 
+using StrVec = std::vector<std::string>;
+
+struct ModuleEntry;
+using ModuleEntryPtr = std::shared_ptr<ModuleEntry>;
+
+struct ModuleEntry
+{
+    ModuleEntry(std::string name) :
+        m_name{name}, m_level{QOF_LOG_WARNING}, m_children{4} {}
+    ~ModuleEntry() = default;
+    std::string m_name;
+    QofLogLevel m_level;
+    std::vector<ModuleEntryPtr> m_children;
+};
+
+static ModuleEntryPtr modules = NULL;
+
+static StrVec
+split_domain (const std::string domain)
+{
+    static constexpr int parts = 4; //enough room for most cases
+    std::vector<std::string> domain_parts{4};
+    int start = 0;
+    auto pos = domain.find(".");
+    if (pos == std::string::npos)
+        domain_parts.emplace_back(domain);
+    else
+        while (pos != std::string::npos)
+        {
+            domain_parts.emplace_back(domain.substr(start, pos));
+            start = pos + 1;
+            pos = domain.find(".", start);
+        }
+    return domain_parts;
+}
+
 void
 qof_log_indent(void)
 {
@@ -82,7 +120,7 @@ qof_log_dedent(void)
       : qof_log_num_spaces - QOF_LOG_INDENT_WIDTH;
 }
 
-static void
+void
 qof_log_set_file(FILE *outfile)
 {
     if (!outfile)
@@ -148,9 +186,8 @@ void
 qof_log_init_filename(const gchar* log_filename)
 {
     gboolean warn_about_missing_permission = FALSE;
-    if (log_table == NULL)
-        log_table = g_hash_table_new_full(g_str_hash, g_str_equal,
-                                          g_free, NULL);
+    if (!modules)
+        modules = std::make_shared<ModuleEntry>("");
 
     if (!qof_logger_format)
         qof_logger_format = g_strdup ("* %s %*s <%s> %*s%s%s"); //default format
@@ -194,9 +231,8 @@ qof_log_init_filename(const gchar* log_filename)
     if (!fout)
         fout = stderr;
 
-    // @@fixme really, the userdata is a struct { log_table, fout, previous_handler }
     if (previous_handler == NULL)
-        previous_handler = g_log_set_default_handler(log4glib_handler, log_table);
+        previous_handler = g_log_set_default_handler(log4glib_handler, &modules);
 
     if (warn_about_missing_permission)
     {
@@ -219,10 +255,9 @@ qof_log_shutdown (void)
         function_buffer = NULL;
     }
 
-    if (log_table != NULL)
+    if (modules != NULL)
     {
-        g_hash_table_destroy(log_table);
-        log_table = NULL;
+        modules = nullptr;
     }
 
     if (previous_handler != NULL)
@@ -236,14 +271,55 @@ void
 qof_log_set_level(QofLogModule log_module, QofLogLevel level)
 {
     if (!log_module || level == 0)
-    {
         return;
+    if (!modules)
+    {
+        modules = std::make_shared<ModuleEntry>("");
+        modules->m_level = QOF_LOG_WARNING;
     }
-    if (!log_table)
+    auto module_parts = split_domain(log_module);
+    auto module = modules;
+    for (auto part : module_parts)
     {
-        log_table = g_hash_table_new(g_str_hash, g_str_equal);
+        auto iter = std::find_if(module->m_children.begin(),
+                              module->m_children.end(),
+                              [part](ModuleEntryPtr child){
+                                  return child && part == child->m_name;
+                              });
+        if (iter == module->m_children.end())
+        {
+            auto child = std::make_shared<ModuleEntry>(part);
+            module->m_children.push_back(child);
+            module = child;
+        }
+        else
+        {
+            module = *iter;
+        }
     }
-    g_hash_table_insert(log_table, g_strdup((gchar*)log_module), GINT_TO_POINTER((gint)level));
+    module->m_level = level;
+}
+
+
+gboolean
+qof_log_check(QofLogModule domain, QofLogLevel level)
+{
+    g_return_val_if_fail (domain && level && modules, FALSE);
+    if (level < modules->m_level)
+        return TRUE;
+    auto domain_vec = split_domain(domain);
+    auto module = modules;
+    for (auto part : domain_vec)
+    {
+        auto iter = std::find_if(module->m_children.begin(),
+                               module->m_children.end(),
+                               [part](ModuleEntryPtr child) {
+                                   return child && part == child->m_name; });
+        if (iter == module->m_children.end()) return FALSE;
+        if (level <= (*iter)->m_level) return TRUE;
+        module = *iter;
+    }
+    return FALSE;
 }
 
 const char *
@@ -381,54 +457,6 @@ qof_log_parse_log_config(const char *filename)
     g_key_file_free(conf);
 }
 
-gboolean
-qof_log_check(QofLogModule log_domain, QofLogLevel log_level)
-{
-//#define _QLC_DBG(x) x
-#define _QLC_DBG(x)
-    GHashTable *log_levels = log_table;
-    gchar *domain_copy = g_strdup(log_domain == NULL ? "" : log_domain);
-    gchar *dot_pointer = domain_copy;
-    static const QofLogLevel default_log_thresh = QOF_LOG_WARNING;
-    QofLogLevel longest_match_level = default_log_thresh;
-
-    {
-        gpointer match_level;
-        if (log_levels && (match_level = g_hash_table_lookup(log_levels, "")) != NULL)
-            longest_match_level = (QofLogLevel)GPOINTER_TO_INT(match_level);
-    }
-
-_QLC_DBG( { printf("trying [%s] (%d):", log_domain, log_levels != NULL ? g_hash_table_size(log_levels) : 0); });
-    if (G_LIKELY(log_levels))
-    {
-        // e.g., "a.b.c\0" -> "a\0b.c\0" -> "a.b\0c\0", "a.b.c\0"
-        gpointer match_level;
-        while ((dot_pointer = g_strstr_len(dot_pointer, strlen(dot_pointer), ".")) != NULL)
-        {
-            *dot_pointer = '\0';
-            _QLC_DBG( { printf(" [%s]", domain_copy); });
-            if (g_hash_table_lookup_extended(log_levels, domain_copy, NULL, &match_level))
-            {
-                longest_match_level = (QofLogLevel)GPOINTER_TO_INT(match_level);
-                _QLC_DBG(printf("*"););
-            }
-            *dot_pointer = '.';
-            dot_pointer++;
-        }
-
-        _QLC_DBG( { printf(" [%s]", domain_copy); });
-        if (g_hash_table_lookup_extended(log_levels, domain_copy, NULL, &match_level))
-        {
-            longest_match_level = (QofLogLevel)GPOINTER_TO_INT(match_level);
-            _QLC_DBG( { printf("*"); });
-        }
-    }
-    _QLC_DBG( { printf(" found [%d]\n", longest_match_level); });
-    g_free(domain_copy);
-
-    return log_level <= longest_match_level;
-}
-
 void
 qof_log_set_default(QofLogLevel log_level)
 {

commit 3e442a0ef9316f9bb6d2f3a9ee49a211e89dd1c6
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Jan 22 14:10:39 2019 -0800

    Make qof_log_set_file static.
    
    Used only internally.

diff --git a/libgnucash/engine/qoflog.cpp b/libgnucash/engine/qoflog.cpp
index 841e85536..f787e7602 100644
--- a/libgnucash/engine/qoflog.cpp
+++ b/libgnucash/engine/qoflog.cpp
@@ -82,7 +82,7 @@ qof_log_dedent(void)
       : qof_log_num_spaces - QOF_LOG_INDENT_WIDTH;
 }
 
-void
+static void
 qof_log_set_file(FILE *outfile)
 {
     if (!outfile)

commit 0403e4906c8c8697c7a5ed144e8834ea146ba305
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Jan 22 08:47:14 2019 -0800

    Move QofLogModule typedef to qoflog.h where it belongs.

diff --git a/libgnucash/engine/qofid.h b/libgnucash/engine/qofid.h
index 13314ea25..c9012b6ac 100644
--- a/libgnucash/engine/qofid.h
+++ b/libgnucash/engine/qofid.h
@@ -85,8 +85,6 @@ extern "C"
 typedef const gchar * QofIdType;
 /** QofIdTypeConst declaration */
 typedef const gchar * QofIdTypeConst;
-/** QofLogModule declaration */
-typedef const gchar* QofLogModule;
 
 typedef struct QofCollection_s QofCollection;
 
diff --git a/libgnucash/engine/qoflog.h b/libgnucash/engine/qoflog.h
index 345ad5f1a..c4ee1dfdc 100644
--- a/libgnucash/engine/qoflog.h
+++ b/libgnucash/engine/qoflog.h
@@ -94,6 +94,8 @@ extern "C"
 #include <glib.h>
 #include "qofutil.h"
 
+typedef const gchar* QofLogModule;
+
 #define QOF_MOD_ENGINE "qof.engine"
 
 typedef enum



Summary of changes:
 libgnucash/backend/xml/test/CMakeLists.txt |   2 +-
 libgnucash/engine/qofid.h                  |   2 -
 libgnucash/engine/qoflog.cpp               | 150 +++++++++++++++++------------
 libgnucash/engine/qoflog.h                 |   2 +
 4 files changed, 92 insertions(+), 64 deletions(-)



More information about the gnucash-changes mailing list