diff options
Diffstat (limited to 'src/analysis/db/collection.c')
-rw-r--r-- | src/analysis/db/collection.c | 429 |
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(×tamp, 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; + +} |