+/**
+ * Context for a PUT request used to see if the content is
+ * already present.
+ */
+struct PutContext
+{
+ /**
+ * Client to notify on completion.
+ */
+ struct GNUNET_SERVER_Client *client;
+
+#if ! HAVE_UNALIGNED_64_ACCESS
+ void *reserved;
+#endif
+
+ /* followed by the 'struct DataMessage' */
+};
+
+
+/**
+ * Actually put the data message.
+ *
+ * @param client sender of the message
+ * @param dm message with the data to store
+ */
+static void
+execute_put (struct GNUNET_SERVER_Client *client, const struct DataMessage *dm)
+{
+ uint32_t size;
+ char *msg;
+ int ret;
+
+ size = ntohl (dm->size);
+ msg = NULL;
+ ret =
+ plugin->api->put (plugin->api->cls, &dm->key, size, &dm[1],
+ ntohl (dm->type), ntohl (dm->priority),
+ ntohl (dm->anonymity), ntohl (dm->replication),
+ GNUNET_TIME_absolute_ntoh (dm->expiration), &msg);
+ if (GNUNET_OK == ret)
+ {
+ GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes stored"), size,
+ GNUNET_YES);
+ GNUNET_CONTAINER_bloomfilter_add (filter, &dm->key);
+#if DEBUG_DATASTORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Successfully stored %u bytes of type %u under key `%s'\n",
+ size, ntohl (dm->type), GNUNET_h2s (&dm->key));
+#endif
+ }
+ transmit_status (client, ret, msg);
+ GNUNET_free_non_null (msg);
+ if (quota - reserved - cache_size < payload)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Need %llu bytes more space (%llu allowed, using %llu)\n"),
+ (unsigned long long) size + GNUNET_DATASTORE_ENTRY_OVERHEAD,
+ (unsigned long long) (quota - reserved - cache_size),
+ (unsigned long long) payload);
+ manage_space (size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
+ }
+}
+
+
+/**
+ * Function that will check if the given datastore entry
+ * matches the put and if none match executes the put.
+ *
+ * @param cls closure, pointer to the client (of type 'struct PutContext').
+ * @param key key for the content
+ * @param size number of bytes in data
+ * @param data content stored
+ * @param type type of the content
+ * @param priority priority of the content
+ * @param anonymity anonymity-level for the content
+ * @param expiration expiration time for the content
+ * @param uid unique identifier for the datum;
+ * maybe 0 if no unique identifier is available
+ *
+ * @return GNUNET_OK usually
+ * GNUNET_NO to delete the item
+ */
+static int
+check_present (void *cls, const GNUNET_HashCode * key, uint32_t size,
+ const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority,
+ uint32_t anonymity, struct GNUNET_TIME_Absolute expiration,
+ uint64_t uid)
+{
+ struct PutContext *pc = cls;
+ const struct DataMessage *dm;
+
+ dm = (const struct DataMessage *) &pc[1];
+ if (key == NULL)
+ {
+ execute_put (pc->client, dm);
+ GNUNET_SERVER_client_drop (pc->client);
+ GNUNET_free (pc);
+ return GNUNET_OK;
+ }
+ if ((GNUNET_BLOCK_TYPE_FS_DBLOCK == type) ||
+ (GNUNET_BLOCK_TYPE_FS_IBLOCK == type) || ((size == ntohl (dm->size)) &&
+ (0 ==
+ memcmp (&dm[1], data, size))))
+ {
+#if DEBUG_MYSQL
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Result already present in datastore\n");
+#endif
+ /* FIXME: change API to allow increasing 'replication' counter */
+ if ((ntohl (dm->priority) > 0) ||
+ (GNUNET_TIME_absolute_ntoh (dm->expiration).abs_value >
+ expiration.abs_value))
+ plugin->api->update (plugin->api->cls, uid,
+ (int32_t) ntohl (dm->priority),
+ GNUNET_TIME_absolute_ntoh (dm->expiration), NULL);
+ transmit_status (pc->client, GNUNET_NO, NULL);
+ GNUNET_SERVER_client_drop (pc->client);
+ GNUNET_free (pc);
+ }
+ else
+ {
+ execute_put (pc->client, dm);
+ GNUNET_SERVER_client_drop (pc->client);
+ GNUNET_free (pc);
+ }
+ return GNUNET_OK;
+}
+
+