remote_handle.hpp
1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION.
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #pragma once
6 
7 #include <cassert>
8 #include <cstddef>
9 #include <cstring>
10 #include <memory>
11 #include <optional>
12 #include <string>
13 #include <vector>
14 
15 #include <kvikio/defaults.hpp>
16 #include <kvikio/error.hpp>
17 #include <kvikio/threadpool_wrapper.hpp>
18 #include <kvikio/utils.hpp>
19 
20 struct curl_slist;
21 
22 namespace kvikio {
23 
24 class CurlHandle; // Prototype
25 
32 enum class RemoteEndpointType : uint8_t {
33  AUTO,
35  S3,
38  S3_PUBLIC,
43  WEBHDFS,
45  HTTP,
47 };
48 
55 enum class RemoteIOBackend : uint8_t {
57  0,
61  MULTI_POLL =
62  1,
66 };
67 
75 enum class RemoteReactorDispatch : uint8_t {
76  PER_CHUNK =
77  0,
81  PER_PREAD =
82  1,
86 };
87 
97  protected:
98  RemoteEndpointType _remote_endpoint_type{RemoteEndpointType::AUTO};
100 
101  public:
102  virtual ~RemoteEndpoint() = default;
103 
111  virtual void setopt(CurlHandle& curl) = 0;
112 
118  virtual std::string str() const = 0;
119 
125  virtual std::size_t get_file_size() = 0;
126 
131  virtual void setup_range_request(CurlHandle& curl, std::size_t file_offset, std::size_t size) = 0;
132 
138  [[nodiscard]] RemoteEndpointType remote_endpoint_type() const noexcept;
139 };
140 
147 class HttpEndpoint : public RemoteEndpoint {
148  private:
149  std::string _url;
150 
151  public:
157  HttpEndpoint(std::string url);
158 
159  ~HttpEndpoint() override = default;
160  void setopt(CurlHandle& curl) override;
161  std::string str() const override;
162  std::size_t get_file_size() override;
163  void setup_range_request(CurlHandle& curl, std::size_t file_offset, std::size_t size) override;
164 
171  static bool is_url_valid(std::string const& url) noexcept;
172 };
173 
180 class S3Endpoint : public RemoteEndpoint {
181  private:
182  std::string _url;
183  std::string _aws_sigv4;
184  std::string _aws_userpwd;
185  curl_slist* _curl_header_list{};
186 
187  public:
203  static std::string url_from_bucket_and_object(std::string bucket_name,
204  std::string object_name,
205  std::optional<std::string> aws_region,
206  std::optional<std::string> aws_endpoint_url);
207 
216  [[nodiscard]] static std::pair<std::string, std::string> parse_s3_url(std::string const& s3_url);
217 
233  S3Endpoint(std::string url,
234  std::optional<std::string> aws_region = std::nullopt,
235  std::optional<std::string> aws_access_key = std::nullopt,
236  std::optional<std::string> aws_secret_access_key = std::nullopt,
237  std::optional<std::string> aws_session_token = std::nullopt);
238 
256  S3Endpoint(std::pair<std::string, std::string> bucket_and_object_names,
257  std::optional<std::string> aws_region = std::nullopt,
258  std::optional<std::string> aws_access_key = std::nullopt,
259  std::optional<std::string> aws_secret_access_key = std::nullopt,
260  std::optional<std::string> aws_endpoint_url = std::nullopt,
261  std::optional<std::string> aws_session_token = std::nullopt);
262 
263  ~S3Endpoint() override;
264  void setopt(CurlHandle& curl) override;
265  std::string str() const override;
266  std::size_t get_file_size() override;
267  void setup_range_request(CurlHandle& curl, std::size_t file_offset, std::size_t size) override;
268 
275  static bool is_url_valid(std::string const& url) noexcept;
276 };
277 
285  private:
286  std::string _url;
287 
288  public:
289  explicit S3PublicEndpoint(std::string url);
290 
291  ~S3PublicEndpoint() override = default;
292  void setopt(CurlHandle& curl) override;
293  std::string str() const override;
294  std::size_t get_file_size() override;
295  void setup_range_request(CurlHandle& curl, std::size_t file_offset, std::size_t size) override;
296 
303  static bool is_url_valid(std::string const& url) noexcept;
304 };
305 
313  private:
314  std::string _url;
315 
316  public:
317  explicit S3EndpointWithPresignedUrl(std::string presigned_url);
318 
319  ~S3EndpointWithPresignedUrl() override = default;
320  void setopt(CurlHandle& curl) override;
321  std::string str() const override;
322  std::size_t get_file_size() override;
323  void setup_range_request(CurlHandle& curl, std::size_t file_offset, std::size_t size) override;
324 
331  static bool is_url_valid(std::string const& url) noexcept;
332 };
333 
347 
352  private:
353  std::unique_ptr<RemoteEndpoint> _endpoint;
354  std::size_t _nbytes;
355 
356  public:
434  static RemoteHandle open(std::string const& url,
436  std::optional<std::vector<RemoteEndpointType>> allow_list = std::nullopt,
437  std::optional<std::size_t> nbytes = std::nullopt);
438 
445  RemoteHandle(std::unique_ptr<RemoteEndpoint> endpoint, std::size_t nbytes);
446 
454  RemoteHandle(std::unique_ptr<RemoteEndpoint> endpoint);
455 
456  // A remote handle is moveable but not copyable.
457  RemoteHandle(RemoteHandle&& o) = default;
458  RemoteHandle& operator=(RemoteHandle&& o) = default;
459  RemoteHandle(RemoteHandle const&) = delete;
460  RemoteHandle& operator=(RemoteHandle const&) = delete;
461 
467  [[nodiscard]] RemoteEndpointType remote_endpoint_type() const noexcept;
468 
477  [[nodiscard]] std::size_t nbytes() const noexcept;
478 
484  [[nodiscard]] RemoteEndpoint const& endpoint() const noexcept;
485 
498  std::size_t read(void* buf, std::size_t size, std::size_t file_offset = 0);
499 
526  std::future<std::size_t> pread(void* buf,
527  std::size_t size,
528  std::size_t file_offset = 0,
529  std::size_t task_size = defaults::task_size(),
530  ThreadPool* thread_pool = &defaults::thread_pool());
531 };
532 
533 } // namespace kvikio
Representation of a curl easy handle pointer and its operations.
Definition: libcurl.hpp:80
A remote endpoint for HTTP/HTTPS resources.
void setup_range_request(CurlHandle &curl, std::size_t file_offset, std::size_t size) override
Set up the range request in order to read part of a file given the file offset and read size.
std::size_t get_file_size() override
Get the size of the remote file.
std::string str() const override
Get a description of this remote point instance.
HttpEndpoint(std::string url)
Create an http endpoint from a url.
void setopt(CurlHandle &curl) override
Set needed connection options on a curl handle.
static bool is_url_valid(std::string const &url) noexcept
Whether the given URL is valid for HTTP/HTTPS endpoints.
Abstract base class for remote endpoints.
RemoteEndpointType remote_endpoint_type() const noexcept
Get the type of the remote file.
virtual std::size_t get_file_size()=0
Get the size of the remote file.
virtual void setup_range_request(CurlHandle &curl, std::size_t file_offset, std::size_t size)=0
Set up the range request in order to read part of a file given the file offset and read size.
virtual void setopt(CurlHandle &curl)=0
Set needed connection options on a curl handle.
virtual std::string str() const =0
Get a description of this remote point instance.
Handle of remote file.
RemoteEndpointType remote_endpoint_type() const noexcept
Get the type of the remote file.
static RemoteHandle open(std::string const &url, RemoteEndpointType remote_endpoint_type=RemoteEndpointType::AUTO, std::optional< std::vector< RemoteEndpointType >> allow_list=std::nullopt, std::optional< std::size_t > nbytes=std::nullopt)
Create a remote file handle from a URL.
RemoteHandle(std::unique_ptr< RemoteEndpoint > endpoint)
Create a new remote handle from an endpoint (infers the file size).
RemoteHandle(std::unique_ptr< RemoteEndpoint > endpoint, std::size_t nbytes)
Create a new remote handle from an endpoint and a file size.
A remote endpoint for AWS S3 storage using presigned URLs.
std::size_t get_file_size() override
Get the size of the remote file.
std::string str() const override
Get a description of this remote point instance.
void setup_range_request(CurlHandle &curl, std::size_t file_offset, std::size_t size) override
Set up the range request in order to read part of a file given the file offset and read size.
static bool is_url_valid(std::string const &url) noexcept
Whether the given URL is valid for S3 endpoints with presigned URL.
void setopt(CurlHandle &curl) override
Set needed connection options on a curl handle.
A remote endpoint for AWS S3 storage requiring credentials.
static std::string url_from_bucket_and_object(std::string bucket_name, std::string object_name, std::optional< std::string > aws_region, std::optional< std::string > aws_endpoint_url)
Get url from a AWS S3 bucket and object name.
static bool is_url_valid(std::string const &url) noexcept
Whether the given URL is valid for S3 endpoints (excluding presigned URL).
S3Endpoint(std::pair< std::string, std::string > bucket_and_object_names, std::optional< std::string > aws_region=std::nullopt, std::optional< std::string > aws_access_key=std::nullopt, std::optional< std::string > aws_secret_access_key=std::nullopt, std::optional< std::string > aws_endpoint_url=std::nullopt, std::optional< std::string > aws_session_token=std::nullopt)
Create a S3 endpoint from a bucket and object name.
S3Endpoint(std::string url, std::optional< std::string > aws_region=std::nullopt, std::optional< std::string > aws_access_key=std::nullopt, std::optional< std::string > aws_secret_access_key=std::nullopt, std::optional< std::string > aws_session_token=std::nullopt)
Create a S3 endpoint from a url.
void setopt(CurlHandle &curl) override
Set needed connection options on a curl handle.
void setup_range_request(CurlHandle &curl, std::size_t file_offset, std::size_t size) override
Set up the range request in order to read part of a file given the file offset and read size.
static std::pair< std::string, std::string > parse_s3_url(std::string const &s3_url)
Given an url like "s3://<bucket>/<object>", return the name of the bucket and object.
std::string str() const override
Get a description of this remote point instance.
std::size_t get_file_size() override
Get the size of the remote file.
A remote endpoint for publicly accessible S3 objects without authentication.
static bool is_url_valid(std::string const &url) noexcept
Whether the given URL is valid for S3 public endpoints.
std::size_t get_file_size() override
Get the size of the remote file.
void setup_range_request(CurlHandle &curl, std::size_t file_offset, std::size_t size) override
Set up the range request in order to read part of a file given the file offset and read size.
void setopt(CurlHandle &curl) override
Set needed connection options on a curl handle.
std::string str() const override
Get a description of this remote point instance.
Singleton class of default values used throughout KvikIO.
Definition: defaults.hpp:122
KvikIO namespace.
Definition: batch.hpp:16
BS::thread_pool ThreadPool
Thread pool type used for parallel I/O operations.
RemoteReactorDispatch
How sub-ranges of a single pread() are distributed across reactor threads when the MULTI_POLL backend...
RemoteIOBackend
Selects the remote I/O backend.
RemoteEndpointType infer_remote_endpoint_type(std::string const &url)
Infer remote endpoint type from URL.
RemoteEndpointType
Types of remote file endpoints supported by KvikIO.