Example #1
0
static int leveldb_backend_read(struct leveldb_backend *s, void *state, struct dnet_cmd *cmd, void *iodata, int last)
{
	struct dnet_io_attr *io = iodata;
	struct dnet_ext_list elist;
	char *data;
	size_t data_size;
	int err = -EINVAL;
	char *error_string = NULL;

	dnet_ext_list_init(&elist);

	dnet_convert_io_attr(io);
	if (io->size || io->offset) {
		err = -ERANGE;
		goto err_out_exit;
	}

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

	/* Extract original data and extension list from &data */
	err = dnet_ext_list_extract((void *)&data, (uint64_t *)&data_size,
			&elist, DNET_EXT_FREE_ON_DESTROY);
	if (err != 0)
		goto err_out_exit;
	dnet_ext_list_to_io(&elist, io);

	io->size = data_size;
	if (data_size && data && last)
		cmd->flags &= ~DNET_FLAGS_NEED_ACK;
	err = dnet_send_read_data(state, cmd, io, data, -1, io->offset, 0);
	if (err < 0)
		goto err_out_exit;

	dnet_backend_log(DNET_LOG_NOTICE, "%s: leveldb: : READ: Ok: size: %llu.\n",
			dnet_dump_id(&cmd->id), (unsigned long long)io->size);

err_out_exit:
	dnet_ext_list_destroy(&elist);
	if (err < 0)
		dnet_backend_log(DNET_LOG_ERROR, "%s: leveldb: READ: error: %s: %d\n",
			dnet_dump_id(&cmd->id), error_string, err);

	free(error_string);
	return err;
}
Example #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;
}
Example #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;
}
Example #4
0
static int leveldb_backend_write(struct leveldb_backend *s, void *state, struct dnet_cmd *cmd, void *data)
{
	struct dnet_ext_list elist;
	int err = -EINVAL;
	char *error_string = NULL;
	struct dnet_io_attr *io = data;
	void *read_data = NULL;

	dnet_ext_list_init(&elist);

	dnet_convert_io_attr(io);

	data += sizeof(struct dnet_io_attr);

	/* Combine data with empty extension list header */
	err = dnet_ext_list_combine(&data, &io->size, &elist);
	if (err != 0)
		goto err_out_exit;

	/*
	 * key should be locked by elliptics here, so it is safe to run read-modify-write cycle
	 * if one performs write without lock we do not really care that one write may overwrite another one
	 */

	if (io->offset || (io->flags & DNET_IO_FLAGS_APPEND)) {
		size_t data_size;
		size_t offset = io->offset;

		read_data = leveldb_get(s->db, s->roptions, (const char *)io->id, DNET_ID_SIZE, &data_size, &error_string);
		if (error_string || !read_data) {
			free(error_string);
			error_string = NULL;
			goto plain_write;
		}

		if (io->flags & DNET_IO_FLAGS_APPEND) {
			io->offset = 0;
			offset = data_size;
		}

		/*
		 * XXX: Account for extended header
		 */

		if (io->offset > data_size) {
			err = -ERANGE;
			goto err_out_exit;
		}

		if (offset + io->size > data_size) {
			read_data = realloc(read_data, data_size + io->size);
			if (!read_data) {
				err = -ENOMEM;
				goto err_out_exit;
			}
		}

		memcpy(read_data + offset, data, io->size);

		data = read_data;
		if (offset + io->size > data_size)
			io->size = offset + io->size;
		else
			io->size = data_size;
	}

plain_write:
	leveldb_put(s->db, s->woptions, (const char *)cmd->id.id, DNET_ID_SIZE, data, io->size, &error_string);
	if (error_string)
		goto err_out_free;

	if (io->flags & DNET_IO_FLAGS_WRITE_NO_FILE_INFO) {
		cmd->flags |= DNET_FLAGS_NEED_ACK;
		err = 0;
		goto err_out_exit;
	}

	err = dnet_send_file_info_ts_without_fd(state, cmd, 0, io->size, &elist.timestamp);
	if (err < 0)
		goto err_out_free;

	dnet_backend_log(DNET_LOG_NOTICE, "%s: leveldb: : WRITE: Ok: offset: %llu, size: %llu, ioflags: %x.\n",
			dnet_dump_id(&cmd->id), (unsigned long long)io->offset, (unsigned long long)io->size, io->flags);

err_out_free:
	free(data);
err_out_exit:
	dnet_ext_list_destroy(&elist);

	if (err < 0)
		dnet_backend_log(DNET_LOG_ERROR, "%s: leveldb: : WRITE: error: %s: %d.\n",
			dnet_dump_id(&cmd->id), error_string, err);
	free(read_data);
	free(error_string);
	return err;
}