Files
scylladb/utils/s3/client.hh
Pavel Emelyanov 81d1bfce2a s3/client: Maintain several http clients on-board
The intent is to isolate workloads from different sched groups from each
other and not let one sched group consume all sockets from the http
client thus affecting requests made by other sched groups.

The conention happens in the maximim number of socket an http client may
have (see scylladb/seastar#1652). If requests take time and client is
asked to make more and more it will eventually stop spawning new
connections and would get blocked internally waiting for running
requests to complete and put a socket back to pool. If a sched group
workload (e.g. -- memtable flush) consumes all the available sockets
then workload from another group (e.g. -- query) would be blocked thus
spoiling its latency (which is poor on its own, but still)

After this change S3 client maintains a sched_group:http_client map
thus making sure different sched groups don't clash with each other so
that e.g. query requests don't wait for flush/compaction to release a
socket.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2023-06-08 18:28:55 +03:00

83 lines
2.5 KiB
C++

/*
* Copyright (C) 2022-present ScyllaDB
*/
/*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <seastar/core/file.hh>
#include <seastar/core/sstring.hh>
#include <seastar/core/shared_ptr.hh>
#include <seastar/http/client.hh>
#include "utils/s3/creds.hh"
using namespace seastar;
class memory_data_sink_buffers;
namespace s3 {
struct range {
uint64_t off;
size_t len;
};
future<> ignore_reply(const http::reply& rep, input_stream<char>&& in_);
class client : public enable_shared_from_this<client> {
class upload_sink_base;
class upload_sink;
class upload_jumbo_sink;
class readable_file;
std::string _host;
endpoint_config_ptr _cfg;
std::unordered_map<seastar::scheduling_group, http::experimental::client> _https;
using global_factory = std::function<shared_ptr<client>(std::string)>;
global_factory _gf;
struct private_tag {};
void authorize(http::request&);
future<> make_request(http::request req, http::experimental::client::reply_handler handle = ignore_reply, http::reply::status_type expected = http::reply::status_type::ok);
future<> get_object_header(sstring object_name, http::experimental::client::reply_handler handler);
public:
explicit client(std::string host, endpoint_config_ptr cfg, global_factory gf, private_tag);
static shared_ptr<client> make(std::string endpoint, endpoint_config_ptr cfg, global_factory gf = {});
future<uint64_t> get_object_size(sstring object_name);
struct stats {
uint64_t size;
std::time_t last_modified;
};
future<stats> get_object_stats(sstring object_name);
future<temporary_buffer<char>> get_object_contiguous(sstring object_name, std::optional<range> range = {});
future<> put_object(sstring object_name, temporary_buffer<char> buf);
future<> put_object(sstring object_name, ::memory_data_sink_buffers bufs);
future<> delete_object(sstring object_name);
file make_readable_file(sstring object_name);
data_sink make_upload_sink(sstring object_name);
data_sink make_upload_jumbo_sink(sstring object_name, std::optional<unsigned> max_parts_per_piece = {});
void update_config(endpoint_config_ptr);
struct handle {
std::string _host;
global_factory _gf;
public:
handle(const client& cln)
: _host(cln._host)
, _gf(cln._gf)
{}
shared_ptr<client> to_client() && {
return _gf(std::move(_host));
}
};
future<> close();
};
} // s3 namespace