* @see http://gnunet.org/encoding
* @author Krista Bennett
* @author Christian Grothoff
- *
- * TODO:
- * - indexing cleanup: unindex on failure (can wait)
- * - datastore reservation support (optimization)
- * - location URIs (publish with anonymity-level zero)
*/
#include "platform.h"
{
struct GNUNET_FS_PublishContext *pc = cls;
+ if (pc->fhc != NULL)
+ {
+ GNUNET_CRYPTO_hash_file_cancel (pc->fhc);
+ pc->fhc = NULL;
+ }
GNUNET_FS_file_information_destroy (pc->fi, NULL, NULL);
if (pc->namespace != NULL)
GNUNET_FS_namespace_delete (pc->namespace, GNUNET_NO);
if (GNUNET_OK != success)
{
GNUNET_asprintf (&pcc->p->emsg,
- _("Upload failed: %s"),
+ _("Publishing failed: %s"),
msg);
pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
pi.value.publish.specifics.error.message = pcc->p->emsg;
pcc->p->client_info = GNUNET_FS_publish_make_status_ (&pi, pcc->sc, pcc->p, 0);
+ if ( (pcc->p->is_directory == GNUNET_NO) &&
+ (pcc->p->filename != NULL) &&
+ (pcc->p->data.file.do_index == GNUNET_YES) )
+ {
+ /* run unindex to clean up */
+ GNUNET_FS_unindex_start (pcc->sc->h,
+ pcc->p->filename,
+ NULL);
+ }
}
if (NULL != pcc->cont)
pcc->sc->upload_task
pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
pi.value.publish.specifics.error.message =emsg;
p->client_info = GNUNET_FS_publish_make_status_ (&pi, sc, p, 0);
+ if ( (p->is_directory == GNUNET_NO) &&
+ (p->filename != NULL) &&
+ (p->data.file.do_index == GNUNET_YES) )
+ {
+ /* run unindex to clean up */
+ GNUNET_FS_unindex_start (sc->h,
+ p->filename,
+ NULL);
+ }
+
+}
+
+
+/**
+ * Datastore returns from reservation cancel request.
+ *
+ * @param cls the 'struct GNUNET_FS_PublishContext'
+ * @param success success code (not used)
+ * @param msg error message (typically NULL, not used)
+ */
+static void
+finish_release_reserve (void *cls,
+ int success,
+ const char *msg)
+{
+ struct GNUNET_FS_PublishContext *pc = cls;
+
+ pc->qre = NULL;
+ signal_publish_completion (pc->fi, pc);
+ pc->all_done = GNUNET_YES;
+ GNUNET_FS_publish_sync_ (pc);
}
GNUNET_FS_publish_sync_ (pc);
return;
}
- // FIXME: release the datastore reserve here!
- signal_publish_completion (pc->fi, pc);
- pc->all_done = GNUNET_YES;
- GNUNET_FS_publish_sync_ (pc);
+ GNUNET_assert (pc->qre == NULL);
+ if ( (pc->dsh != NULL) &&
+ (pc->rid != 0) )
+ {
+ pc->qre = GNUNET_DATASTORE_release_reserve (pc->dsh,
+ pc->rid,
+ UINT_MAX,
+ UINT_MAX,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &finish_release_reserve,
+ pc);
+ }
+ else
+ {
+ finish_release_reserve (pc, GNUNET_OK, NULL);
+ }
}
emsg);
#endif
GNUNET_asprintf (&p->emsg,
- _("Upload failed: %s"),
+ _("Publishing failed: %s"),
emsg);
GNUNET_free (emsg);
pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Finished with tree encoder\n");
#endif
+ /* final progress event */
+ pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS;
+ pi.value.publish.specifics.progress.data = NULL;
+ pi.value.publish.specifics.progress.offset = GNUNET_FS_uri_chk_get_file_size (p->chk_uri);
+ pi.value.publish.specifics.progress.data_len = 0;
+ pi.value.publish.specifics.progress.depth = 0;
+ p->client_info = GNUNET_FS_publish_make_status_ (&pi, sc, p,
+ GNUNET_FS_uri_chk_get_file_size (p->chk_uri));
+
/* continue with main */
sc->upload_task
= GNUNET_SCHEDULER_add_with_priority (sc->h->sched,
odb.offset = GNUNET_htonll (offset);
odb.file_id = p->data.file.file_id;
GNUNET_DATASTORE_put (sc->dsh,
- sc->rid,
+ (p->is_directory) ? 0 : sc->rid,
query,
sizeof(struct OnDemandBlock),
&odb,
(unsigned int) block_size);
#endif
GNUNET_DATASTORE_put (sc->dsh,
- sc->rid,
+ (p->is_directory) ? 0 : sc->rid,
query,
block_size,
block,
uint64_t ino;
char *fn;
+ sc->fhc = NULL;
p = sc->fi_pos;
if (NULL == res)
{
struct GNUNET_FS_PublishContext *pc = cls;
struct GNUNET_FS_ProgressInfo pi;
struct GNUNET_FS_FileInformation *p;
+ struct GNUNET_FS_Uri *loc;
char *fn;
pc->upload_task = GNUNET_SCHEDULER_NO_TASK;
{
#if DEBUG_PUBLISH
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Upload complete, now publishing SKS and KSK blocks.\n");
+ "Publishing complete, now publishing SKS and KSK blocks.\n");
#endif
/* upload of entire hierarchy complete,
publish namespace entries */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"File upload complete, now publishing KSK blocks.\n");
#endif
+ if (0 == p->anonymity)
+ {
+ /* zero anonymity, box CHK URI in LOC URI */
+ loc = GNUNET_FS_uri_loc_create (p->chk_uri,
+ pc->h->cfg,
+ p->expirationTime);
+ GNUNET_FS_uri_destroy (p->chk_uri);
+ p->chk_uri = loc;
+ }
GNUNET_FS_publish_sync_ (pc);
/* upload of "p" complete, publish KBlocks! */
if (p->keywords != NULL)
else
{
p->start_time = GNUNET_TIME_absolute_get ();
- GNUNET_CRYPTO_hash_file (pc->h->sched,
- GNUNET_SCHEDULER_PRIORITY_IDLE,
- p->filename,
- HASHING_BLOCKSIZE,
- &hash_for_index_cb,
- pc);
+ pc->fhc = GNUNET_CRYPTO_hash_file (pc->h->sched,
+ GNUNET_SCHEDULER_PRIORITY_IDLE,
+ p->filename,
+ HASHING_BLOCKSIZE,
+ &hash_for_index_cb,
+ pc);
}
return;
}
{
struct GNUNET_FS_PublishContext *sc = cls;
struct GNUNET_FS_ProgressInfo pi;
+ unsigned int kc;
+ uint64_t left;
+ if (*do_index)
+ {
+ /* space for on-demand blocks */
+ sc->reserve_space += ((length + DBLOCK_SIZE - 1) / DBLOCK_SIZE) * sizeof (struct OnDemandBlock);
+ }
+ else
+ {
+ /* space for DBlocks */
+ sc->reserve_space += length;
+ }
+ /* entries for IBlocks and DBlocks, space for IBlocks */
+ left = length;
+ while (1)
+ {
+ left = (left + DBLOCK_SIZE - 1) / DBLOCK_SIZE;
+ sc->reserve_entries += left;
+ if (left <= 1)
+ break;
+ left = left * sizeof (struct ContentHashKey);
+ sc->reserve_space += left;
+ }
+ sc->reserve_entries++;
+ /* entries and space for keywords */
+ if (NULL != *uri)
+ {
+ kc = GNUNET_FS_uri_ksk_get_keyword_count (*uri);
+ sc->reserve_entries += kc;
+ sc->reserve_space += GNUNET_SERVER_MAX_MESSAGE_SIZE * kc;
+ }
pi.status = GNUNET_FS_STATUS_PUBLISH_START;
*client_info = GNUNET_FS_publish_make_status_ (&pi, sc, fi, 0);
GNUNET_FS_file_information_sync_ (fi);
}
+/**
+ * We have gotten a reply for our space reservation request.
+ * Either fail (insufficient space) or start publishing for good.
+ *
+ * @param cls the 'struct GNUNET_FS_PublishContext*'
+ * @param success positive reservation ID on success
+ * @param msg error message on error, otherwise NULL
+ */
+static void
+finish_reserve (void *cls,
+ int success,
+ const char *msg)
+{
+ struct GNUNET_FS_PublishContext *pc = cls;
+
+ pc->qre = NULL;
+ if ( (msg != NULL) ||
+ (success <= 0) )
+ {
+ GNUNET_asprintf (&pc->fi->emsg,
+ _("Insufficient space for publishing: %s"),
+ msg);
+ signal_publish_error (pc->fi,
+ pc,
+ pc->fi->emsg);
+ return;
+ }
+ pc->rid = success;
+ pc->upload_task
+ = GNUNET_SCHEDULER_add_with_priority (pc->h->sched,
+ GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
+ &GNUNET_FS_publish_main_,
+ pc);
+}
+
+
/**
* Publish a file or directory.
*
struct GNUNET_FS_PublishContext *ret;
struct GNUNET_DATASTORE_Handle *dsh;
+ GNUNET_assert (NULL != h);
if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
{
dsh = GNUNET_DATASTORE_connect (h->cfg,
ret->fi_pos = ret->fi;
ret->top = GNUNET_FS_make_top (h, &GNUNET_FS_publish_signal_suspend_, ret);
GNUNET_FS_publish_sync_ (ret);
- // FIXME: calculate space needed for "fi"
- // and reserve as first task (then trigger
- // "publish_main" from that continuation)!
- ret->upload_task
- = GNUNET_SCHEDULER_add_with_priority (h->sched,
- GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
- &GNUNET_FS_publish_main_,
- ret);
+ if (NULL != ret->dsh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Reserving space for %u entries and %llu bytes for publication\n"),
+ (unsigned int) ret->reserve_entries,
+ (unsigned long long) ret->reserve_space);
+ ret->qre = GNUNET_DATASTORE_reserve (ret->dsh,
+ ret->reserve_space,
+ ret->reserve_entries,
+ UINT_MAX,
+ UINT_MAX,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &finish_reserve,
+ ret);
+ }
+ else
+ {
+ ret->upload_task
+ = GNUNET_SCHEDULER_add_with_priority (h->sched,
+ GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
+ &GNUNET_FS_publish_main_,
+ ret);
+ }
return ret;
}
GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *pc)
{
GNUNET_FS_end_top (pc->h, pc->top);
+ if (NULL != pc->qre)
+ {
+ GNUNET_DATASTORE_cancel (pc->qre);
+ pc->qre = NULL;
+ }
if (NULL != pc->dsh)
{
GNUNET_DATASTORE_disconnect (pc->dsh, GNUNET_NO);