From f161e22f82ecb692eae903a535c3f99533e3eaeb Mon Sep 17 00:00:00 2001 From: uhm0311 Date: Mon, 1 Apr 2024 16:29:05 +0900 Subject: [PATCH] FEATURE: Add stats_tcp_retrans() --- Makefile.am | 2 + include/memcached/types.h | 1 + memcached.c | 5 ++ memcached.h | 3 + stats.c | 140 ++++++++++++++++++++++++++++++++++++++ stats.h | 22 ++++++ stats_prefix.h | 2 +- 7 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 stats.c create mode 100644 stats.h diff --git a/Makefile.am b/Makefile.am index b6aab092e..b9699dd60 100644 --- a/Makefile.am +++ b/Makefile.am @@ -81,6 +81,8 @@ memcached_SOURCES = \ sasl_defs.h \ stats_prefix.c \ stats_prefix.h \ + stats.c \ + stats.h \ thread.c \ thread.h \ mc_util.c \ diff --git a/include/memcached/types.h b/include/memcached/types.h index 82e4612e5..7bf22a164 100644 --- a/include/memcached/types.h +++ b/include/memcached/types.h @@ -40,6 +40,7 @@ struct iovec { #define SUPPORT_BOP_SMGET #define JHPARK_OLD_SMGET_INTERFACE #define MULTI_NOTIFY_IO_COMPLETE +#define STATS_TCP_RETRANS #ifdef __cplusplus extern "C" { diff --git a/memcached.c b/memcached.c index 5fe19b54b..e36c1e40a 100644 --- a/memcached.c +++ b/memcached.c @@ -8092,6 +8092,11 @@ static void server_stats(ADD_STAT add_stats, conn *c, bool aggregate) APPEND_STAT("limit_maxconns", "%d", settings.maxconns); APPEND_STAT("threads", "%d", settings.num_threads); APPEND_STAT("conn_yields", "%"PRIu64, thread_stats.conn_yields); +#ifdef STATS_TCP_RETRANS + if (IS_TCP(c->transport)) { + APPEND_STAT("tcp_retrans", "%ld", stats_tcp_retrans()); + } +#endif UNLOCK_STATS(); } diff --git a/memcached.h b/memcached.h index 059bf84f7..30b3d0143 100644 --- a/memcached.h +++ b/memcached.h @@ -190,6 +190,8 @@ enum network_transport { udp_transport }; +#define IS_TCP(x) (x == tcp_transport) + #define IS_UDP(x) (x == udp_transport) /** @@ -575,6 +577,7 @@ extern int daemonize(int nochdir, int noclose); #endif #include "stats_prefix.h" +#include "stats.h" #include "trace.h" #include "hash.h" #include diff --git a/stats.c b/stats.c new file mode 100644 index 000000000..57f90c091 --- /dev/null +++ b/stats.c @@ -0,0 +1,140 @@ +/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * arcus-memcached - Arcus memory cache server + * Copyright 2010-2014 NAVER Corp. + * Copyright 2015 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Detailed statistics management. For simple stats like total number of + * "get" requests, we use inline code in memcached.c and friends, but when + * stats detail mode is activated, the code here records more information. + * + * Author: + * Steven Grimm + */ +#include "config.h" +#include "memcached.h" + +#ifdef STATS_TCP_RETRANS +#include +#include +#include + +static void rtrim(char **src) { + if (src == NULL || *src == NULL || strlen(*src) == 0) { + return; + } + + char *str = *src; + for (int i = strlen(str) - 1; i >= 0; i--) { + if (!isspace(str[i])) { + break; + } + + str[i] = '\0'; + } + + *src = str; +} + +int64_t stats_tcp_retrans(void) { + char *key_line = NULL; + char *value_line = NULL; + uint64_t tcp_retrans = -1; + + FILE *fp = fopen("/proc/net/snmp", "r"); + if (fp == NULL) { + goto done; + } + + size_t key_len = 0; + size_t value_len = 0; + ssize_t key_read = -1; + ssize_t value_read = -1; + + char *prefix = "Tcp:"; + size_t prefix_len = strlen(prefix); + + while ((key_read = getline(&key_line, &key_len, fp)) != -1) { + if (strncmp(prefix, key_line, prefix_len) != 0) { + continue; + } + + if ((value_read = getline(&value_line, &value_len, fp)) != -1) { + break; + } + } + + if (key_read < 0 || value_read < 0) { + goto done; + } + + /* + * below lines are examples of key_line and value_line. + * for examples below, tcp_retrans = 9814784 + * + * Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors + * Tcp: 1 200 120000 -1 231273424 45758374 43975115 12045288 360 9853401239 10104984649 9814784 12765 17318799 883 + */ + + char *delimiter = " "; + char *retrans_segs = "RetransSegs"; + + char *key_next = NULL; + char *value_next = NULL; + + char *key_token = strtok_r(key_line, delimiter, &key_next); + char *value_token = strtok_r(value_line, delimiter, &value_next); + + // first token is always "Tcp:" + key_token = strtok_r(NULL, delimiter, &key_next); + value_token = strtok_r(NULL, delimiter, &value_next); + + while (key_token && value_token) { + // last token always ends with "\n" + rtrim(&key_token); + rtrim(&value_token); + + if (strcmp(key_token, retrans_segs) == 0) { + char *end = NULL; + errno = 0; + tcp_retrans = strtoll(value_token, &end, 10); + + if (errno > 0 || *end != '\0') { + tcp_retrans = -1; + } + goto done; + } + + key_token = strtok_r(NULL, delimiter, &key_next); + value_token = strtok_r(NULL, delimiter, &value_next); + } + +done: + if (fp != NULL) { + fclose(fp); + } + + if (key_line != NULL) { + free(key_line); + } + + if (value_line != NULL) { + free(value_line); + } + + return tcp_retrans; +} +#endif diff --git a/stats.h b/stats.h new file mode 100644 index 000000000..9cc2b861e --- /dev/null +++ b/stats.h @@ -0,0 +1,22 @@ +/* + * arcus-memcached - Arcus memory cache server + * Copyright 2010-2014 NAVER Corp. + * Copyright 2015 JaM2in Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* stats */ + +#ifdef STATS_TCP_RETRANS +int64_t stats_tcp_retrans(void); +#endif diff --git a/stats_prefix.h b/stats_prefix.h index 23802f8a3..b713b26eb 100644 --- a/stats_prefix.h +++ b/stats_prefix.h @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* stats */ +/* stats_prefix */ void stats_prefix_init(char delimiter, void (*cb_when_prefix_overflow)(void)); void stats_prefix_clear(void); int stats_prefix_count(void);