RESTinio

write_group_output_ctx.hpp
Go to the documentation of this file.
1/*
2 restinio
3*/
4
9#pragma once
10
11#include <vector>
12
13#include <restinio/asio_include.hpp>
14
15#include <restinio/buffers.hpp>
16#include <restinio/optional.hpp>
17#include <restinio/variant.hpp>
18#include <restinio/impl/sendfile_operation.hpp>
19
20#include <restinio/compiler_features.hpp>
21
22 namespace restinio
23{
24
25 namespace impl
26{
27
28 using asio_bufs_container_t = std::vector< asio_ns::const_buffer >;
29
30//
31// write_group_output_ctx_t
32//
33
35
79 class write_group_output_ctx_t
80{
83 static constexpr auto
84 max_iov_len() noexcept
85 {
86 using len_t = decltype( asio_ns::detail::max_iov_len );
87 return static_cast< asio_bufs_container_t::size_type >(
88 std::min< len_t >( asio_ns::detail::max_iov_len, 64 ) );
89 }
90
91 public:
93 /*
94 Space for m_asio_bufs is reserved to be ready to store max_iov_len() asio bufs.
95 */
96 write_group_output_ctx_t()
97 {
98 m_asio_bufs.reserve( max_iov_len() );
99 }
100
102
105 class trivial_write_operation_t
106 {
107 friend class write_group_output_ctx_t;
108
109 explicit trivial_write_operation_t(
111 const asio_bufs_container_t & asio_bufs,
113 std::size_t total_size ) noexcept
114 : m_asio_bufs{ &asio_bufs }
115 , m_total_size{ total_size }
116 {}
117
118 public:
119 trivial_write_operation_t( const trivial_write_operation_t & ) = default;
120 trivial_write_operation_t & operator = ( const trivial_write_operation_t & ) = default;
121
122 trivial_write_operation_t( trivial_write_operation_t && ) = default;
123 trivial_write_operation_t & operator = ( trivial_write_operation_t && ) = default;
124
126 const std::vector< asio_ns::const_buffer > &
127 get_trivial_bufs() const noexcept
128 {
129 return *m_asio_bufs;
130 }
131
133 auto size() const noexcept { return m_total_size; }
134
135 private:
136 const asio_bufs_container_t * m_asio_bufs;
137 size_t m_total_size;
138 };
139
141 class file_write_operation_t
142 {
143 friend class write_group_output_ctx_t;
144
145 explicit file_write_operation_t(
146 sendfile_t & sendfile,
147 sendfile_operation_shared_ptr_t & sendfile_operation ) noexcept
148 : m_sendfile{ &sendfile }
149 , m_sendfile_operation{ &sendfile_operation }
150 {}
151
152 public:
153 file_write_operation_t( const file_write_operation_t & ) = default;
154 file_write_operation_t & operator = ( const file_write_operation_t & ) = default;
155
156 file_write_operation_t( file_write_operation_t && ) = default;
157 file_write_operation_t & operator = ( file_write_operation_t && ) = default;
158
160
165 template< typename Socket, typename After_Write_CB >
166 void
167 start_sendfile_operation(
168 default_asio_executor executor,
169 Socket & socket,
170 After_Write_CB after_sendfile_cb )
171 {
172 assert( m_sendfile->is_valid() );
173
174 if( !m_sendfile->is_valid() )
175 {
176 // This must never happen.
177 throw exception_t{ "invalid file descriptor in sendfile operation." };
178 }
179
180 auto sendfile_operation =
181 std::make_shared< sendfile_operation_runner_t< Socket > >(
182 *m_sendfile,
183 std::move( executor ),
184 socket,
185 std::move( after_sendfile_cb ) );
186
187 *m_sendfile_operation = std::move( sendfile_operation );
188 (*m_sendfile_operation)->start();
189 }
190
192 auto
193 timelimit() const noexcept
194 {
195 assert( m_sendfile->is_valid() );
196
197 return m_sendfile->timelimit();
198 }
199
201
205 void
206 reset() noexcept
207 {
208 RESTINIO_ENSURE_NOEXCEPT_CALL( m_sendfile_operation->reset() );
209 }
210
212 auto size() const noexcept { return m_sendfile->size(); }
213
214 private:
216 sendfile_t * m_sendfile; // Pointer is used to be able to copy/assign.
217
219
223 sendfile_operation_shared_ptr_t * m_sendfile_operation;
224 };
225
227
232 struct none_write_operation_t {};
233
235 bool transmitting() const noexcept { return static_cast< bool >( m_current_wg ); }
236
238 void
239 start_next_write_group( optional_t< write_group_t > next_wg ) noexcept
240 {
241 m_current_wg = std::move( next_wg );
242 }
243
245 using solid_write_operation_variant_t =
246 variant_t<
247 none_write_operation_t,
248 trivial_write_operation_t,
249 file_write_operation_t >;
250
252 solid_write_operation_variant_t
253 extract_next_write_operation()
254 {
255 assert( m_current_wg );
256
257 solid_write_operation_variant_t result{ none_write_operation_t{} };
258
259 if( m_next_writable_item_index < m_current_wg->items_count() )
260 {
261 // Has writable items.
262 const auto next_wi_type =
263 m_current_wg->items()[ m_next_writable_item_index ].write_type();
264
265 if( writable_item_type_t::trivial_write_operation == next_wi_type )
266 {
267 // Trivial buffers.
268 result = prepare_trivial_buffers_wo();
269 }
270 else
271 {
272 // Sendfile.
273 assert( writable_item_type_t::file_write_operation == next_wi_type );
274 result = prepare_sendfile_wo();
275 }
276 }
277
278 return result;
279 }
280
282 void
283 fail_write_group( const asio_ns::error_code & ec )
284 {
285 assert( m_current_wg );
286
287 invoke_after_write_notificator_if_necessary( ec );
288 m_current_wg.reset();
289 m_sendfile_operation.reset();
290 }
291
293 void
294 finish_write_group()
295 {
296 assert( m_current_wg );
297
298 invoke_after_write_notificator_if_necessary( asio_ns::error_code{} );
299 reset_write_group();
300 }
301
302 private:
304 void
305 reset_write_group()
306 {
307 m_current_wg.reset();
308 m_next_writable_item_index = 0;
309 }
310
312 void
313 invoke_after_write_notificator_if_necessary( const asio_ns::error_code & ec )
314 {
315 try
316 {
317 m_current_wg->invoke_after_write_notificator_if_exists( ec );
318 }
319 catch( const std::exception & ex )
320 {
321 // Actualy no need to reset m_current_wg as a thrown exception
322 // will break working circle of connection.
323 // But as it is used as flag for transmitting()
324 // we reset the object.
325 reset_write_group();
326
327 throw exception_t{
328 fmt::format( "after write callback failed: {}", ex.what() ) };
329 }
330 }
331
333 trivial_write_operation_t
334 prepare_trivial_buffers_wo()
335 {
336 m_asio_bufs.clear();
337
338 const auto & items = m_current_wg->items();
339 std::size_t total_size{ 0 };
340
341 for( ;m_next_writable_item_index < items.size() &&
342 writable_item_type_t::trivial_write_operation ==
343 items[ m_next_writable_item_index ].write_type() &&
344 max_iov_len() > m_asio_bufs.size();
345 ++m_next_writable_item_index )
346 {
347 const auto & item = items[ m_next_writable_item_index ];
348 m_asio_bufs.emplace_back( item.buf() );
349 total_size += item.size();
350 }
351
352 assert( !m_asio_bufs.empty() );
353 return trivial_write_operation_t{ m_asio_bufs, total_size };
354 }
355
357 file_write_operation_t
358 prepare_sendfile_wo()
359 {
360 auto & sf =
361 m_current_wg->items()[ m_next_writable_item_index++ ].sendfile_operation();
362
363 return file_write_operation_t{ sf, m_sendfile_operation };
364 }
365
367 optional_t< write_group_t > m_current_wg;
368
370
374 std::size_t m_next_writable_item_index{ 0 };
375
377 asio_bufs_container_t m_asio_bufs;
378
380 sendfile_operation_shared_ptr_t m_sendfile_operation;
381};
382
383} /* namespace impl */
384
385} /* namespace restinio */
asio_include.hpp
buffers.hpp
nonstd::optional_lite::optional
class optional
Definition: optional.hpp:919
nonstd::variants::variant
Definition: variant.hpp:1301
restinio::exception_t
Exception class for all exceptions thrown by RESTinio.
Definition: exception.hpp:26
restinio::impl::write_group_output_ctx_t::file_write_operation_t
Write operaton using sendfile.
Definition: write_group_output_ctx.hpp:142
restinio::impl::write_group_output_ctx_t::file_write_operation_t::m_sendfile_operation
sendfile_operation_shared_ptr_t * m_sendfile_operation
A curernt sendfile operation.
Definition: write_group_output_ctx.hpp:223
restinio::impl::write_group_output_ctx_t::file_write_operation_t::operator=
file_write_operation_t & operator=(const file_write_operation_t &)=default
restinio::impl::write_group_output_ctx_t::file_write_operation_t::file_write_operation_t
file_write_operation_t(sendfile_t &sendfile, sendfile_operation_shared_ptr_t &sendfile_operation) noexcept
Definition: write_group_output_ctx.hpp:145
restinio::impl::write_group_output_ctx_t::file_write_operation_t::file_write_operation_t
file_write_operation_t(const file_write_operation_t &)=default
restinio::impl::write_group_output_ctx_t::file_write_operation_t::reset
void reset() noexcept
Reset write operation context.
Definition: write_group_output_ctx.hpp:206
restinio::impl::write_group_output_ctx_t::file_write_operation_t::timelimit
auto timelimit() const noexcept
Get the timelimit on this sendfile operation.
Definition: write_group_output_ctx.hpp:193
restinio::impl::write_group_output_ctx_t::file_write_operation_t::start_sendfile_operation
void start_sendfile_operation(default_asio_executor executor, Socket &socket, After_Write_CB after_sendfile_cb)
Start a sendfile operation.
Definition: write_group_output_ctx.hpp:167
restinio::impl::write_group_output_ctx_t::file_write_operation_t::m_sendfile
sendfile_t * m_sendfile
A pointer to sendfile.
Definition: write_group_output_ctx.hpp:216
restinio::impl::write_group_output_ctx_t::file_write_operation_t::size
auto size() const noexcept
Get the size of sendfile operation.
Definition: write_group_output_ctx.hpp:212
restinio::impl::write_group_output_ctx_t::file_write_operation_t::file_write_operation_t
file_write_operation_t(file_write_operation_t &&)=default
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t
Trivial write operaton.
Definition: write_group_output_ctx.hpp:106
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t::trivial_write_operation_t
trivial_write_operation_t(trivial_write_operation_t &&)=default
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t::m_asio_bufs
const asio_bufs_container_t * m_asio_bufs
Definition: write_group_output_ctx.hpp:136
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t::trivial_write_operation_t
trivial_write_operation_t(const trivial_write_operation_t &)=default
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t::operator=
trivial_write_operation_t & operator=(const trivial_write_operation_t &)=default
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t::trivial_write_operation_t
trivial_write_operation_t(const asio_bufs_container_t &asio_bufs, std::size_t total_size) noexcept
Definition: write_group_output_ctx.hpp:109
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t::size
auto size() const noexcept
The size of data within this operation.
Definition: write_group_output_ctx.hpp:133
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t::m_total_size
size_t m_total_size
Definition: write_group_output_ctx.hpp:137
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t::get_trivial_bufs
const std::vector< asio_ns::const_buffer > & get_trivial_bufs() const noexcept
Get buffer "iovec" for performing gather write.
Definition: write_group_output_ctx.hpp:127
restinio::impl::write_group_output_ctx_t
Helper class for writting response data.
Definition: write_group_output_ctx.hpp:80
restinio::impl::write_group_output_ctx_t::fail_write_group
void fail_write_group(const asio_ns::error_code &ec)
Handle current group write process failed.
Definition: write_group_output_ctx.hpp:283
restinio::impl::write_group_output_ctx_t::extract_next_write_operation
solid_write_operation_variant_t extract_next_write_operation()
et an object with next write operation to perform.
Definition: write_group_output_ctx.hpp:253
restinio::impl::write_group_output_ctx_t::m_next_writable_item_index
std::size_t m_next_writable_item_index
Keeps track of the next writable item stored in m_current_wg.
Definition: write_group_output_ctx.hpp:374
restinio::impl::write_group_output_ctx_t::prepare_trivial_buffers_wo
trivial_write_operation_t prepare_trivial_buffers_wo()
Prepare write operation for trivial buffers.
Definition: write_group_output_ctx.hpp:334
restinio::impl::write_group_output_ctx_t::write_group_output_ctx_t
write_group_output_ctx_t()
Contruct an object.
Definition: write_group_output_ctx.hpp:96
restinio::impl::write_group_output_ctx_t::finish_write_group
void finish_write_group()
Finish writing group normally.
Definition: write_group_output_ctx.hpp:294
restinio::impl::write_group_output_ctx_t::m_sendfile_operation
sendfile_operation_shared_ptr_t m_sendfile_operation
Sendfile operation storage context.
Definition: write_group_output_ctx.hpp:380
restinio::impl::write_group_output_ctx_t::m_asio_bufs
asio_bufs_container_t m_asio_bufs
Asio buffers storage.
Definition: write_group_output_ctx.hpp:377
restinio::impl::write_group_output_ctx_t::invoke_after_write_notificator_if_necessary
void invoke_after_write_notificator_if_necessary(const asio_ns::error_code &ec)
Execute notification callback if necessary.
Definition: write_group_output_ctx.hpp:313
restinio::impl::write_group_output_ctx_t::start_next_write_group
void start_next_write_group(optional_t< write_group_t > next_wg) noexcept
Start handlong next write group.
Definition: write_group_output_ctx.hpp:239
restinio::impl::write_group_output_ctx_t::max_iov_len
static constexpr auto max_iov_len() noexcept
Get the maximum number of buffers that can be written with gather write operation.
Definition: write_group_output_ctx.hpp:84
restinio::impl::write_group_output_ctx_t::reset_write_group
void reset_write_group()
Reset the write group and associated context.
Definition: write_group_output_ctx.hpp:305
restinio::impl::write_group_output_ctx_t::transmitting
bool transmitting() const noexcept
Check if data is trunsmitting now.
Definition: write_group_output_ctx.hpp:235
restinio::impl::write_group_output_ctx_t::m_current_wg
optional_t< write_group_t > m_current_wg
Real buffers with data.
Definition: write_group_output_ctx.hpp:367
restinio::impl::write_group_output_ctx_t::prepare_sendfile_wo
file_write_operation_t prepare_sendfile_wo()
Prepare write operation for sendfile.
Definition: write_group_output_ctx.hpp:358
restinio::sendfile_t
Send file write operation description.
Definition: sendfile.hpp:226
restinio::sendfile_t::size
auto size() const noexcept
Get size of data to write.
Definition: sendfile.hpp:306
restinio::sendfile_t::timelimit
auto timelimit() const noexcept
Definition: sendfile.hpp:376
restinio::sendfile_t::is_valid
bool is_valid() const noexcept
Check if file is valid.
Definition: sendfile.hpp:294
compiler_features.hpp
Detection of compiler version and absence of various features.
RESTINIO_ENSURE_NOEXCEPT_CALL
#define RESTINIO_ENSURE_NOEXCEPT_CALL(expr)
A wrapper around static_assert for checking that an expression is noexcept and execution of that expr...
Definition: compiler_features.hpp:60
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:465
restinio::impl::asio_bufs_container_t
std::vector< asio_ns::const_buffer > asio_bufs_container_t
Definition: write_group_output_ctx.hpp:28
restinio::impl::sendfile_operation_shared_ptr_t
std::shared_ptr< sendfile_operation_base_t > sendfile_operation_shared_ptr_t
Definition: sendfile_operation.hpp:36
restinio
Definition: asio_include.hpp:21
restinio::sendfile
sendfile_t sendfile(file_descriptor_holder_t fd, file_meta_t meta, file_size_t chunk_size=sendfile_default_chunk_size) noexcept
Definition: sendfile.hpp:468
restinio::default_asio_executor
asio_ns::executor default_asio_executor
Definition: asio_include.hpp:224
restinio::writable_item_type_t::trivial_write_operation
@ trivial_write_operation
Item is a buffer and must be written trivially.
restinio::writable_item_type_t::file_write_operation
@ file_write_operation
Item is a sendfile operation and implicates file write operation.
optional.hpp
sendfile_operation.hpp
restinio::impl::write_group_output_ctx_t::none_write_operation_t
None write operation.
Definition: write_group_output_ctx.hpp:232
variant.hpp
const
#define const
Definition: zconf.h:230