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 #include <inttypes.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <pthread.h>
25
26 #include "massert.h"
27
28 // #define CHUNKS_MAX_ENTRIES 1000000
29 // #define CHUNKS_MAX_TIME 60
30
31 #define CHUNKS_INODE_HASH_SIZE 65536
32 #define CHUNKS_DATA_HASH_SIZE 524288
33
34 struct _chunks_inode_entry;
35
36 typedef struct _chunks_data_entry {
37 uint32_t inode;
38 uint32_t chindx;
39 uint64_t chunkid;
40 uint32_t version;
41 uint8_t csdataver;
42 uint8_t *csdata;
43 uint32_t csdatasize;
44 struct _chunks_inode_entry *parent;
45 struct _chunks_data_entry **previnode,*nextinode;
46 struct _chunks_data_entry **prevdata,*nextdata;
47 // struct _chunks_data_entry **prevlru,*nextlru;
48 } chunks_data_entry;
49
50 typedef struct _chunks_inode_entry {
51 uint32_t inode;
52 struct _chunks_data_entry *data_head;
53 struct _chunks_inode_entry **prev,*next;
54 } chunks_inode_entry;
55
56 static chunks_inode_entry **chunks_inode_hash;
57 static chunks_data_entry **chunks_data_hash;
58 //static chunks_data_entry *lruhead,**lrutail;
59 static pthread_mutex_t lock;
60
61 //static uint32_t entries;
62
chunks_inode_hash_fn(uint32_t inode)63 static inline uint32_t chunks_inode_hash_fn(uint32_t inode) {
64 return ((inode*0x72B5F387U)&(CHUNKS_INODE_HASH_SIZE-1));
65 }
66
chunks_data_hash_fn(uint32_t inode,uint32_t chindx)67 static inline uint32_t chunks_data_hash_fn(uint32_t inode,uint32_t chindx) {
68 return ((((inode*0x72B5F387U)+chindx)*0x56BF7623U)&(CHUNKS_DATA_HASH_SIZE-1));
69 }
70
chunks_try_remove_inode(chunks_inode_entry * ih)71 static inline void chunks_try_remove_inode(chunks_inode_entry *ih) {
72 if (ih->data_head==NULL) {
73 *(ih->prev) = ih->next;
74 if (ih->next) {
75 ih->next->prev = ih->prev;
76 }
77 free(ih);
78 }
79 }
80
chunks_remove_entry(chunks_data_entry * ca)81 static inline void chunks_remove_entry(chunks_data_entry *ca) {
82 *(ca->previnode) = ca->nextinode;
83 if (ca->nextinode) {
84 ca->nextinode->previnode = ca->previnode;
85 }
86 *(ca->prevdata) = ca->nextdata;
87 if (ca->nextdata) {
88 ca->nextdata->prevdata = ca->prevdata;
89 }
90 // *(ca->prevlru) = ca->nextlru;
91 // if (ca->nextlru) {
92 // ca->nextlru->prevlru = ca->prevlru;
93 // } else {
94 // lrutail = ca->prevlru;
95 // }
96 if (ca->csdata) {
97 free(ca->csdata);
98 }
99 chunks_try_remove_inode(ca->parent);
100 free(ca);
101 // entries--;
102 }
103
chunks_new_entry(uint32_t inode,uint32_t chindx)104 static inline chunks_data_entry* chunks_new_entry(uint32_t inode,uint32_t chindx) {
105 chunks_inode_entry *ih;
106 chunks_data_entry *ca;
107 uint32_t hash,ihash;
108
109 ihash = chunks_inode_hash_fn(inode);
110 for (ih = chunks_inode_hash[ihash] ; ih && ih->inode!=inode ; ih = ih->next) {}
111
112 if (ih==NULL) {
113 ih = malloc(sizeof(chunks_inode_entry));
114 ih->inode = inode;
115 ih->data_head = NULL;
116 ih->next = chunks_inode_hash[ihash];
117 if (ih->next) {
118 ih->next->prev = &(ih->next);
119 }
120 ih->prev = chunks_inode_hash + ihash;
121 chunks_inode_hash[ihash] = ih;
122 }
123 hash = chunks_data_hash_fn(inode,chindx);
124 ca = malloc(sizeof(chunks_data_entry));
125 ca->inode = inode;
126 ca->chindx = chindx;
127 ca->chunkid = 0;
128 ca->version = 0;
129 ca->csdata = NULL;
130 ca->csdatasize = 0;
131 ca->csdataver = 0;
132 ca->parent = ih;
133 ca->nextinode = ih->data_head;
134 if (ca->nextinode) {
135 ca->nextinode->previnode = &(ca->nextinode);
136 }
137 ca->previnode = &(ih->data_head);
138 ih->data_head = ca;
139 ca->nextdata = chunks_data_hash[hash];
140 if (ca->nextdata) {
141 ca->nextdata->prevdata = &(ca->nextdata);
142 }
143 ca->prevdata = chunks_data_hash + hash;
144 chunks_data_hash[hash] = ca;
145 // *lrutail = ca;
146 // ca->prevlru = lrutail;
147 // ca->nextlru = NULL;
148 // lrutail = &(ca->nextlru);
149 return ca;
150 }
151 /*
152 static inline void chunks_lru_move(chunks_data_entry *ca) {
153 if (ca->nextlru==NULL) {
154 return;
155 }
156 *(ca->prevlru) = ca->nextlru;
157 ca->nextlru->prevlru = ca->prevlru;
158 *lrutail = ca;
159 ca->prevlru = lrutail;
160 ca->nextlru = NULL;
161 lrutail = &(ca->nextlru);
162 }
163 */
164
165 // clears all entries with chindx higher or equal to given
chunksdatacache_clear_inode(uint32_t inode,uint32_t chindx)166 void chunksdatacache_clear_inode(uint32_t inode,uint32_t chindx) {
167 chunks_inode_entry *ih,*ihn;
168 chunks_data_entry *ca,*can;
169
170 pthread_mutex_lock(&lock);
171 ih = chunks_inode_hash[chunks_inode_hash_fn(inode)];
172 while (ih) {
173 ihn = ih->next;
174 if (ih->inode==inode) {
175 ca = ih->data_head;
176 while (ca) {
177 can = ca->nextinode;
178 if (ca->chindx>=chindx) {
179 chunks_remove_entry(ca);
180 }
181 ca = can;
182 }
183 }
184 ih = ihn;
185 }
186 pthread_mutex_unlock(&lock);
187 }
188
chunksdatacache_invalidate(uint32_t inode,uint32_t chindx)189 void chunksdatacache_invalidate(uint32_t inode,uint32_t chindx) {
190 chunks_data_entry *ca;
191 uint32_t hash;
192
193 pthread_mutex_lock(&lock);
194 hash = chunks_data_hash_fn(inode,chindx);
195 for (ca = chunks_data_hash[hash] ; ca ; ca=ca->nextdata) {
196 if (ca->inode==inode && ca->chindx==chindx) {
197 chunks_remove_entry(ca);
198 pthread_mutex_unlock(&lock);
199 return;
200 }
201 }
202 pthread_mutex_unlock(&lock);
203 }
204
chunksdatacache_check(uint32_t inode,uint32_t chindx,uint64_t chunkid,uint32_t version)205 uint8_t chunksdatacache_check(uint32_t inode,uint32_t chindx,uint64_t chunkid,uint32_t version) {
206 chunks_data_entry *ca;
207 uint32_t hash;
208
209 pthread_mutex_lock(&lock);
210 hash = chunks_data_hash_fn(inode,chindx);
211 for (ca = chunks_data_hash[hash] ; ca ; ca=ca->nextdata) {
212 if (ca->inode==inode && ca->chindx==chindx) {
213 if (ca->chunkid==chunkid && ca->version==version) {
214 pthread_mutex_unlock(&lock);
215 return 1;
216 } else {
217 pthread_mutex_unlock(&lock);
218 return 0;
219 }
220 }
221 }
222 pthread_mutex_unlock(&lock);
223 return 0;
224 }
225
chunksdatacache_change(uint32_t inode,uint32_t chindx,uint64_t chunkid,uint32_t version)226 void chunksdatacache_change(uint32_t inode,uint32_t chindx,uint64_t chunkid,uint32_t version) {
227 chunks_data_entry *ca;
228 uint32_t hash;
229
230 pthread_mutex_lock(&lock);
231 hash = chunks_data_hash_fn(inode,chindx);
232 for (ca = chunks_data_hash[hash] ; ca ; ca=ca->nextdata) {
233 if (ca->inode==inode && ca->chindx==chindx) {
234 ca->chunkid = chunkid;
235 ca->version = version;
236 pthread_mutex_unlock(&lock);
237 return;
238 }
239 }
240 pthread_mutex_unlock(&lock);
241 }
242
chunksdatacache_insert(uint32_t inode,uint32_t chindx,uint64_t chunkid,uint32_t version,uint8_t csdataver,const uint8_t * csdata,uint32_t csdatasize)243 void chunksdatacache_insert(uint32_t inode,uint32_t chindx,uint64_t chunkid,uint32_t version,uint8_t csdataver,const uint8_t *csdata,uint32_t csdatasize) {
244 chunks_data_entry *ca;
245 uint32_t hash;
246
247 pthread_mutex_lock(&lock);
248 hash = chunks_data_hash_fn(inode,chindx);
249 for (ca = chunks_data_hash[hash] ; ca ; ca=ca->nextdata) {
250 if (ca->inode==inode && ca->chindx==chindx) {
251 // chunks_lru_move(ca);
252 break;
253 }
254 }
255
256 if (ca==NULL) {
257 // while (entries>=CHUNKS_MAX_ENTRIES) {
258 // chunks_remove_entry(lruhead);
259 // }
260 ca = chunks_new_entry(inode,chindx);
261 }
262
263 ca->chunkid = chunkid;
264 ca->version = version;
265 ca->csdataver = csdataver;
266 if (ca->csdatasize==csdatasize) {
267 if (csdatasize>0) {
268 memcpy(ca->csdata,csdata,csdatasize);
269 }
270 } else {
271 if (ca->csdata) {
272 free(ca->csdata);
273 }
274 if (csdatasize>0) {
275 ca->csdata = malloc(csdatasize);
276 memcpy(ca->csdata,csdata,csdatasize);
277 } else {
278 ca->csdata = NULL;
279 }
280 ca->csdatasize = csdatasize;
281 }
282 pthread_mutex_unlock(&lock);
283 }
284
chunksdatacache_find(uint32_t inode,uint32_t chindx,uint64_t * chunkid,uint32_t * version,uint8_t * csdataver,uint8_t * csdata,uint32_t * csdatasize)285 uint8_t chunksdatacache_find(uint32_t inode,uint32_t chindx,uint64_t *chunkid,uint32_t *version,uint8_t *csdataver,uint8_t *csdata,uint32_t *csdatasize) {
286 chunks_data_entry *ca;
287 uint32_t hash;
288
289 pthread_mutex_lock(&lock);
290 hash = chunks_data_hash_fn(inode,chindx);
291 for (ca = chunks_data_hash[hash] ; ca ; ca=ca->nextdata) {
292 if (ca->inode==inode && ca->chindx==chindx) {
293 // chunks_lru_move(ca);
294 if (*csdatasize < ca->csdatasize) { // not enough space in external buffer
295 pthread_mutex_unlock(&lock);
296 return 0;
297 }
298 *chunkid = ca->chunkid;
299 *version = ca->version;
300 *csdataver = ca->csdataver;
301 memcpy(csdata,ca->csdata,ca->csdatasize);
302 *csdatasize = ca->csdatasize;
303 pthread_mutex_unlock(&lock);
304 return 1;
305 }
306 }
307 pthread_mutex_unlock(&lock);
308 return 0;
309 }
310
chunksdatacache_cleanup(void)311 void chunksdatacache_cleanup(void) {
312 chunks_inode_entry *ih,*ihn;
313 chunks_data_entry *ca,*can;
314 uint32_t hash;
315
316 pthread_mutex_lock(&lock);
317 for (hash = 0 ; hash < CHUNKS_INODE_HASH_SIZE ; hash++) {
318 ih = chunks_inode_hash[hash];
319 while (ih) {
320 ihn = ih->next;
321 free(ih);
322 ih = ihn;
323 }
324 chunks_inode_hash[hash] = NULL;
325 }
326 for (hash = 0 ; hash < CHUNKS_DATA_HASH_SIZE ; hash++) {
327 ca = chunks_data_hash[hash];
328 while (ca) {
329 can = ca->nextdata;
330 if (ca->csdata) {
331 free(ca->csdata);
332 }
333 free(ca);
334 ca = can;
335 }
336 chunks_data_hash[hash] = NULL;
337 }
338 // lruhead = NULL;
339 // lrutail = &lruhead;
340 // entries = 0;
341 pthread_mutex_unlock(&lock);
342 }
343
chunksdatacache_term(void)344 void chunksdatacache_term(void) {
345 chunksdatacache_cleanup();
346 free(chunks_inode_hash);
347 free(chunks_data_hash);
348 pthread_mutex_destroy(&lock);
349 }
350
chunksdatacache_init(void)351 void chunksdatacache_init(void) {
352 uint32_t hash;
353
354 chunks_inode_hash = malloc(sizeof(chunks_inode_entry*)*CHUNKS_INODE_HASH_SIZE);
355 passert(chunks_inode_hash);
356
357 chunks_data_hash = malloc(sizeof(chunks_data_entry*)*CHUNKS_DATA_HASH_SIZE);
358 passert(chunks_data_hash);
359
360 for (hash = 0 ; hash < CHUNKS_INODE_HASH_SIZE ; hash++) {
361 chunks_inode_hash[hash] = NULL;
362 }
363 for (hash = 0 ; hash < CHUNKS_DATA_HASH_SIZE ; hash++) {
364 chunks_data_hash[hash] = NULL;
365 }
366 // lruhead = NULL;
367 // lrutail = &lruhead;
368 // entries = 0;
369 pthread_mutex_init(&lock,NULL);
370 }
371