예제 #1
0
파일: backends.c 프로젝트: 3Hren/elliptics
/*!
 * Extracts \a elist from \a datap, replaces \a datap pointer and adjusts \a
 * sizep. In case \a free_data is set then data pointed by \a *datap is free'd.
 */
int dnet_ext_list_extract(void **datap, uint64_t *sizep,
		struct dnet_ext_list *elist, enum dnet_ext_free_data free_data)
{
	struct dnet_ext_list_hdr *hdr;	/* Extensions header */
	uint64_t new_size;		/* Size of data without extensions */
	void *new_data;			/* Data without extensions */
	static const size_t hdr_size = sizeof(struct dnet_ext_list_hdr);

	/* Parameter checks */
	if (datap == NULL || *datap == NULL)
		return -EINVAL;
	if (sizep == NULL || elist == NULL)
		return -EINVAL;

	/* Sanity checks */
	if (*sizep < hdr_size)
		return -ERANGE;

	/*
	 * Shortcut
	 *
	 * TODO: For now we account only for header size, but when we add
	 * support additional extensions we should account for hdr_size +
	 * hdr->size
	 */
	new_size = *sizep - hdr_size;
	hdr = (struct dnet_ext_list_hdr *)*datap;

	/* Extract payload from \a datap */
	new_data = (unsigned char *)*datap + hdr_size;
	dnet_ext_hdr_to_list(hdr, elist);

	/*
	 * Currently we do not support any extensions beyond header itself
	 * so assert on any extensions.
	 *
	 * TODO: Extract all extensions
	 */
	if (elist->size != 0)
		return -ENOTSUP;
	if (elist->version <= DNET_EXT_VERSION_FIRST
			|| elist->version >= DNET_EXT_VERSION_LAST)
		return -ENOTSUP;

	/* Save original pointer to data */
	if (free_data == DNET_EXT_FREE_ON_DESTROY)
		elist->data = *datap;

	/* Swap data, adjust size */
	*datap = new_data;
	*sizep = new_size;

	return 0;
}
예제 #2
0
static int leveldb_backend_lookup(struct leveldb_backend *s, void *state, struct dnet_cmd *cmd)
{
	char *data = NULL;
	size_t data_size;
	int err = -EINVAL;
	char *error_string = NULL;
	struct dnet_ext_list elist;
	static const size_t ehdr_size = sizeof(struct dnet_ext_list_hdr);
	struct dnet_ext_list_hdr *ehdr = NULL;

	dnet_ext_list_init(&elist);

	data = leveldb_get(s->db, s->roptions, (const char *)cmd->id.id, DNET_ID_SIZE, &data_size, &error_string);
	if (error_string || !data) {
		if (!data)
			err = -ENOENT;
		goto err_out_exit;
	}

	if (data_size < ehdr_size) {
		err = -ERANGE;
		goto err_out_exit;
	}

	ehdr = (struct dnet_ext_list_hdr *)data;
	dnet_ext_hdr_to_list(ehdr, &elist);

	data_size -= ehdr_size;
	data += ehdr_size;

	err = dnet_send_file_info_ts_without_fd(state, cmd, data, data_size, &elist.timestamp);
	if (err < 0)
		goto err_out_free;

err_out_free:
	free(data);
err_out_exit:
	free(error_string);
	dnet_ext_list_destroy(&elist);
	return err;
}
예제 #3
0
/* Pre-callback that formats arguments and calls ictl->callback */
static int blob_iterate_callback_common(struct eblob_disk_control *dc, int fd, uint64_t data_offset, void *priv, int no_meta) {
	struct dnet_iterator_ctl *ictl = priv;
	struct dnet_ext_list_hdr ehdr;
	struct dnet_ext_list elist;
	struct eblob_backend_config *c = ictl->iterate_private;
	uint64_t size;
	int err;

	assert(dc != NULL);

	size = dc->data_size;
	dnet_ext_list_init(&elist);

	/* If it's an extended record - extract header, move data pointer */
	if (dc->flags & BLOB_DISK_CTL_EXTHDR) {
		/*
		 * Skip reading/extracting header of the committed records if iterator runs with no_meta.
		 * Header of uncommitted records should be read in any cases for correct recovery.
		 */
		if (!no_meta || (dc->flags & BLOB_DISK_CTL_UNCOMMITTED)) {
			err = dnet_ext_hdr_read(&ehdr, fd, data_offset);
			if (!err) {
				dnet_ext_hdr_to_list(&ehdr, &elist);
			} else {
				/* If extended header couldn't be extracted reset elist,
				 * call callback for key with empty elist
				 * and continue iteration because the rest records can be ok.
				 * We need to reset the error to make iteration continue.
				 */
				char buffer[2*DNET_ID_SIZE + 1] = {0};
				dnet_backend_log(c->blog, DNET_LOG_ERROR,
					"blob: iter: %s: dnet_ext_hdr_read failed: %d. Use empty extended header for this key\n",
					dnet_dump_id_len_raw((const unsigned char*)&dc->key, DNET_ID_SIZE, buffer), err);

				err = 0;
			}
		}

		data_offset += sizeof(struct dnet_ext_list_hdr);

		/*
		 * When record has not been committed (no matter whether data has been written or not)
		 * its @data_size is zero and removing ext header size ends up with
		 * negative size converted back to very large positive number (0xffffffffffffffd0).
		 *
		 * It is possible that iterator will catch this key before commit time,
		 * we have to be ready and do not provide invalid size.
		 *
		 * For more details, see blob_write() function below and prepare section comments.
		 *
		 * @data_header is safe, since we have preallocated all needed space for ext header
		 * it just hasn't yet been committed to disk and thus @data_size hasn't yet been updated.
		 */

		if (size >= sizeof(struct dnet_ext_list_hdr)) {
			size -= sizeof(struct dnet_ext_list_hdr);
		}
	}

	err = ictl->callback(ictl->callback_private,
	                     (struct dnet_raw_id *)&dc->key, dc->flags,
	                     fd, data_offset, size, &elist);

	dnet_ext_list_destroy(&elist);
	return err;
}