summaryrefslogtreecommitdiff
path: root/src/analysis/db/collection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis/db/collection.c')
-rw-r--r--src/analysis/db/collection.c429
1 files changed, 391 insertions, 38 deletions
diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c
index c3b9f2c..91f9872 100644
--- a/src/analysis/db/collection.c
+++ b/src/analysis/db/collection.c
@@ -68,6 +68,8 @@ static bool g_db_collection_setup_load(GDbCollection *, bound_value **, size_t *
/* Enregistre un élément de collection dans une base de données. */
static bool g_db_collection_store_item(const GDbCollection *, const GDbItem *, sqlite3 *);
+/* Met à jour un élément de collection dans une base de données. */
+static bool g_db_collection_store_updated_item(const GDbCollection *, const GDbItem *, sqlite3 *);
@@ -285,6 +287,9 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db)
item = g_object_new(collec->type, NULL);
+ if (db != NULL)
+ g_db_item_set_server_side(item);
+
status = g_db_item_recv(item, fd, 0);
if (!status) return false;
@@ -312,8 +317,13 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db)
case DBA_REM_ITEM:
break;
- case DBA_MOD_ITEM:
- result = g_db_collection_modify_item(collec, item);
+ case DBA_CHANGE_STATE:
+
+ if (db == NULL)
+ result = g_db_collection_update_item_activity(collec, item);
+ else
+ result = false;
+
break;
default:
@@ -322,6 +332,8 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db)
}
+ g_object_unref(G_OBJECT(item));
+
return result;
}
@@ -511,7 +523,7 @@ bool g_db_collection_has_item(GDbCollection *collec, GDbItem *item)
printf(" --- has\n");
- found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare);
+ found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare_with_timestamp);
printf(" --- has: %p\n", found);
@@ -539,33 +551,23 @@ bool g_db_collection_has_item(GDbCollection *collec, GDbItem *item)
bool _g_db_collection_add_item(GDbCollection *collec, GDbItem *item, bool lock)
{
bool result; /* Bilan à faire remonter */
- GList *found; /* Test de présence existante */
+
+ result = true;
if (lock)
g_db_collection_wlock(collec);
- found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare);
-
- if (found != NULL)
- result = g_db_collection_modify_item(collec, item);
-
- else
- {
- g_object_ref(G_OBJECT(item));
- collec->items = g_list_append(collec->items, item);
-
- g_object_ref(G_OBJECT(item));
- collec->sorted = g_list_insert_sorted(collec->sorted, item, (GCompareFunc)g_db_item_compare);
+ g_object_ref(G_OBJECT(item));
+ collec->items = g_list_append(collec->items, item);
- g_signal_emit_by_name(collec, "content-changed", DBA_ADD_ITEM, item);
+ g_object_ref(G_OBJECT(item));
+ collec->sorted = g_list_insert_sorted(collec->sorted, item, (GCompareFunc)g_db_item_compare_with_timestamp);
+ g_signal_emit_by_name(collec, "content-changed", DBA_ADD_ITEM, item);
- printf(" ==== CONTENT CHANGED (-> %u) !!!\n", g_list_length(collec->items));
+ printf(" ==== CONTENT CHANGED (-> %u) !!!\n", g_list_length(collec->items));
- result = true;
-
- }
if (lock)
g_db_collection_wunlock(collec);
@@ -578,10 +580,10 @@ bool _g_db_collection_add_item(GDbCollection *collec, GDbItem *item, bool lock)
/******************************************************************************
* *
* Paramètres : collec = ensemble d'éléments à considérer. *
-* item = élément de collection à copier. *
+* item = élément de collection à manipuler. *
* lock = indique si le verrou d'écriture doit être posé. *
* *
-* Description : Procède à la modification d'un élément dans la collection. *
+* Description : Met à jour le statut d'activité d'un élément de collection. *
* *
* Retour : Bilan de l'exécution de l'opération. *
* *
@@ -589,26 +591,127 @@ bool _g_db_collection_add_item(GDbCollection *collec, GDbItem *item, bool lock)
* *
******************************************************************************/
-bool _g_db_collection_modify_item(GDbCollection *collec, GDbItem *item, bool lock)
+bool _g_db_collection_update_item_activity(GDbCollection *collec, GDbItem *item, bool lock)
{
bool result; /* Bilan à faire remonter */
GList *found; /* Test de présence existante */
+ GDbItem *internal; /* Elément interne à modifier */
- found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare);
+ if (lock)
+ g_db_collection_wlock(collec);
+ found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare_without_timestamp);
+ result = (found != NULL);
- result = true;
+ if (result)
+ {
+ internal = G_DB_ITEM(found->data);
+
+ g_db_item_set_activity(internal, (timestamp_t []) { g_db_item_get_timestamp(item) + 1 });
+
+ g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, internal);
+
+ }
+
+ if (lock)
+ g_db_collection_wunlock(collec);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : collec = ensemble d'éléments à considérer. *
+* timestamp = date du dernier élément à garder comme actif. *
+* inactive = date du premier élément inactif rencontré. [OUT] *
+* db = base de données à mettre à jour. *
+* *
+* Description : Active les éléments en amont d'un horodatage donné. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GList *g_db_collection_set_last_active(GDbCollection *collec, timestamp_t timestamp, timestamp_t *inactive, sqlite3 *db)
+{
+ GList *result; /* Liste d'inactifs à renvoyer */
+ GList *i; /* Parcours des éléments */
+ GDbItem *item; /* Elément à traiter */
+ timestamp_t stamp; /* Horodatage de l'élément */
+ result = NULL;
+ for (i = g_list_first(collec->items); i != NULL; i = g_list_next(i))
+ {
+ item = G_DB_ITEM(i->data);
+ stamp = g_db_item_get_timestamp(item);
+ if (timestamp_is_younger(stamp, timestamp))
+ {
+ if (!g_db_item_is_active(item))
+ {
+ g_db_item_set_activity(item, NULL);
+ /* ... */g_db_collection_store_updated_item(collec, item, db);
+ g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, item);
+ }
+ }
+
+ else
+ {
+ if (!g_db_item_is_active(item))
+ {
+ if (timestamp_is_younger(stamp, *inactive))
+ *inactive = stamp;
+ }
+
+ else
+ result = g_list_append(result, item);
+
+ }
+
+ }
return result;
}
+/******************************************************************************
+* *
+* Paramètres : collec = ensemble d'éléments à considérer. *
+* item = élément à désactiver. *
+* timestamp = date du premier élément inactif rencontré. [OUT] *
+* *
+* Description : Désactive les éléments en aval d'un horodatage donné. *
+* *
+* Retour : true si l'élément a été traité, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_db_collection_set_inactive(GDbCollection *collec, GDbItem *item, timestamp_t *timestamp)
+{
+ /* Si cette collection n'est pas concernée, on ne bouge pas ! */
+ if (G_OBJECT_TYPE(G_OBJECT(item)) != collec->type) return false;
+
+ assert(g_db_item_is_active(item));
+
+ g_db_item_set_activity(item, timestamp);
+
+ g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, item);
+
+ return true;
+
+}
+
+
/* ---------------------------------------------------------------------------------- */
/* MANIPULATIONS AVEC UNE BASE DE DONNEES */
@@ -630,8 +733,6 @@ bool _g_db_collection_modify_item(GDbCollection *collec, GDbItem *item, bool loc
bool g_db_collection_create_db_table(const GDbCollection *collec, sqlite3 *db)
{
- fprintf(stderr, "CREATE '%s'\n", collec->name);
-
return G_DB_COLLECTION_GET_CLASS(collec)->create_table(collec, db);
}
@@ -653,12 +754,11 @@ bool g_db_collection_create_db_table(const GDbCollection *collec, sqlite3 *db)
static bool _g_db_collection_setup_load(GDbCollection *collec, bound_value **values, size_t *count)
{
- *count += 2;
- *values = (bound_value *)realloc(*values, *count * sizeof(bound_value));
-
- (*values)[*count - 2].name = "created";
+ if (!setup_load_of_timestamp(NULL, "created", values, count))
+ return false;
- (*values)[*count - 1].name = "modified";
+ if (!setup_load_of_timestamp(NULL, "timestamp", values, count))
+ return false;
if (!setup_load_of_rle_string(NULL, "author", values, count))
return false;
@@ -666,9 +766,6 @@ static bool _g_db_collection_setup_load(GDbCollection *collec, bound_value **val
if (!setup_load_of_rle_string(NULL, "tool", values, count))
return false;
- if (!setup_load_of_rle_string(NULL, "label", values, count))
- return false;
-
return true;
}
@@ -796,6 +893,8 @@ bool g_db_collection_load_all_items(GDbCollection *collec, sqlite3 *db)
new = g_object_new(G_DB_COLLECTION(collec)->type, NULL);
+ g_db_item_set_server_side(new);
+
result = g_db_item_load(new, values, count);
result &= g_db_collection_add_item(G_DB_COLLECTION(collec), new);
@@ -931,13 +1030,157 @@ static bool g_db_collection_store_item(const GDbCollection *collec, const GDbIte
free(sql);
- printf("INSERT ? %d\n", result);
-
return result;
}
+/******************************************************************************
+* *
+* Paramètres : collec = ensemble d'éléments à considérer. *
+* item = élément de collection à enregistrer. *
+* db = base de données à mettre à jour. *
+* *
+* Description : Met à jour un élément de collection dans une base de données.*
+* *
+* Retour : Bilan de l'exécution de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_db_collection_store_updated_item(const GDbCollection *collec, const GDbItem *item, sqlite3 *db)
+{
+ bool result; /* Conclusion à faire remonter */
+ bound_value *values; /* Champs de table à inclure */
+ size_t count; /* Nombre de ces champs */
+ char *sql; /* Requête SQL à construire */
+ bool first; /* Première valeur ? */
+ size_t i; /* Boucle de parcours */
+ sqlite3_stmt *stmt; /* Déclaration mise en place */
+ int ret; /* Bilan d'un appel à SQLite */
+ int index; /* Indice de valeur attachée */
+ const bound_value *timestamp; /* Valeur de l'horodatage */
+
+ if (!g_db_item_prepare_db_statement(item, &values, &count))
+ return false;
+
+ result = false;
+
+ /* Préparation de la requête */
+
+ sql = strdup("UPDATE ");
+ sql = stradd(sql, collec->name);
+
+ sql = stradd(sql, " SET timestamp = ? ");
+
+ sql = stradd(sql, "WHERE ");
+
+ first = true;
+
+ for (i = 0; i < count; i++)
+ {
+ if (strcmp(values[i].name, "timestamp") == 0)
+ continue;
+
+ if (first)
+ first = false;
+ else
+ sql = stradd(sql, " AND ");
+
+ sql = stradd(sql, values[i].name);
+
+ sql = stradd(sql, " = ");
+
+ if (values[i].type == SQLITE_RAW)
+ sql = stradd(sql, values[i].cstring);
+ else
+ sql = stradd(sql, "?");
+
+ }
+
+ sql = stradd(sql, ";");
+
+ fprintf(stderr, "UPDATE SQL '%s'\n", sql);
+
+ ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+ if (ret != SQLITE_OK)
+ {
+ fprintf(stderr, "Can't prepare INSERT statment '%s' (ret=%d): %s\n", sql, ret, sqlite3_errmsg(db));
+ goto gdcsi_exit;
+ }
+
+ /* Attribution des valeurs */
+
+ index = 1;
+
+ timestamp = find_bound_value(values, count, "timestamp");
+ assert(timestamp->type == SQLITE_INT64);
+
+ ret = sqlite3_bind_int64(stmt, index, values[i].integer64);
+ index++;
+
+ if (ret != SQLITE_OK)
+ {
+ fprintf(stderr, "Can't bind value for parameter nb %d in '%s' (ret=%d): %s\n",
+ index - 1, sql, ret, sqlite3_errmsg(db));
+ goto gdcsi_exit;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ if (strcmp(values[i].name, "timestamp") == 0)
+ continue;
+
+ switch (values[i].type)
+ {
+ case SQLITE_INT64:
+ ret = sqlite3_bind_int64(stmt, index, values[i].integer64);
+ index++;
+ break;
+
+ case SQLITE_TEXT:
+ ret = sqlite3_bind_text(stmt, index, values[i].string, -1, values[i].delete);
+ index++;
+ break;
+
+ default:
+ ret = SQLITE_OK;
+ break;
+
+ }
+
+ if (ret != SQLITE_OK)
+ {
+ fprintf(stderr, "Can't bind value for parameter nb %d in '%s' (ret=%d): %s\n",
+ index - 1, sql, ret, sqlite3_errmsg(db));
+ goto gdcsi_exit;
+ }
+
+ }
+
+ /* Exécution finale */
+
+ ret = sqlite3_step(stmt);
+
+ if (ret != SQLITE_DONE)
+ {
+ fprintf(stderr, "UPDATE statement '%s' didn't return DONE (ret=%d): %s\n", sql, ret, sqlite3_errmsg(db));
+ goto gdcsi_exit;
+ }
+
+ sqlite3_finalize(stmt);
+
+ result = true;
+
+ gdcsi_exit:
+
+ free(sql);
+
+ return result;
+
+}
+
/* ---------------------------------------------------------------------------------- */
@@ -1007,3 +1250,113 @@ GDbCollection *find_collection_in_list(GList *list, uint32_t id)
return (iter != NULL ? result : NULL);
}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = ensemble de collectons à parcourir. *
+* write = précise le type d'accès prévu (lecture/écriture). *
+* lock = indique le sens du verrouillage à mener. *
+* *
+* Description : Met à disposition un encadrement des accès aux éléments. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void lock_unlock_collections(GList *list, bool write, bool lock)
+{
+ GList *iter; /* Boucle de parcours */
+
+ for (iter = g_list_first(list);
+ iter != NULL;
+ iter = g_list_next(iter))
+ {
+ g_db_collection_lock_unlock(G_DB_COLLECTION(iter->data), write, lock);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = ensemble de collectons à traiter. *
+* fd = canal de communication ouvert en lecture. *
+* db = base de données à mettre à jour. *
+* *
+* Description : Met à jour les statuts d'activité des éléments. *
+* *
+* Retour : Bilan du déroulement des opérations. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool update_activity_in_collections(GList *list, int fd, sqlite3 *db)
+{
+ bool result; /* Résultat global à renvoyer */
+ bool status; /* Bilan de lecture initiale */
+ timestamp_t timestamp; /* Horodatage de limite */
+ timestamp_t inactive; /* Date du premier inactif */
+ GList *remaining; /* Eléments restants à traiter */
+ GList *c; /* Boucle de parcours #1 */
+ GDbCollection *collec; /* Collection à manipuler */
+ GList *got; /* Eléments restants à traiter */
+ GList *i; /* Boucle de parcours #2 */
+ GDbItem *item; /* Elément collecté à manipuler*/
+
+ status = recv_timestamp(&timestamp, fd, 0);
+ if (!status) return false;
+
+ inactive = TIMESTAMP_ALL_ACTIVE;
+
+ remaining = NULL;
+
+ wlock_collections(list);
+
+ for (c = g_list_first(list); c != NULL; c = g_list_next(c))
+ {
+ collec = G_DB_COLLECTION(c->data);
+
+ got = g_db_collection_set_last_active(collec, timestamp, &inactive, db);
+ remaining = g_list_concat(remaining, got);
+
+ }
+
+ gint sort_with_timestamp(GDbItem *a, GDbItem *b)
+ {
+ return g_db_item_cmp(a, b, false);
+ }
+
+ remaining = g_list_sort(remaining, (GCompareFunc)sort_with_timestamp);
+
+ result = true;
+
+ for (i = g_list_last(remaining); i != NULL && result; i = g_list_previous(i))
+ {
+ item = G_DB_ITEM(i->data);
+
+ for (c = g_list_first(list); c != NULL && result; c = g_list_next(c))
+ {
+ collec = G_DB_COLLECTION(c->data);
+
+ if (g_db_collection_set_inactive(collec, item, &inactive))
+ {
+ result = g_db_collection_store_updated_item(collec, item, db);
+ break;
+ }
+
+ }
+
+ }
+
+ wunlock_collections(list);
+
+ g_list_free(remaining);
+
+ return result;
+
+}