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