grpc 1.55.0 → 1.55.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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