grpc 1.55.0 → 1.55.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -23,7 +23,9 @@
23
23
  #include <sys/socket.h> // IWYU pragma: keep
24
24
  #include <unistd.h> // IWYU pragma: keep
25
25
 
26
+ #include <atomic>
26
27
  #include <string>
28
+ #include <tuple>
27
29
  #include <utility>
28
30
 
29
31
  #include "absl/functional/any_invocable.h"
@@ -41,6 +43,7 @@
41
43
  #include "src/core/lib/event_engine/posix_engine/tcp_socket_utils.h"
42
44
  #include "src/core/lib/event_engine/tcp_socket_utils.h"
43
45
  #include "src/core/lib/gprpp/status_helper.h"
46
+ #include "src/core/lib/gprpp/time.h"
44
47
  #include "src/core/lib/iomgr/socket_mutator.h"
45
48
 
46
49
  namespace grpc_event_engine {
@@ -136,6 +139,32 @@ void PosixEngineListenerImpl::AsyncConnectionAcceptor::NotifyOnAccept(
136
139
  switch (errno) {
137
140
  case EINTR:
138
141
  continue;
142
+ case EMFILE:
143
+ // When the process runs out of fds, accept4() returns EMFILE. When
144
+ // this happens, the connection is left in the accept queue until
145
+ // either a read event triggers the on_read callback, or time has
146
+ // passed and the accept should be re-tried regardless. This callback
147
+ // is not cancelled, so a spurious wakeup may occur even when there's
148
+ // nothing to accept. This is not a performant code path, but if an fd
149
+ // limit has been reached, the system is likely in an unhappy state
150
+ // regardless.
151
+ GRPC_LOG_EVERY_N_SEC(1, GPR_ERROR, "%s",
152
+ "File descriptor limit reached. Retrying.");
153
+ handle_->NotifyOnRead(notify_on_accept_);
154
+ // Do not schedule another timer if one is already armed.
155
+ if (retry_timer_armed_.exchange(true)) return;
156
+ // Hold a ref while the retry timer is waiting, to prevent listener
157
+ // destruction and the races that would ensue.
158
+ Ref();
159
+ std::ignore =
160
+ engine_->RunAfter(grpc_core::Duration::Seconds(1), [this]() {
161
+ retry_timer_armed_.store(false);
162
+ if (!handle_->IsHandleShutdown()) {
163
+ handle_->SetReadable();
164
+ }
165
+ Unref();
166
+ });
167
+ return;
139
168
  case EAGAIN:
140
169
  case ECONNABORTED:
141
170
  handle_->NotifyOnRead(notify_on_accept_);
@@ -121,6 +121,9 @@ class PosixEngineListenerImpl
121
121
  ListenerSocketsContainer::ListenerSocket socket_;
122
122
  EventHandle* handle_;
123
123
  PosixEngineClosure* notify_on_accept_;
124
+ // Tracks the status of a backup timer to retry accept4 calls after file
125
+ // descriptor exhaustion.
126
+ std::atomic<bool> retry_timer_armed_{false};
124
127
  };
125
128
  class ListenerAsyncAcceptors : public ListenerSocketsContainer {
126
129
  public:
@@ -16,13 +16,17 @@
16
16
  //
17
17
  //
18
18
 
19
+ #include <grpc/support/port_platform.h>
20
+
21
+ #include <utility>
22
+
23
+ #include <grpc/support/atm.h>
24
+
19
25
  // FIXME: "posix" files shouldn't be depending on _GNU_SOURCE
20
26
  #ifndef _GNU_SOURCE
21
27
  #define _GNU_SOURCE
22
28
  #endif
23
29
 
24
- #include <grpc/support/port_platform.h>
25
-
26
30
  #include "src/core/lib/iomgr/port.h"
27
31
 
28
32
  #ifdef GRPC_POSIX_SOCKET_TCP_SERVER
@@ -45,6 +49,7 @@
45
49
 
46
50
  #include <grpc/byte_buffer.h>
47
51
  #include <grpc/event_engine/endpoint_config.h>
52
+ #include <grpc/event_engine/event_engine.h>
48
53
  #include <grpc/support/alloc.h>
49
54
  #include <grpc/support/log.h>
50
55
  #include <grpc/support/sync.h>
@@ -75,6 +80,8 @@
75
80
  #include "src/core/lib/transport/error_utils.h"
76
81
 
77
82
  static std::atomic<int64_t> num_dropped_connections{0};
83
+ static constexpr grpc_core::Duration kRetryAcceptWaitTime{
84
+ grpc_core::Duration::Seconds(1)};
78
85
 
79
86
  using ::grpc_event_engine::experimental::EndpointConfig;
80
87
  using ::grpc_event_engine::experimental::EventEngine;
@@ -339,22 +346,38 @@ static void on_read(void* arg, grpc_error_handle err) {
339
346
  if (fd < 0) {
340
347
  if (errno == EINTR) {
341
348
  continue;
342
- } else if (errno == EAGAIN || errno == ECONNABORTED ||
343
- errno == EWOULDBLOCK) {
349
+ }
350
+ // When the process runs out of fds, accept4() returns EMFILE. When this
351
+ // happens, the connection is left in the accept queue until either a
352
+ // read event triggers the on_read callback, or time has passed and the
353
+ // accept should be re-tried regardless. This callback is not cancelled,
354
+ // so a spurious wakeup may occur even when there's nothing to accept.
355
+ // This is not a performant code path, but if an fd limit has been
356
+ // reached, the system is likely in an unhappy state regardless.
357
+ if (errno == EMFILE) {
358
+ GRPC_LOG_EVERY_N_SEC(1, GPR_ERROR, "%s",
359
+ "File descriptor limit reached. Retrying.");
360
+ grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
361
+ if (gpr_atm_full_xchg(&sp->retry_timer_armed, true)) return;
362
+ grpc_timer_init(&sp->retry_timer,
363
+ grpc_core::Timestamp::Now() + kRetryAcceptWaitTime,
364
+ &sp->retry_closure);
365
+ return;
366
+ }
367
+ if (errno == EAGAIN || errno == ECONNABORTED || errno == EWOULDBLOCK) {
344
368
  grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
345
369
  return;
370
+ }
371
+ gpr_mu_lock(&sp->server->mu);
372
+ if (!sp->server->shutdown_listeners) {
373
+ gpr_log(GPR_ERROR, "Failed accept4: %s",
374
+ grpc_core::StrError(errno).c_str());
346
375
  } else {
347
- gpr_mu_lock(&sp->server->mu);
348
- if (!sp->server->shutdown_listeners) {
349
- gpr_log(GPR_ERROR, "Failed accept4: %s",
350
- grpc_core::StrError(errno).c_str());
351
- } else {
352
- // if we have shutdown listeners, accept4 could fail, and we
353
- // needn't notify users
354
- }
355
- gpr_mu_unlock(&sp->server->mu);
356
- goto error;
376
+ // if we have shutdown listeners, accept4 could fail, and we
377
+ // needn't notify users
357
378
  }
379
+ gpr_mu_unlock(&sp->server->mu);
380
+ goto error;
358
381
  }
359
382
 
360
383
  if (sp->server->memory_quota->IsMemoryPressureHigh()) {
@@ -547,6 +570,7 @@ static grpc_error_handle clone_port(grpc_tcp_listener* listener,
547
570
  sp->port_index = listener->port_index;
548
571
  sp->fd_index = listener->fd_index + count - i;
549
572
  GPR_ASSERT(sp->emfd);
573
+ grpc_tcp_server_listener_initialize_retry_timer(sp);
550
574
  while (listener->server->tail->next != nullptr) {
551
575
  listener->server->tail = listener->server->tail->next;
552
576
  }
@@ -780,6 +804,7 @@ static void tcp_server_shutdown_listeners(grpc_tcp_server* s) {
780
804
  if (s->active_ports) {
781
805
  grpc_tcp_listener* sp;
782
806
  for (sp = s->head; sp; sp = sp->next) {
807
+ grpc_timer_cancel(&sp->retry_timer);
783
808
  grpc_fd_shutdown(sp->emfd, GRPC_ERROR_CREATE("Server shutdown"));
784
809
  }
785
810
  }
@@ -30,6 +30,7 @@
30
30
  #include "src/core/lib/iomgr/resolve_address.h"
31
31
  #include "src/core/lib/iomgr/socket_utils_posix.h"
32
32
  #include "src/core/lib/iomgr/tcp_server.h"
33
+ #include "src/core/lib/iomgr/timer.h"
33
34
  #include "src/core/lib/resource_quota/memory_quota.h"
34
35
 
35
36
  // one listening port
@@ -52,6 +53,11 @@ typedef struct grpc_tcp_listener {
52
53
  // identified while iterating through 'next'.
53
54
  struct grpc_tcp_listener* sibling;
54
55
  int is_sibling;
56
+ // If an accept4() call fails, a timer is started to drain the accept queue in
57
+ // case no further connection attempts reach the gRPC server.
58
+ grpc_closure retry_closure;
59
+ grpc_timer retry_timer;
60
+ gpr_atm retry_timer_armed;
55
61
  } grpc_tcp_listener;
56
62
 
57
63
  // the overall server
@@ -139,4 +145,10 @@ grpc_error_handle grpc_tcp_server_prepare_socket(
139
145
  // Ruturn true if the platform supports ifaddrs
140
146
  bool grpc_tcp_server_have_ifaddrs(void);
141
147
 
148
+ // Initialize (but don't start) the timer and callback to retry accept4() on a
149
+ // listening socket after file descriptors have been exhausted. This must be
150
+ // called when creating a new listener.
151
+ void grpc_tcp_server_listener_initialize_retry_timer(
152
+ grpc_tcp_listener* listener);
153
+
142
154
  #endif // GRPC_SRC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H
@@ -18,6 +18,8 @@
18
18
 
19
19
  #include <grpc/support/port_platform.h>
20
20
 
21
+ #include <grpc/support/atm.h>
22
+
21
23
  #include "src/core/lib/iomgr/port.h"
22
24
 
23
25
  #ifdef GRPC_POSIX_SOCKET_TCP_SERVER_UTILS_COMMON
@@ -81,6 +83,24 @@ static int get_max_accept_queue_size(void) {
81
83
  return s_max_accept_queue_size;
82
84
  }
83
85
 
86
+ static void listener_retry_timer_cb(void* arg, grpc_error_handle err) {
87
+ // Do nothing if cancelled.
88
+ if (!err.ok()) return;
89
+ grpc_tcp_listener* listener = static_cast<grpc_tcp_listener*>(arg);
90
+ gpr_atm_no_barrier_store(&listener->retry_timer_armed, false);
91
+ if (!grpc_fd_is_shutdown(listener->emfd)) {
92
+ grpc_fd_set_readable(listener->emfd);
93
+ }
94
+ }
95
+
96
+ void grpc_tcp_server_listener_initialize_retry_timer(
97
+ grpc_tcp_listener* listener) {
98
+ gpr_atm_no_barrier_store(&listener->retry_timer_armed, false);
99
+ grpc_timer_init_unset(&listener->retry_timer);
100
+ GRPC_CLOSURE_INIT(&listener->retry_closure, listener_retry_timer_cb, listener,
101
+ grpc_schedule_on_exec_ctx);
102
+ }
103
+
84
104
  static grpc_error_handle add_socket_to_server(grpc_tcp_server* s, int fd,
85
105
  const grpc_resolved_address* addr,
86
106
  unsigned port_index,
@@ -112,6 +132,7 @@ static grpc_error_handle add_socket_to_server(grpc_tcp_server* s, int fd,
112
132
  sp->server = s;
113
133
  sp->fd = fd;
114
134
  sp->emfd = grpc_fd_create(fd, name.c_str(), true);
135
+ grpc_tcp_server_listener_initialize_retry_timer(sp);
115
136
 
116
137
  // Check and set fd as prellocated
117
138
  if (grpc_tcp_server_pre_allocated_fd(s) == fd) {
@@ -21,8 +21,6 @@
21
21
  #include "src/core/lib/surface/validate_metadata.h"
22
22
 
23
23
  #include "absl/status/status.h"
24
- #include "absl/strings/escaping.h"
25
- #include "absl/strings/str_cat.h"
26
24
  #include "absl/strings/string_view.h"
27
25
 
28
26
  #include <grpc/grpc.h>
@@ -46,32 +44,49 @@ class LegalHeaderKeyBits : public BitSet<256> {
46
44
  };
47
45
  constexpr LegalHeaderKeyBits g_legal_header_key_bits;
48
46
 
49
- GPR_ATTRIBUTE_NOINLINE
50
- absl::Status DoesNotConformTo(absl::string_view x, const char* err_desc) {
51
- return absl::InternalError(absl::StrCat(err_desc, ": ", x, " (hex ",
52
- absl::BytesToHexString(x), ")"));
53
- }
54
-
55
- absl::Status ConformsTo(absl::string_view x, const BitSet<256>& legal_bits,
56
- const char* err_desc) {
47
+ ValidateMetadataResult ConformsTo(absl::string_view x,
48
+ const BitSet<256>& legal_bits,
49
+ ValidateMetadataResult error) {
57
50
  for (uint8_t c : x) {
58
51
  if (!legal_bits.is_set(c)) {
59
- return DoesNotConformTo(x, err_desc);
52
+ return error;
60
53
  }
61
54
  }
62
- return absl::OkStatus();
55
+ return ValidateMetadataResult::kOk;
56
+ }
57
+
58
+ absl::Status UpgradeToStatus(ValidateMetadataResult result) {
59
+ if (result == ValidateMetadataResult::kOk) return absl::OkStatus();
60
+ return absl::InternalError(ValidateMetadataResultToString(result));
63
61
  }
62
+
64
63
  } // namespace
65
64
 
66
- absl::Status ValidateHeaderKeyIsLegal(absl::string_view key) {
65
+ ValidateMetadataResult ValidateHeaderKeyIsLegal(absl::string_view key) {
67
66
  if (key.empty()) {
68
- return absl::InternalError("Metadata keys cannot be zero length");
67
+ return ValidateMetadataResult::kCannotBeZeroLength;
69
68
  }
70
69
  if (key.size() > UINT32_MAX) {
71
- return absl::InternalError(
72
- "Metadata keys cannot be larger than UINT32_MAX");
70
+ return ValidateMetadataResult::kTooLong;
71
+ }
72
+ return ConformsTo(key, g_legal_header_key_bits,
73
+ ValidateMetadataResult::kIllegalHeaderKey);
74
+ }
75
+
76
+ const char* ValidateMetadataResultToString(ValidateMetadataResult result) {
77
+ switch (result) {
78
+ case ValidateMetadataResult::kOk:
79
+ return "Ok";
80
+ case ValidateMetadataResult::kCannotBeZeroLength:
81
+ return "Metadata keys cannot be zero length";
82
+ case ValidateMetadataResult::kTooLong:
83
+ return "Metadata keys cannot be larger than UINT32_MAX";
84
+ case ValidateMetadataResult::kIllegalHeaderKey:
85
+ return "Illegal header key";
86
+ case ValidateMetadataResult::kIllegalHeaderValue:
87
+ return "Illegal header value";
73
88
  }
74
- return ConformsTo(key, g_legal_header_key_bits, "Illegal header key");
89
+ GPR_UNREACHABLE_CODE(return "Unknown");
75
90
  }
76
91
 
77
92
  } // namespace grpc_core
@@ -82,8 +97,8 @@ static int error2int(grpc_error_handle error) {
82
97
  }
83
98
 
84
99
  grpc_error_handle grpc_validate_header_key_is_legal(const grpc_slice& slice) {
85
- return grpc_core::ValidateHeaderKeyIsLegal(
86
- grpc_core::StringViewFromSlice(slice));
100
+ return grpc_core::UpgradeToStatus(grpc_core::ValidateHeaderKeyIsLegal(
101
+ grpc_core::StringViewFromSlice(slice)));
87
102
  }
88
103
 
89
104
  int grpc_header_key_is_legal(grpc_slice slice) {
@@ -104,9 +119,9 @@ constexpr LegalHeaderNonBinValueBits g_legal_header_non_bin_value_bits;
104
119
 
105
120
  grpc_error_handle grpc_validate_header_nonbin_value_is_legal(
106
121
  const grpc_slice& slice) {
107
- return grpc_core::ConformsTo(grpc_core::StringViewFromSlice(slice),
108
- g_legal_header_non_bin_value_bits,
109
- "Illegal header value");
122
+ return grpc_core::UpgradeToStatus(grpc_core::ConformsTo(
123
+ grpc_core::StringViewFromSlice(slice), g_legal_header_non_bin_value_bits,
124
+ grpc_core::ValidateMetadataResult::kIllegalHeaderValue));
110
125
  }
111
126
 
112
127
  int grpc_header_nonbin_value_is_legal(grpc_slice slice) {
@@ -25,7 +25,6 @@
25
25
 
26
26
  #include <cstring>
27
27
 
28
- #include "absl/status/status.h"
29
28
  #include "absl/strings/string_view.h"
30
29
 
31
30
  #include <grpc/slice.h>
@@ -35,9 +34,20 @@
35
34
 
36
35
  namespace grpc_core {
37
36
 
38
- absl::Status ValidateHeaderKeyIsLegal(absl::string_view key);
37
+ enum class ValidateMetadataResult : uint8_t {
38
+ kOk,
39
+ kCannotBeZeroLength,
40
+ kTooLong,
41
+ kIllegalHeaderKey,
42
+ kIllegalHeaderValue
43
+ };
39
44
 
40
- }
45
+ const char* ValidateMetadataResultToString(ValidateMetadataResult result);
46
+
47
+ // Returns nullopt if the key is legal, otherwise returns an error message.
48
+ ValidateMetadataResult ValidateHeaderKeyIsLegal(absl::string_view key);
49
+
50
+ } // namespace grpc_core
41
51
 
42
52
  grpc_error_handle grpc_validate_header_key_is_legal(const grpc_slice& slice);
43
53
  grpc_error_handle grpc_validate_header_nonbin_value_is_legal(
@@ -14,5 +14,5 @@
14
14
 
15
15
  # GRPC contains the General RPC module.
16
16
  module GRPC
17
- VERSION = '1.55.0'
17
+ VERSION = '1.55.3'
18
18
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grpc
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.55.0
4
+ version: 1.55.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - gRPC Authors
8
8
  autorequire:
9
9
  bindir: src/ruby/bin
10
10
  cert_chain: []
11
- date: 2023-05-19 00:00:00.000000000 Z
11
+ date: 2023-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: google-protobuf
@@ -462,6 +462,8 @@ files:
462
462
  - src/core/ext/transport/chttp2/transport/hpack_encoder.h
463
463
  - src/core/ext/transport/chttp2/transport/hpack_encoder_table.cc
464
464
  - src/core/ext/transport/chttp2/transport/hpack_encoder_table.h
465
+ - src/core/ext/transport/chttp2/transport/hpack_parse_result.cc
466
+ - src/core/ext/transport/chttp2/transport/hpack_parse_result.h
465
467
  - src/core/ext/transport/chttp2/transport/hpack_parser.cc
466
468
  - src/core/ext/transport/chttp2/transport/hpack_parser.h
467
469
  - src/core/ext/transport/chttp2/transport/hpack_parser_table.cc
@@ -3208,7 +3210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
3208
3210
  - !ruby/object:Gem::Version
3209
3211
  version: '0'
3210
3212
  requirements: []
3211
- rubygems_version: 3.4.13
3213
+ rubygems_version: 3.4.17
3212
3214
  signing_key:
3213
3215
  specification_version: 4
3214
3216
  summary: GRPC system in Ruby