src/block_service/block_service.h (175 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #pragma once #include "task/task_code.h" #include "task/task_tracker.h" #include "runtime/api_task.h" #include "runtime/api_layer1.h" #include "runtime/app_model.h" #include "utils/api_utilities.h" #include "utils/error_code.h" #include "utils/threadpool_code.h" #include "task/task_code.h" #include "common/gpid.h" #include "rpc/serialization.h" #include "rpc/rpc_stream.h" #include "runtime/serverlet.h" #include "runtime/service_app.h" #include "rpc/rpc_address.h" #include "common/replication_other_types.h" #include "common/replication.codes.h" #include <functional> namespace dsn { namespace dist { namespace block_service { class block_file; using block_file_ptr = dsn::ref_ptr<block_file>; /** * @brief The ls_request struct, use to list all the files and directories under the dir_name * dir_name: a valid absolute path string, which "/" as splitter.We don't support relative path */ struct ls_request { std::string dir_name; }; /** * @brief The ls_entry struct * entry_name: an entry name which doesn't contain the directory preceding */ struct ls_entry { std::string entry_name; bool is_directory; }; /** * @brief The ls_response struct * err: ERR_OK means the ls request is responsed succeed. Then * user can view all entries by entries. * ERR_OBJECT_NOT_FOUND: can't find the dir by ls_request.dir_name * ERR_INVALID_PARAMETERS: the ls_request.dir_name is not a dir * ERR_TIMEOUT: request timeout * ERR_FS_INTERNAL: an internal error occured in the service implementation * which we can't handle */ struct ls_response { dsn::error_code err; // use shared_ptr to avoid extra memory copy std::shared_ptr<std::vector<ls_entry>> entries; ls_response() : entries(std::make_shared<std::vector<ls_entry>>()) {} }; typedef std::function<void(const ls_response &)> ls_callback; typedef future_task<ls_response> ls_future; typedef dsn::ref_ptr<ls_future> ls_future_ptr; /** * @brief The create_file_request struct, used to create a block_file_ptr * file_name: a valid absolute path string, which "/" as splitter. * We don't support relative path. * ignore_metadata: With the flag set, implementation is not necessary to pre-fetch the * metadata(size, md5sum..) when create the handle. This is useful in * cases that users don't care the current content of the file, and they * simply need the handle and do operations. An implementation can do * some optimization according to this options. */ struct create_file_request { std::string file_name; bool ignore_metadata; }; /** * @brief The create_file_response struct * err: ERR_OK: the file handle is successfully created. * ERR_TIMEOUT: request timeout * ERR_FS_INTERNAL: an internal error occured in the service implementation * which we can't handle * file_handle: the file_handle will not be null if err is ERR_OK. * user can read/write the file by the handle, and get the metata(size, md5..). * please ref {@link #block_file::get_size}, {@link #block_file::get_md5sum} for * the return value of metadata */ struct create_file_response { dsn::error_code err; block_file_ptr file_handle; }; typedef std::function<void(const create_file_response &)> create_file_callback; typedef future_task<create_file_response> create_file_future; typedef dsn::ref_ptr<create_file_future> create_file_future_ptr; /** * @brief The remove_path_request struct * path: a valid absolute path string, which point to file or directory, which "/" as splitter * recursive: if path point to a non-empty directory, and if recursive = true, then all the * files or dirs under the path will be removed; if recursive = false, then the * non-empty directory will not be removed. * if path point to an empty directory or file, just remove the path. */ struct remove_path_request { std::string path; bool recursive; }; /** * @brief The remove_path_response struct * err: ERR_OK: request succeed, and the remove path succeed * ERR_OBJECT_NOT_FOUND: request succeed, but the path do not exist * ERR_TIMEOUT: request timeout * ERR_DIR_NOT_EMPTY: the directory is non-empty, can't be removed * ERR_FS_INTERNAL: remove directory failed, need check it again */ struct remove_path_response { dsn::error_code err; }; typedef std::function<void(const remove_path_response &)> remove_path_callback; typedef future_task<remove_path_response> remove_path_future; typedef dsn::ref_ptr<remove_path_future> remove_path_future_ptr; /** * @brief The read_request struct * remote_pos: where of the file to start read * remote_length: the amount of bytes to read. * if set -1, means read to the end of the file */ struct read_request { uint64_t remote_pos; int64_t remote_length; }; /** * @brief The read_response struct * err: ERR_OK: read succeed * ERR_OBJECT_NOT_FOUND: try to read an non-exist file. * this happens when try to read a file handle which * doesn't have a coressponding remote file * ERR_TIMEOUT: request timeout * ERR_FS_INTERNAL: an internal error occured in the service implementation * which we can't handle * buffer: the read data. The implementation can choose to return partially read data when * error occured, or discard them and only return an empty buffer. But implementation * should never return ERR_OK if partitial data got, otherwize the user can't tell * whether partital data is transfered or reach the end of file with remote_length == -1. * If ERR_OK returned but only partitial data got, means reach the end of file. */ struct read_response { dsn::error_code err; dsn::blob buffer; }; typedef std::function<void(const read_response &)> read_callback; typedef future_task<read_response> read_future; typedef dsn::ref_ptr<read_future> read_future_ptr; /** * @brief The write_request struct * buffer: the new content of the file. Returns ERR_OK if and only if all the data in buffer * has been written into the file. * Notice: we don't have the insert/append semantic for file, only truncate. */ struct write_request { dsn::blob buffer; }; /** * @brief The write_response struct * err: ERR_OK: write succeed * ERR_TIMEOUT: request timeout * ERR_FS_INTERNAL: an internal error occured in the service implementation * which we can't handle * written_size: amount of bytes have been written. * * Notice: user can call get_size/get_md5sum to get the metadata of the file */ struct write_response { dsn::error_code err; uint64_t written_size; }; typedef std::function<void(const write_response &)> write_callback; typedef future_task<write_response> write_future; typedef dsn::ref_ptr<write_future> write_future_ptr; /** * @brief The upload_request struct * input_local_name: a local filesystem path, you can use a relative or absolute path. */ struct upload_request { std::string input_local_name; }; /** * @brief The upload_response struct * similar to write_response with more errors in err: * ERR_FILE_OPERATION_FAILED: open the local file for read failed. * * Notice: user can call get_size/get_md5sum to get the metadata of the file */ struct upload_response { dsn::error_code err = ERR_OK; uint64_t uploaded_size = 0; }; typedef std::function<void(const upload_response &)> upload_callback; typedef future_task<upload_response> upload_future; typedef dsn::ref_ptr<upload_future> upload_future_ptr; /** * @brief The download_request struct * output_local_file: a local filesystem path, you can use a relative or absolute path. */ struct download_request { std::string output_local_name; uint64_t remote_pos; int64_t remote_length; }; /** * @brief The download_response struct * similar to read_response. With more errors in err: * ERR_FILE_OPERATION_FAILED: open output_local_name for write failed. * if try to download a non-exist file and with an invalid output_local_name, * it's up to implementation to return which error. */ struct download_response { dsn::error_code err; uint64_t downloaded_size; std::string file_md5; }; typedef std::function<void(const download_response &)> download_callback; typedef future_task<download_response> download_future; typedef dsn::ref_ptr<download_future> download_future_ptr; class block_filesystem { public: template <typename T> static block_filesystem *create() { return new T(); } typedef block_filesystem *(*factory)(); block_filesystem() {} /** * @brief initialize * @param args, the implemented related parameter in initializing * should be represented as strings and passed by args * @return ERR_OK if initialized succeed. If failed, return with the failed error. */ virtual error_code initialize(const std::vector<std::string> &args) = 0; /** * @brief list_dir * @param req, ref {@link #ls_request} * @param code, a task_code, describe how the callback executed * @param callback, called when get the list result * @param tracker * @return a task which represent the async operation */ virtual dsn::task_ptr list_dir(const ls_request &req, dsn::task_code code, const ls_callback &callback, dsn::task_tracker *tracker = nullptr) = 0; /** * @brief create_file * @param req, ref {@link #create_file_request} * @param code, a task_code, describe how the callback executed * @param callback, called when get the list result * @param tracker * @return a task which represent the async operation */ virtual dsn::task_ptr create_file(const create_file_request &req, dsn::task_code code, const create_file_callback &cb, dsn::task_tracker *tracker = nullptr) = 0; /** * @brief remove_path * @param req, ref {@link #remove_path_request} * @param code, a task_code, describe how the callback executed * @param callback, called when get the list result * @param tracker * @return a task which represent the async operation */ virtual dsn::task_ptr remove_path(const remove_path_request &req, dsn::task_code code, const remove_path_callback &cb, dsn::task_tracker *tracker = nullptr) = 0; virtual bool is_root_path_set() const { return false; } virtual ~block_filesystem() {} }; class block_file : public dsn::ref_counter { public: block_file(const std::string &name) : _name(name) {} virtual ~block_file() {} const std::string &file_name() const { return _name; } /** * @brief get_size * this api should never block, implementation should * fetch the size in {@link block_filesystem::create_file}. * if the block_file is created by "ignore_metadata" {@link create_file_request}, * should return 0 * @return the file_size. If the file doesn't exist, should return 0 */ virtual uint64_t get_size() = 0; /** * @brief get_md5sum * this api should never block, implementation should * fetch the md5sum in {@link block_filesystem::create_file}. * if the block_file is created by "ignore_metadata" {@link create_file_request}, * should return "" * @return the md5 value. If the file doesn't exist, should return "". * NOTICE: if an existing file is empty(size == 0), the returning value is not "". * user can use this feature to check if a file exist. */ virtual const std::string &get_md5sum() = 0; /** * @brief write * @param req, ref {@link #write_request} * @param code, a task_code, describe how the callback executed * @param callback, called when get the list result * @param tracker * @return a task which represent the async operation */ virtual dsn::task_ptr write(const write_request &req, dsn::task_code code, const write_callback &cb, dsn::task_tracker *tracker = nullptr) = 0; // TODO(yingchun): it seems every read() will read the whole file, consider to read the whole // file directly. /** * @brief read * @param req, ref {@link #read_request} * @param code, a task_code, describe how the callback executed * @param callback, called when get the list result * @param tracker * @return a task which represent the async operation */ virtual dsn::task_ptr read(const read_request &req, dsn::task_code code, const read_callback &cb, dsn::task_tracker *tracker = nullptr) = 0; /** * @brief upload * @param req, ref {@link #upload_request} * @param code, a task_code, describe how the callback executed * @param callback, called when get the list result * @param tracker * @return a task which represent the async operation */ virtual dsn::task_ptr upload(const upload_request &req, dsn::task_code code, const upload_callback &cb, dsn::task_tracker *tracker = nullptr) = 0; /** * @brief download * @param req, ref {@link #download_request} * @param code, a task_code, describe how the callback executed * @param callback, called when get the list result * @param tracker * @return a task which represent the async operation */ virtual dsn::task_ptr download(const download_request &req, dsn::task_code code, const download_callback &cb, dsn::task_tracker *tracker = nullptr) = 0; protected: std::string _name; }; } // namespace block_service } // namespace dist } // namespace dsn