From a22b3a083c0b92de6b5d9b154773a26aeb99db0c Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 30 Jul 2015 00:56:33 +0000
Subject: Removed collection items by deactivating them using the activity
 timestamps.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@560 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                    |  13 ++++
 src/analysis/binary.c        |  56 +++++++++++++++++
 src/analysis/binary.h        |   8 ++-
 src/analysis/db/collection.c | 145 ++++++++++++++++++++++++++++++++++++++++---
 src/analysis/db/collection.h |  12 +++-
 src/analysis/db/item-int.h   |   2 -
 src/analysis/db/item.c       |  26 +++-----
 7 files changed, 227 insertions(+), 35 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index c92a45e..0eda0bf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+15-07-30  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/analysis/binary.c:
+	* src/analysis/binary.h:
+	* src/analysis/db/collection.c:
+	* src/analysis/db/collection.h:
+	Remove collection items by deactivating them using the activity timestamps.
+
+	* src/analysis/db/item.c:
+	* src/analysis/db/item-int.h:
+	Always send and receive timestamps on the network, so do not remember
+	the side of the collected item (server or not) anymore.
+
 15-07-29  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/analysis/db/collection.c:
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index c6ae4e5..615e72e 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -862,6 +862,62 @@ bool _g_loaded_binary_add_to_collection(GLoadedBinary *binary, DBFeatures featur
 
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : binary  = élément binaire à consulter.                       *
+*                feature = fonctionnalité visée par la requête.               *
+*                item    = élémnent à retirer d'un serveur de collection.     *
+*                lock    = indique si le verrou d'écriture doit être posé.    *
+*                                                                             *
+*  Description : Demande la suppression de modification dans une collection.  *
+*                                                                             *
+*  Retour      : Bilan partiel de l'opération demandée.                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool _g_loaded_binary_remove_from_collection(GLoadedBinary *binary, DBFeatures feature, GDbItem *item, bool lock)
+{
+    bool result;                            /* Bilan à faire remonter      */
+    GDbCollection *collec;                  /* Collection visée au final   */
+    DBStorage storage;                      /* Forme d'enregistrement      */
+    GDbClient *client;                      /* Liaison à utiliser          */
+    int fd;                                 /* Identifiant du canal de com.*/
+
+    collec = g_loaded_binary_find_collection(binary, feature);
+    if (collec == NULL) return false;
+
+    /* S'il n'y a pas besoin de sauvegarde... */
+    if (g_db_item_is_volatile(item))
+        _g_db_collection_remove_item(collec, item, lock);
+
+    /* Sinon on envoie par le réseau ! */
+    else
+    {
+        storage = g_loaded_binary_get_storage(binary, feature);
+
+
+        /* TODO : sélection du bon client... */
+        client = binary->local;
+
+
+        fd = g_db_client_get_fd(client);
+
+        result = g_db_collection_send(collec, fd, DBA_REM_ITEM, item);
+
+        g_db_client_put_fd(client);
+
+    }
+
+    g_object_unref(G_OBJECT(collec));
+
+    return result;
+
+}
+
+
+
 
 
 
diff --git a/src/analysis/binary.h b/src/analysis/binary.h
index fb37310..768f53a 100644
--- a/src/analysis/binary.h
+++ b/src/analysis/binary.h
@@ -128,13 +128,15 @@ GDbCollection *g_loaded_binary_find_collection(const GLoadedBinary *, DBFeatures
 bool _g_loaded_binary_add_to_collection(GLoadedBinary *, DBFeatures, GDbItem *, bool);
 
 #define g_loaded_binary_add_to_collection(b, f, i) \
-    _g_loaded_binary_add_to_collection(b, f, i, true);
+    _g_loaded_binary_add_to_collection(b, f, i, true)
 
+/* Demande la suppression de modification dans une collection. */
+bool _g_loaded_binary_remove_from_collection(GLoadedBinary *, DBFeatures, GDbItem *, bool);
 
+#define g_loaded_binary_remove_from_collection(b, f, i) \
+    _g_loaded_binary_remove_from_collection(b, f, i, true)
 
 
-#define g_loaded_binary_remove_from_collection(b, f, i)
-
 
 /**
  * TODO :
diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c
index 5e5adb7..0292c5c 100644
--- a/src/analysis/db/collection.c
+++ b/src/analysis/db/collection.c
@@ -278,6 +278,8 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db)
     bool status;                            /* Bilan de lecture initiale   */
     DBAction action;                        /* Commande de la requête      */
     GDbItem *item;                          /* Définition d'élément visé   */
+    GList *found;                           /* Test de présence existante  */
+    timestamp_t inactive;                   /* Horodatage de désactivation */
 
     status = safe_recv(fd, &val32, sizeof(uint32_t), 0);
     if (!status) return false;
@@ -287,9 +289,6 @@ 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;
 
@@ -299,6 +298,10 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db)
     {
         case DBA_ADD_ITEM:
 
+            /* Ecrasement des horodatages par les valeurs communes du serveur */
+            if (db != NULL)
+                g_db_item_set_server_side(item);
+
             result = g_db_collection_add_item(collec, item);
 
             if (result)
@@ -310,17 +313,44 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db)
             }
 
             if (!result)
-                /* TODO : retirer l'élémnt */;
+                /* TODO : retirer l'élément */;
 
             break;
 
         case DBA_REM_ITEM:
+
+            g_db_collection_wlock(collec);
+
+            found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare_with_timestamp);
+
+            result = (found != NULL);
+
+            if (result)
+            {
+                /* Côté client */
+                if (db == NULL)
+                    result = _g_db_collection_remove_item(collec, item, false);
+
+                /* Côté serveur */
+                else
+                {
+                    if (g_db_item_is_active(G_DB_ITEM(found->data)))
+                    {
+                        inactive = _g_db_collection_compute_inactivity_timestamp(collec, false);
+                        result = _g_db_collection_update_item_activity(collec, item, inactive, false);
+                    }
+                }
+
+            }
+
+            g_db_collection_wunlock(collec);
+
             break;
 
         case DBA_CHANGE_STATE:
 
             if (db == NULL)
-                result = g_db_collection_update_item_activity(collec, item);
+                result = g_db_collection_update_item_activity(collec, item, g_db_item_get_timestamp(item) + 1);
             else
                 result = false;
 
@@ -565,9 +595,104 @@ bool _g_db_collection_add_item(GDbCollection *collec, GDbItem *item, bool lock)
 
     g_signal_emit_by_name(collec, "content-changed", DBA_ADD_ITEM, item);
 
+    if (lock)
+        g_db_collection_wunlock(collec);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : collec = ensemble d'éléments à considérer.                   *
+*                item   = élément de collection à manipuler.                  *
+*                lock   = indique si le verrou d'écriture doit être posé.     *
+*                                                                             *
+*  Description : Procède au retrait d'un nouvel élément dans la collection.   *
+*                                                                             *
+*  Retour      : Bilan de l'exécution de l'opération.                         *
+*                                                                             *
+*  Remarques   : L'appelant reste le propriétaire de l'object transféré.      *
+*                                                                             *
+******************************************************************************/
+
+bool _g_db_collection_remove_item(GDbCollection *collec, GDbItem *item, bool lock)
+{
+    bool result;                            /* Bilan à faire remonter      */
+    GList *found;                           /* Test de présence existante  */
+    GDbItem *internal;                      /* Elément interne à modifier  */
+
+    result = true;
+
+    if (lock)
+        g_db_collection_wlock(collec);
+
+    found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare_with_timestamp);
+
+    result = (found != NULL);
+
+    if (result)
+    {
+        internal = G_DB_ITEM(found->data);
+
+        collec->items = g_list_delete_link(collec->items, found);
+
+        g_signal_emit_by_name(collec, "content-changed", DBA_REM_ITEM, internal);
+
+        g_object_unref(G_OBJECT(internal));
+
+    }
+
+    if (lock)
+        g_db_collection_wunlock(collec);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : collec = ensemble d'éléments à considérer.                   *
+*                lock   = indique si le verrou d'écriture doit être posé.     *
+*                                                                             *
+*  Description : Détermine l'horodatage le plus jeune pour une désactivation. *
+*                                                                             *
+*  Retour      : Horodatage à utiliser pour une phase de désactivation.       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+timestamp_t _g_db_collection_compute_inactivity_timestamp(GDbCollection *collec, bool lock)
+{
+    timestamp_t result;                     /* Horodatage à retourner      */
+    GList *iter;                            /* Boucle de parcours          */
+    GDbItem *item;                          /* Elément interne à consulter */
+    timestamp_t stamp;                      /* Horodatage de l'élément     */
+
+    result = TIMESTAMP_ALL_ACTIVE;
+
+    if (lock)
+        g_db_collection_wlock(collec);
+
+    for (iter = g_list_first(collec->items);
+         iter != NULL && result;
+         iter = g_list_next(iter))
+    {
+        item = G_DB_ITEM(iter->data);
+
+        if (!g_db_item_is_active(item))
+        {
+            stamp = g_db_item_get_timestamp(item);
 
-    printf(" ==== CONTENT CHANGED (-> %u) !!!\n", g_list_length(collec->items));
+            if (timestamp_is_younger(stamp, result))
+                result = stamp;
 
+        }
+
+    }
 
     if (lock)
         g_db_collection_wunlock(collec);
@@ -591,7 +716,7 @@ bool _g_db_collection_add_item(GDbCollection *collec, GDbItem *item, bool lock)
 *                                                                             *
 ******************************************************************************/
 
-bool _g_db_collection_update_item_activity(GDbCollection *collec, GDbItem *item, bool lock)
+bool _g_db_collection_update_item_activity(GDbCollection *collec, GDbItem *item, timestamp_t timestamp, bool lock)
 {
     bool result;                            /* Bilan à faire remonter      */
     GList *found;                           /* Test de présence existante  */
@@ -608,7 +733,7 @@ bool _g_db_collection_update_item_activity(GDbCollection *collec, GDbItem *item,
     {
         internal = G_DB_ITEM(found->data);
 
-        g_db_item_set_activity(internal, (timestamp_t []) { g_db_item_get_timestamp(item) + 1 });
+        g_db_item_set_activity(internal, (timestamp_t []) { timestamp });
 
         g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, internal);
 
@@ -893,8 +1018,6 @@ 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);
 
@@ -1321,6 +1444,8 @@ bool update_activity_in_collections(GList *list, int fd, sqlite3 *db)
     GList *i;                               /* Boucle de parcours #2       */
     GDbItem *item;                          /* Elément collecté à manipuler*/
 
+    /* TODO : lock ? */
+
     status = recv_timestamp(&timestamp, fd, 0);
     if (!status) return false;
 
diff --git a/src/analysis/db/collection.h b/src/analysis/db/collection.h
index ac3e60f..e9f93d2 100644
--- a/src/analysis/db/collection.h
+++ b/src/analysis/db/collection.h
@@ -102,11 +102,19 @@ bool g_db_collection_has_item(GDbCollection *, GDbItem *);
 /* Procède à l'ajout d'un nouvel élément dans la collection. */
 bool _g_db_collection_add_item(GDbCollection *, GDbItem *, bool);
 
+/* Procède au retrait d'un nouvel élément dans la collection. */
+bool _g_db_collection_remove_item(GDbCollection *, GDbItem *, bool);
+
+/* Détermine l'horodatage le plus jeune pour une désactivation. */
+timestamp_t _g_db_collection_compute_inactivity_timestamp(GDbCollection *, bool);
+
 /* Met à jour le statut d'activité d'un élément de collection. */
-bool _g_db_collection_update_item_activity(GDbCollection *, GDbItem *, bool);
+bool _g_db_collection_update_item_activity(GDbCollection *, GDbItem *, timestamp_t, bool);
 
 #define g_db_collection_add_item(c, i) _g_db_collection_add_item(c, i, true)
-#define g_db_collection_update_item_activity(c, i) _g_db_collection_update_item_activity(c, i, true)
+#define g_db_collection_remove_item(c, i) _g_db_collection_remove_item(c, i, true)
+#define g_db_collection_compute_inactivity_timestamp(c) _g_db_collection_compute_inactivity_timestamp(c, true)
+#define g_db_collection_update_item_activity(c, i, t) _g_db_collection_update_item_activity(c, i, t, true)
 
 /* Active les éléments en amont d'un horodatage donné. */
 GList *g_db_collection_set_last_active(GDbCollection *, timestamp_t, timestamp_t *, sqlite3 *);
diff --git a/src/analysis/db/item-int.h b/src/analysis/db/item-int.h
index 1af1048..fb33c72 100644
--- a/src/analysis/db/item-int.h
+++ b/src/analysis/db/item-int.h
@@ -63,8 +63,6 @@ struct _GDbItem
 {
     GObject parent;                         /* A laisser en premier        */
 
-    bool server_side;                       /* Instance côté serveur       */
-
     timestamp_t created;                    /* Date de création            */
     timestamp_t timestamp;                  /* Date dernière activité      */
 
diff --git a/src/analysis/db/item.c b/src/analysis/db/item.c
index 5463e85..3fc6f6f 100644
--- a/src/analysis/db/item.c
+++ b/src/analysis/db/item.c
@@ -191,8 +191,6 @@ void g_db_item_set_server_side(GDbItem *item)
     init_timestamp(&item->created);
     item->timestamp = item->created;
 
-    item->server_side = true;
-
 }
 
 
@@ -288,15 +286,11 @@ static bool g_db_item_recv_from_fd(GDbItem *item, int fd, int flags)
 {
     bool status;                            /* Bilan d'une réception       */
 
-    if (!item->server_side)
-    {
-        status = recv_timestamp(&item->created, fd, flags);
-        if (!status) return false;
-
-        status = recv_timestamp(&item->timestamp, fd, flags);
-        if (!status) return false;
+    status = recv_timestamp(&item->created, fd, flags);
+    if (!status) return false;
 
-    }
+    status = recv_timestamp(&item->timestamp, fd, flags);
+    if (!status) return false;
 
     status = recv_rle_string(&item->author, fd, flags);
     if (!status) return false;
@@ -354,15 +348,11 @@ static bool g_db_item_send_to_fd(const GDbItem *item, int fd, int flags)
 {
     bool status;                            /* Bilan d'une émission        */
 
-    if (item->server_side)
-    {
-        status = send_timestamp(&item->created, fd, MSG_MORE | flags);
-        if (!status) return false;
-
-        status = send_timestamp(&item->timestamp, fd, MSG_MORE | flags);
-        if (!status) return false;
+    status = send_timestamp(&item->created, fd, MSG_MORE | flags);
+    if (!status) return false;
 
-    }
+    status = send_timestamp(&item->timestamp, fd, MSG_MORE | flags);
+    if (!status) return false;
 
     status = send_rle_string(&item->author, fd, MSG_MORE | flags);
     if (!status) return false;
-- 
cgit v0.11.2-87-g4458