1 /*
2  * Copyright (C) 2021 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3  *
4  * This file is part of MooseFS.
5  *
6  * MooseFS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, version 2 (only).
9  *
10  * MooseFS is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with MooseFS; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18  * or visit http://www.gnu.org/licenses/gpl-2.0.html
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <sys/stat.h>
26 #include <inttypes.h>
27 #include <syslog.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <pthread.h>
32 
33 #include "MFSCommunication.h"
34 #include "lwthread.h"
35 #include "massert.h"
36 #include "portable.h"
37 #include "clocks.h"
38 
39 // #define SSTATS_DEBUG 1
40 
41 #ifdef SSTATS_DEBUG
42 #include <stdio.h>
43 #endif
44 
45 #ifndef HAVE___SYNC_FETCH_AND_OP
46 static pthread_mutex_t glock;
47 #endif
48 static uint8_t term;
49 static pthread_t clthread;
50 
51 #define HASHSIZE 65536
52 #define SSTATS_TIMEOUT 60.0
53 
54 static uint8_t default_attr[35]={0, 0x01 | (TYPE_DIRECTORY<<4) ,0xFF, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,0,0,0,0};
55 
56 typedef struct _inode_stats {
57 	uint32_t inode;
58 	uint8_t attr[35];
59 //	uint8_t sustained;
60 	double lastrefresh;
61 	struct _inode_stats *next;
62 } inode_stats;
63 
64 static inode_stats **ishash;
65 static pthread_mutex_t *locktab;
66 
67 /*
68 void sstats_activate(uint32_t inode) {
69 	uint32_t hash;
70 	inode_stats *isc;
71 
72 #ifdef SSTATS_DEBUG
73 	printf(" : sstats_activate(%"PRIu32")\n",inode);
74 #endif
75 	hash = inode % HASHSIZE;
76 	zassert(pthread_mutex_lock(locktab+hash));
77 	for (isc = ishash[hash] ; isc ; isc = isc->next) {
78 		if (isc->inode == inode) {
79 			isc->sustained = 1;
80 			isc->lastrefresh = monotonic_seconds();
81 			break;
82 		}
83 	}
84 	if (isc==NULL) {
85 		syslog(LOG_WARNING,"no sustained stats for node: %"PRIu32" - using defaults",inode);
86 		isc = malloc(sizeof(inode_stats));
87 		passert(isc);
88 		isc->inode = inode;
89 		memcpy(isc->attr,default_attr,35);
90 		isc->sustained = 1;
91 		isc->lastrefresh = monotonic_seconds();
92 		isc->next = ishash[hash];
93 		ishash[hash] = isc;
94 	}
95 	zassert(pthread_mutex_unlock(locktab+hash));
96 	return;
97 }
98 
99 void sstats_deactivate(uint32_t inode) {
100 	uint32_t hash;
101 	inode_stats *isc;
102 
103 #ifdef SSTATS_DEBUG
104 	printf(" : sstats_deactivate(%"PRIu32")\n",inode);
105 #endif
106 	hash = inode % HASHSIZE;
107 	zassert(pthread_mutex_lock(locktab+hash));
108 	for (isc = ishash[hash] ; isc ; isc = isc->next) {
109 		if (isc->inode == inode) {
110 			isc->sustained = 0;
111 			isc->lastrefresh = monotonic_seconds();
112 			break;
113 		}
114 	}
115 	if (isc==NULL) {
116 		syslog(LOG_WARNING,"no sustained stats for node: %"PRIu32" - ignored",inode);
117 	}
118 	zassert(pthread_mutex_unlock(locktab+hash));
119 	return;
120 }
121 */
122 
sstats_get(uint32_t inode,uint8_t attr[35],uint8_t forceok)123 int sstats_get(uint32_t inode,uint8_t attr[35],uint8_t forceok) {
124 	uint32_t hash;
125 	inode_stats *isc;
126 //	uint8_t sustained;
127 
128 #ifdef SSTATS_DEBUG
129 	printf(" : sstats_get(%"PRIu32",%"PRIu8")\n",inode,forceok);
130 #endif
131 	hash = inode % HASHSIZE;
132 	zassert(pthread_mutex_lock(locktab+hash));
133 	for (isc = ishash[hash] ; isc ; isc = isc->next) {
134 		if (isc->inode == inode) {
135 			memcpy(attr,isc->attr,35);
136 //			sustained = isc->sustained;
137 			isc->lastrefresh = monotonic_seconds();
138 			zassert(pthread_mutex_unlock(locktab+hash));
139 //			return (sustained || forceok)?MFS_STATUS_OK:MFS_ERROR_ENOENT;
140 			return MFS_STATUS_OK;
141 		}
142 	}
143 	if (forceok) {
144 		syslog(LOG_WARNING,"no sustained stats for node: %"PRIu32" - using defaults",inode);
145 		isc = malloc(sizeof(inode_stats));
146 		passert(isc);
147 		isc->inode = inode;
148 		memcpy(isc->attr,default_attr,35);
149 		memcpy(attr,default_attr,35);
150 //		isc->sustained = 0;
151 		isc->lastrefresh = monotonic_seconds();
152 		isc->next = ishash[hash];
153 		ishash[hash] = isc;
154 	}
155 	zassert(pthread_mutex_unlock(locktab+hash));
156 	return MFS_ERROR_ENOENT;
157 }
158 
sstats_set(uint32_t inode,const uint8_t attr[35],uint8_t createflag)159 void sstats_set(uint32_t inode,const uint8_t attr[35],uint8_t createflag) {
160 	uint32_t hash;
161 	inode_stats *isc;
162 
163 #ifdef SSTATS_DEBUG
164 	printf(" : sstats_set(%"PRIu32",%"PRIu8")\n",inode,createflag);
165 #endif
166 	hash = inode % HASHSIZE;
167 	zassert(pthread_mutex_lock(locktab+hash));
168 	for (isc = ishash[hash] ; isc ; isc = isc->next) {
169 		if (isc->inode == inode) {
170 			memcpy(isc->attr,attr,35);
171 			isc->lastrefresh = monotonic_seconds();
172 			zassert(pthread_mutex_unlock(locktab+hash));
173 			return;
174 		}
175 	}
176 	if (createflag) {
177 		isc = malloc(sizeof(inode_stats));
178 		passert(isc);
179 		isc->inode = inode;
180 		memcpy(isc->attr,attr,35);
181 //		isc->sustained = 0;
182 		isc->lastrefresh = monotonic_seconds();
183 		isc->next = ishash[hash];
184 		ishash[hash] = isc;
185 	}
186 	zassert(pthread_mutex_unlock(locktab+hash));
187 }
188 
sstats_thread(void * arg)189 void* sstats_thread(void *arg) {
190 	uint32_t hash = 0;
191 	inode_stats *isc,**isp;
192 	double now;
193 	(void)arg;
194 
195 	while(1) {
196 		now = monotonic_seconds();
197 		zassert(pthread_mutex_lock(locktab+hash));
198 		isp = ishash+hash;
199 		while ((isc = *isp)) {
200 			if (isc->lastrefresh + SSTATS_TIMEOUT < now) {
201 				*isp = isc->next;
202 				free(isc);
203 			} else {
204 				isp = &(isc->next);
205 			}
206 		}
207 		zassert(pthread_mutex_unlock(locktab+hash));
208 		portable_usleep(100000);
209 #ifdef HAVE___SYNC_FETCH_AND_OP
210 		if (__sync_fetch_and_or(&term,0)==1) {
211 			return NULL;
212 		}
213 #else
214 		zassert(pthread_mutex_lock(&glock));
215 		if (term==1) {
216 			zassert(pthread_mutex_unlock(&glock));
217 			return NULL;
218 		}
219 		zassert(pthread_mutex_unlock(&glock));
220 #endif
221 	}
222 }
223 
sstats_term(void)224 void sstats_term(void) {
225 	uint32_t i;
226 	inode_stats *isc,*isn;
227 
228 #ifdef HAVE___SYNC_FETCH_AND_OP
229 	__sync_fetch_and_or(&term,1);
230 #else
231 	zassert(pthread_mutex_lock(&glock));
232 	term = 1;
233 	zassert(pthread_mutex_unlock(&glock));
234 #endif
235 	pthread_join(clthread,NULL);
236 #ifndef HAVE___SYNC_FETCH_AND_OP
237 	zassert(pthread_mutex_destroy(&glock));
238 #endif
239 
240 	for (i=0 ; i<HASHSIZE ; i++) {
241 		zassert(pthread_mutex_destroy(locktab+i));
242 		for (isc = ishash[i] ; isc ; isc = isn) {
243 			isn = isc->next;
244 			free(isc);
245 		}
246 	}
247 	free(locktab);
248 	free(ishash);
249 }
250 
sstats_init(void)251 void sstats_init(void) {
252 	uint32_t i;
253 	ishash = (inode_stats**)malloc(sizeof(inode_stats*)*HASHSIZE);
254 	passert(ishash);
255 	locktab = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t)*HASHSIZE);
256 	passert(locktab);
257 	for (i=0 ; i<HASHSIZE ; i++) {
258 		ishash[i] = NULL;
259 		zassert(pthread_mutex_init(locktab+i,NULL));
260 	}
261 
262 #ifdef HAVE___SYNC_FETCH_AND_OP
263 	__sync_fetch_and_and(&term,0);
264 #else
265 	zassert(pthread_mutex_init(&glock,NULL));
266 	zassert(pthread_mutex_lock(&glock));
267 	term = 0;
268 	zassert(pthread_mutex_unlock(&glock));
269 #endif
270 	lwt_minthread_create(&clthread,0,sstats_thread,NULL);
271 }
272