peerstore: record expiry
authorOmar Tarabai <tarabai@devegypt.com>
Mon, 19 May 2014 12:07:15 +0000 (12:07 +0000)
committerOmar Tarabai <tarabai@devegypt.com>
Mon, 19 May 2014 12:07:15 +0000 (12:07 +0000)
src/include/gnunet_peerstore_plugin.h
src/peerstore/gnunet-service-peerstore.c
src/peerstore/plugin_peerstore_sqlite.c
src/peerstore/test_peerstore_api.c

index e9563b5089cd561fd8570334e2186b808bc1e943..18b3f690dda0a928e81bdaf70bd59fd86399a7bd 100644 (file)
@@ -89,6 +89,17 @@ struct GNUNET_PEERSTORE_PluginFunctions
       const char *key,
       GNUNET_PEERSTORE_Processor iter, void *iter_cls);
 
+  /**
+   * Delete expired records (expiry < now)
+   *
+   * @param cls closure (internal context for the plugin)
+   * @param now time to use as reference
+   * @return number of records deleted
+   */
+  int
+  (*expire_records) (void *cls,
+      struct GNUNET_TIME_Absolute now);
+
 };
 
 
index ea6268bf126f1555f1d4973aec9ae1e22e27c56e..b7827692242733db2641eb1d30ffcfe459fe6131 100644 (file)
 #include "peerstore_common.h"
 
 //TODO: GNUNET_SERVER_receive_done() ?
-//TODO: implement value lifetime
+
+/**
+ * Interval for expired records cleanup (in seconds)
+ */
+#define CLEANUP_INTERVAL 300 /* 5mins */
 
 /**
  * Our configuration.
@@ -65,6 +69,23 @@ shutdown_task (void *cls,
   }
 }
 
+/**
+ * Deletes any expired records from storage
+ */
+static void
+cleanup_expired_records(void *cls,
+    const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  int deleted;
+
+  GNUNET_assert(NULL != db);
+  deleted = db->expire_records(db->cls, GNUNET_TIME_absolute_get());
+  GNUNET_log(GNUNET_ERROR_TYPE_INFO, "%d records expired.\n", deleted);
+  GNUNET_SCHEDULER_add_delayed(
+      GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, CLEANUP_INTERVAL),
+      &cleanup_expired_records, NULL);
+}
+
 
 /**
  * A client disconnected.  Remove all of its data structure entries.
@@ -245,6 +266,7 @@ run (void *cls,
          GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not load database backend `%s'\n", db_lib_name);
   else
   {
+    cleanup_expired_records(NULL, NULL);
     GNUNET_SERVER_add_handlers (server, handlers);
     GNUNET_SERVER_disconnect_notify (server,
              &handle_client_disconnect,
index 9d044aa0773fe2d55f5d8da28116461f85ee109c..ead2aade6bd450e30d4e1573f1098c803fa77e8e 100644 (file)
@@ -97,8 +97,51 @@ struct Plugin
    */
   sqlite3_stmt *select_peerstoredata_by_all;
 
+  /**
+   * Precompiled SQL for selecting from peerstoredata
+   */
+  sqlite3_stmt *select_peerstoredata_by_all_and_value;
+
+  /**
+   * Precompiled SQL for deleting expired records from peerstoredata
+   */
+  sqlite3_stmt *expire_peerstoredata;
+
 };
 
+/**
+ * Delete expired records (expiry < now)
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param now time to use as reference
+ * @return number of records deleted
+ */
+static int
+peerstore_sqlite_expire_records(void *cls,
+    struct GNUNET_TIME_Absolute now)
+{
+  struct Plugin *plugin = cls;
+  sqlite3_stmt *stmt = plugin->expire_peerstoredata;
+
+  if(SQLITE_OK != sqlite3_bind_int64(stmt, 1, (sqlite3_int64)now.abs_value_us))
+  {
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind");
+  }
+  else if (SQLITE_DONE != sqlite3_step (stmt))
+  {
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                "sqlite3_step");
+  }
+  if (SQLITE_OK != sqlite3_reset (stmt))
+  {
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                "sqlite3_reset");
+    return 0;
+  }
+  return sqlite3_changes(plugin->dbh);
+
+}
+
 /**
  * Iterate over the records given an optional peer id
  * and/or key.
@@ -193,6 +236,42 @@ peerstore_sqlite_iterate_records (void *cls,
   return GNUNET_OK;
 }
 
+/**
+ * Checks if a record with the given information
+ * already exists
+ *
+ * @return #GNUNET_YES / #GNUNET_NO
+ *
+static int
+check_existing(void *cls,
+    const char *sub_system,
+    const struct GNUNET_PeerIdentity *peer,
+    const char *key,
+    const void *value,
+    size_t size)
+{
+  struct Plugin *plugin = cls;
+  sqlite3_stmt *stmt = plugin->select_peerstoredata_by_all_and_value;
+  int sret;
+
+  if(SQLITE_OK != sqlite3_bind_text(stmt, 1, sub_system, strlen(sub_system) + 1, SQLITE_STATIC)
+      || SQLITE_OK != sqlite3_bind_blob(stmt, 2, peer, sizeof(struct GNUNET_PeerIdentity), SQLITE_STATIC)
+      || SQLITE_OK != sqlite3_bind_text(stmt, 3, key, strlen(key) + 1, SQLITE_STATIC)
+      || SQLITE_OK != sqlite3_bind_blob(stmt, 4, value, size, SQLITE_STATIC))
+  {
+    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+        "sqlite3_bind");
+    sqlite3_reset(stmt);
+    return GNUNET_NO;
+  }
+  sret = sqlite3_step (stmt);
+  sqlite3_reset(stmt);
+  if(SQLITE_ROW == sret)
+    return GNUNET_YES;
+  return GNUNET_NO;
+
+}*/
+
 /**
  * Store a record in the peerstore.
  * Key is the combination of sub system and peer identity.
@@ -218,6 +297,15 @@ peerstore_sqlite_store_record(void *cls,
   sqlite3_stmt *stmt = plugin->insert_peerstoredata;
 
   //FIXME: check if value exists with the same key first
+  /*if(GNUNET_YES == check_existing(cls,
+      sub_system,
+      peer,
+      key,
+      value,
+      size))
+  {
+
+  }*/
 
   if(SQLITE_OK != sqlite3_bind_text(stmt, 1, sub_system, strlen(sub_system) + 1, SQLITE_STATIC)
       || SQLITE_OK != sqlite3_bind_blob(stmt, 2, peer, sizeof(struct GNUNET_PeerIdentity), SQLITE_STATIC)
@@ -377,6 +465,17 @@ database_setup (struct Plugin *plugin)
       " AND peer_id = ?"
       " AND key = ?",
       &plugin->select_peerstoredata_by_all);
+  sql_prepare(plugin->dbh,
+      "SELECT * FROM peerstoredata"
+      " WHERE sub_system = ?"
+      " AND peer_id = ?"
+      " AND key = ?"
+      " AND value = ?",
+      &plugin->select_peerstoredata_by_all_and_value);
+  sql_prepare(plugin->dbh,
+      "DELETE FROM peerstoredata"
+      " WHERE expiry < ?",
+      &plugin->expire_peerstoredata);
 
   return GNUNET_OK;
 }
@@ -430,6 +529,7 @@ libgnunet_plugin_peerstore_sqlite_init (void *cls)
   api->cls = &plugin;
   api->store_record = &peerstore_sqlite_store_record;
   api->iterate_records = &peerstore_sqlite_iterate_records;
+  api->expire_records = &peerstore_sqlite_expire_records;
   LOG(GNUNET_ERROR_TYPE_DEBUG, "Sqlite plugin is running\n");
   return api;
 }
index 71dbd64ba840b5a2949b23742426751e88516215..e3585d31a2135fe5d18898585e259bddec1c7c60 100644 (file)
@@ -84,9 +84,11 @@ run (void *cls,
   struct GNUNET_PeerIdentity pid;
   char *val = "peerstore-test-value";
   size_t val_size = strlen(val);
+  struct GNUNET_TIME_Absolute expiry;
 
   ok = 0;
   memset (&pid, 32, sizeof (pid));
+  expiry = GNUNET_TIME_absolute_get();
   h = GNUNET_PEERSTORE_connect(cfg);
   GNUNET_assert(NULL != h);
   GNUNET_PEERSTORE_store(h,
@@ -95,7 +97,7 @@ run (void *cls,
       "peerstore-test-key",
       val,
       val_size,
-      GNUNET_TIME_UNIT_FOREVER_ABS,
+      expiry,
       &store_cont,
       NULL);