LCOV - code coverage report
Current view: top level - src - blockcache.cc (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 416 529 78.6 %
Date: 2015-01-12 15:17:13 Functions: 25 28 89.3 %
Branches: 169 248 68.1 %

           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                 :            : 

Generated by: LCOV version 1.11