summaryrefslogtreecommitdiff
path: root/src/analysis/db/cdb.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2019-10-10 21:45:56 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2019-10-10 21:45:56 (GMT)
commit96afc0325e1c85bf1a76d63c6441cf8f044708fe (patch)
tree1cf431fb3a888f9da14c0f3d46ee70bcd336a983 /src/analysis/db/cdb.c
parentae1744244fa777535cc707b9e6a014eb281b982c (diff)
Introduced first steps towards database snapshots.
Diffstat (limited to 'src/analysis/db/cdb.c')
-rw-r--r--src/analysis/db/cdb.c391
1 files changed, 201 insertions, 190 deletions
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c
index ca39a58..e03b875 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -44,6 +44,7 @@
#include "collection.h"
#include "protocol.h"
+#include "snapshot.h"
#include "../../common/compression.h"
#include "../../common/cpp.h"
#include "../../common/extstr.h"
@@ -54,6 +55,9 @@
+/* ------------------------- COEUR DE LA GESTION D'ARCHIVES ------------------------- */
+
+
/* Informations relatives à un client */
typedef struct _cdb_client
{
@@ -73,17 +77,14 @@ struct _GCdbArchive
rle_string hash; /* Empreinte cryptographique */
char *filename; /* Chemin d'accès à l'archive */
-
+ char *tmpdir; /* Répertoire de travail */
char *xml_desc; /* Fichier de description */
- char *sql_db; /* Base de données SQLite */
- xmlDocPtr xdoc; /* Document XML à créer */
- xmlXPathContextPtr context; /* Contexte pour les recherches*/
+ GList *collections; /* Ensemble de modifications */
+ GDbSnapshot *snapshot; /* Instantanés de bases SQL */
sqlite3 *db; /* Base de données à manipuler */
- GList *collections; /* Ensemble de modifications */
-
cdb_client *clients; /* Connexions en place */
size_t count; /* Quantité de clients */
GMutex clients_access; /* Verrou pour l'accès */
@@ -116,7 +117,7 @@ static void g_cdb_archive_dispose(GCdbArchive *);
static void g_cdb_archive_finalize(GCdbArchive *);
/* Ouvre une archive avec tous les éléments à conserver. */
-static bool g_cdb_archive_read(GCdbArchive *);
+static DBError g_cdb_archive_read(GCdbArchive *);
@@ -124,27 +125,22 @@ static bool g_cdb_archive_read(GCdbArchive *);
/* Crée la description XML correspondant à l'archive. */
-static bool g_cdb_archive_create_xml_desc(GCdbArchive *);
+static bool g_cdb_archive_create_xml_desc(const GCdbArchive *, xmlDocPtr *, xmlXPathContextPtr *);
/* Vérifie la conformité d'une description XML avec le serveur. */
-static bool g_cdb_archive_check_xml_version(const GCdbArchive *);
-
-
-
-/* ------------------------- ACCES A LA BASE DE DONNEES SQL ------------------------- */
+static bool g_cdb_archive_check_xml_version(const GCdbArchive *, xmlXPathContextPtr);
-/* Crée la base de données correspondant à l'archive. */
-static bool g_cdb_archive_create_db(const GCdbArchive *);
-
-
-/////////////////////////:
+/* -------------------------- ACTUALISATION DE COLLECTIONS -------------------------- */
/* Crée et remplit les collections à partir de leurs bases. */
static bool g_cdb_archive_load_collections(GCdbArchive *);
+/* Enregistre les signaux associés au suivi des collections. */
+static void g_cdb_archive_register_signals(GCdbArchive *);
+
/* Réagit à une modification au sein d'une collection donnée. */
static void on_collection_extended(GDbCollection *, GDbItem *, GCdbArchive *);
@@ -156,6 +152,9 @@ static void g_cdb_archive_remove_client(GCdbArchive *, size_t);
+/* ---------------------------------------------------------------------------------- */
+/* COEUR DE LA GESTION D'ARCHIVES */
+/* ---------------------------------------------------------------------------------- */
/* Indique le type défini pour une une archive d'éléments utilisateur. */
@@ -200,8 +199,12 @@ static void g_cdb_archive_class_init(GCdbArchiveClass *klass)
static void g_cdb_archive_init(GCdbArchive *archive)
{
+ archive->tmpdir = NULL;
+
archive->collections = create_collections_list();
+ archive->snapshot = NULL;
+
g_mutex_init(&archive->clients_access);
g_mutex_init(&archive->id_access);
@@ -224,6 +227,8 @@ static void g_cdb_archive_init(GCdbArchive *archive)
static void g_cdb_archive_dispose(GCdbArchive *archive)
{
+ g_clear_object(&archive->snapshot);
+
g_cond_clear(&archive->id_cond);
g_mutex_clear(&archive->id_access);
@@ -256,29 +261,14 @@ static void g_cdb_archive_finalize(GCdbArchive *archive)
assert(ret == SQLITE_OK);
}
- if (archive->xdoc != NULL)
- close_xml_file(archive->xdoc, archive->context);
-
if (archive->xml_desc != NULL)
- {
- ret = unlink(archive->xml_desc);
- if (ret != 0) LOG_ERROR_N("unlink");
-
free(archive->xml_desc);
- }
-
- if (archive->sql_db != NULL)
- {
- ret = unlink(archive->sql_db);
- if (ret != 0) LOG_ERROR_N("unlink");
-
- free(archive->sql_db);
-
- }
-
free(archive->filename);
+ if (archive->tmpdir != NULL)
+ free(archive->tmpdir);
+
exit_rle_string(&archive->hash);
G_OBJECT_CLASS(g_cdb_archive_parent_class)->finalize(G_OBJECT(archive));
@@ -307,11 +297,14 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl
GCdbArchive *result; /* Adresse à retourner */
int ret; /* Retour d'un appel */
struct stat finfo; /* Information sur l'archive */
+ const char *id; /* Identifiant d'instantané */
result = g_object_new(G_TYPE_CDB_ARCHIVE, NULL);
dup_into_rle_string(&result->hash, get_rle_string(hash));
+ *error = DBE_SYS_ERROR;
+
/* Chemin de l'archive */
result->filename = strdup(basedir);
@@ -319,21 +312,20 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl
result->filename = stradd(result->filename, ".cdb.tar.xz");
if (!mkpath(result->filename))
- goto gcan_error;
+ goto error;
/* Chemin des enregistrements temporaires */
+ result->tmpdir = strdup(tmpdir);
+
if (!mkpath(tmpdir))
- goto gcan_error;
+ goto error;
- ret = asprintf(&result->xml_desc, "%s" G_DIR_SEPARATOR_S "%s_desc.xml", tmpdir, result->hash.data);
- if (ret == -1) goto gcan_no_tmp;
+ ret = asprintf(&result->xml_desc, "%s" G_DIR_SEPARATOR_S "%s_desc.xml", tmpdir, get_rle_string(hash));
+ if (ret == -1) goto no_tmp;
ret = ensure_path_exists(result->xml_desc);
- if (ret == -1) goto gcan_no_tmp;
-
- ret = asprintf(&result->sql_db, "%s" G_DIR_SEPARATOR_S "%s_db.sql", tmpdir, result->hash.data);
- if (ret == -1) goto gcan_no_tmp;
+ if (ret == -1) goto no_tmp;
/* Création de l'archive si elle n'existe pas */
@@ -342,44 +334,74 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl
if (ret != 0)
{
/* Le soucis ne vient pas de l'absence du fichier... */
- if (errno != ENOENT) goto gcan_error;
+ if (errno != ENOENT) goto error;
- g_cdb_archive_create_xml_desc(result);
- g_cdb_archive_create_db(result);
+ result->snapshot = g_db_snapshot_new_empty(tmpdir, get_rle_string(hash), result->collections);
- *error = g_cdb_archive_write(result);
+ if (result->snapshot == NULL)
+ goto error;
- if (*error != DBE_NONE)
- goto gcan_error;
+ /* Récupération de la base courante */
- }
- else if (!S_ISREG(finfo.st_mode))
- goto gcan_error;
+ id = g_db_snapshot_get_current_id(result->snapshot);
+ assert(id != NULL);
+
+ result->db = g_db_snapshot_get_database(result->snapshot, id);
- /* Ouverture de l'archive */
+ if (result->db == NULL)
+ {
+ *error = DBE_XML_ERROR;
+ goto error;
+ }
- if (!g_cdb_archive_read(result))
- goto gcan_error;
+ *error = DBE_NONE;
- if (!g_cdb_archive_check_xml_version(result))
- {
- *error = DBE_XML_VERSION_ERROR;
- goto gcan_error;
}
- /* Chargement des éléments sauvegardés */
+ else if (!S_ISREG(finfo.st_mode))
+ goto error;
- if (!g_cdb_archive_load_collections(result))
+ else
{
- *error = DBE_DB_LOADING_ERROR;
- goto gcan_error;
+ /* Ouverture de l'archive */
+
+ *error = g_cdb_archive_read(result);
+
+ if (*error != DBE_NONE)
+ goto error;
+
+ /* Récupération de la base courante */
+
+ id = g_db_snapshot_get_current_id(result->snapshot);
+ assert(id != NULL);
+
+ result->db = g_db_snapshot_get_database(result->snapshot, id);
+
+ if (result->db == NULL)
+ {
+ *error = DBE_XML_ERROR;
+ goto error;
+ }
+
+ /* Chargement des éléments sauvegardés */
+
+ if (!g_cdb_archive_load_collections(result))
+ {
+ *error = DBE_DB_LOADING_ERROR;
+ goto error;
+ }
+
}
+ /* Ultimes connexions */
+
+ g_cdb_archive_register_signals(result);
+
return result;
- gcan_no_tmp:
+ no_tmp:
- gcan_error:
+ error:
g_object_unref(G_OBJECT(result));
@@ -400,22 +422,25 @@ GCdbArchive *g_cdb_archive_new(const char *basedir, const char *tmpdir, const rl
* *
******************************************************************************/
-static bool g_cdb_archive_read(GCdbArchive *archive)
+static DBError g_cdb_archive_read(GCdbArchive *archive)
{
- bool result; /* Conclusion à retourner */
+ DBError result; /* Conclusion à retourner */
struct archive *in; /* Archive à consulter */
int ret; /* Bilan d'un appel */
struct archive_entry *entry; /* Elément de l'archive */
const char *path; /* Désignation d'un fichier */
+ xmlDocPtr xdoc; /* Document XML à créer */
+ xmlXPathContextPtr context; /* Contexte pour les recherches*/
+ bool status; /* Bilan d'un chargement */
- result = false;
+ result = DBE_ARCHIVE_ERROR;
in = archive_read_new();
archive_read_support_filter_all(in);
archive_read_support_format_all(in);
ret = archive_read_open_filename(in, archive->filename, 10240 /* ?! */);
- if (ret != ARCHIVE_OK) goto gcar_bad_archive;
+ if (ret != ARCHIVE_OK) goto bad_archive;
for (ret = archive_read_next_header(in, &entry);
ret == ARCHIVE_OK;
@@ -426,33 +451,53 @@ static bool g_cdb_archive_read(GCdbArchive *archive)
if (strcmp(path, "desc.xml") == 0)
{
if (!dump_archive_entry_into_file(in, entry, archive->xml_desc))
- goto gcar_exit;
+ goto load_error;
- if (!open_xml_file(archive->xml_desc, &archive->xdoc, &archive->context))
- goto gcar_exit;
+ if (!open_xml_file(archive->xml_desc, &xdoc, &context))
+ goto load_error;
- }
- else if (strcmp(path, "sql.db") == 0)
- {
- if (!dump_archive_entry_into_file(in, entry, archive->sql_db))
- goto gcar_exit;
+ if (!g_cdb_archive_check_xml_version(archive, context))
+ {
+ result = DBE_XML_VERSION_ERROR;
+ goto load_error;
+ }
+
+ archive->snapshot = g_db_snapshot_new_from_xml(archive->tmpdir, get_rle_string(&archive->hash),
+ xdoc, context);
+
+ close_xml_file(xdoc, context);
+
+ ret = unlink(archive->xml_desc);
+ if (ret != 0) LOG_ERROR_N("unlink");
+
+ if (archive->snapshot == NULL)
+ goto load_error;
+
+ break;
- ret = sqlite3_open(archive->sql_db, &archive->db);
- if (ret != SQLITE_OK)
- goto gcar_exit;
}
}
- if (ret != ARCHIVE_EOF)
- goto gcar_exit;
+ archive_read_close(in);
+ archive_read_free(in);
+
+ in = archive_read_new();
+ archive_read_support_filter_all(in);
+ archive_read_support_format_all(in);
+
+ ret = archive_read_open_filename(in, archive->filename, 10240 /* ?! */);
+ if (ret != ARCHIVE_OK) goto bad_archive;
+
+ status = g_db_snapshot_fill(archive->snapshot, in);
+ if (!status) goto load_error;
- result = true;
+ result = DBE_NONE;
- gcar_exit:
+ load_error:
- gcar_bad_archive:
+ bad_archive:
archive_read_close(in);
archive_read_free(in);
@@ -479,23 +524,54 @@ DBError g_cdb_archive_write(const GCdbArchive *archive)
DBError result; /* Conclusion à retourner */
struct archive *out; /* Archive à constituer */
int ret; /* Bilan d'un appel */
- CPError status; /* Bilan d'une compression */
-
- result = DBE_ARCHIVE_ERROR;
+ xmlDocPtr xdoc; /* Document XML à créer */
+ xmlXPathContextPtr context; /* Contexte pour les recherches*/
+ bool status; /* Bilan d'un appel */
+ CPError error; /* Bilan d'une compression */
out = archive_write_new();
archive_write_add_filter_xz(out);
archive_write_set_format_gnutar(out);
ret = archive_write_open_filename(out, archive->filename);
- if (ret != ARCHIVE_OK) goto gcaw_bad_archive;
+ if (ret != ARCHIVE_OK)
+ {
+ result = DBE_ARCHIVE_ERROR;
+ goto bad_archive;
+ }
- status = add_file_into_archive(out, archive->xml_desc, "desc.xml");
+ status = g_cdb_archive_create_xml_desc(archive, &xdoc, &context);
- switch (status)
+ if (!status)
+ {
+ result = DBE_XML_ERROR;
+ goto bad_archive;
+ }
+
+ /* Enregistrement des bases */
+
+ result = g_db_snapshot_save(archive->snapshot, xdoc, context, out);
+
+ if (result != DBE_NONE)
+ goto bad_archive;
+
+ /* Enregistrement du document XML */
+
+ status = save_xml_file(xdoc, archive->xml_desc);
+
+ close_xml_file(xdoc, context);
+
+ if (!status)
+ {
+ result = DBE_SYS_ERROR;
+ goto bad_xml;
+ }
+
+ error = add_file_into_archive(out, archive->xml_desc, "desc.xml");
+
+ switch (error)
{
case CPE_NO_ERROR:
- result = DBE_NONE;
break;
case CPE_SYSTEM_ERROR:
@@ -508,29 +584,12 @@ DBError g_cdb_archive_write(const GCdbArchive *archive)
}
- if (result == DBE_NONE)
- {
- status = add_file_into_archive(out, archive->sql_db, "sql.db");
+ bad_xml:
- switch (status)
- {
- case CPE_NO_ERROR:
- result = DBE_NONE;
- break;
+ ret = unlink(archive->xml_desc);
+ if (ret != 0) LOG_ERROR_N("unlink");
- case CPE_SYSTEM_ERROR:
- result = DBE_SYS_ERROR;
- break;
-
- case CPE_ARCHIVE_ERROR:
- result = DBE_ARCHIVE_ERROR;
- break;
-
- }
-
- }
-
- gcaw_bad_archive:
+ bad_archive:
archive_write_close(out);
archive_write_free(out);
@@ -569,6 +628,8 @@ int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *has
/******************************************************************************
* *
* Paramètres : archive = archive à constituer. *
+* xdoc = document XML à compléter. [OUT] *
+* context = contexte pour les recherches. [OUT] *
* *
* Description : Crée la description XML correspondant à l'archive. *
* *
@@ -578,38 +639,20 @@ int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *has
* *
******************************************************************************/
-static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive)
+static bool g_cdb_archive_create_xml_desc(const GCdbArchive *archive, xmlDocPtr *xdoc, xmlXPathContextPtr *context)
{
bool result; /* Bilan à retourner */
- timestamp_t timestamp; /* Date de création */
- char tmp[sizeof(XSTR(UINT64_MAX))]; /* Stockage temporaire */
-
- result = create_new_xml_file(&archive->xdoc, &archive->context);
- if (result)
- result = add_content_to_node(archive->xdoc, archive->context,
- "/ChrysalideBinary/Version", PACKAGE_VERSION);
-
- if (result)
- result = add_content_to_node(archive->xdoc, archive->context,
- "/ChrysalideBinary/Protocol", XSTR(CDB_PROTOCOL_VERSION));
+ result = create_new_xml_file(xdoc, context);
if (result)
- result = add_content_to_node(archive->xdoc, archive->context,
- "/ChrysalideBinary/Hash", archive->hash.data);
+ result = add_content_to_node(*xdoc, *context, "/ChrysalideBinary/Version", PACKAGE_VERSION);
if (result)
- {
- init_timestamp(&timestamp);
- snprintf(tmp, sizeof(tmp), "%" PRIu64, timestamp);
-
- result = add_content_to_node(archive->xdoc, archive->context,
- "/ChrysalideBinary/CreationDate", tmp);
-
- }
+ result = add_content_to_node(*xdoc, *context, "/ChrysalideBinary/Protocol", XSTR(CDB_PROTOCOL_VERSION));
if (result)
- result = save_xml_file(archive->xdoc, archive->xml_desc);
+ result = add_content_to_node(*xdoc, *context, "/ChrysalideBinary/Hash", archive->hash.data);
return result;
@@ -619,6 +662,7 @@ static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive)
/******************************************************************************
* *
* Paramètres : archive = archive à consulter. *
+* context = contexte pour les recherches. *
* *
* Description : Vérifie la conformité d'une description XML avec le serveur. *
* *
@@ -628,7 +672,7 @@ static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive)
* *
******************************************************************************/
-static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive)
+static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive, xmlXPathContextPtr context)
{
bool result; /* Bilan à retourner */
char *version; /* Version protocolaire */
@@ -636,7 +680,7 @@ static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive)
result = NULL;
- version = get_node_text_value(archive->context, "/ChrysalideBinary/Protocol");
+ version = get_node_text_value(context, "/ChrysalideBinary/Protocol");
if (version == NULL) return false;
used = strtoul(version, NULL, 16);
@@ -650,16 +694,17 @@ static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive)
}
+
/* ---------------------------------------------------------------------------------- */
-/* ACCES A LA BASE DE DONNEES SQL */
+/* ACTUALISATION DE COLLECTIONS */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
-* Paramètres : archive = archive à constituer. *
+* Paramètres : archive = archive dont les collections sont à initialiser. *
* *
-* Description : Crée la base de données correspondant à l'archive. *
+* Description : Crée et remplit les collections à partir de leurs bases. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -667,72 +712,40 @@ static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive)
* *
******************************************************************************/
-static bool g_cdb_archive_create_db(const GCdbArchive *archive)
+static bool g_cdb_archive_load_collections(GCdbArchive *archive)
{
- bool result; /* Bilan à retourner */
- sqlite3 *db; /* Base de données à constituer*/
- int ret; /* Bilan de la création */
GList *iter; /* Boucle de parcours */
GDbCollection *collec; /* Collection visée manipulée */
- ret = sqlite3_open(archive->sql_db, &db);
-
- if (ret != SQLITE_OK)
- {
- fprintf(stderr, "sqlite3_open(): %s\n", sqlite3_errmsg(db));
- return false;
- }
-
- result = true;
-
for (iter = g_list_first(archive->collections);
- iter != NULL && result;
+ iter != NULL;
iter = g_list_next(iter))
{
collec = G_DB_COLLECTION(iter->data);
- result = g_db_collection_create_db_table(collec, db);
- }
-
- sqlite3_close(db);
-
- return result;
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* ACCES A LA BASE DE DONNEES SQL */
-/* ACCES A LA BASE DE DONNEES SQL */
-/* ---------------------------------------------------------------------------------- */
+ if (!g_db_collection_load_all_items(collec, archive->db))
+ return false;
+ }
+ return true;
+}
/******************************************************************************
* *
-* Paramètres : archive = archive dont les collections sont à initialiser. *
+* Paramètres : archive = archive dont les collections sont à suivre. *
* *
-* Description : Crée et remplit les collections à partir de leurs bases. *
+* Description : Enregistre les signaux associés au suivi des collections. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool g_cdb_archive_load_collections(GCdbArchive *archive)
+static void g_cdb_archive_register_signals(GCdbArchive *archive)
{
GList *iter; /* Boucle de parcours */
GDbCollection *collec; /* Collection visée manipulée */
@@ -742,15 +755,11 @@ static bool g_cdb_archive_load_collections(GCdbArchive *archive)
iter = g_list_next(iter))
{
collec = G_DB_COLLECTION(iter->data);
- g_signal_connect(collec, "content-extended", G_CALLBACK(on_collection_extended), archive);
- if (!g_db_collection_load_all_items(collec, archive->db))
- return false;
+ g_signal_connect(collec, "content-extended", G_CALLBACK(on_collection_extended), archive);
}
- return true;
-
}
@@ -1001,6 +1010,8 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
LOG_ERROR(LMT_ERROR, _("Bad exchange"));
+ assert(0);
+
exit_packed_buffer(&in_pbuf);
closed_exchange: