[CCF Archive] Store object type eviction policy submission #3

Closed
kancel wants to merge 382 commits from kancel:ccf-archive-pr2746 into main
4 changed files with 90 additions and 2 deletions
Showing only changes of commit 474f67852a - Show all commits

View File

@ -295,6 +295,7 @@ For advanced users, TransferEngine provides the following advanced runtime optio
- `MC_LOG_LEVEL` This option can be set as `TRACE`/`INFO`/`WARNING`/`ERROR` (see [glog doc](https://github.com/google/glog/blob/master/docs/logging.md)), and more detailed logs will be output during runtime
- `MC_DISABLE_METACACHE` Disable local meta cache to prevent transfer failure due to dynamic memory registrations, which may downgrades the performance
- `MC_HANDSHAKE_LISTEN_BACKLOG` The backlog size of socket listening for handshaking, default value is 128
- `MC_HANDSHAKE_CONNECT_TIMEOUT` Connect timeout in seconds for outbound handshake-port requests (QP handshake, probe, notify, metadata exchange), default value is 5. Bounds the stall when the peer address is unreachable; without it, a connect to an unroutable address (e.g. a removed node) blocks for the kernel's full TCP SYN retry cycle, which can take minutes
- `MC_HANDSHAKE_MAX_LENGTH` The maximum handshake message length in bytes for P2P mode. Valid range: 1MB to 128MB. Default value is 1MB (1048576 bytes). Increase this value when using a single RDMA instance with many registered memory buffers (>10,000) to avoid handshake failures. Example: set to 10485760 for 10MB
- `MC_LOG_DIR` Specify the directory path for log redirection files. If invalid, log to stderr instead.
- `MC_REDIS_PASSWORD` The password for Redis storage plugin, only takes effect when Redis is specified as the metadata server. If not set, no authentication will be attempted to log in to the Redis.

View File

@ -52,6 +52,12 @@ struct GlobalConfig {
int retry_cnt = 9;
int auto_gid_max_retries = 2;
int handshake_listen_backlog = 128;
// Connect timeout (seconds) for outbound handshake-port RPCs (QP
// handshake, probe, notify, metadata exchange). A plain blocking
// connect() has no deadline: to an unroutable address (e.g. a
// torn-down pod IP) it stalls for the kernel's full SYN-retry cycle,
// which is minutes. Override via MC_HANDSHAKE_CONNECT_TIMEOUT.
int handshake_connect_timeout = 5;
bool metacache = true;
int log_level = google::INFO;
bool trace = false;

View File

@ -258,6 +258,17 @@ void loadGlobalConfig(GlobalConfig& config) {
}
}
const char* handshake_connect_timeout =
std::getenv("MC_HANDSHAKE_CONNECT_TIMEOUT");
if (handshake_connect_timeout) {
int val = atoi(handshake_connect_timeout);
if (val > 0 && val < 3600)
config.handshake_connect_timeout = val;
else
LOG(WARNING) << "Ignore value from environment variable "
"MC_HANDSHAKE_CONNECT_TIMEOUT";
}
const char* log_level = std::getenv("MC_LOG_LEVEL");
config.trace = false;
if (log_level) {

View File

@ -16,10 +16,12 @@
#include <arpa/inet.h>
#include <bits/stdint-uintn.h>
#include <fcntl.h>
#include <ifaddrs.h>
#include <json/value.h>
#include <net/if.h>
#include <netdb.h>
#include <poll.h>
#include <sys/socket.h>
#include <random>
@ -960,9 +962,77 @@ struct SocketHandShakePlugin : public HandShakePlugin {
return ERR_SOCKET;
}
// SO_RCVTIMEO does not apply to connect(). A blocking connect() to
// an unroutable address (e.g. a torn-down pod IP) stalls for the
// kernel's full SYN-retry cycle -- minutes -- and this runs on RDMA
// worker threads, where the stall also blocks CQ polling. Connect in
// non-blocking mode and bound the wait with poll().
int flags = fcntl(conn_fd, F_GETFL, 0);
if (flags == -1 || fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
PLOG(ERROR) << "SocketHandShakePlugin: fcntl(O_NONBLOCK)";
close(conn_fd);
return ERR_SOCKET;
}
if (connect(conn_fd, addr->ai_addr, addr->ai_addrlen)) {
PLOG(ERROR) << "SocketHandShakePlugin: connect()"
<< getNetworkAddress(addr->ai_addr);
if (errno != EINPROGRESS) {
PLOG(ERROR) << "SocketHandShakePlugin: connect()"
<< getNetworkAddress(addr->ai_addr);
close(conn_fd);
return ERR_SOCKET;
}
const int64_t deadline_ms =
getCurrentTimeInMilli() +
globalConfig().handshake_connect_timeout * 1000;
struct pollfd pfd;
pfd.fd = conn_fd;
pfd.events = POLLOUT;
while (true) {
const int64_t remaining_ms =
deadline_ms - getCurrentTimeInMilli();
// poll() returning 0 already means the timeout expired; an
// exhausted deadline (only reachable after EINTR) is the
// same condition.
int ret =
remaining_ms <= 0 ? 0 : poll(&pfd, 1, (int)remaining_ms);
if (ret > 0) break;
if (ret == 0) {
errno = ETIMEDOUT;
PLOG(ERROR) << "SocketHandShakePlugin: connect() "
<< getNetworkAddress(addr->ai_addr);
close(conn_fd);
return ERR_SOCKET;
}
if (errno != EINTR) {
PLOG(ERROR) << "SocketHandShakePlugin: poll()";
close(conn_fd);
return ERR_SOCKET;
}
// EINTR: retry with the remaining time.
}
int conn_err = 0;
socklen_t err_len = sizeof(conn_err);
if (getsockopt(conn_fd, SOL_SOCKET, SO_ERROR, &conn_err,
&err_len)) {
PLOG(ERROR) << "SocketHandShakePlugin: getsockopt(SO_ERROR)";
close(conn_fd);
return ERR_SOCKET;
}
if (conn_err) {
errno = conn_err;
PLOG(ERROR) << "SocketHandShakePlugin: connect()"
<< getNetworkAddress(addr->ai_addr);
close(conn_fd);
return ERR_SOCKET;
}
}
// Restore blocking mode; the request/response exchange relies on
// blocking reads bounded by SO_RCVTIMEO.
if (fcntl(conn_fd, F_SETFL, flags) == -1) {
PLOG(ERROR) << "SocketHandShakePlugin: fcntl(restore flags)";
close(conn_fd);
return ERR_SOCKET;
}