Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 : : /*
3 : : * Copyright 2010 Couchbase, Inc
4 : : *
5 : : * Licensed under the Apache License, Version 2.0 (the "License");
6 : : * you may not use this file except in compliance with the License.
7 : : * You may obtain a copy of the License at
8 : : *
9 : : * http://www.apache.org/licenses/LICENSE-2.0
10 : : *
11 : : * Unless required by applicable law or agreed to in writing, software
12 : : * distributed under the License is distributed on an "AS IS" BASIS,
13 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : : * See the License for the specific language governing permissions and
15 : : * limitations under the License.
16 : : */
17 : :
18 : : #include <stdlib.h>
19 : : #include <string.h>
20 : : #include <stdint.h>
21 : :
22 : : #include "hash_functions.h"
23 : : #include "common.h"
24 : : #include "hash.h"
25 : : #include "list.h"
26 : : #include "blockcache.h"
27 : : #include "avltree.h"
28 : :
29 : : #include "memleak.h"
30 : :
31 : : #ifdef __DEBUG
32 : : #ifndef __DEBUG_BCACHE
33 : : #undef DBG
34 : : #undef DBGCMD
35 : : #undef DBGSW
36 : : #define DBG(...)
37 : : #define DBGCMD(...)
38 : : #define DBGSW(n, ...)
39 : : #endif
40 : : #endif
41 : :
42 : : // global lock
43 : : static spin_t bcache_lock;
44 : : static size_t fnames;
45 : :
46 : : // hash table for filename
47 : : static struct hash fnamedic;
48 : :
49 : : // free block list
50 : : static size_t freelist_count=0;
51 : : static struct list freelist;
52 : : static spin_t freelist_lock;
53 : :
54 : : // file structure list
55 : : static struct list file_lru, file_empty;
56 : : static spin_t filelist_lock;
57 : :
58 : : //static struct list cleanlist, dirtylist;
59 : : //static uint64_t nfree, nclean, ndirty;
60 : : static uint64_t bcache_nblock;
61 : :
62 : : static int bcache_blocksize;
63 : : static size_t bcache_flush_unit;
64 : :
65 : : struct fnamedic_item {
66 : : char *filename;
67 : : uint16_t filename_len;
68 : : uint32_t hash;
69 : :
70 : : // current opened filemgr instance
71 : : // (can be changed on-the-fly when file is closed and re-opened)
72 : : struct filemgr *curfile;
73 : :
74 : : // list for clean blocks
75 : : struct list cleanlist;
76 : : // tree for normal dirty blocks
77 : : struct avl_tree tree;
78 : : // tree for index nodes
79 : : struct avl_tree tree_idx;
80 : : // hash table for block lookup
81 : : struct hash hashtable;
82 : :
83 : : // list elem for FILE_LRU
84 : : struct list_elem le;
85 : : // current list poitner (FILE_LRU or FILE_EMPTY)
86 : : struct list *curlist;
87 : : // hash elem for FNAMEDIC
88 : : struct hash_elem hash_elem;
89 : :
90 : : spin_t lock;
91 : : uint64_t nvictim;
92 : : uint64_t nitems;
93 : : };
94 : :
95 : : #define BCACHE_DIRTY (0x1)
96 : : #define BCACHE_FREE (0x4)
97 : :
98 : : struct bcache_item {
99 : : // BID
100 : : bid_t bid;
101 : : // contents address
102 : : void *addr;
103 : : struct fnamedic_item *fname;
104 : : // pointer of the list to which this item belongs
105 : : //struct list *list;
106 : : // hash elem for lookup hash table
107 : : struct hash_elem hash_elem;
108 : : // list elem for {free, clean, dirty} lists
109 : : struct list_elem list_elem;
110 : : // flag
111 : : uint8_t flag;
112 : : // score
113 : : uint8_t score;
114 : : // spin lock
115 : : spin_t lock;
116 : :
117 : : };
118 : :
119 : : struct dirty_item {
120 : : struct bcache_item *item;
121 : : struct avl_node avl;
122 : : };
123 : :
124 : 3250329 : INLINE int _dirty_cmp(struct avl_node *a, struct avl_node *b, void *aux)
125 : : {
126 : : struct dirty_item *aa, *bb;
127 : 3250329 : aa = _get_entry(a, struct dirty_item, avl);
128 : 3250329 : bb = _get_entry(b, struct dirty_item, avl);
129 : :
130 : : #ifdef __BIT_CMP
131 : 3250329 : return _CMP_U64(aa->item->bid , bb->item->bid);
132 : :
133 : : #else
134 : : if (aa->item->bid < bb->item->bid) return -1;
135 : : else if (aa->item->bid > bb->item->bid) return 1;
136 : : else return 0;
137 : :
138 : : #endif
139 : : }
140 : :
141 : 240 : INLINE uint32_t _fname_hash(struct hash *hash, struct hash_elem *e)
142 : : {
143 : : struct fnamedic_item *item;
144 : 240 : item = _get_entry(e, struct fnamedic_item, hash_elem);
145 : 240 : return item->hash & ((unsigned)(BCACHE_NDICBUCKET-1));
146 : : }
147 : :
148 : 120 : INLINE int _fname_cmp(struct hash_elem *a, struct hash_elem *b)
149 : : {
150 : : size_t len;
151 : : struct fnamedic_item *aa, *bb;
152 : 120 : aa = _get_entry(a, struct fnamedic_item, hash_elem);
153 : 120 : bb = _get_entry(b, struct fnamedic_item, hash_elem);
154 : :
155 [ + - ]: 120 : if (aa->filename_len == bb->filename_len) {
156 : 120 : return memcmp(aa->filename, bb->filename, aa->filename_len);
157 : : }else {
158 [ # # ]: 0 : len = MIN(aa->filename_len , bb->filename_len);
159 : 0 : int cmp = memcmp(aa->filename, bb->filename, len);
160 [ # # ]: 0 : if (cmp != 0) return cmp;
161 : : else {
162 : 120 : return (int)((int)aa->filename_len - (int)bb->filename_len);
163 : : }
164 : : }
165 : : }
166 : :
167 : 38313792 : INLINE uint32_t _bcache_hash(struct hash *hash, struct hash_elem *e)
168 : : {
169 : 38313792 : struct bcache_item *item = _get_entry(e, struct bcache_item, hash_elem);
170 : 38313792 : return (item->bid) & ((uint32_t)BCACHE_NBUCKET-1);
171 : : }
172 : :
173 : 44245359 : INLINE int _bcache_cmp(struct hash_elem *a, struct hash_elem *b)
174 : : {
175 : : struct bcache_item *aa, *bb;
176 : 44245359 : aa = _get_entry(a, struct bcache_item, hash_elem);
177 : 44245359 : bb = _get_entry(b, struct bcache_item, hash_elem);
178 : :
179 : : #ifdef __BIT_CMP
180 : :
181 : 44245359 : return _CMP_U64(aa->bid, bb->bid);
182 : :
183 : : #else
184 : :
185 : : if (aa->bid == bb->bid) return 0;
186 : : else if (aa->bid < bb->bid) return -1;
187 : : else return 1;
188 : :
189 : : #endif
190 : : }
191 : :
192 : 33980993 : void _bcache_move_fname_list(struct fnamedic_item *fname, struct list *list)
193 : : {
194 : : file_status_t fs;
195 : :
196 : 33980993 : spin_lock(&filelist_lock);
197 : :
198 [ + + ]: 33981773 : if (fname->curlist != list) {
199 [ + + ]: 2475256 : if (list == &file_lru) {
200 : 1237568 : fnames++;
201 : : } else {
202 : 1237688 : fnames--;
203 : : }
204 : : }
205 : :
206 [ + + ]: 33981773 : if (fname->curlist) list_remove(fname->curlist, &fname->le);
207 [ + + ]: 33981773 : if (list) {
208 : 33981653 : fs = filemgr_get_file_status(fname->curfile);
209 : :
210 [ + + ][ + + ]: 33981653 : if (list == &file_lru && fs == FILE_COMPACT_OLD) {
211 : : // insert compact old file always at the tail of LRU
212 : 395219 : list_push_back(list, &fname->le);
213 : : }else{
214 : 33981653 : list_push_front(list, &fname->le);
215 : : }
216 : : }
217 : 33981773 : fname->curlist = list;
218 : :
219 : 33981773 : spin_unlock(&filelist_lock);
220 : 33981771 : }
221 : :
222 : : #define _list_empty(list) (((list).head) == NULL)
223 : : #define _tree_empty(tree) (((tree).root) == NULL)
224 : :
225 : : #define _file_empty(fname) \
226 : : ( _list_empty((fname)->cleanlist) && \
227 : : _tree_empty((fname)->tree) && \
228 : : _tree_empty((fname)->tree_idx) )
229 : :
230 : 22109666 : struct fnamedic_item *_bcache_get_victim()
231 : : {
232 : 22109666 : struct list_elem *e = NULL, *prev;
233 : :
234 : 22109666 : spin_lock(&filelist_lock);
235 : :
236 : : #ifdef __BCACHE_RANDOM_VICTIM
237 : : size_t i, r;
238 : :
239 [ - + ]: 22109666 : if (fnames > BCACHE_RANDOM_VICTIM_UNIT){
240 : 0 : r = rand() % BCACHE_RANDOM_VICTIM_UNIT;
241 : : }else{
242 : 22109666 : r = 0;
243 : : }
244 : 22109666 : e = prev = list_end(&file_lru);
245 : :
246 [ - + ]: 22109666 : for (i=0;i<r;++i){
247 [ # # ]: 0 : if (e == NULL) {
248 : 0 : e = prev;
249 : 0 : break;
250 : : }
251 : 0 : prev = e;
252 : 0 : e = list_prev(e);
253 : : }
254 : :
255 : : #else
256 : : e = list_end(&file_lru);
257 : : #endif
258 : :
259 [ + + ]: 22109666 : if (e==NULL) {
260 : 20627800 : e = list_begin(&file_empty);
261 : :
262 [ + + ]: 41255600 : while (e) {
263 : : struct fnamedic_item *fname;
264 : 20627800 : fname = _get_entry(e, struct fnamedic_item, le);
265 [ + + ][ + + ]: 20627800 : if (!_file_empty(fname)) {
[ - + ]
266 : 45302 : break;
267 : : }
268 : 20582498 : e = list_next(e);
269 : : }
270 : : }
271 : :
272 : 22109666 : spin_unlock(&filelist_lock);
273 : :
274 [ + + ]: 22109666 : if (e) {
275 : 1527168 : return _get_entry(e, struct fnamedic_item, le);
276 : : }
277 : 22109666 : return NULL;
278 : : }
279 : :
280 : 3362338 : struct bcache_item *_bcache_alloc_freeblock()
281 : : {
282 : 3362338 : struct list_elem *e = NULL;
283 : : struct bcache_item *item;
284 : :
285 : 3362338 : spin_lock(&freelist_lock);
286 : 3362338 : e = list_pop_front(&freelist);
287 [ + + ]: 3362338 : if (e) freelist_count--;
288 : 3362338 : spin_unlock(&freelist_lock);
289 : :
290 [ + + ]: 3362338 : if (e) {
291 : 1880359 : item = _get_entry(e, struct bcache_item, list_elem);
292 : 1880359 : return item;
293 : : }
294 : 3362338 : return NULL;
295 : : }
296 : :
297 : 1880359 : void _bcache_release_freeblock(struct bcache_item *item)
298 : : {
299 : 1880359 : spin_lock(&freelist_lock);
300 : 1880359 : item->flag = BCACHE_FREE;
301 : 1880359 : item->score = 0;
302 : 1880359 : list_push_front(&freelist, &item->list_elem);
303 : 1880359 : freelist_count++;
304 : 1880359 : spin_unlock(&freelist_lock);
305 : 1880359 : }
306 : :
307 : : // flush a bunch of dirty blocks (BCACHE_FLUSH_UNIT) & make then as clean
308 : : //2 FNAME_LOCK is already acquired by caller (of the caller)
309 : 202629 : fdb_status _bcache_evict_dirty(struct fnamedic_item *fname_item, int sync)
310 : : {
311 : : // get oldest dirty block
312 : 202629 : void *buf = NULL;
313 : : struct list_elem *prevhead;
314 : : struct avl_tree *cur_tree;
315 : : struct avl_node *a;
316 : : struct dirty_item *ditem;
317 : : uint64_t count;
318 : : ssize_t ret;
319 : : bid_t start_bid, prev_bid;
320 : 202629 : void *ptr = NULL;
321 : 202629 : uint8_t marker = 0x0;
322 : 202629 : fdb_status status = FDB_RESULT_SUCCESS;
323 : 202629 : bool o_direct = false;
324 : :
325 [ - + ]: 202629 : if (fname_item->curfile->config->flag & _ARCH_O_DIRECT) {
326 : 0 : o_direct = true;
327 : : }
328 : :
329 : : // scan and write back dirty blocks sequentially
330 [ + + ][ - + ]: 202629 : if (sync && o_direct) {
331 : 0 : malloc_align(buf, FDB_SECTOR_SIZE, bcache_flush_unit);
332 : : }
333 : :
334 : 202629 : prev_bid = start_bid = BLK_NOT_FOUND;
335 : 202629 : count = 0;
336 : :
337 : : // evict normal dirty block first
338 : 202629 : cur_tree = &fname_item->tree;
339 : 202629 : a = avl_first(cur_tree);
340 [ + + ]: 202629 : if (!a) {
341 : : // if there is no normal dirty block,
342 : : // evict index nodes next
343 : 1853 : cur_tree = &fname_item->tree_idx;
344 : 1853 : a = avl_first(cur_tree);
345 : : }
346 : :
347 : : // traverse tree in a sequential order
348 [ + + ]: 697124 : while(a) {
349 : 497132 : ditem = _get_entry(a, struct dirty_item, avl);
350 : :
351 : : // if BID of next dirty block is not consecutive .. stop
352 [ + + ][ + + ]: 497132 : if (ditem->item->bid != prev_bid + 1 &&
[ + - ]
353 : : prev_bid != BLK_NOT_FOUND &&
354 : 2118 : sync) break;
355 : : // set START_BID if this is the first loop
356 [ + + ]: 495014 : if (start_bid == BLK_NOT_FOUND) start_bid = ditem->item->bid;
357 : :
358 : : // set PREV_BID and go to next block
359 : 495014 : prev_bid = ditem->item->bid;
360 : 495014 : a = avl_next(a);
361 : :
362 : 495014 : spin_lock(&ditem->item->lock);
363 : : // set PTR and get block MARKER
364 : 495014 : ptr = ditem->item->addr;
365 : 495014 : marker = *((uint8_t*)(ptr) + bcache_blocksize-1);
366 : :
367 : 495014 : ditem->item->flag &= ~(BCACHE_DIRTY);
368 [ + + ]: 495014 : if (sync) {
369 : : // copy to buffer
370 : : #ifdef __CRC32
371 [ + + ]: 495009 : if (marker == BLK_MARKER_BNODE ) {
372 : : // b-tree node .. calculate crc32 and put it into the block
373 : 87049 : memset((uint8_t *)(ptr) + BTREE_CRC_OFFSET,
374 : 87049 : 0xff, BTREE_CRC_FIELD_LEN);
375 : 87049 : uint32_t crc = chksum(ptr, bcache_blocksize);
376 : 87049 : crc = _endian_encode(crc);
377 : 87049 : memcpy((uint8_t *)(ptr) + BTREE_CRC_OFFSET, &crc, sizeof(crc));
378 : : }
379 : : #endif
380 : :
381 [ - + ]: 495009 : if (o_direct) {
382 : 0 : memcpy((uint8_t *)(buf) + count*bcache_blocksize,
383 : : ditem->item->addr,
384 : 0 : bcache_blocksize);
385 : : } else {
386 : : ret = fname_item->curfile->ops->pwrite(
387 : : fname_item->curfile->fd,
388 : : ditem->item->addr,
389 : : bcache_blocksize,
390 : 495009 : ditem->item->bid * bcache_blocksize);
391 [ - + ]: 495009 : if (ret != bcache_blocksize) {
392 : 0 : spin_unlock(&ditem->item->lock);
393 : 0 : status = FDB_RESULT_WRITE_FAIL;
394 : 0 : break;
395 : : }
396 : : }
397 : : }
398 : :
399 : : // remove from rb-tree
400 : 495014 : avl_remove(cur_tree, &ditem->avl);
401 : : // move to clean list
402 : 495014 : prevhead = fname_item->cleanlist.head;
403 : : (void)prevhead;
404 : 495014 : list_push_front(&fname_item->cleanlist, &ditem->item->list_elem);
405 : :
406 [ - + ]: 495014 : assert(!(ditem->item->flag & BCACHE_FREE));
407 : 0 : assert(ditem->item->list_elem.prev == NULL &&
408 [ + - ][ - + ]: 495014 : prevhead == ditem->item->list_elem.next);
409 : 495014 : spin_unlock(&ditem->item->lock);
410 : :
411 : 495014 : mempool_free(ditem);
412 : :
413 : : // if we have to sync the dirty block, and
414 : : // the size of dirty blocks exceeds the BCACHE_FLUSH_UNIT
415 : 495014 : count++;
416 [ + + ][ + - ]: 495014 : if (count*bcache_blocksize >= bcache_flush_unit && sync) {
417 : 519 : break;
418 : : }
419 : : }
420 : :
421 : : // synchronize
422 [ + + ][ + - ]: 202629 : if (sync && count > 0 && o_direct) {
[ - + ]
423 : : ret = fname_item->curfile->ops->pwrite(
424 : : fname_item->curfile->fd, buf,
425 : : count * bcache_blocksize,
426 : 0 : start_bid * bcache_blocksize);
427 : :
428 [ # # ]: 0 : if (ret != count * bcache_blocksize) {
429 : 0 : status = FDB_RESULT_WRITE_FAIL;
430 : : }
431 : 0 : free_align(buf);
432 : : }
433 : 202629 : return status;
434 : : }
435 : :
436 : : // perform eviction
437 : 1481979 : struct list_elem * _bcache_evict(struct fnamedic_item *curfile)
438 : : {
439 : : size_t n_evict;
440 : 1481979 : struct list_elem *e = NULL;
441 : : struct bcache_item *item;
442 : 1481979 : struct fnamedic_item *victim = NULL;
443 : :
444 : 1481979 : spin_lock(&bcache_lock);
445 : :
446 [ + + ]: 23591645 : while(victim == NULL) {
447 : : // select victim file (the tail of FILE_LRU)
448 : 22109666 : victim = _bcache_get_victim();
449 [ + + ]: 22154855 : while(victim) {
450 : 1527168 : spin_lock(&victim->lock);
451 : :
452 : : // check whether this file has at least one block to be evictied
453 [ + + ][ + + ]: 1527168 : if (!_file_empty(victim)) {
[ - + ]
454 : : // select this file as victim
455 : 1481979 : break;
456 : : }else{
457 : : // empty file
458 : : // move this file to empty list (it is ok that
459 : : // this was already moved to empty list by other thread)
460 : 45189 : _bcache_move_fname_list(victim, &file_empty);
461 : 45189 : spin_unlock(&victim->lock);
462 : :
463 : 45189 : victim = NULL;
464 : : }
465 : : }
466 : : }
467 [ - + ]: 1481979 : assert(victim);
468 : 1481979 : spin_unlock(&bcache_lock);
469 : :
470 : 1481979 : victim->nvictim++;
471 : :
472 : : // select victim clean block of the victim file
473 : 1481979 : n_evict = 0;
474 [ + + ]: 1491223 : while(n_evict < BCACHE_EVICT_UNIT) {
475 : :
476 : : #ifdef __BCACHE_SECOND_CHANCE
477 : 1901 : while(1) {
478 : : // repeat until zero-score item is found
479 : 1483880 : e = list_pop_back(&victim->cleanlist);
480 [ + + ]: 1679848 : while (e == NULL) {
481 : : // when the victim file has no clean block .. evict dirty block
482 [ - + ]: 195968 : if (_bcache_evict_dirty(victim, 1) != FDB_RESULT_SUCCESS) {
483 : 0 : spin_unlock(&victim->lock);
484 : 0 : return NULL;
485 : : }
486 : :
487 : : // pop back from cleanlist
488 : 195968 : e = list_pop_back(&victim->cleanlist);
489 : : }
490 : :
491 : 1483880 : item = _get_entry(e, struct bcache_item, list_elem);
492 [ + + ]: 1483880 : if (item->score == 0) {
493 : 1481979 : break;
494 : : } else {
495 : : // give second chance to the item
496 : 1901 : item->score--;
497 : 1901 : list_push_front(&victim->cleanlist, &item->list_elem);
498 : : }
499 : : }
500 : : #else
501 : : e = list_pop_back(&victim->cleanlist);
502 : : while (e == NULL) {
503 : : // when the victim file has no clean block .. evict dirty block
504 : : if (_bcache_evict_dirty(victim, 1) != FDB_RESULT_SUCCESS) {
505 : : spin_unlock(&victim->lock);
506 : : return NULL;
507 : : }
508 : :
509 : : // pop back from cleanlist
510 : : e = list_pop_back(&victim->cleanlist);
511 : : }
512 : : item = _get_entry(e, struct bcache_item, list_elem);
513 : : #endif
514 : :
515 : 1481979 : victim->nitems--;
516 : :
517 : 1481979 : spin_lock(&item->lock);
518 : :
519 : : // remove from hash and insert into freelist
520 : 1481979 : hash_remove(&victim->hashtable, &item->hash_elem);
521 : :
522 : : // add to freelist
523 : 1481979 : _bcache_release_freeblock(item);
524 : 1481979 : n_evict++;
525 : :
526 : 1481979 : spin_unlock(&item->lock);
527 : :
528 [ + + ]: 1481979 : if (victim->nitems == 0) {
529 : 1472735 : break;
530 : : }
531 : : }
532 : :
533 : : // check whether the victim file has no cached block
534 [ + + ][ + + ]: 1481979 : if (_file_empty(victim)) {
[ + - ]
535 : : // remove from FILE_LRU and insert into FILE_EMPTY
536 : 1472735 : _bcache_move_fname_list(victim, &file_empty);
537 : : }
538 : :
539 : 1481979 : spin_unlock(&victim->lock);
540 : :
541 : 1481979 : return &item->list_elem;
542 : : }
543 : :
544 : 120 : struct fnamedic_item * _fname_create(struct filemgr *file) {
545 : : // TODO: we MUST NOT directly read file sturcture
546 : :
547 : : struct fnamedic_item *fname_new;
548 : 120 : fname_new = (struct fnamedic_item *)malloc(sizeof(struct fnamedic_item));
549 : :
550 : 120 : fname_new->filename_len = strlen(file->filename);
551 : 120 : fname_new->filename = (char *)malloc(fname_new->filename_len + 1);
552 : 120 : memcpy(fname_new->filename, file->filename, fname_new->filename_len);
553 : : //strcpy(fname_new->filename, file->filename);
554 : 120 : fname_new->filename[fname_new->filename_len] = 0;
555 : :
556 : : // calculate hash value
557 : 120 : fname_new->hash = chksum((void *)fname_new->filename,
558 : 120 : fname_new->filename_len);
559 : 120 : spin_init(&fname_new->lock);
560 : 120 : fname_new->curlist = NULL;
561 : 120 : fname_new->curfile = file;
562 : 120 : fname_new->nvictim = 0;
563 : 120 : fname_new->nitems = 0;
564 : :
565 : : // initialize tree
566 : 120 : avl_init(&fname_new->tree, NULL);
567 : 120 : avl_init(&fname_new->tree_idx, NULL);
568 : : // initialize clean list
569 : 120 : list_init(&fname_new->cleanlist);
570 : : // initialize hash table
571 : : hash_init(&fname_new->hashtable, BCACHE_NBUCKET,
572 : 120 : _bcache_hash, _bcache_cmp);
573 : :
574 : : // insert into fname dictionary
575 : 120 : hash_insert(&fnamedic, &fname_new->hash_elem);
576 : 120 : file->bcache = fname_new;
577 : :
578 : 120 : return fname_new;
579 : : }
580 : :
581 : 120 : void _fname_free(struct fnamedic_item *fname)
582 : : {
583 : : // remove from corresponding list
584 : 120 : _bcache_move_fname_list(fname, NULL);
585 : :
586 : : // file must be empty
587 [ + - ][ + - ]: 120 : assert(_file_empty(fname));
[ - + ]
588 : :
589 : : // free hash
590 : 120 : hash_free(&fname->hashtable);
591 : :
592 : 120 : free(fname->filename);
593 : 120 : spin_destroy(&fname->lock);
594 : 120 : }
595 : :
596 : 30683673 : INLINE void _bcache_set_score(struct bcache_item *item)
597 : : {
598 : : #ifdef __CRC32
599 : : uint8_t marker;
600 : :
601 : : // set PTR and get block MARKER
602 : 30683673 : marker = *((uint8_t*)(item->addr) + bcache_blocksize-1);
603 [ + + ]: 30683673 : if (marker == BLK_MARKER_BNODE ) {
604 : : // b-tree node .. set item's score to 1
605 : 16093565 : item->score = 1;
606 : : } else {
607 : 14590108 : item->score = 0;
608 : : }
609 : : #endif
610 : 30683673 : }
611 : :
612 : 13104770 : int bcache_read(struct filemgr *file, bid_t bid, void *buf)
613 : : {
614 : : struct hash_elem *h;
615 : : struct bcache_item *item;
616 : : struct bcache_item query;
617 : : struct fnamedic_item *fname;
618 : :
619 : 13104770 : spin_lock(&bcache_lock);
620 : 13114183 : fname = file->bcache;
621 : 13114183 : spin_unlock(&bcache_lock);
622 : :
623 [ + + ]: 13113783 : if (fname) {
624 : : // file exists
625 : : // set query
626 : 13113742 : query.bid = bid;
627 : 13113742 : query.fname = fname;
628 : 13113742 : query.fname->curfile = file;
629 : :
630 : : // relay lock
631 : 13113742 : spin_lock(&fname->lock);
632 : :
633 : : // move the file to the head of FILE_LRU
634 : 13114074 : _bcache_move_fname_list(fname, &file_lru);
635 : :
636 : : // search BHASH
637 : 13114131 : h = hash_find(&fname->hashtable, &query.hash_elem);
638 [ + + ]: 13113812 : if (h) {
639 : : // cache hit
640 : 11390451 : item = _get_entry(h, struct bcache_item, hash_elem);
641 [ - + ]: 11390451 : assert(item->fname == fname);
642 : 11390451 : spin_lock(&item->lock);
643 : :
644 [ - + ]: 11390624 : assert(!(item->flag & BCACHE_FREE));
645 : :
646 : : // move the item to the head of list if the block is clean
647 : : // (don't care if the block is dirty)
648 [ + + ]: 11390624 : if (!(item->flag & BCACHE_DIRTY)) {
649 : 5243404 : list_remove(&item->fname->cleanlist, &item->list_elem);
650 : 5242490 : list_push_front(&item->fname->cleanlist, &item->list_elem);
651 : : }
652 : :
653 : : // relay lock
654 : 11388954 : spin_unlock(&fname->lock);
655 : :
656 : 11388244 : memcpy(buf, item->addr, bcache_blocksize);
657 : 11388244 : _bcache_set_score(item);
658 : :
659 : 11380546 : spin_unlock(&item->lock);
660 : :
661 : 11381009 : return bcache_blocksize;
662 : : }else {
663 : : // cache miss
664 : 1723361 : spin_unlock(&fname->lock);
665 : : }
666 : : }
667 : :
668 : : // does not exist .. cache miss
669 : 13101497 : return 0;
670 : : }
671 : :
672 : 33427 : void bcache_invalidate_block(struct filemgr *file, bid_t bid)
673 : : {
674 : : struct hash_elem *h;
675 : : struct bcache_item *item;
676 : : struct bcache_item query;
677 : : struct fnamedic_item *fname;
678 : :
679 : 33427 : fname = file->bcache;
680 [ + - ]: 33427 : if (fname) {
681 : : // file exists
682 : : // set query
683 : 33427 : query.bid = bid;
684 : 33427 : query.fname = fname;
685 : 33427 : query.fname->curfile = file;
686 : :
687 : : // relay lock
688 : 33427 : spin_lock(&fname->lock);
689 : :
690 : : // move the file to the head of FILE_LRU
691 : 33427 : _bcache_move_fname_list(fname, &file_lru);
692 : :
693 : : // search BHASH
694 : 33427 : h = hash_find(&fname->hashtable, &query.hash_elem);
695 [ + - ]: 33427 : if (h) {
696 : : // cache hit
697 : 33427 : item = _get_entry(h, struct bcache_item, hash_elem);
698 [ - + ]: 33427 : assert(item->fname == fname);
699 : 33427 : spin_lock(&item->lock);
700 : :
701 [ - + ]: 33427 : assert(!(item->flag & BCACHE_FREE));
702 : :
703 : 33427 : fname->nitems--;
704 : :
705 [ + - ]: 33427 : if (!(item->flag & BCACHE_DIRTY)) {
706 : : // only for clean blocks
707 : : // remove from hash and insert into freelist
708 : 33427 : hash_remove(&fname->hashtable, &item->hash_elem);
709 : : // remove from clean list
710 : 33427 : list_remove(&item->fname->cleanlist, &item->list_elem);
711 : :
712 : : // add to freelist
713 : 33427 : _bcache_release_freeblock(item);
714 : :
715 : : // check whether the victim file has no cached block
716 [ - + ][ # # ]: 33427 : if (_file_empty(fname)) {
[ # # ]
717 : : // remove from FILE_LRU and insert into FILE_EMPTY
718 : 0 : _bcache_move_fname_list(fname, &file_empty);
719 : : }
720 : : }
721 : :
722 : 33427 : spin_unlock(&item->lock);
723 : 33427 : spin_unlock(&fname->lock);
724 : : }else {
725 : : // cache miss
726 : 0 : spin_unlock(&fname->lock);
727 : : }
728 : : }
729 : :
730 : : // does not exist .. cache miss
731 : 33427 : }
732 : :
733 : 10504911 : int bcache_write(struct filemgr *file,
734 : : bid_t bid,
735 : : void *buf,
736 : : bcache_dirty_t dirty)
737 : : {
738 : 10504911 : struct hash_elem *h = NULL;
739 : : struct bcache_item *item;
740 : : struct bcache_item query;
741 : : struct fnamedic_item *fname_new;
742 : :
743 : 10504911 : spin_lock(&bcache_lock);
744 : 10525669 : fname_new = file->bcache;
745 [ + + ]: 10525669 : if (fname_new == NULL) {
746 : : // filename doesn't exist in filename dictionary .. create
747 : 31 : fname_new = _fname_create(file);
748 : : }
749 : 10525669 : spin_unlock(&bcache_lock);
750 : :
751 : : // acquire lock
752 : 10525639 : spin_lock(&fname_new->lock);
753 : :
754 : : // move to the head of FILE_LRU
755 : 10525669 : _bcache_move_fname_list(fname_new, &file_lru);
756 : :
757 : : // set query
758 : 10525669 : query.bid = bid;
759 : 10525669 : query.fname = fname_new;
760 : 10525669 : query.fname->curfile = file;
761 : :
762 : : // search hash table
763 : 10525669 : h = hash_find(&fname_new->hashtable, &query.hash_elem);
764 [ + + ]: 10525669 : if (h == NULL) {
765 : : // cache miss
766 : : // get a free block
767 [ + + ]: 3362338 : while ((item = _bcache_alloc_freeblock()) == NULL) {
768 : : // no free block .. perform eviction
769 : 1481979 : spin_unlock(&fname_new->lock);
770 : :
771 : 1481979 : _bcache_evict(fname_new);
772 : :
773 : 1479425 : spin_lock(&fname_new->lock);
774 : : }
775 : :
776 : : // re-search hash table
777 : 1880359 : h = hash_find(&fname_new->hashtable, &query.hash_elem);
778 [ + - ]: 1880359 : if (h == NULL) {
779 : : // insert into hash table
780 : 1880359 : item->bid = bid;
781 : 1880359 : item->fname = fname_new;
782 : 1880359 : item->flag = BCACHE_FREE;
783 : 1880359 : hash_insert(&fname_new->hashtable, &item->hash_elem);
784 : 1880359 : h = &item->hash_elem;
785 : 1880359 : spin_lock(&item->lock);
786 : : }else{
787 : : // insert into freelist again
788 : 0 : _bcache_release_freeblock(item);
789 : 0 : item = _get_entry(h, struct bcache_item, hash_elem);
790 : 0 : spin_lock(&item->lock);
791 : : }
792 : : }else{
793 : 8645310 : item = _get_entry(h, struct bcache_item, hash_elem);
794 : 8645310 : spin_lock(&item->lock);
795 : : }
796 : :
797 [ - + ]: 10525669 : assert(h);
798 : :
799 [ + + ]: 10525669 : if (item->flag & BCACHE_FREE) {
800 : 1880359 : fname_new->nitems++;
801 : : }
802 : :
803 : : // remove from the list if the block is in clean list
804 [ + + ][ + + ]: 10525669 : if (!(item->flag & BCACHE_DIRTY) && !(item->flag & BCACHE_FREE)) {
805 : 330262 : list_remove(&fname_new->cleanlist, &item->list_elem);
806 : : }
807 : 10525669 : item->flag &= ~BCACHE_FREE;
808 : :
809 [ + + ]: 10525669 : if (dirty == BCACHE_REQ_DIRTY) {
810 : : // DIRTY request
811 : : // to avoid re-insert already existing item into tree
812 [ + + ]: 8802278 : if (!(item->flag & BCACHE_DIRTY)) {
813 : : // dirty block
814 : : // insert into tree
815 : : struct dirty_item *ditem;
816 : : uint8_t marker;
817 : :
818 : : ditem = (struct dirty_item *)
819 : 493783 : mempool_alloc(sizeof(struct dirty_item));
820 : 493783 : ditem->item = item;
821 : :
822 : 493783 : marker = *((uint8_t*)buf + bcache_blocksize-1);
823 [ + + ]: 493783 : if (marker == BLK_MARKER_BNODE ) {
824 : : // b-tree node
825 : 87050 : avl_insert(&item->fname->tree_idx, &ditem->avl, _dirty_cmp);
826 : : } else {
827 : 406733 : avl_insert(&item->fname->tree, &ditem->avl, _dirty_cmp);
828 : : }
829 : : }
830 : 8802278 : item->flag |= BCACHE_DIRTY;
831 : : }else{
832 : : // CLEAN request
833 : : // insert into clean list only when it was originally clean
834 [ + + ]: 1723391 : if (!(item->flag & BCACHE_DIRTY)) {
835 : 1716838 : list_push_front(&item->fname->cleanlist, &item->list_elem);
836 : 1716838 : item->flag &= ~(BCACHE_DIRTY);
837 : : }
838 : : }
839 : :
840 : 10525669 : spin_unlock(&fname_new->lock);
841 : :
842 : 10525669 : memcpy(item->addr, buf, bcache_blocksize);
843 : 10525669 : _bcache_set_score(item);
844 : :
845 : 10525544 : spin_unlock(&item->lock);
846 : :
847 : 10525524 : return bcache_blocksize;
848 : : }
849 : :
850 : 9001116 : int bcache_write_partial(struct filemgr *file,
851 : : bid_t bid,
852 : : void *buf,
853 : : size_t offset,
854 : : size_t len)
855 : : {
856 : : struct hash_elem *h;
857 : : struct bcache_item *item;
858 : : struct bcache_item query;
859 : : struct fnamedic_item *fname_new;
860 : :
861 : 9001116 : spin_lock(&bcache_lock);
862 : 9001116 : fname_new = file->bcache;
863 [ + + ]: 9001116 : if (fname_new == NULL) {
864 : : // filename doesn't exist in filename dictionary .. create
865 : 89 : fname_new = _fname_create(file);
866 : : }
867 : 9001116 : spin_unlock(&bcache_lock);
868 : :
869 : : // relay lock
870 : 9001116 : spin_lock(&fname_new->lock);
871 : :
872 : : // set query
873 : 9001116 : query.bid = bid;
874 : 9001116 : query.fname = fname_new;
875 : 9001116 : query.fname->curfile = file;
876 : :
877 : : // search hash table
878 : 9001116 : h = hash_find(&fname_new->hashtable, &query.hash_elem);
879 [ + + ]: 9001116 : if (h == NULL) {
880 : : // cache miss .. partial write fail .. return 0
881 : 210755 : spin_unlock(&fname_new->lock);
882 : 210755 : return 0;
883 : :
884 : : }else{
885 : : // cache hit .. get the block
886 : 8790361 : item = _get_entry(h, struct bcache_item, hash_elem);
887 : : }
888 : :
889 : : // move to the head of FILE_LRU
890 : 8790361 : _bcache_move_fname_list(fname_new, &file_lru);
891 : :
892 : 8790361 : spin_lock(&item->lock);
893 : :
894 [ - + ]: 8790361 : assert(!(item->flag & BCACHE_FREE));
895 : :
896 : : // check whether this is dirty block
897 : : // to avoid re-insert already existing item into tree
898 [ + + ]: 8790361 : if (!(item->flag & BCACHE_DIRTY)) {
899 : : // this block was clean block
900 : : uint8_t marker;
901 : : struct dirty_item *ditem;
902 : :
903 : : // remove from clean list
904 : 1231 : list_remove(&item->fname->cleanlist, &item->list_elem);
905 : :
906 : 1231 : ditem = (struct dirty_item *)mempool_alloc(sizeof(struct dirty_item));
907 : 1231 : ditem->item = item;
908 : :
909 : : // insert into tree
910 : 1231 : marker = *((uint8_t*)buf + bcache_blocksize-1);
911 [ - + ]: 1231 : if (marker == BLK_MARKER_BNODE ) {
912 : : // b-tree node
913 : 0 : avl_insert(&item->fname->tree_idx, &ditem->avl, _dirty_cmp);
914 : : } else {
915 : 1231 : avl_insert(&item->fname->tree, &ditem->avl, _dirty_cmp);
916 : : }
917 : : }
918 : :
919 : : // always set this block as dirty
920 : 8790361 : item->flag |= BCACHE_DIRTY;
921 : :
922 : 8790361 : spin_unlock(&fname_new->lock);
923 : :
924 : 8790361 : memcpy((uint8_t *)(item->addr) + offset, buf, len);
925 : 8790361 : _bcache_set_score(item);
926 : :
927 : 8790361 : spin_unlock(&item->lock);
928 : :
929 : 9001116 : return len;
930 : : }
931 : :
932 : : // remove all dirty blocks of the FILE
933 : : // (they are only discarded and not written back)
934 : 242 : void bcache_remove_dirty_blocks(struct filemgr *file)
935 : : {
936 : : struct fnamedic_item *fname_item;
937 : :
938 : 242 : fname_item = file->bcache;
939 : :
940 [ + + ]: 242 : if (fname_item) {
941 : : // acquire lock
942 : 240 : spin_lock(&fname_item->lock);
943 : :
944 : : // remove all dirty block
945 [ + + ][ - + ]: 244 : while(!_tree_empty(fname_item->tree) ||
[ + + ]
946 : 240 : !_tree_empty(fname_item->tree_idx)) {
947 : 4 : _bcache_evict_dirty(fname_item, 0);
948 : : }
949 : :
950 : : // check whether the victim file is empty
951 [ - + ][ # # ]: 240 : if (_file_empty(fname_item)) {
[ # # ]
952 : : // remove from FILE_LRU and insert into FILE_EMPTY
953 : 0 : _bcache_move_fname_list(fname_item, &file_empty);
954 : : }
955 : :
956 : 240 : spin_unlock(&fname_item->lock);
957 : : }
958 : 242 : }
959 : :
960 : : // remove all clean blocks of the FILE
961 : 121 : void bcache_remove_clean_blocks(struct filemgr *file)
962 : : {
963 : : struct list_elem *e;
964 : : struct bcache_item *item;
965 : : struct fnamedic_item *fname_item;
966 : :
967 : 121 : fname_item = file->bcache;
968 : :
969 [ + + ]: 121 : if (fname_item) {
970 : : // acquire lock
971 : 120 : spin_lock(&fname_item->lock);
972 : :
973 : : // remove all clean blocks
974 : 120 : e = list_begin(&fname_item->cleanlist);
975 [ + + ]: 365073 : while(e){
976 : 364953 : item = _get_entry(e, struct bcache_item, list_elem);
977 : 364953 : spin_lock(&item->lock);
978 : :
979 : : // remove from clean list
980 : 364953 : e = list_remove(&fname_item->cleanlist, e);
981 : : // remove from hash table
982 : 364953 : hash_remove(&fname_item->hashtable, &item->hash_elem);
983 : : // insert into free list
984 : 364953 : _bcache_release_freeblock(item);
985 : 364953 : spin_unlock(&item->lock);
986 : : }
987 : :
988 : : // check whether the victim file is empty
989 [ + - ][ + - ]: 120 : if (_file_empty(fname_item)) {
[ + - ]
990 : : // remove from FILE_LRU and insert into FILE_EMPTY
991 : 120 : _bcache_move_fname_list(fname_item, &file_empty);
992 : : }
993 : :
994 : 120 : spin_unlock(&fname_item->lock);
995 : : }
996 : 121 : }
997 : :
998 : : // remove file from filename dictionary
999 : : // MUST sure that there is no dirty block belongs to this FILE
1000 : : // (or memory leak occurs)
1001 : 121 : void bcache_remove_file(struct filemgr *file)
1002 : : {
1003 : : struct fnamedic_item *fname_item;
1004 : :
1005 : 121 : fname_item = file->bcache;
1006 : :
1007 [ + + ]: 121 : if (fname_item) {
1008 : : // acquire lock
1009 : 120 : spin_lock(&bcache_lock);
1010 : 120 : spin_lock(&fname_item->lock);
1011 : : // file must be empty
1012 [ + - ][ + - ]: 120 : assert(_file_empty(fname_item));
[ - + ]
1013 : :
1014 : : // remove from fname dictionary hash table
1015 : 120 : hash_remove(&fnamedic, &fname_item->hash_elem);
1016 : 120 : spin_unlock(&bcache_lock);
1017 : :
1018 : 120 : _fname_free(fname_item);
1019 : :
1020 : 120 : spin_unlock(&fname_item->lock);
1021 : :
1022 : 120 : free(fname_item);
1023 : : }
1024 : 121 : }
1025 : :
1026 : : // flush and synchronize all dirty blocks of the FILE
1027 : : // dirty blocks will be changed to clean blocks (not discarded)
1028 : 3758 : fdb_status bcache_flush(struct filemgr *file)
1029 : : {
1030 : : struct fnamedic_item *fname_item;
1031 : 3758 : fdb_status status = FDB_RESULT_SUCCESS;
1032 : :
1033 : 3758 : fname_item = file->bcache;
1034 : :
1035 [ + + ]: 3758 : if (fname_item) {
1036 : : // acquire lock
1037 : 3757 : spin_lock(&fname_item->lock);
1038 : :
1039 [ + + ][ + + ]: 10414 : while(!_tree_empty(fname_item->tree) ||
[ + + ]
1040 : 5610 : !_tree_empty(fname_item->tree_idx)) {
1041 : 6657 : status = _bcache_evict_dirty(fname_item, 1);
1042 [ - + ]: 6657 : if (status != FDB_RESULT_SUCCESS) {
1043 : 0 : break;
1044 : : }
1045 : : }
1046 : :
1047 : 3757 : spin_unlock(&fname_item->lock);
1048 : : }
1049 : 3758 : return status;
1050 : : }
1051 : :
1052 : 58 : void bcache_init(int nblock, int blocksize)
1053 : : {
1054 : : int i;
1055 : : struct bcache_item *item;
1056 : : struct list_elem *e;
1057 : :
1058 : 58 : list_init(&freelist);
1059 : 58 : list_init(&file_lru);
1060 : 58 : list_init(&file_empty);
1061 : :
1062 : 58 : hash_init(&fnamedic, BCACHE_NDICBUCKET, _fname_hash, _fname_cmp);
1063 : :
1064 : 58 : bcache_blocksize = blocksize;
1065 : 58 : bcache_flush_unit = BCACHE_FLUSH_UNIT;
1066 : 58 : bcache_nblock = nblock;
1067 : 58 : spin_init(&bcache_lock);
1068 : 58 : spin_init(&freelist_lock);
1069 : 58 : spin_init(&filelist_lock);
1070 : 58 : fnames = 0;
1071 : :
1072 [ + + ]: 1506624 : for (i=0;i<nblock;++i){
1073 : 1506566 : item = (struct bcache_item *)malloc(sizeof(struct bcache_item));
1074 : :
1075 : 1506566 : item->bid = BLK_NOT_FOUND;
1076 : 1506566 : item->fname = NULL;
1077 : 1506566 : item->flag = 0x0 | BCACHE_FREE;
1078 : 1506566 : spin_init(&item->lock);
1079 : 1506566 : item->score = 0;
1080 : :
1081 : 1506566 : list_push_front(&freelist, &item->list_elem);
1082 : 1506566 : freelist_count++;
1083 : : //hash_insert(&bhash, &item->hash_elem);
1084 : : }
1085 : 58 : e = list_begin(&freelist);
1086 [ + + ]: 1506624 : while(e){
1087 : 1506566 : item = _get_entry(e, struct bcache_item, list_elem);
1088 : 1506566 : item->addr = (void *)malloc(bcache_blocksize);
1089 : 1506566 : e = list_next(e);
1090 : : }
1091 : :
1092 : 58 : }
1093 : :
1094 : 95472 : uint64_t bcache_get_num_free_blocks()
1095 : : {
1096 : 95472 : return freelist_count;
1097 : : }
1098 : :
1099 : 0 : void bcache_print_items()
1100 : : {
1101 : 0 : int n=1;
1102 : 0 : size_t sw=0;
1103 : : size_t nfiles, nitems, nfileitems, nclean, ndirty;
1104 : : size_t scores[100], i, scores_local[100];
1105 : : size_t docs, bnodes;
1106 : : size_t docs_local, bnodes_local;
1107 : : uint8_t *ptr;
1108 : :
1109 : 0 : nfiles = nitems = nfileitems = nclean = ndirty = 0;
1110 : 0 : docs = bnodes = 0;
1111 : 0 : memset(scores, 0, sizeof(size_t)*100);
1112 : :
1113 : : struct fnamedic_item *fname;
1114 : : struct bcache_item *item;
1115 : : struct dirty_item *dirty;
1116 : : struct list_elem *e, *ee;
1117 : : struct avl_node *a;
1118 : :
1119 : 0 : e = list_begin(&file_lru);
1120 : 0 : printf(" === Block cache statistics summary ===\n");
1121 : : printf("%3s %20s (%6s)(%6s)(c%6s d%6s)",
1122 : 0 : "No", "Filename", "#Pages", "#Evict", "Clean", "Dirty");
1123 : : #ifdef __CRC32
1124 : 0 : printf("%6s%6s", "Doc", "Node");
1125 : : #endif
1126 [ # # ]: 0 : for (i=0;i<=n;++i) {
1127 : 0 : printf(" [%d] ", (int)i);
1128 : : }
1129 : 0 : printf("\n");
1130 : :
1131 : : scan:
1132 [ # # ]: 0 : while(e){
1133 : 0 : fname = _get_entry(e, struct fnamedic_item, le);
1134 : 0 : ee = list_begin(&fname->cleanlist);
1135 : 0 : a = avl_first(&fname->tree);
1136 : 0 : memset(scores_local, 0, sizeof(size_t)*100);
1137 : 0 : nfileitems = nclean = ndirty = 0;
1138 : 0 : docs_local = bnodes_local = 0;
1139 : :
1140 [ # # ]: 0 : while(ee){
1141 : 0 : item = _get_entry(ee, struct bcache_item, list_elem);
1142 : 0 : scores[item->score]++;
1143 : 0 : scores_local[item->score]++;
1144 : 0 : nitems++;
1145 : 0 : nfileitems++;
1146 : 0 : nclean++;
1147 : : #ifdef __CRC32
1148 : 0 : ptr = (uint8_t*)item->addr + bcache_blocksize - 1;
1149 [ # # # ]: 0 : switch (*ptr) {
1150 : : case BLK_MARKER_BNODE:
1151 : 0 : bnodes_local++;
1152 : 0 : break;
1153 : : case BLK_MARKER_DOC:
1154 : 0 : docs_local++;
1155 : 0 : break;
1156 : : }
1157 : : #endif
1158 : 0 : ee = list_next(ee);
1159 : : }
1160 [ # # ]: 0 : while(a){
1161 : 0 : dirty = _get_entry(a, struct dirty_item, avl);
1162 : 0 : item = dirty->item;
1163 : 0 : scores[item->score]++;
1164 : 0 : scores_local[item->score]++;
1165 : 0 : nitems++;
1166 : 0 : nfileitems++;
1167 : 0 : ndirty++;
1168 : : #ifdef __CRC32
1169 : 0 : ptr = (uint8_t*)item->addr + bcache_blocksize - 1;
1170 [ # # # ]: 0 : switch (*ptr) {
1171 : : case BLK_MARKER_BNODE:
1172 : 0 : bnodes_local++;
1173 : 0 : break;
1174 : : case BLK_MARKER_DOC:
1175 : 0 : docs_local++;
1176 : 0 : break;
1177 : : }
1178 : : #endif
1179 : 0 : a = avl_next(a);
1180 : : }
1181 : :
1182 : : printf("%3d %20s (%6d)(%6d)(c%6d d%6d)",
1183 : : (int)nfiles+1, fname->filename,
1184 : : (int)fname->nitems, (int)fname->nvictim,
1185 : 0 : (int)nclean, (int)ndirty);
1186 : 0 : printf("%6d%6d", (int)docs_local, (int)bnodes_local);
1187 [ # # ]: 0 : for (i=0;i<=n;++i){
1188 : 0 : printf("%6d ", (int)scores_local[i]);
1189 : : }
1190 : 0 : printf("\n");
1191 : :
1192 : 0 : docs += docs_local;
1193 : 0 : bnodes += bnodes_local;
1194 : :
1195 : 0 : nfiles++;
1196 : 0 : e = list_next(e);
1197 : : }
1198 : 0 : printf(" ===\n");
1199 [ # # ]: 0 : if (sw == 0){
1200 : 0 : e = list_begin(&file_empty);
1201 : 0 : sw=1;
1202 : 0 : goto scan;
1203 : : }
1204 : :
1205 : 0 : printf("%d files %d items\n", (int)nfiles, (int)nitems);
1206 [ # # ]: 0 : for (i=0;i<=n;++i){
1207 : 0 : printf("[%d]: %d\n", (int)i, (int)scores[i]);
1208 : : }
1209 : 0 : printf("Documents: %d blocks\n", (int)docs);
1210 : 0 : printf("Index nodes: %d blocks\n", (int)bnodes);
1211 : 0 : }
1212 : :
1213 : 0 : INLINE void _bcache_free_bcache_item(struct hash_elem *h)
1214 : : {
1215 : 0 : struct bcache_item *item = _get_entry(h, struct bcache_item, hash_elem);
1216 : 0 : free(item->addr);
1217 : 0 : spin_destroy(&item->lock);
1218 : 0 : free(item);
1219 : 0 : }
1220 : :
1221 : 0 : INLINE void _bcache_free_fnamedic(struct hash_elem *h)
1222 : : {
1223 : : struct fnamedic_item *item;
1224 : 0 : item = _get_entry(h, struct fnamedic_item, hash_elem);
1225 : 0 : hash_free_active(&item->hashtable, _bcache_free_bcache_item);
1226 : :
1227 : 0 : _bcache_move_fname_list(item, NULL);
1228 : :
1229 : 0 : free(item->filename);
1230 : 0 : free(item);
1231 : 0 : }
1232 : :
1233 : 56 : void bcache_shutdown()
1234 : : {
1235 : : struct bcache_item *item;
1236 : : struct list_elem *e;
1237 : :
1238 : 56 : e = list_begin(&freelist);
1239 [ + + ]: 1504574 : while(e) {
1240 : 1504518 : item = _get_entry(e, struct bcache_item, list_elem);
1241 : 1504518 : e = list_remove(&freelist, e);
1242 : 1504518 : free(item->addr);
1243 : 1504518 : spin_destroy(&item->lock);
1244 : 1504518 : free(item);
1245 : : }
1246 : :
1247 : 56 : spin_lock(&bcache_lock);
1248 : 56 : hash_free_active(&fnamedic, _bcache_free_fnamedic);
1249 : 56 : spin_unlock(&bcache_lock);
1250 : :
1251 : 56 : spin_destroy(&bcache_lock);
1252 : 56 : spin_destroy(&freelist_lock);
1253 : 56 : spin_destroy(&filelist_lock);
1254 : 56 : }
1255 : :
|