- fix
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed_cache.c
index c75ae7dc45b1c32a38037ffae9f7e96b11fb2cf0..e75ded9b2698cea83b6b982055d81c4f31bd2333 100644 (file)
   GNUNET_log_from (kind, "testbed-cache", __VA_ARGS__)
 
 
+/**
+ * Time to expire a cache entry
+ */
+#define CACHE_EXPIRY                            \
+  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
+
+
 /**
  * Type of cache-get requests
  */
@@ -117,12 +124,12 @@ struct GSTCacheGetHandle
    * The cache entry object this handle corresponds to
    */
   struct CacheEntry *entry;
-  
+
   /**
    * The cache callback to call when a handle is available
    */
   GST_cache_handle_ready_cb cb;
-   
+
   /**
    * The closure for the above callback
    */
@@ -130,7 +137,7 @@ struct GSTCacheGetHandle
 
   /**
    * The peer connect notify context created for this handle; can be NULL
-   */  
+   */
   struct ConnectNotifyContext *nctxt;
 
   /**
@@ -147,7 +154,7 @@ struct GSTCacheGetHandle
 /**
  * Cache entry
  */
-struct CacheEntry 
+struct CacheEntry
 {
   /**
    * DLL next ptr for least recently used cache entries
@@ -162,12 +169,12 @@ struct CacheEntry
   /**
    * The transport handle to the peer corresponding to this entry; can be NULL
    */
-  struct GNUNET_TRANSPORT_Handle *transport_handle_;
+  struct GNUNET_TRANSPORT_Handle *transport_handle;
 
   /**
    * The operation handle for transport handle
    */
-  struct GNUNET_TESTBED_Operation *transport_op_;
+  struct GNUNET_TESTBED_Operation *transport_op;
 
   /**
    * The core handle to the peer corresponding to this entry; can be NULL
@@ -229,6 +236,12 @@ struct CacheEntry
    */
   GNUNET_SCHEDULER_TaskIdentifier notify_task;
 
+  /**
+   * The task to expire this cache entry, free any handlers it has opened and
+   * mark their corresponding operations as done.
+   */
+  GNUNET_SCHEDULER_TaskIdentifier expire_task;
+
   /**
    * Number of operations this cache entry is being used
    */
@@ -238,6 +251,11 @@ struct CacheEntry
    * The id of the peer this entry corresponds to
    */
   unsigned int peer_id;
+
+  /**
+   * Is this entry in LRU cache queue?
+   */
+  unsigned int in_lru;
 };
 
 
@@ -307,32 +325,40 @@ static void
 close_handles (struct CacheEntry *entry)
 {
   struct ConnectNotifyContext *ctxt;
-  
+
   GNUNET_assert (0 == entry->demand);
-  if ((NULL != entry->next) || (NULL != entry->prev))
+  if (GNUNET_YES == entry->in_lru)
   {
     GNUNET_assert (0 < lru_cache_size);
+    if (GNUNET_SCHEDULER_NO_TASK != entry->expire_task)
+    {
+      GNUNET_SCHEDULER_cancel (entry->expire_task);
+      entry->expire_task = GNUNET_SCHEDULER_NO_TASK;
+    }
     GNUNET_CONTAINER_DLL_remove (lru_cache_head, lru_cache_tail, entry);
     lru_cache_size--;
+    entry->in_lru = GNUNET_NO;
   }
+  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == entry->expire_task);
   while (NULL != (ctxt = entry->nctxt_qhead))
   {
     GNUNET_CONTAINER_DLL_remove (entry->nctxt_qhead, entry->nctxt_qtail, ctxt);
     GNUNET_free (ctxt);
   }
   LOG_DEBUG ("Cleaning up handles from an entry in cache\n");
-  if (NULL != entry->transport_handle_)
+  if (NULL != entry->transport_handle)
+    GNUNET_assert (NULL != entry->transport_op);
+  if (NULL != entry->transport_op)
   {
-    GNUNET_assert (NULL != entry->transport_op_);
-    GNUNET_TESTBED_operation_done (entry->transport_op_);
-    entry->transport_op_ = NULL;
+    GNUNET_TESTBED_operation_done (entry->transport_op);
+    entry->transport_op = NULL;    
   }
-  if (NULL != entry->core_handle)
+  if (NULL != entry->core_op)
   {
-    GNUNET_assert (NULL != entry->core_op);
     GNUNET_TESTBED_operation_done (entry->core_op);
     entry->core_op = NULL;
   }
+  GNUNET_assert (NULL == entry->core_handle);
   if (NULL != entry->cfg)
   {
     GNUNET_CONFIGURATION_destroy (entry->cfg);
@@ -341,6 +367,24 @@ close_handles (struct CacheEntry *entry)
 }
 
 
+/**
+ * The task to expire this cache entry, free any handlers it has opened and
+ * mark their corresponding operations as done.
+ *
+ * @param cls the CacheEntry
+ * @param tc the scheduler task context
+ */
+static void
+expire_cache_entry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct CacheEntry *entry = cls;
+
+  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != entry->expire_task);
+  entry->expire_task = GNUNET_SCHEDULER_NO_TASK;
+  close_handles (entry);
+}
+
+
 /**
  * Creates a new cache entry and then puts it into the cache's hashtable.
  *
@@ -357,8 +401,7 @@ add_entry (const struct GNUNET_HashCode *key, unsigned int peer_id)
   entry->peer_id = peer_id;
   memcpy (&entry->key, key, sizeof (struct GNUNET_HashCode));
   GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONTAINER_multihashmap_put (cache, &entry->key,
-                                                    entry,
+                 GNUNET_CONTAINER_multihashmap_put (cache, &entry->key, entry,
                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
   cache_size++;
   return entry;
@@ -382,14 +425,14 @@ search_suitable_cgh (const struct CacheEntry *entry,
 {
   const struct GSTCacheGetHandle *cgh;
 
-  for (cgh=head; NULL != cgh; cgh=cgh->next)
+  for (cgh = head; NULL != cgh; cgh = cgh->next)
   {
     if (GNUNET_YES == cgh->notify_called)
       return NULL;
     switch (cgh->type)
     {
     case CGT_TRANSPORT_HANDLE:
-      if (NULL == entry->transport_handle_)
+      if (NULL == entry->transport_handle)
         continue;
       break;
     case CGT_CORE_HANDLE:
@@ -398,7 +441,7 @@ search_suitable_cgh (const struct CacheEntry *entry,
       break;
     }
     break;
-  }  
+  }
   return (struct GSTCacheGetHandle *) cgh;
 }
 
@@ -416,7 +459,7 @@ call_cgh_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct CacheEntry *entry = cls;
   struct GSTCacheGetHandle *cgh;
   const struct GSTCacheGetHandle *cgh2;
-  
+
   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != entry->notify_task);
   entry->notify_task = GNUNET_SCHEDULER_NO_TASK;
   cgh = search_suitable_cgh (entry, entry->cgh_qhead);
@@ -430,13 +473,13 @@ call_cgh_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   if (NULL != cgh2)
     entry->notify_task = GNUNET_SCHEDULER_add_now (&call_cgh_cb, entry);
   if (NULL != cgh->nctxt)
-  {/* Register the peer connect notify callback */
+  {                             /* Register the peer connect notify callback */
     GNUNET_CONTAINER_DLL_insert_tail (entry->nctxt_qhead, entry->nctxt_qtail,
                                       cgh->nctxt);
   }
   LOG_DEBUG ("Calling notify for handle type %u\n", cgh->type);
-  cgh->cb (cgh->cb_cls, entry->core_handle, 
-           entry->transport_handle_, entry->peer_identity);
+  cgh->cb (cgh->cb_cls, entry->core_handle, entry->transport_handle,
+           entry->peer_identity);
 }
 
 
@@ -449,9 +492,8 @@ call_cgh_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * @param peer the peer that connected
  * @param type the type of the handle this notification corresponds to
  */
-static void 
-peer_connect_notify_cb (void *cls,
-                        const struct GNUNET_PeerIdentity *peer,
+static void
+peer_connect_notify_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
                         const enum CacheGetType type)
 {
   struct CacheEntry *entry = cls;
@@ -460,8 +502,8 @@ peer_connect_notify_cb (void *cls,
   GST_cache_peer_connect_notify cb;
   void *cb_cls;
 
-  
-  for (ctxt=entry->nctxt_qhead; NULL != ctxt;)
+
+  for (ctxt = entry->nctxt_qhead; NULL != ctxt;)
   {
     GNUNET_assert (NULL != ctxt->cgh);
     if (type != ctxt->cgh->type)
@@ -481,11 +523,11 @@ peer_connect_notify_cb (void *cls,
     GNUNET_CONTAINER_DLL_remove (entry->nctxt_qhead, entry->nctxt_qtail, ctxt);
     GNUNET_free (ctxt);
     ctxt = ctxt2;
-    cb (cb_cls, peer);  
+    cb (cb_cls, peer);
   }
   if (NULL == ctxt)
     return;
-  
+
 }
 
 
@@ -498,7 +540,7 @@ peer_connect_notify_cb (void *cls,
  * @param ats performance data
  * @param ats_count number of entries in ats (excluding 0-termination)
  */
-static void 
+static void
 transport_peer_connect_notify_cb (void *cls,
                                   const struct GNUNET_PeerIdentity *peer,
                                   const struct GNUNET_ATS_Information *ats,
@@ -521,12 +563,10 @@ opstart_get_handle_transport (void *cls)
 
   GNUNET_assert (NULL != entry);
   LOG_DEBUG ("Opening a transport connection to peer %u\n", entry->peer_id);
-  entry->transport_handle_ = 
-      GNUNET_TRANSPORT_connect (entry->cfg,
-                                NULL, entry,
-                                NULL,
+  entry->transport_handle =
+      GNUNET_TRANSPORT_connect (entry->cfg, NULL, entry, NULL,
                                 &transport_peer_connect_notify_cb, NULL);
-  if (NULL == entry->transport_handle_)
+  if (NULL == entry->transport_handle)
   {
     GNUNET_break (0);
     return;
@@ -550,11 +590,11 @@ static void
 oprelease_get_handle_transport (void *cls)
 {
   struct CacheEntry *entry = cls;
-  
-  if (NULL == entry->transport_handle_)
+
+  if (NULL == entry->transport_handle)
     return;
-  GNUNET_TRANSPORT_disconnect (entry->transport_handle_);
-  entry->transport_handle_ = NULL;
+  GNUNET_TRANSPORT_disconnect (entry->transport_handle);
+  entry->transport_handle = NULL;
 }
 
 
@@ -571,9 +611,8 @@ oprelease_get_handle_transport (void *cls)
  * @param server handle to the server, NULL if we failed
  * @param my_identity ID of this peer, NULL if we failed
  */
-static void 
-core_startup_cb (void *cls,
-                 struct GNUNET_CORE_Handle * server,
+static void
+core_startup_cb (void *cls, struct GNUNET_CORE_Handle *server,
                  const struct GNUNET_PeerIdentity *my_identity)
 {
   struct CacheEntry *entry = cls;
@@ -589,7 +628,7 @@ core_startup_cb (void *cls,
   memcpy (entry->peer_identity, my_identity,
           sizeof (struct GNUNET_PeerIdentity));
   if (0 == entry->demand)
-    return;  
+    return;
   if (GNUNET_SCHEDULER_NO_TASK != entry->notify_task)
     return;
   if (NULL != search_suitable_cgh (entry, entry->cgh_qhead))
@@ -605,12 +644,11 @@ core_startup_cb (void *cls,
  * @param atsi performance data for the connection
  * @param atsi_count number of records in 'atsi'
  */
-static void 
-core_peer_connect_cb (void *cls,
-                      const struct GNUNET_PeerIdentity * peer,
-                      const struct GNUNET_ATS_Information * atsi,
+static void
+core_peer_connect_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
+                      const struct GNUNET_ATS_Information *atsi,
                       unsigned int atsi_count)
-{  
+{
   peer_connect_notify_cb (cls, peer, CGT_CORE_HANDLE);
 }
 
@@ -625,24 +663,23 @@ static void
 opstart_get_handle_core (void *cls)
 {
   struct CacheEntry *entry = cls;
+
   const struct GNUNET_CORE_MessageHandler no_handlers[] = {
     {NULL, 0, 0}
   };
 
   GNUNET_assert (NULL != entry);
   LOG_DEBUG ("Opening a CORE connection to peer %u\n", entry->peer_id);
-  /* void?: We also get the handle when the connection to CORE is successful */
-  (void) GNUNET_CORE_connect (entry->cfg,
-                              entry,
-                              &core_startup_cb,
-                              &core_peer_connect_cb,
-                              NULL, /* disconnect cb */
-                              NULL, /* inbound notify */
-                              GNUNET_NO,
-                              NULL, /* outbound notify */
-                              GNUNET_NO,
-                              no_handlers);
-  //GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == entry->notify_task);
+  entry->core_handle =
+      GNUNET_CORE_connect (entry->cfg, entry,        /* closure */
+                           &core_startup_cb, /* core startup notify */
+                           &core_peer_connect_cb,    /* peer connect notify */
+                           NULL,     /* peer disconnect notify */
+                           NULL,     /* inbound notify */
+                           GNUNET_NO,        /* inbound header only? */
+                           NULL,     /* outbound notify */
+                           GNUNET_NO,        /* outbound header only? */
+                           no_handlers);
 }
 
 
@@ -656,7 +693,7 @@ static void
 oprelease_get_handle_core (void *cls)
 {
   struct CacheEntry *entry = cls;
-  
+
   if (NULL == entry->core_handle)
     return;
   GNUNET_CORE_disconnect (entry->core_handle);
@@ -676,8 +713,7 @@ oprelease_get_handle_core (void *cls)
  * @param cls the cache entry
  */
 static struct GSTCacheGetHandle *
-cache_get_handle (unsigned int peer_id,
-                  struct GSTCacheGetHandle *cgh,
+cache_get_handle (unsigned int peer_id, struct GSTCacheGetHandle *cgh,
                   const struct GNUNET_CONFIGURATION_Handle *cfg,
                   const struct GNUNET_PeerIdentity *target,
                   GST_cache_peer_connect_notify connect_notify_cb,
@@ -695,18 +731,26 @@ cache_get_handle (unsigned int peer_id,
   entry = cache_lookup (&key);
   if (NULL != entry)
   {
-    if (0 == entry->demand)
+    if (GNUNET_YES == entry->in_lru)
     {
+      GNUNET_assert (0 == entry->demand);
       GNUNET_assert (0 < lru_cache_size);
+      if (GNUNET_SCHEDULER_NO_TASK != entry->expire_task)
+      {
+        GNUNET_SCHEDULER_cancel (entry->expire_task);
+        entry->expire_task = GNUNET_SCHEDULER_NO_TASK;
+      }
       GNUNET_CONTAINER_DLL_remove (lru_cache_head, lru_cache_tail, entry);
       lru_cache_size--;
+      entry->in_lru = GNUNET_NO;
     }
     switch (cgh->type)
     {
     case CGT_TRANSPORT_HANDLE:
-      handle = entry->transport_handle_;
+      handle = entry->transport_handle;
       if (NULL != handle)
-        LOG_DEBUG ("Found TRANSPORT handle in cache for peer %u\n", entry->peer_id);
+        LOG_DEBUG ("Found TRANSPORT handle in cache for peer %u\n",
+                   entry->peer_id);
       break;
     case CGT_CORE_HANDLE:
       handle = entry->core_handle;
@@ -741,11 +785,11 @@ cache_get_handle (unsigned int peer_id,
   switch (cgh->type)
   {
   case CGT_TRANSPORT_HANDLE:
-    if (NULL != entry->transport_op_)
+    if (NULL != entry->transport_op)
       return cgh;
     op = GNUNET_TESTBED_operation_create_ (entry, &opstart_get_handle_transport,
                                            &oprelease_get_handle_transport);
-    entry->transport_op_ = op;
+    entry->transport_op = op;
     break;
   case CGT_CORE_HANDLE:
     if (NULL != entry->core_op)
@@ -772,9 +816,7 @@ cache_get_handle (unsigned int peer_id,
  *         GNUNET_NO if not.
  */
 static int
-cache_clear_iterator (void *cls,
-                      const struct GNUNET_HashCode * key,
-                      void *value)
+cache_clear_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
 {
   struct CacheEntry *entry = value;
   static unsigned int ncleared;
@@ -783,14 +825,14 @@ cache_clear_iterator (void *cls,
   GNUNET_break (0 == entry->demand);
   LOG_DEBUG ("Clearing entry %u of %u\n", ++ncleared, cache_size);
   GNUNET_CONTAINER_multihashmap_remove (cache, key, value);
-  if (0 == entry->demand)
-    close_handles (entry);
+  close_handles (entry);
   GNUNET_free_non_null (entry->hello);
-  GNUNET_break (NULL == entry->transport_handle_);
-  GNUNET_break (NULL == entry->transport_op_);
-  GNUNET_break (NULL == entry->core_handle);
-  GNUNET_break (NULL == entry->core_op);
-  GNUNET_break (NULL == entry->cfg);
+  GNUNET_break (GNUNET_SCHEDULER_NO_TASK == entry->expire_task);
+  GNUNET_assert (NULL == entry->transport_handle);
+  GNUNET_assert (NULL == entry->transport_op);
+  GNUNET_assert (NULL == entry->core_handle);
+  GNUNET_assert (NULL == entry->core_op);
+  GNUNET_assert (NULL == entry->cfg);
   GNUNET_assert (NULL == entry->cgh_qhead);
   GNUNET_assert (NULL == entry->cgh_qtail);
   GNUNET_assert (NULL == entry->nctxt_qhead);
@@ -854,14 +896,18 @@ GST_cache_get_handle_done (struct GSTCacheGetHandle *cgh)
   {
     GNUNET_assert (cgh == cgh->nctxt->cgh);
     if (GNUNET_YES == cgh->notify_called)
-      GNUNET_CONTAINER_DLL_remove (entry->nctxt_qhead, entry->nctxt_qtail, cgh->nctxt);
+      GNUNET_CONTAINER_DLL_remove (entry->nctxt_qhead, entry->nctxt_qtail,
+                                   cgh->nctxt);
     GNUNET_free (cgh->nctxt);
   }
-  GNUNET_free (cgh);  
+  GNUNET_free (cgh);
   if (0 == entry->demand)
   {
+    entry->expire_task =
+        GNUNET_SCHEDULER_add_delayed (CACHE_EXPIRY, &expire_cache_entry, entry);
     GNUNET_CONTAINER_DLL_insert_tail (lru_cache_head, lru_cache_tail, entry);
     lru_cache_size++;
+    entry->in_lru = GNUNET_YES;
     if (lru_cache_size > lru_cache_threshold_size)
       close_handles (lru_cache_head);
   }
@@ -898,8 +944,7 @@ GST_cache_get_handle_done (struct GSTCacheGetHandle *cgh)
 struct GSTCacheGetHandle *
 GST_cache_get_handle_transport (unsigned int peer_id,
                                 const struct GNUNET_CONFIGURATION_Handle *cfg,
-                                GST_cache_handle_ready_cb cb,
-                                void *cb_cls,
+                                GST_cache_handle_ready_cb cb, void *cb_cls,
                                 const struct GNUNET_PeerIdentity *target,
                                 GST_cache_peer_connect_notify connect_notify_cb,
                                 void *connect_notify_cb_cls)
@@ -910,8 +955,8 @@ GST_cache_get_handle_transport (unsigned int peer_id,
   cgh->cb = cb;
   cgh->cb_cls = cb_cls;
   cgh->type = CGT_TRANSPORT_HANDLE;
-  return cache_get_handle (peer_id, cgh, cfg,
-                           target, connect_notify_cb, connect_notify_cb_cls);
+  return cache_get_handle (peer_id, cgh, cfg, target, connect_notify_cb,
+                           connect_notify_cb_cls);
 }
 
 
@@ -939,8 +984,7 @@ GST_cache_get_handle_transport (unsigned int peer_id,
 struct GSTCacheGetHandle *
 GST_cache_get_handle_core (unsigned int peer_id,
                            const struct GNUNET_CONFIGURATION_Handle *cfg,
-                           GST_cache_handle_ready_cb cb,
-                           void *cb_cls,
+                           GST_cache_handle_ready_cb cb, void *cb_cls,
                            const struct GNUNET_PeerIdentity *target,
                            GST_cache_peer_connect_notify connect_notify_cb,
                            void *connect_notify_cb_cls)
@@ -951,8 +995,8 @@ GST_cache_get_handle_core (unsigned int peer_id,
   cgh->cb = cb;
   cgh->cb_cls = cb_cls;
   cgh->type = CGT_CORE_HANDLE;
-  return cache_get_handle (peer_id, cgh, cfg,
-                           target, connect_notify_cb, connect_notify_cb_cls);
+  return cache_get_handle (peer_id, cgh, cfg, target, connect_notify_cb,
+                           connect_notify_cb_cls);
 }
 
 
@@ -967,7 +1011,7 @@ GST_cache_lookup_hello (const unsigned int peer_id)
 {
   struct CacheEntry *entry;
   struct GNUNET_HashCode key;
-  
+
   LOG_DEBUG ("Looking up HELLO for peer %u\n", peer_id);
   GNUNET_CRYPTO_hash (&peer_id, sizeof (peer_id), &key);
   entry = cache_lookup (&key);