From 12f5f75327d6f30d94e9ef34551aac0126767f2c Mon Sep 17 00:00:00 2001
From: "roman.khlopkov" <roman.khlopkov@demlabs.net>
Date: Fri, 21 Mar 2025 11:50:01 +0300
Subject: [PATCH] [*] Cell loading sorting by id

---
 dap-sdk                                |  2 +-
 modules/chain/dap_chain.c              | 74 ++++++++++++++++++--------
 modules/chain/dap_chain_cell.c         | 30 +----------
 modules/chain/include/dap_chain_cell.h |  8 +--
 4 files changed, 61 insertions(+), 53 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index 84afcccb3f..e19cc10d05 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 84afcccb3f8de976ba0029801844421406ff83a7
+Subproject commit e19cc10d05f66dff8611d11b7b9482093ccf01c1
diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index 3b4d549191..eb9355737f 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -517,6 +517,13 @@ static bool s_load_notify_callback(dap_chain_t* a_chain) {
     return true;
 }
 
+static int s_ids_sort(const void *a_cell_id1, const void *a_cell_id2)
+{
+    uint64_t a = ((dap_chain_cell_id_t *)a_cell_id1)->uint64,
+             b = ((dap_chain_cell_id_t *)a_cell_id2)->uint64;
+    return a > b ? 1 : (a < b ? -1 : 0);
+}
+
 /**
  * @brief dap_chain_load_all
  * @param l_chain
@@ -536,36 +543,61 @@ int dap_chain_load_all(dap_chain_t *a_chain)
     DIR *l_dir = opendir(l_storage_dir);
     dap_return_val_if_fail_err(l_dir, -3, "Cannot open directory %s, error %d: \"%s\"",
                                           DAP_CHAIN_PVT(a_chain)->file_storage_dir, errno, dap_strerror(errno));
-    int l_err = -1;
-    const char l_suffix[] = ".dchaincell", *l_filename;
+    int l_err = 0, l_cell_idx = 0;
+    const char l_suffix[] = "." DAP_CHAIN_CELL_FILE_EXT, *l_filename;
     struct dirent *l_dir_entry = NULL;
-    dap_time_t l_ts_start = dap_time_now();
+    dap_chain_cell_id_t l_cell_ids[DAP_CHAIN_CELL_MAX_COUNT];
     while (( l_dir_entry = readdir(l_dir) ) ) {
         l_filename = l_dir_entry->d_name;
         size_t l_namelen = strlen(l_filename);
-        if ( l_namelen >= sizeof(l_suffix) && !strncmp(l_filename + l_namelen - (sizeof(l_suffix) - 1), l_suffix, sizeof(l_suffix) - 1) ) {
-            dap_timerfd_t* l_load_notify_timer = dap_timerfd_start(5000, (dap_timerfd_callback_t)s_load_notify_callback, a_chain);
-            l_err = dap_chain_cell_open(a_chain, l_filename, 'a');
-            dap_timerfd_delete(l_load_notify_timer->worker, l_load_notify_timer->esocket_uuid);
-            if (l_err)
+        if (l_namelen >= sizeof(l_suffix)) {
+             /* Check filename */
+            char l_fmt[32] = "", l_ext[ sizeof(DAP_CHAIN_CELL_FILE_EXT) ] = "", l_ext2 = '\0';
+            snprintf(l_fmt, sizeof(l_fmt), "%s%lu%s", "%"DAP_UINT64_FORMAT_x".%", sizeof(DAP_CHAIN_CELL_FILE_EXT) - 1, "[^.].%c");
+            switch ( sscanf(l_filename, l_fmt, &l_cell_ids[l_cell_idx].uint64, l_ext, &l_ext2) ) {
+            case 3:
+                // TODO: X.dchaincell.*, just ignore for now
                 break;
-            s_load_notify_callback(a_chain);
+            case 2:
+                if ( !dap_strncmp(l_ext, DAP_CHAIN_CELL_FILE_EXT, sizeof(l_ext)) ) {
+                    l_cell_idx++;
+                    break;
+                }
+            default:
+                log_it(L_ERROR, "Invalid cell file name \"%s\"", l_filename);
+                l_err = EINVAL;
+                break;
+            }
         }
     }
     closedir(l_dir);
-    
-    switch (l_err) {
-    case 0:
-        log_it(L_INFO, "Loaded all chain \"%s : %s\" cells in %lf s",
-                        a_chain->net_name, a_chain->name, difftime((time_t)dap_time_now(), l_ts_start));
-        break;
-    case -1:
-        if (!( l_err = dap_chain_cell_open(a_chain, "0.dchaincell", 'w') ))
+
+    if (!l_cell_idx) {
+        if (!l_err)
+            l_err = dap_chain_cell_open(a_chain, c_dap_chain_cell_id_null, 'w');
+        if (l_err)
+            log_it(L_ERROR, "Chain \"%s : %s\" was not loaded, error %d", a_chain->net_name, a_chain->name, l_err);
+        else
             log_it(L_INFO, "Initialized chain \"%s : %s\" cell 0", a_chain->net_name, a_chain->name);
-        break;
-    default:
-        log_it(L_ERROR, "Chain \"%s : %s\" cell was not loaded, error %d", a_chain->net_name, a_chain->name, l_err);
+        return l_err;
     }
+
+    qsort(l_cell_ids, l_cell_idx, sizeof(dap_chain_cell_id_t), s_ids_sort);
+
+    dap_time_t l_ts_start = dap_time_now();
+    for (int i = 0; i < l_cell_idx; i++) {
+        dap_timerfd_t* l_load_notify_timer = dap_timerfd_start(5000, (dap_timerfd_callback_t)s_load_notify_callback, a_chain);
+        l_err = dap_chain_cell_open(a_chain, l_cell_ids[i], 'a');
+        dap_timerfd_delete(l_load_notify_timer->worker, l_load_notify_timer->esocket_uuid);
+        if (l_err) {
+            log_it(L_ERROR, "Chain \"%s : %s\" cell 0x%016" DAP_UINT64_FORMAT_x " was not loaded, error %d",
+                                    a_chain->net_name, a_chain->name, (uint64_t)l_cell_idx, l_err);
+            return l_err;
+        }
+        s_load_notify_callback(a_chain);
+    }
+    log_it(L_INFO, "Loaded all chain \"%s : %s\" cells in %lf s",
+                    a_chain->net_name, a_chain->name, difftime((time_t)dap_time_now(), l_ts_start));
     return l_err;
 }
 
@@ -960,4 +992,4 @@ const char *dap_chain_type_to_str(const dap_chain_type_t a_default_chain_type)
         default:
             return "unknown";
     }
-}
\ No newline at end of file
+}
diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c
index f2b61e19c8..18bac156b3 100644
--- a/modules/chain/dap_chain_cell.c
+++ b/modules/chain/dap_chain_cell.c
@@ -43,8 +43,6 @@
 #define DAP_CHAIN_CELL_FILE_TYPE_COMPRESSED 1
 #define DAP_MAPPED_VOLUME_LIMIT ( 1 << 28 ) // 256 MB for now, may be should be configurable?
 
-#define CELL_FILE_EXT "dchaincell"
-
 /**
   * @struct dap_chain_cell_file_header
   */
@@ -451,33 +449,9 @@ DAP_STATIC_INLINE int s_cell_open(dap_chain_t *a_chain, const char *a_filepath,
 #undef m_ret_err
 }
 
-int dap_chain_cell_open(dap_chain_t *a_chain, const char *a_filename, const char a_mode) {
-    dap_chain_cell_id_t l_cell_id = { };
-    { /* Check filename */
-        char l_fmt[32] = "", l_ext[ sizeof(CELL_FILE_EXT) ] = "", l_ext2 = '\0';
-        snprintf(l_fmt, sizeof(l_fmt), "%s%lu%s", "%"DAP_UINT64_FORMAT_x".%", sizeof(CELL_FILE_EXT) - 1, "[^.].%c");
-
-        switch ( sscanf(a_filename, l_fmt, &l_cell_id.uint64, l_ext, &l_ext2) ) {
-        case 3:
-            // TODO: X.dchaincell.*
-        case 2:
-            if ( !dap_strncmp(l_ext, CELL_FILE_EXT, sizeof(l_ext)) )
-                break;
-        default:
-            return log_it(L_ERROR, "Invalid cell file name \"%s\"", a_filename), EINVAL;
-        }
-    }
-    char l_full_path[MAX_PATH];
-    snprintf(l_full_path, MAX_PATH, "%s/%s", DAP_CHAIN_PVT(a_chain)->file_storage_dir, a_filename);
-    pthread_rwlock_wrlock(&a_chain->cell_rwlock);
-    int l_ret = s_cell_open(a_chain, l_full_path, l_cell_id, a_mode);
-    pthread_rwlock_unlock(&a_chain->cell_rwlock);
-    return l_ret;
-}
-
-int dap_chain_cell_open_by_id(dap_chain_t *a_chain, const dap_chain_cell_id_t a_cell_id, const char a_mode) {
+int dap_chain_cell_open(dap_chain_t *a_chain, const dap_chain_cell_id_t a_cell_id, const char a_mode) {
     char l_full_path[MAX_PATH];
-    snprintf(l_full_path, MAX_PATH, "%s/%"DAP_UINT64_FORMAT_x"."CELL_FILE_EXT, DAP_CHAIN_PVT(a_chain)->file_storage_dir, a_cell_id.uint64);
+    snprintf(l_full_path, MAX_PATH, "%s/%"DAP_UINT64_FORMAT_x"."DAP_CHAIN_CELL_FILE_EXT, DAP_CHAIN_PVT(a_chain)->file_storage_dir, a_cell_id.uint64);
     pthread_rwlock_wrlock(&a_chain->cell_rwlock);
     int l_ret = s_cell_open(a_chain, l_full_path, a_cell_id, a_mode);
     pthread_rwlock_unlock(&a_chain->cell_rwlock);
diff --git a/modules/chain/include/dap_chain_cell.h b/modules/chain/include/dap_chain_cell.h
index 658a8b90e2..54e34fa2d8 100644
--- a/modules/chain/include/dap_chain_cell.h
+++ b/modules/chain/include/dap_chain_cell.h
@@ -29,6 +29,9 @@
 #include "dap_chain.h"
 #include "dap_chain_common.h"
 
+#define DAP_CHAIN_CELL_MAX_COUNT    32
+#define DAP_CHAIN_CELL_FILE_EXT     "dchaincell"
+
 typedef struct dap_chain_cell_mmap_data dap_chain_cell_mmap_data_t;
 
 typedef struct dap_chain_cell {
@@ -76,10 +79,9 @@ typedef struct dap_chain_cell_decl{
 
 
 int dap_chain_cell_init(void);
-int dap_chain_cell_open(dap_chain_t *a_chain, const char *a_filename, const char a_mode);
-int dap_chain_cell_open_by_id(dap_chain_t *a_chain, const dap_chain_cell_id_t a_cell_id, const char a_mode);
+int dap_chain_cell_open(dap_chain_t *a_chain, const dap_chain_cell_id_t a_cell_id, const char a_mode);
 DAP_STATIC_INLINE int dap_chain_cell_create(dap_chain_t *a_chain, const dap_chain_cell_id_t a_cell_id) {
-    return dap_chain_cell_open_by_id(a_chain, a_cell_id, 'w');
+    return dap_chain_cell_open(a_chain, a_cell_id, 'w');
 }
 
 DAP_INLINE dap_chain_cell_t *dap_chain_cell_find_by_id(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id) {
-- 
GitLab