MySQL 9.1.0
Source Code Documentation
linux_epoll_io_service.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2019, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef MYSQL_HARNESS_NET_TS_IMPL_LINUX_EPOLL_IO_SERVICE_H_
27#define MYSQL_HARNESS_NET_TS_IMPL_LINUX_EPOLL_IO_SERVICE_H_
28
29#include "my_config.h" // HAVE_EPOLL
30
31#define USE_EVENTFD
32
33#ifdef HAVE_EPOLL
34#include <chrono>
35#include <mutex>
36#include <optional>
37#include <system_error>
38#include <unordered_map>
39
40#if defined(USE_EVENTFD)
41#include <sys/eventfd.h>
42#endif
43
44#include <iostream> // cerr
45#include <sstream>
46
47#include "my_compiler.h" // MY_COMPILER_*
52
53namespace net {
54// See
55//
56// - https://idea.popcount.org/2017-02-20-epoll-is-fundamentally-broken-12/
57// - https://idea.popcount.org/2017-03-20-epoll-is-fundamentally-broken-22/
59 public:
61
62 static constexpr const int kSettableEvents = EPOLLIN | EPOLLOUT;
63 static constexpr const int kAlwaysEnabledEvents = EPOLLHUP | EPOLLERR;
64 static constexpr const int kAllEvents =
66
68
69 bool is_open() const noexcept {
74 }
75
77 if (is_open()) {
79 }
80
81 auto res = impl::epoll::create();
82 if (!res) return stdx::unexpected(res.error());
83
84 epfd_ = *res;
85#if defined(USE_EVENTFD)
86 notify_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
89
90 return {};
91 }
92#endif
93 auto pipe_res = impl::file::pipe(O_NONBLOCK);
94 if (!pipe_res) return stdx::unexpected(pipe_res.error());
95
96 wakeup_fds_ = *pipe_res;
97
98 // set both ends of the pipe non-blocking as
99 //
100 // - read() shouldn't block is pipe is empty
101 // - write() shouldn't block is pipe is full as it only matters there is
102 // something in the pipe to wakeup the poll_one()
103 auto non_block_wakeup_0_res =
105 if (!non_block_wakeup_0_res) return non_block_wakeup_0_res;
106 auto non_block_wakeup_1_res =
108 if (!non_block_wakeup_1_res) return non_block_wakeup_1_res;
109
112
113 return {};
114 }
115
116 void on_notify() {
118 uint64_t some{1};
119 ssize_t res;
120 do {
121 res = ::read(notify_fd_, &some, sizeof(some));
122 // in case of EINTR, loop again
123 // otherwise exit
124 //
125 // no need to loop again on success, as the read() will reset the
126 // counter to 0 anyway.
127 } while (res == -1 && errno == EINTR);
128 } else {
129 std::array<uint8_t, 256> buf;
130 ssize_t res;
131 do {
132 res = ::read(wakeup_fds_.first, buf.data(), buf.size());
133 // in case of EINTR, loop again
134 // in case of read > 0, loop again
135 // otherwise exist
136 } while (res > 0 || (res == -1 && errno == EINTR));
137 }
138 }
139
140 /**
141 * notify the poll_one() that something may have changed.
142 *
143 * can be called from another thread then poll_one().
144 */
145 void notify() override {
146 if (!is_open()) return;
147
148 // optimization idea:
149 //
150 // if notify() runs in the same thread as poll_one() runs in,
151 // then there is no need to interrupt the poll_one() as it couldn't be
152 // running
153 //
154 // it would save the poll_one(), read(), write() call.
155
157 ssize_t res;
158 do {
159 uint64_t one{1};
160 res = ::write(notify_fd_, &one, sizeof(one));
161 // retry if interrupted
162 } while ((res == -1) && (errno == EINTR));
163 } else {
164 ssize_t res;
165 do {
166 res = ::write(wakeup_fds_.second, ".", 1);
167 // retry if interrupted
168 } while ((res == -1) && (errno == EINTR));
169 }
170 }
171
174 remove_fd(wakeup_fds_.first);
175
178 }
179
183 }
184
188 }
189
193 }
194
195 return {};
196 }
197
199 public:
202 bool oneshot) {
203 uint32_t new_events{};
204 switch (wt) {
206 new_events = EPOLLIN;
207 break;
209 new_events = EPOLLOUT;
210 break;
212 new_events = EPOLLERR | EPOLLHUP;
213 break;
214 }
215
216 epoll_event ev{};
217 ev.data.fd = fd;
218 new_events |= EPOLLET;
219
220 if (oneshot) {
221 new_events |= EPOLLONESHOT;
222 }
223
224 auto &b = bucket(fd);
225
226 std::lock_guard<std::mutex> lk(b.mtx_);
227 const auto it = b.interest_.find(fd);
228
229 auto old_events = (it == b.interest_.end()) ? 0 : it->second;
230 auto merged_events = new_events | old_events;
231
232 // the events passed to epoll should only contain IN|OUT
233 ev.events = merged_events & ~kAlwaysEnabledEvents;
234
235 if ((old_events & kAllEvents) == 0) {
236 // no events where registered before, add.
237 const auto ctl_res =
239 if (!ctl_res) return ctl_res;
240 } else {
241 const auto ctl_res =
243 if (!ctl_res) return ctl_res;
244 }
245
246 // the tracked events should contain IN|OUT|ERR|HUP
247 if (it != b.interest_.end()) {
248 it->second = merged_events;
249 } else {
250 b.interest_.emplace(fd, merged_events);
251 }
252
253 return {};
254 }
255
258 auto &b = bucket(fd);
259 // std::cerr << __LINE__ << ": del: " << fd << std::endl;
260
261 std::lock_guard<std::mutex> lk(b.mtx_);
262
263 // may be called from another thread through ->cancel()
264 const auto it = b.interest_.find(fd);
265 if (it != b.interest_.end()) {
266 if ((it->second & kAllEvents) != 0) {
267 auto epoll_ctl_res =
268 impl::epoll::ctl(epfd, impl::epoll::Cmd::del, fd, nullptr);
269 if (!epoll_ctl_res) return epoll_ctl_res;
270 }
271
272 b.interest_.erase(it);
273 } else {
274 // return ENOENT as epoll_ctl() would do
275 return stdx::unexpected(
276 make_error_code(std::errc::no_such_file_or_directory));
277 }
278
279 return {};
280 }
281
282 // remove interest for revent from file-descriptor.
284 int epfd, native_handle_type fd, uint32_t revent) {
285 auto &b = bucket(fd);
286
287 std::lock_guard<std::mutex> lk(b.mtx_);
288
289 const auto it = b.interest_.find(fd);
290 if (it == b.interest_.end()) {
291 // return ENOENT as epoll_ctl() would do
292 return stdx::unexpected(
293 make_error_code(std::errc::no_such_file_or_directory));
294 }
295
296 // fd is found
297 auto &interest = *it;
298
299 // one-shot-events which fired
300 const auto fd_events = revent & kAllEvents;
301 const auto updated_fd_events = interest.second & ~fd_events;
302
303 if ((updated_fd_events & kSettableEvents) != 0) {
304 epoll_event ev{};
305 ev.data.fd = fd;
306 ev.events = updated_fd_events & ~kAlwaysEnabledEvents;
307
308 const auto ctl_res =
310 if (!ctl_res) return stdx::unexpected(ctl_res.error());
311 } else if ((updated_fd_events & kAllEvents) == 0) {
312 const auto ctl_res =
313 impl::epoll::ctl(epfd, impl::epoll::Cmd::del, fd, nullptr);
314 if (!ctl_res) return stdx::unexpected(ctl_res.error());
315 }
316
317 interest.second = updated_fd_events;
318
319 return {};
320 }
321
322 /**
323 * update registered fd-interest after a oneshot event fired.
324 */
326 int epfd, native_handle_type fd, uint32_t revent) {
327 auto &b = bucket(fd);
328
329 std::lock_guard<std::mutex> lk(b.mtx_);
330
331 const auto it = b.interest_.find(fd);
332 if (it == b.interest_.end()) {
333 // return ENOENT as epoll_ctl() would do
334 return stdx::unexpected(
335 make_error_code(std::errc::no_such_file_or_directory));
336 }
337
338 auto &interest = *it;
339
340 if (!(interest.second & EPOLLONESHOT)) {
341 // not a oneshot event. The interest hasn't changed.
342 return {};
343 }
344
345 // check that the one-shot-events IN and OUT are expected and tracked.
346 //
347 // interest | revent | result
348 // -----------+----------+-------
349 // {} | {IN} | Fail
350 // {} | {OUT} | Fail
351 // {} | {IN,OUT} | Fail
352 // {} | {ERR} | Ok({})
353 // {} | {IN,ERR} | Fail
354 // {IN} | {IN} | Ok({})
355 // {IN} | {OUT} | Fail
356 // {IN} | {IN,OUT} | Fail
357 // {IN} | {ERR} | Ok({IN})
358 // {IN} | {IN,ERR} | Ok({})
359 // {IN,OUT} | {IN} | Ok({OUT})
360 // {IN,OUT} | {OUT} | Ok({IN})
361 // {IN,OUT} | {IN,OUT} | Ok({})
362 // {IN,OUT} | {ERR} | Ok({IN,OUT})
363 // {IN,OUT} | {IN,ERR} | Ok({OUT})
364
365 // events which fired
366 const auto fd_events = revent & kAllEvents;
367
368 // events that we are interested in.
369 const auto fd_interest = interest.second & kAllEvents;
370
371 if (fd_events != 0 && //
372 (fd_events & fd_interest) == 0) {
373 std::cerr << "after_event_fired(" << fd << ", "
374 << std::bitset<32>(fd_events) << ") not in "
375 << std::bitset<32>(fd_interest) << std::endl;
376 return stdx::unexpected(
377 make_error_code(std::errc::argument_out_of_domain));
378 }
379
380 // update the fd-interest
381 const auto updated_fd_events = interest.second & ~fd_events;
382
383 if ((updated_fd_events & kSettableEvents) != 0) {
384 // if a one shot event with multiple waiting events fired for one of the
385 // events, it removes all interests for the fd.
386 //
387 // waiting for: IN|OUT
388 // fires: IN
389 // epoll.interesting:0
390 // not fired: OUT
391 //
392 // add back the events that have not fired yet.
393 epoll_event ev{};
394 ev.data.fd = fd;
395 ev.events = updated_fd_events & ~kAlwaysEnabledEvents;
396
397 const auto ctl_res =
399 if (!ctl_res) return stdx::unexpected(ctl_res.error());
400 } else if ((updated_fd_events & kAllEvents) == 0) {
401 // no interest anymore.
402 const auto ctl_res =
403 impl::epoll::ctl(epfd, impl::epoll::Cmd::del, fd, nullptr);
404 if (!ctl_res) return stdx::unexpected(ctl_res.error());
405 }
406
407 interest.second = updated_fd_events;
408
409 return {};
410 }
411
412 std::optional<int32_t> interest(native_handle_type fd) const {
413 auto &b = bucket(fd);
414
415 std::lock_guard<std::mutex> lk(b.mtx_);
416
417 const auto it = b.interest_.find(fd);
418 if (it != b.interest_.end()) {
419 return it->second;
420 } else {
421 return std::nullopt;
422 }
423 }
424
425 private:
426 // segmented map of fd-to-interest
427 //
428 // allows to split the map and the mutex
430 mutable std::mutex mtx_;
431 std::unordered_map<impl::socket::native_handle_type, uint32_t> interest_;
432 };
433
434 // get locked bucket by file-descriptor.
436 const size_t ndx = fd % buckets_.size();
437
438 return buckets_[ndx];
439 }
440
442 const size_t ndx = fd % buckets_.size();
443
444 return buckets_[ndx];
445 }
446
447 // segment the fd-to-interest map into N buckets
448 std::array<locked_bucket, 101> buckets_;
449 };
450
453 return registered_events_.merge(epfd_, fd, wt, true);
454 }
455
458 return registered_events_.merge(epfd_, fd, wt, false);
459 }
460
462 native_handle_type fd) override {
463 std::lock_guard lk(fd_events_mtx_);
464 auto res = registered_events_.erase(epfd_, fd);
465 if (res) {
466 // remove all events which are already fetched by poll_one()
467 for (size_t ndx = fd_events_processed_; ndx < fd_events_size_;) {
468 auto ev = fd_events_[ndx];
469
470 if (ev.data.fd == fd) {
471 // found one, move it to the end and throw away this one.
472 if (ndx != fd_events_size_ - 1) {
474 }
475
477 } else {
478 ++ndx;
479 }
480 }
481 }
482
483 return res;
484 }
485
487 native_handle_type fd, uint32_t revents) {
488 return registered_events_.remove_fd_interest(epfd_, fd, revents);
489 }
490
491 /**
492 * get current fd-interest.
493 *
494 * @returns fd-interest as bitmask of raw EPOLL* flags
495 */
496 std::optional<int32_t> interest(native_handle_type fd) const {
497 return registered_events_.interest(fd);
498 }
499
501 size_t ndx = fd_events_processed_;
502
503 auto ev = fd_events_[ndx];
504
505 // if there are multiple events:
506 // - OUT before IN.
507 // - IN before ERR|HUP.
508 // - ERR before HUP.
509 short revent{};
510 if (ev.events & EPOLLOUT) {
511 fd_events_[ndx].events &= ~EPOLLOUT;
512 revent = EPOLLOUT;
513 } else if (ev.events & EPOLLIN) {
514 fd_events_[ndx].events &= ~EPOLLIN;
515 revent = EPOLLIN;
516 } else if (ev.events & EPOLLERR) {
517 fd_events_[ndx].events &= ~EPOLLERR;
518 revent = EPOLLERR;
519 } else if (ev.events & EPOLLHUP) {
520 fd_events_[ndx].events &= ~EPOLLHUP;
521 revent = EPOLLHUP;
522 }
523
524 // all interesting events processed, go the next one.
525 if ((fd_events_[ndx].events & (EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP)) ==
526 0) {
528 }
529
530 return fd_event{ev.data.fd, revent};
531 }
532
534 std::chrono::milliseconds timeout) {
536 MY_COMPILER_GCC_DIAGNOSTIC_IGNORE("-Wmaybe-uninitialized")
537
538 // not initialized as it is write-only to by epoll::wait().
539 decltype(fd_events_) evs;
540
541 auto res = impl::epoll::wait(epfd_, evs.data(), evs.size(), timeout);
543
544 if (!res) return stdx::unexpected(res.error());
545
546 std::lock_guard lk(fd_events_mtx_);
547 // copy the fd-events that were returned.
548 std::copy_n(evs.begin(), *res, fd_events_.begin());
549
551 fd_events_size_ = *res;
552
553 if (fd_events_size_ == 0) {
554 return stdx::unexpected(make_error_code(std::errc::timed_out));
555 }
556
557 for (size_t ndx{}; ndx < fd_events_size_; ++ndx) {
558 const ::epoll_event ev = fd_events_[ndx];
559
560 auto after_res = after_event_fired(epfd_, ev.data.fd, ev.events);
561 if (!after_res) {
563 oss << "after_event_fired(" << ev.data.fd << ", "
564 << std::bitset<32>(ev.events) << ") " << after_res.error() << " "
565 << after_res.error().message() << std::endl;
566 std::cerr << oss.str();
567 }
568 }
569
570 return pop_event();
571 }
572
573 /**
574 * poll one event from the registered fd-interest.
575 *
576 * removes the interest of the event that fired
577 *
578 * @param timeout wait at most timeout milliseconds
579 *
580 * @returns fd_event which fired
581 * @retval std::errc::timed_out in case of timeout
582 */
584 std::chrono::milliseconds timeout) override {
585 if (!is_open()) {
586 return stdx::unexpected(make_error_code(std::errc::invalid_argument));
587 }
588
589 auto ev_res = [this]() -> stdx::expected<fd_event, std::error_code> {
590 std::lock_guard lk(fd_events_mtx_);
591
593 // no event.
594 return stdx::unexpected(
595 make_error_code(std::errc::no_such_file_or_directory));
596 }
597
598 return pop_event();
599 }();
600
601 if (!ev_res) {
602 if (ev_res.error() == std::errc::no_such_file_or_directory) {
603 ev_res = update_fd_events(timeout);
604 }
605
606 if (!ev_res) return stdx::unexpected(ev_res.error());
607 }
608
609 auto ev = *ev_res;
610
612 ? (ev.fd == notify_fd_)
613 : (ev.fd == wakeup_fds_.first)) {
614 // wakeup fd fired
615 //
616 // - don't remove the interest for it
617 // - report to the caller that we don't have an event yet by saying we got
618 // interrupted
619 on_notify();
620
622 }
623
624 return ev;
625 }
626
627 private:
629
630 // the event-set should be large enough to get a full picture as we otherwise
631 // might starve connections because we fetch a hot set of fds instead of the
632 // full set
633 //
634 // ready-set = [ 1 2 3 4 5 6 ]
635 //
636 // epoll_wait(.., 4, ...) = [ 1 2 3 4 ]
637 // epoll_ctl(MOD, POLLIN, 1)
638 // epoll_ctl(MOD, POLLIN, 2)
639 // epoll_ctl(MOD, POLLIN, 3)
640 // epoll_ctl(MOD, POLLIN, 4)
641 //
642 // ... 1, 2, 3, 4 may become ready in the meantime
643 //
644 // epoll_wait(.., 4, ...) = [ 1 2 3 4 ]
645 //
646 // ... and 5, 6 never get processed.
647 std::mutex fd_events_mtx_;
648 std::array<epoll_event, 8192> fd_events_{};
652
653 std::pair<impl::file::file_handle_type, impl::file::file_handle_type>
655
657
660 uint32_t revents) {
661 return registered_events_.after_event_fired(epfd, fd, revents);
662 }
663};
664} // namespace net
665
666#endif
667#endif
Definition: io_service_base.h:87
impl::socket::native_handle_type native_handle_type
Definition: io_service_base.h:89
Definition: linux_epoll_io_service.h:198
stdx::expected< void, std::error_code > erase(int epfd, native_handle_type fd)
Definition: linux_epoll_io_service.h:256
stdx::expected< void, std::error_code > merge(int epfd, native_handle_type fd, impl::socket::wait_type wt, bool oneshot)
Definition: linux_epoll_io_service.h:200
std::optional< int32_t > interest(native_handle_type fd) const
Definition: linux_epoll_io_service.h:412
const locked_bucket & bucket(native_handle_type fd) const
Definition: linux_epoll_io_service.h:441
stdx::expected< void, std::error_code > after_event_fired(int epfd, native_handle_type fd, uint32_t revent)
update registered fd-interest after a oneshot event fired.
Definition: linux_epoll_io_service.h:325
std::array< locked_bucket, 101 > buckets_
Definition: linux_epoll_io_service.h:448
stdx::expected< void, std::error_code > remove_fd_interest(int epfd, native_handle_type fd, uint32_t revent)
Definition: linux_epoll_io_service.h:283
locked_bucket & bucket(native_handle_type fd)
Definition: linux_epoll_io_service.h:435
Definition: linux_epoll_io_service.h:58
stdx::expected< fd_event, std::error_code > update_fd_events(std::chrono::milliseconds timeout)
Definition: linux_epoll_io_service.h:533
~linux_epoll_io_service() override
Definition: linux_epoll_io_service.h:67
stdx::expected< void, std::error_code > add_fd_interest(native_handle_type fd, impl::socket::wait_type wt) override
Definition: linux_epoll_io_service.h:451
static constexpr const int kAlwaysEnabledEvents
Definition: linux_epoll_io_service.h:63
impl::file::file_handle_type notify_fd_
Definition: linux_epoll_io_service.h:656
stdx::expected< void, std::error_code > add_fd_interest_permanent(native_handle_type fd, impl::socket::wait_type wt)
Definition: linux_epoll_io_service.h:456
size_t fd_events_size_
Definition: linux_epoll_io_service.h:650
static constexpr const int kSettableEvents
Definition: linux_epoll_io_service.h:62
void notify() override
notify the poll_one() that something may have changed.
Definition: linux_epoll_io_service.h:145
stdx::expected< void, std::error_code > after_event_fired(int epfd, native_handle_type fd, uint32_t revents)
Definition: linux_epoll_io_service.h:658
std::mutex fd_events_mtx_
Definition: linux_epoll_io_service.h:647
bool is_open() const noexcept
Definition: linux_epoll_io_service.h:69
FdInterest registered_events_
Definition: linux_epoll_io_service.h:628
void on_notify()
Definition: linux_epoll_io_service.h:116
impl::file::file_handle_type epfd_
Definition: linux_epoll_io_service.h:651
stdx::expected< fd_event, std::error_code > pop_event()
Definition: linux_epoll_io_service.h:500
stdx::expected< fd_event, std::error_code > poll_one(std::chrono::milliseconds timeout) override
poll one event from the registered fd-interest.
Definition: linux_epoll_io_service.h:583
stdx::expected< void, std::error_code > close()
Definition: linux_epoll_io_service.h:172
static constexpr const int kAllEvents
Definition: linux_epoll_io_service.h:64
stdx::expected< void, std::error_code > open() noexcept override
open the io-service.
Definition: linux_epoll_io_service.h:76
std::array< epoll_event, 8192 > fd_events_
Definition: linux_epoll_io_service.h:648
stdx::expected< void, std::error_code > remove_fd(native_handle_type fd) override
Definition: linux_epoll_io_service.h:461
size_t fd_events_processed_
Definition: linux_epoll_io_service.h:649
stdx::expected< void, std::error_code > remove_fd_interest(native_handle_type fd, uint32_t revents)
Definition: linux_epoll_io_service.h:486
std::optional< int32_t > interest(native_handle_type fd) const
get current fd-interest.
Definition: linux_epoll_io_service.h:496
std::pair< impl::file::file_handle_type, impl::file::file_handle_type > wakeup_fds_
Definition: linux_epoll_io_service.h:654
Definition: expected.h:286
static char buf[MAX_BUF]
Definition: conf_to_src.cc:73
if(!(yy_init))
Definition: lexyy.cc:1144
Header for compiler-dependent features.
#define MY_COMPILER_GCC_DIAGNOSTIC_IGNORE(X)
Definition: my_compiler.h:242
#define MY_COMPILER_DIAGNOSTIC_PUSH()
save the compiler's diagnostic (enabled warnings, errors, ...) state
Definition: my_compiler.h:277
#define MY_COMPILER_DIAGNOSTIC_POP()
restore the compiler's diagnostic (enabled warnings, errors, ...) state
Definition: my_compiler.h:278
static bool interrupted
Definition: mysqladmin.cc:72
Definition: buf0block_hint.cc:30
static bool timeout(bool(*wait_condition)())
Timeout function.
Definition: log0meb.cc:498
stdx::expected< void, std::error_code > ctl(int epfd, Cmd cmd, int fd, epoll_event *ev)
Definition: linux_epoll.h:71
stdx::expected< int, std::error_code > create()
Definition: linux_epoll.h:60
stdx::expected< size_t, std::error_code > wait(int epfd, epoll_event *fd_events, size_t num_fd_events, std::chrono::milliseconds timeout)
Definition: linux_epoll.h:81
int file_handle_type
Definition: file.h:53
constexpr file_handle_type kInvalidHandle
Definition: file.h:54
stdx::expected< std::pair< file_handle_type, file_handle_type >, std::error_code > pipe(int flags=0)
create pipe.
Definition: file.h:144
stdx::expected< void, std::error_code > close(file_handle_type native_handle)
close file handle.
Definition: file.h:239
wait_type
Definition: socket_constants.h:86
stdx::expected< bool, error_type > native_non_blocking(native_handle_type native_handle)
Definition: socket.h:106
int native_handle_type
Definition: socket_constants.h:51
Definition: buffer.h:45
stdx::expected< size_t, std::error_code > write(SyncWriteStream &stream, const ConstBufferSequence &buffers)
Definition: buffer.h:977
stdx::expected< size_t, std::error_code > read(SyncReadStream &stream, const MutableBufferSequence &buffers)
Definition: buffer.h:835
std::error_code make_error_code(net::stream_errc e) noexcept
Definition: buffer.h:103
unexpected(E) -> unexpected< E >
std::basic_ostringstream< char, std::char_traits< char >, ut::allocator< char > > ostringstream
Specialization of basic_ostringstream which uses ut::allocator.
Definition: ut0new.h:2872
static void swap(String &a, String &b) noexcept
Definition: sql_string.h:663
Definition: io_service_base.h:69
native_handle_type fd
Definition: io_service_base.h:75
Definition: linux_epoll_io_service.h:429
std::mutex mtx_
Definition: linux_epoll_io_service.h:430
std::unordered_map< impl::socket::native_handle_type, uint32_t > interest_
Definition: linux_epoll_io_service.h:431