feat: add asynchronous investigation graph loading
This commit is contained in:
parent
c389dba0d9
commit
be6ab166b7
5 changed files with 3751 additions and 2 deletions
30
Makefile
30
Makefile
|
|
@ -51,6 +51,10 @@ RELATION_SERVICE_TEST_CFLAGS := \
|
||||||
-DRELATION_SERVICE_ENABLE_TEST_HOOKS
|
-DRELATION_SERVICE_ENABLE_TEST_HOOKS
|
||||||
INVESTIGATION_GRAPH_MODEL_TEST_CFLAGS := $(TEST_CFLAGS) -Wpedantic
|
INVESTIGATION_GRAPH_MODEL_TEST_CFLAGS := $(TEST_CFLAGS) -Wpedantic
|
||||||
INVESTIGATION_GRAPH_LOADER_TEST_CFLAGS := $(TEST_CFLAGS) -Wpedantic
|
INVESTIGATION_GRAPH_LOADER_TEST_CFLAGS := $(TEST_CFLAGS) -Wpedantic
|
||||||
|
INVESTIGATION_GRAPH_LOAD_TASK_TEST_CFLAGS := \
|
||||||
|
$(TEST_CFLAGS) \
|
||||||
|
-Wpedantic \
|
||||||
|
-DINVESTIGATION_GRAPH_LOAD_TASK_ENABLE_TEST_HOOKS
|
||||||
|
|
||||||
SRC := $(shell find src -name "*.c")
|
SRC := $(shell find src -name "*.c")
|
||||||
|
|
||||||
|
|
@ -102,6 +106,7 @@ TEST_RELATION_EVIDENCE_DAO := tests/test_relation_evidence_dao
|
||||||
TEST_RELATION_SERVICE := tests/test_relation_service
|
TEST_RELATION_SERVICE := tests/test_relation_service
|
||||||
TEST_INVESTIGATION_GRAPH_MODEL := tests/test_investigation_graph_model
|
TEST_INVESTIGATION_GRAPH_MODEL := tests/test_investigation_graph_model
|
||||||
TEST_INVESTIGATION_GRAPH_LOADER := tests/test_investigation_graph_loader
|
TEST_INVESTIGATION_GRAPH_LOADER := tests/test_investigation_graph_loader
|
||||||
|
TEST_INVESTIGATION_GRAPH_LOAD_TASK := tests/test_investigation_graph_load_task
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
|
|
@ -505,6 +510,24 @@ $(TEST_INVESTIGATION_GRAPH_LOADER): \
|
||||||
$(CC) $(INVESTIGATION_GRAPH_LOADER_TEST_CFLAGS) $^ -o $@ \
|
$(CC) $(INVESTIGATION_GRAPH_LOADER_TEST_CFLAGS) $^ -o $@ \
|
||||||
$(TEST_LDFLAGS) -lsqlite3
|
$(TEST_LDFLAGS) -lsqlite3
|
||||||
|
|
||||||
|
$(TEST_INVESTIGATION_GRAPH_LOAD_TASK): \
|
||||||
|
tests/test_investigation_graph_load_task.c \
|
||||||
|
src/core/investigation_graph_load_task.c \
|
||||||
|
src/core/investigation_graph_loader.c \
|
||||||
|
src/core/background_task.c \
|
||||||
|
src/dao/entity_dao.c \
|
||||||
|
src/dao/relation_dao.c \
|
||||||
|
src/models/investigation_graph_model.c \
|
||||||
|
src/models/entity_record.c \
|
||||||
|
src/models/relation_record.c \
|
||||||
|
src/database/database.c \
|
||||||
|
src/database/schema.c \
|
||||||
|
src/database/statement.c \
|
||||||
|
src/database/transaction.c \
|
||||||
|
src/database/error.c
|
||||||
|
$(CC) $(INVESTIGATION_GRAPH_LOAD_TASK_TEST_CFLAGS) $^ -o $@ \
|
||||||
|
$(TEST_LDFLAGS) -lsqlite3
|
||||||
|
|
||||||
test: \
|
test: \
|
||||||
$(TEST_NODE) \
|
$(TEST_NODE) \
|
||||||
$(TEST_TREE_MODEL) \
|
$(TEST_TREE_MODEL) \
|
||||||
|
|
@ -549,7 +572,8 @@ test: \
|
||||||
$(TEST_RELATION_EVIDENCE_DAO) \
|
$(TEST_RELATION_EVIDENCE_DAO) \
|
||||||
$(TEST_RELATION_SERVICE) \
|
$(TEST_RELATION_SERVICE) \
|
||||||
$(TEST_INVESTIGATION_GRAPH_MODEL) \
|
$(TEST_INVESTIGATION_GRAPH_MODEL) \
|
||||||
$(TEST_INVESTIGATION_GRAPH_LOADER)
|
$(TEST_INVESTIGATION_GRAPH_LOADER) \
|
||||||
|
$(TEST_INVESTIGATION_GRAPH_LOAD_TASK)
|
||||||
@echo "Exécution des tests..."
|
@echo "Exécution des tests..."
|
||||||
@./$(TEST_NODE)
|
@./$(TEST_NODE)
|
||||||
@./$(TEST_TREE_MODEL)
|
@./$(TEST_TREE_MODEL)
|
||||||
|
|
@ -595,6 +619,7 @@ test: \
|
||||||
@$(TEST_RELATION_SERVICE)
|
@$(TEST_RELATION_SERVICE)
|
||||||
@$(TEST_INVESTIGATION_GRAPH_MODEL)
|
@$(TEST_INVESTIGATION_GRAPH_MODEL)
|
||||||
@$(TEST_INVESTIGATION_GRAPH_LOADER)
|
@$(TEST_INVESTIGATION_GRAPH_LOADER)
|
||||||
|
@$(TEST_INVESTIGATION_GRAPH_LOAD_TASK)
|
||||||
@echo "Tous les tests sont valides."
|
@echo "Tous les tests sont valides."
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
|
|
@ -646,6 +671,7 @@ clean:
|
||||||
$(TEST_RELATION_EVIDENCE_DAO) \
|
$(TEST_RELATION_EVIDENCE_DAO) \
|
||||||
$(TEST_RELATION_SERVICE) \
|
$(TEST_RELATION_SERVICE) \
|
||||||
$(TEST_INVESTIGATION_GRAPH_MODEL) \
|
$(TEST_INVESTIGATION_GRAPH_MODEL) \
|
||||||
$(TEST_INVESTIGATION_GRAPH_LOADER)
|
$(TEST_INVESTIGATION_GRAPH_LOADER) \
|
||||||
|
$(TEST_INVESTIGATION_GRAPH_LOAD_TASK)
|
||||||
|
|
||||||
.PHONY: clean run test
|
.PHONY: clean run test
|
||||||
|
|
|
||||||
176
include/core/investigation_graph_load_task.h
Normal file
176
include/core/investigation_graph_load_task.h
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file investigation_graph_load_task.h
|
||||||
|
* @brief Chargement asynchrone du graphe métier d'une enquête.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LABFY_INVESTIGATION_INVESTIGATION_GRAPH_LOAD_TASK_H
|
||||||
|
#define LABFY_INVESTIGATION_INVESTIGATION_GRAPH_LOAD_TASK_H
|
||||||
|
|
||||||
|
#include "models/investigation_graph_model.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tâche opaque de chargement asynchrone d'un graphe d'enquête.
|
||||||
|
*
|
||||||
|
* Chaque exécution ouvre sa propre connexion SQLite dans le worker.
|
||||||
|
*
|
||||||
|
* L'objet peut être réutilisé après la finalisation complète d'une exécution.
|
||||||
|
*/
|
||||||
|
typedef struct InvestigationGraphLoadTask InvestigationGraphLoadTask;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Catégories d'erreurs de la tâche de chargement.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Un argument public est invalide.
|
||||||
|
*/
|
||||||
|
INVESTIGATION_GRAPH_LOAD_TASK_ERROR_INVALID_ARGUMENT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Une allocation mémoire a échoué.
|
||||||
|
*/
|
||||||
|
INVESTIGATION_GRAPH_LOAD_TASK_ERROR_MEMORY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Une exécution est déjà active.
|
||||||
|
*/
|
||||||
|
INVESTIGATION_GRAPH_LOAD_TASK_ERROR_ALREADY_RUNNING,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* La connexion SQLite propre au worker n'a pas pu être ouverte.
|
||||||
|
*/
|
||||||
|
INVESTIGATION_GRAPH_LOAD_TASK_ERROR_DATABASE_OPEN,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Le graphe n'a pas pu être construit depuis SQLite.
|
||||||
|
*/
|
||||||
|
INVESTIGATION_GRAPH_LOAD_TASK_ERROR_LOAD,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Le chargement a été annulé.
|
||||||
|
*/
|
||||||
|
INVESTIGATION_GRAPH_LOAD_TASK_ERROR_CANCELLED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Une incohérence interne empêche la finalisation.
|
||||||
|
*/
|
||||||
|
INVESTIGATION_GRAPH_LOAD_TASK_ERROR_INTERNAL
|
||||||
|
} InvestigationGraphLoadTaskError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Domaine d'erreur de la tâche.
|
||||||
|
*/
|
||||||
|
#define INVESTIGATION_GRAPH_LOAD_TASK_ERROR \
|
||||||
|
investigation_graph_load_task_error_quark()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback final exécuté sur le contexte principal ayant démarré la
|
||||||
|
* tâche.
|
||||||
|
*
|
||||||
|
* En cas de succès, graph_model appartient au destinataire du callback.
|
||||||
|
*
|
||||||
|
* En cas d'échec, error est empruntée et valable uniquement pendant le
|
||||||
|
* callback.
|
||||||
|
*
|
||||||
|
* @param load_task Tâche ayant terminé.
|
||||||
|
* @param graph_model Graphe transféré, ou NULL.
|
||||||
|
* @param error Erreur empruntée, ou NULL.
|
||||||
|
* @param user_data Données fournies au démarrage.
|
||||||
|
*/
|
||||||
|
typedef void (*InvestigationGraphLoadTaskCallback)(
|
||||||
|
InvestigationGraphLoadTask *load_task,
|
||||||
|
InvestigationGraphModel *graph_model,
|
||||||
|
const GError *error,
|
||||||
|
gpointer user_data
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne le domaine d'erreur de la tâche.
|
||||||
|
*/
|
||||||
|
GQuark investigation_graph_load_task_error_quark(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crée une tâche associée à un chemin SQLite.
|
||||||
|
*
|
||||||
|
* Le chemin est copié. La base n'est pas ouverte par le constructeur.
|
||||||
|
*
|
||||||
|
* @param database_path Chemin non vide de la base SQLite.
|
||||||
|
* @param error Emplacement facultatif recevant une erreur.
|
||||||
|
*
|
||||||
|
* @return Nouvelle tâche, ou NULL en cas d'échec.
|
||||||
|
*/
|
||||||
|
InvestigationGraphLoadTask *investigation_graph_load_task_new(
|
||||||
|
const char *database_path,
|
||||||
|
GError **error
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère la référence publique de la tâche.
|
||||||
|
*
|
||||||
|
* Si une exécution est active, elle est annulée et la destruction réelle est
|
||||||
|
* différée jusqu'à la fin du worker. Aucun callback utilisateur n'est alors
|
||||||
|
* invoqué.
|
||||||
|
*
|
||||||
|
* Cette fonction accepte NULL.
|
||||||
|
*
|
||||||
|
* @param load_task Tâche à libérer.
|
||||||
|
*/
|
||||||
|
void investigation_graph_load_task_free(
|
||||||
|
InvestigationGraphLoadTask *load_task
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Démarre le chargement en arrière-plan.
|
||||||
|
*
|
||||||
|
* En cas de succès, la tâche prend possession de user_data et appellera
|
||||||
|
* user_data_destroy exactement une fois après le callback, ou lors de la
|
||||||
|
* destruction anticipée de la tâche.
|
||||||
|
*
|
||||||
|
* En cas d'échec immédiat, l'appelant conserve la propriété de user_data.
|
||||||
|
*
|
||||||
|
* @param load_task Tâche valide et inactive.
|
||||||
|
* @param callback Callback final obligatoire.
|
||||||
|
* @param user_data Données facultatives du callback.
|
||||||
|
* @param user_data_destroy Destructeur facultatif de user_data.
|
||||||
|
* @param error Emplacement facultatif recevant une erreur.
|
||||||
|
*
|
||||||
|
* @return TRUE si l'exécution a été lancée.
|
||||||
|
*/
|
||||||
|
gboolean investigation_graph_load_task_start(
|
||||||
|
InvestigationGraphLoadTask *load_task,
|
||||||
|
InvestigationGraphLoadTaskCallback callback,
|
||||||
|
gpointer user_data,
|
||||||
|
GDestroyNotify user_data_destroy,
|
||||||
|
GError **error
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Demande l'annulation coopérative de l'exécution active.
|
||||||
|
*
|
||||||
|
* Cette fonction accepte NULL et peut être appelée plusieurs fois.
|
||||||
|
*
|
||||||
|
* @param load_task Tâche concernée.
|
||||||
|
*/
|
||||||
|
void investigation_graph_load_task_cancel(
|
||||||
|
InvestigationGraphLoadTask *load_task
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Indique si une exécution est active.
|
||||||
|
*
|
||||||
|
* @param load_task Tâche à consulter.
|
||||||
|
*
|
||||||
|
* @return TRUE uniquement entre le démarrage accepté et la finalisation.
|
||||||
|
*/
|
||||||
|
gboolean investigation_graph_load_task_is_running(
|
||||||
|
const InvestigationGraphLoadTask *load_task
|
||||||
|
);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
||||||
57
include/core/investigation_graph_load_task_test.h
Normal file
57
include/core/investigation_graph_load_task_test.h
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file investigation_graph_load_task_test.h
|
||||||
|
* @brief Hooks déterministes réservés aux tests du chargement asynchrone.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LABFY_INVESTIGATION_INVESTIGATION_GRAPH_LOAD_TASK_TEST_H
|
||||||
|
#define LABFY_INVESTIGATION_INVESTIGATION_GRAPH_LOAD_TASK_TEST_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Réinitialise tous les hooks.
|
||||||
|
*
|
||||||
|
* À appeler uniquement lorsqu'aucun worker n'est encore suspendu.
|
||||||
|
*/
|
||||||
|
void investigation_graph_load_task_test_reset(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure une suspension avant l'ouverture SQLite.
|
||||||
|
*/
|
||||||
|
void investigation_graph_load_task_test_pause_before_open(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Attend que le worker atteigne la suspension avant ouverture.
|
||||||
|
*/
|
||||||
|
void investigation_graph_load_task_test_wait_until_before_open(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère le worker suspendu avant ouverture.
|
||||||
|
*/
|
||||||
|
void investigation_graph_load_task_test_release_before_open(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure une suspension après l'ouverture SQLite.
|
||||||
|
*/
|
||||||
|
void investigation_graph_load_task_test_pause_after_open(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Attend que le worker atteigne la suspension après ouverture.
|
||||||
|
*/
|
||||||
|
void investigation_graph_load_task_test_wait_until_after_open(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère le worker suspendu après ouverture.
|
||||||
|
*/
|
||||||
|
void investigation_graph_load_task_test_release_after_open(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne le nombre de finalisations observées depuis le dernier reset.
|
||||||
|
*/
|
||||||
|
guint investigation_graph_load_task_test_get_completion_count(void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
||||||
1612
src/core/investigation_graph_load_task.c
Normal file
1612
src/core/investigation_graph_load_task.c
Normal file
File diff suppressed because it is too large
Load diff
1878
tests/test_investigation_graph_load_task.c
Normal file
1878
tests/test_investigation_graph_load_task.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue