1+ /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2+ /*
3+ * arcus-memcached - Arcus memory cache server
4+ * Copyright 2010-2014 NAVER Corp.
5+ * Copyright 2015 JaM2in Co., Ltd.
6+ *
7+ * Licensed under the Apache License, Version 2.0 (the "License");
8+ * you may not use this file except in compliance with the License.
9+ * You may obtain a copy of the License at
10+ *
11+ * http://www.apache.org/licenses/LICENSE-2.0
12+ *
13+ * Unless required by applicable law or agreed to in writing, software
14+ * distributed under the License is distributed on an "AS IS" BASIS,
15+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+ * See the License for the specific language governing permissions and
17+ * limitations under the License.
18+ */
19+ /*
20+ * Detailed statistics management. For simple stats like total number of
21+ * "get" requests, we use inline code in memcached.c and friends, but when
22+ * stats detail mode is activated, the code here records more information.
23+ *
24+ * Author:
25+ * Steven Grimm <[email protected] > 26+ */
27+ #include "config.h"
28+ #include "memcached.h"
29+
30+ #ifdef STATS_TCP_RETRANS
31+ #include <ctype.h>
32+ #include <stdlib.h>
33+ #include <string.h>
34+
35+ static void rtrim (char * * src ) {
36+ if (src == NULL || * src == NULL || strlen (* src ) == 0 ) {
37+ return ;
38+ }
39+
40+ char * str = * src ;
41+ for (int i = strlen (str ) - 1 ; i >= 0 ; i -- ) {
42+ if (!isspace (str [i ])) {
43+ break ;
44+ }
45+
46+ str [i ] = '\0' ;
47+ }
48+
49+ * src = str ;
50+ }
51+
52+ int64_t stats_tcp_retrans (void ) {
53+ char * key_line = NULL ;
54+ char * value_line = NULL ;
55+ uint64_t tcp_retrans = -1 ;
56+
57+ FILE * fp = fopen ("/proc/net/snmp" , "r" );
58+ if (fp == NULL ) {
59+ goto done ;
60+ }
61+
62+ size_t key_len = 0 ;
63+ size_t value_len = 0 ;
64+ ssize_t key_read = -1 ;
65+ ssize_t value_read = -1 ;
66+
67+ char * prefix = "Tcp:" ;
68+ size_t prefix_len = strlen (prefix );
69+
70+ while ((key_read = getline (& key_line , & key_len , fp )) != -1 ) {
71+ if (strncmp (prefix , key_line , prefix_len ) != 0 ) {
72+ continue ;
73+ }
74+
75+ if ((value_read = getline (& value_line , & value_len , fp )) != -1 ) {
76+ break ;
77+ }
78+ }
79+
80+ if (key_read < 0 || value_read < 0 ) {
81+ goto done ;
82+ }
83+
84+ /*
85+ * below lines are examples of key_line and value_line.
86+ * for examples below, tcp_retrans = 9814784
87+ *
88+ * Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors
89+ * Tcp: 1 200 120000 -1 231273424 45758374 43975115 12045288 360 9853401239 10104984649 9814784 12765 17318799 883
90+ */
91+
92+ char * delimiter = " " ;
93+ char * retrans_segs = "RetransSegs" ;
94+
95+ char * key_next = NULL ;
96+ char * value_next = NULL ;
97+
98+ char * key_token = strtok_r (key_line , delimiter , & key_next );
99+ char * value_token = strtok_r (value_line , delimiter , & value_next );
100+
101+ // first token is always "Tcp:"
102+ key_token = strtok_r (NULL , delimiter , & key_next );
103+ value_token = strtok_r (NULL , delimiter , & value_next );
104+
105+ while (key_token && value_token ) {
106+ // last token always ends with "\n"
107+ rtrim (& key_token );
108+ rtrim (& value_token );
109+
110+ if (strcmp (key_token , retrans_segs ) == 0 ) {
111+ char * end = NULL ;
112+ errno = 0 ;
113+ tcp_retrans = strtoll (value_token , & end , 10 );
114+
115+ if (errno > 0 || * end != '\0' ) {
116+ tcp_retrans = -1 ;
117+ }
118+ goto done ;
119+ }
120+
121+ key_token = strtok_r (NULL , delimiter , & key_next );
122+ value_token = strtok_r (NULL , delimiter , & value_next );
123+ }
124+
125+ done :
126+ if (fp != NULL ) {
127+ fclose (fp );
128+ }
129+
130+ if (key_line != NULL ) {
131+ free (key_line );
132+ }
133+
134+ if (value_line != NULL ) {
135+ free (value_line );
136+ }
137+
138+ return tcp_retrans ;
139+ }
140+ #endif
0 commit comments