LCOV - code coverage report
Current view: top level - src - btreeblock.cc (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 411 440 93.4 %
Date: 2015-01-12 15:17:13 Functions: 25 27 92.6 %
Branches: 175 196 89.3 %

           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 <stdio.h>
      19                 :            : #include <stdlib.h>
      20                 :            : #include <string.h>
      21                 :            : 
      22                 :            : #include "common.h"
      23                 :            : #include "btreeblock.h"
      24                 :            : 
      25                 :            : #include "memleak.h"
      26                 :            : 
      27                 :            : #ifdef __DEBUG
      28                 :            : #ifndef __DEBUG_BTREEBLOCK
      29                 :            :     #undef DBG
      30                 :            :     #undef DBGCMD
      31                 :            :     #undef DBGSW
      32                 :            :     #define DBG(...)
      33                 :            :     #define DBGCMD(...)
      34                 :            :     #define DBGSW(n, ...)
      35                 :            : #endif
      36                 :            : #endif
      37                 :            : 
      38                 :            : struct btreeblk_addr{
      39                 :            :     void *addr;
      40                 :            :     struct list_elem le;
      41                 :            : };
      42                 :            : 
      43                 :            : struct btreeblk_block {
      44                 :            :     bid_t bid;
      45                 :            :     int sb_no;
      46                 :            :     uint32_t pos;
      47                 :            :     uint8_t dirty;
      48                 :            :     uint8_t age;
      49                 :            :     void *addr;
      50                 :            :     struct list_elem le;
      51                 :            :     struct avl_node avl;
      52                 :            : #ifdef __BTREEBLK_BLOCKPOOL
      53                 :            :     struct btreeblk_addr *addr_item;
      54                 :            : #endif
      55                 :            : };
      56                 :            : 
      57                 :            : #ifdef __BTREEBLK_READ_TREE
      58                 :            : static int _btreeblk_bid_cmp(struct avl_node *a, struct avl_node *b, void *aux)
      59                 :            : {
      60                 :            :     bid_t aa_bid, bb_bid;
      61                 :            :     struct btreeblk_block *aa, *bb;
      62                 :            :     aa = _get_entry(a, struct btreeblk_block, avl);
      63                 :            :     bb = _get_entry(b, struct btreeblk_block, avl);
      64                 :            :     aa_bid = aa->bid;
      65                 :            :     bb_bid = bb->bid;
      66                 :            : 
      67                 :            : #ifdef __BIT_CMP
      68                 :            :     return _CMP_U64(aa_bid, bb_bid);
      69                 :            : #else
      70                 :            :     if (aa->bid < bb->bid) {
      71                 :            :         return -1;
      72                 :            :     } else if (aa->bid > bb->bid) {
      73                 :            :         return 1;
      74                 :            :     } else {
      75                 :            :         return 0;
      76                 :            :     }
      77                 :            : #endif
      78                 :            : }
      79                 :            : #endif
      80                 :            : 
      81                 :    7803495 : INLINE void _btreeblk_get_aligned_block(struct btreeblk_handle *handle,
      82                 :            :                                         struct btreeblk_block *block)
      83                 :            : {
      84                 :            : #ifdef __BTREEBLK_BLOCKPOOL
      85                 :            :     struct list_elem *e;
      86                 :            : 
      87                 :    7803495 :     e = list_pop_front(&handle->blockpool);
      88         [ +  + ]:    7803103 :     if (e) {
      89                 :    7799875 :         block->addr_item = _get_entry(e, struct btreeblk_addr, le);
      90                 :    7799875 :         block->addr = block->addr_item->addr;
      91                 :    7803103 :         return;
      92                 :            :     }
      93                 :            :     // no free addr .. create
      94                 :            :     block->addr_item = (struct btreeblk_addr *)
      95                 :       3228 :                        mempool_alloc(sizeof(struct btreeblk_addr));
      96                 :            : #endif
      97                 :            : 
      98                 :       3228 :     malloc_align(block->addr, FDB_SECTOR_SIZE, handle->file->blocksize);
      99                 :            : }
     100                 :            : 
     101                 :    7801230 : INLINE void _btreeblk_free_aligned_block(struct btreeblk_handle *handle,
     102                 :            :                                          struct btreeblk_block *block)
     103                 :            : {
     104                 :            : #ifdef __BTREEBLK_BLOCKPOOL
     105         [ -  + ]:    7801230 :     assert(block->addr_item);
     106                 :            :     // sync addr & insert into pool
     107                 :    7801230 :     block->addr_item->addr = block->addr;
     108                 :    7801230 :     list_push_front(&handle->blockpool, &block->addr_item->le);
     109                 :    7801169 :     block->addr_item = NULL;
     110                 :    7801169 :     return;
     111                 :            : 
     112                 :            : #endif
     113                 :            : 
     114                 :            :     free_align(block->addr);
     115                 :            : }
     116                 :            : 
     117                 :          0 : INLINE int is_subblock(bid_t subbid)
     118                 :            : {
     119                 :            :     uint8_t flag;
     120                 :          0 :     flag = (subbid >> (8 * (sizeof(bid_t)-2))) & 0x00ff;
     121                 :          0 :     return flag;
     122                 :            : }
     123                 :            : 
     124                 :       5753 : INLINE void bid2subbid(bid_t bid, size_t subblock_no, size_t idx, bid_t *subbid)
     125                 :            : {
     126                 :            :     bid_t flag;
     127                 :            :     // to distinguish subblock_no==0 to non-subblock
     128                 :       5753 :     subblock_no++;
     129                 :       5753 :     flag = (subblock_no << 5) | idx;
     130                 :       5753 :     *subbid = bid | (flag << (8 * (sizeof(bid_t)-2)));
     131                 :       5753 : }
     132                 :  133294526 : INLINE void subbid2bid(bid_t subbid, size_t *subblock_no, size_t *idx, bid_t *bid)
     133                 :            : {
     134                 :            :     uint8_t flag;
     135                 :  133294526 :     flag = (subbid >> (8 * (sizeof(bid_t)-2))) & 0x00ff;
     136                 :  133294526 :     *subblock_no = flag >> 5;
     137                 :            :     // to distinguish subblock_no==0 to non-subblock
     138                 :  133294526 :     *subblock_no -= 1;
     139                 :  133294526 :     *idx = flag & (0x20 - 0x01);
     140                 :  133294526 :     *bid = ((bid_t)(subbid << 16)) >> 16;
     141                 :  133294526 : }
     142                 :            : 
     143                 :      91810 : INLINE void * _btreeblk_alloc(void *voidhandle, bid_t *bid, int sb_no)
     144                 :            : {
     145                 :      91810 :     struct btreeblk_handle *handle = (struct btreeblk_handle *)voidhandle;
     146                 :      91810 :     struct list_elem *e = list_end(&handle->alc_list);
     147                 :            :     struct btreeblk_block *block;
     148                 :            :     uint32_t curpos;
     149                 :            : 
     150         [ +  + ]:      91810 :     if (e) {
     151                 :       1844 :         block = _get_entry(e, struct btreeblk_block, le);
     152         [ +  + ]:       1844 :         if (block->pos <= (handle->file->blocksize) - (handle->nodesize)) {
     153         [ +  - ]:         27 :             if (filemgr_is_writable(handle->file, block->bid)) {
     154                 :         27 :                 curpos = block->pos;
     155                 :         27 :                 block->pos += (handle->nodesize);
     156                 :            :                 *bid = block->bid * handle->nnodeperblock + curpos /
     157                 :         27 :                        (handle->nodesize);
     158                 :         27 :                 return ((uint8_t *)block->addr + curpos);
     159                 :            :             }
     160                 :            :         }
     161                 :            :     }
     162                 :            : 
     163                 :            :     // allocate new block from file manager
     164                 :      91783 :     block = (struct btreeblk_block *)mempool_alloc(sizeof(struct btreeblk_block));
     165                 :      91783 :     _btreeblk_get_aligned_block(handle, block);
     166                 :      91783 :     block->sb_no = sb_no;
     167                 :      91783 :     block->pos = handle->nodesize;
     168                 :      91783 :     block->bid = filemgr_alloc(handle->file, handle->log_callback);
     169                 :      91783 :     block->dirty = 1;
     170                 :      91783 :     block->age = 0;
     171                 :            : 
     172                 :            : #ifdef __CRC32
     173                 :      91783 :     memset((uint8_t *)block->addr + handle->nodesize - BLK_MARKER_SIZE,
     174                 :     183566 :            BLK_MARKER_BNODE, BLK_MARKER_SIZE);
     175                 :            : #endif
     176                 :            : 
     177                 :            :     // btree bid differs to filemgr bid
     178                 :      91783 :     *bid = block->bid * handle->nnodeperblock;
     179                 :      91783 :     list_push_back(&handle->alc_list, &block->le);
     180                 :            : 
     181                 :      91783 :     handle->nlivenodes++;
     182                 :            : 
     183                 :      91810 :     return block->addr;
     184                 :            : }
     185                 :      89950 : void * btreeblk_alloc(void *voidhandle, bid_t *bid) {
     186                 :      89950 :     return _btreeblk_alloc(voidhandle, bid, -1);
     187                 :            : }
     188                 :            : 
     189                 :            : 
     190                 :            : #ifdef __ENDIAN_SAFE
     191                 :    8688953 : INLINE void _btreeblk_encode(struct btreeblk_handle *handle,
     192                 :            :                              struct btreeblk_block *block)
     193                 :            : {
     194                 :            :     size_t i, j, n, nsb, sb_size, offset;
     195                 :            :     void *addr;
     196                 :            :     struct bnode *node;
     197                 :            :     struct bnode **node_arr;
     198                 :            : 
     199         [ +  + ]:   17377933 :     for (offset=0; offset<handle->nnodeperblock; ++offset) {
     200         [ +  + ]:    8688966 :         if (block->sb_no > -1) {
     201                 :      46477 :             nsb = handle->sb[block->sb_no].nblocks;
     202                 :      46477 :             sb_size = handle->sb[block->sb_no].sb_size;
     203                 :            :         } else {
     204                 :    8642489 :             nsb = 1;
     205                 :    8642489 :             sb_size = 0;
     206                 :            :         }
     207                 :            : 
     208         [ +  + ]:   17856253 :         for (i=0;i<nsb;++i) {
     209                 :            :             addr = (uint8_t*)block->addr +
     210                 :            :                    (handle->nodesize) * offset +
     211                 :    9167273 :                    sb_size * i;
     212                 :    9167273 :             node_arr = btree_get_bnode_array(addr, &n);
     213         [ +  + ]:   18334575 :             for (j=0;j<n;++j){
     214                 :    9167288 :                 node = node_arr[j];
     215                 :    9167288 :                 node->flag = _endian_encode(node->flag);
     216                 :    9167288 :                 node->level = _endian_encode(node->level);
     217                 :    9167288 :                 node->nentry = _endian_encode(node->nentry);
     218                 :            :             }
     219                 :    9167287 :             free(node_arr);
     220                 :            :         }
     221                 :            :     }
     222                 :    8688967 : }
     223                 :   16400098 : INLINE void _btreeblk_decode(struct btreeblk_handle *handle,
     224                 :            :                              struct btreeblk_block *block)
     225                 :            : {
     226                 :            :     size_t i, j, n, nsb, sb_size, offset;
     227                 :            :     void *addr;
     228                 :            :     struct bnode *node;
     229                 :            :     struct bnode **node_arr;
     230                 :            : 
     231         [ +  + ]:   32801465 :     for (offset=0; offset<handle->nnodeperblock; ++offset) {
     232         [ +  + ]:   16400088 :         if (block->sb_no > -1) {
     233                 :      60081 :             nsb = handle->sb[block->sb_no].nblocks;
     234                 :      60081 :             sb_size = handle->sb[block->sb_no].sb_size;
     235                 :            :         } else {
     236                 :   16340007 :             nsb = 1;
     237                 :   16340007 :             sb_size = 0;
     238                 :            :         }
     239                 :            : 
     240         [ +  + ]:   33606382 :         for (i=0;i<nsb;++i) {
     241                 :            :             addr = (uint8_t*)block->addr +
     242                 :            :                    (handle->nodesize) * offset +
     243                 :   17205015 :                    sb_size * i;
     244                 :   17205015 :             node_arr = btree_get_bnode_array(addr, &n);
     245         [ +  + ]:   34412487 :             for (j=0;j<n;++j){
     246                 :   17206193 :                 node = node_arr[j];
     247                 :   17206193 :                 node->flag = _endian_decode(node->flag);
     248                 :   17206193 :                 node->level = _endian_decode(node->level);
     249                 :   17206193 :                 node->nentry = _endian_decode(node->nentry);
     250                 :            :             }
     251                 :   17206294 :             free(node_arr);
     252                 :            :         }
     253                 :            :     }
     254                 :   16401377 : }
     255                 :            : #else
     256                 :            : #define _btreeblk_encode(a,b)
     257                 :            : #define _btreeblk_decode(a,b)
     258                 :            : #endif
     259                 :            : 
     260                 :            : INLINE void _btreeblk_free_dirty_block(struct btreeblk_handle *handle,
     261                 :            :                                        struct btreeblk_block *block);
     262                 :            : 
     263                 :  116203564 : INLINE void * _btreeblk_read(void *voidhandle, bid_t bid, int sb_no)
     264                 :            : {
     265                 :  116203564 :     struct list_elem *elm = NULL;
     266                 :  116203564 :     struct btreeblk_block *block = NULL;
     267                 :  116203564 :     struct btreeblk_handle *handle = (struct btreeblk_handle *)voidhandle;
     268                 :            :     bid_t _bid, filebid;
     269                 :            :     int subblock;
     270                 :            :     int offset;
     271                 :            :     size_t sb, idx;
     272                 :            : 
     273                 :  116203564 :     sb = idx = 0;
     274                 :  116203564 :     subbid2bid(bid, &sb, &idx, &_bid);
     275                 :  116172976 :     subblock = is_subblock(bid);
     276                 :  116158125 :     filebid = _bid / handle->nnodeperblock;
     277                 :  116158125 :     offset = _bid % handle->nnodeperblock;
     278                 :            : 
     279                 :            :     // check whether the block is in current lists
     280                 :            :     // read list (clean or dirty)
     281                 :            : #ifdef __BTREEBLK_READ_TREE
     282                 :            :     // AVL-tree
     283                 :            :     // check first 3 elements in the list first,
     284                 :            :     // and then retrieve AVL-tree
     285                 :            :     size_t count = 0;
     286                 :            :     for (elm = list_begin(&handle->read_list);
     287                 :            :          (elm && count < 3); elm = list_next(elm)) {
     288                 :            :         block = _get_entry(elm, struct btreeblk_block, le);
     289                 :            :         if (block->bid == filebid) {
     290                 :            :             block->age = 0;
     291                 :            :             // move the elements to the front
     292                 :            :             list_remove(&handle->read_list, &block->le);
     293                 :            :             list_push_front(&handle->read_list, &block->le);
     294                 :            :             if (subblock) {
     295                 :            :                 return (uint8_t *)block->addr +
     296                 :            :                        (handle->nodesize) * offset +
     297                 :            :                        handle->sb[sb].sb_size * idx;
     298                 :            :             } else {
     299                 :            :                 return (uint8_t *)block->addr +
     300                 :            :                        (handle->nodesize) * offset;
     301                 :            :             }
     302                 :            :         }
     303                 :            :         count++;
     304                 :            :     }
     305                 :            : 
     306                 :            :     struct btreeblk_block query;
     307                 :            :     query.bid = filebid;
     308                 :            :     struct avl_node *a;
     309                 :            :     a = avl_search(&handle->read_tree, &query.avl, _btreeblk_bid_cmp);
     310                 :            :     if (a) { // cache hit
     311                 :            :         block = _get_entry(a, struct btreeblk_block, avl);
     312                 :            :         block->age = 0;
     313                 :            :         // move the elements to the front
     314                 :            :         list_remove(&handle->read_list, &block->le);
     315                 :            :         list_push_front(&handle->read_list, &block->le);
     316                 :            :         if (subblock) {
     317                 :            :             return (uint8_t *)block->addr +
     318                 :            :                    (handle->nodesize) * offset +
     319                 :            :                    handle->sb[sb].sb_size * idx;
     320                 :            :         } else {
     321                 :            :             return (uint8_t *)block->addr +
     322                 :            :                    (handle->nodesize) * offset;
     323                 :            :         }
     324                 :            :     }
     325                 :            : #else
     326                 :            :     // list
     327         [ +  + ]: 1159297980 :     for (elm = list_begin(&handle->read_list); elm; elm = list_next(elm)) {
     328                 : 1151726710 :         block = _get_entry(elm, struct btreeblk_block, le);
     329         [ +  + ]: 1151726710 :         if (block->bid == filebid) {
     330                 :  108586855 :             block->age = 0;
     331         [ +  + ]:  108586855 :             if (subblock) {
     332                 :            :                 return (uint8_t *)block->addr +
     333                 :            :                        (handle->nodesize) * offset +
     334                 :   37034154 :                        handle->sb[sb].sb_size * idx;
     335                 :            :             } else {
     336                 :            :                 return (uint8_t *)block->addr +
     337                 :   71552701 :                        (handle->nodesize) * offset;
     338                 :            :             }
     339                 :            :         }
     340                 :            :     }
     341                 :            : #endif
     342                 :            : 
     343                 :            :     // allocation list (dirty)
     344         [ +  + ]:    7710944 :     for (elm = list_begin(&handle->alc_list); elm; elm = list_next(elm)) {
     345                 :       1810 :         block = _get_entry(elm, struct btreeblk_block, le);
     346 [ +  + ][ +  - ]:       1810 :         if (block->bid == filebid &&
     347                 :            :             block->pos >= (handle->nodesize) * offset) {
     348                 :       1382 :             block->age = 0;
     349         [ +  + ]:       1382 :             if (subblock) {
     350                 :            :                 return (uint8_t *)block->addr +
     351                 :            :                        (handle->nodesize) * offset +
     352                 :        541 :                        handle->sb[sb].sb_size * idx;
     353                 :            :             } else {
     354                 :            :                 return (uint8_t *)block->addr +
     355                 :        841 :                        (handle->nodesize) * offset;
     356                 :            :             }
     357                 :            :         }
     358                 :            :     }
     359                 :            : 
     360                 :            :     // there is no block in lists
     361                 :            :     // if miss, read from file and add item into read list
     362                 :    7712128 :     block = (struct btreeblk_block *)mempool_alloc(sizeof(struct btreeblk_block));
     363         [ +  + ]:    7712128 :     block->sb_no = (subblock)?(sb):(sb_no);
     364                 :    7712128 :     block->pos = (handle->file->blocksize);
     365                 :    7712128 :     block->bid = filebid;
     366                 :    7712128 :     block->dirty = 0;
     367                 :    7712128 :     block->age = 0;
     368                 :            : 
     369                 :    7712128 :     _btreeblk_get_aligned_block(handle, block);
     370         [ -  + ]:    7711684 :     if (filemgr_read(handle->file, block->bid, block->addr,
     371                 :    7711366 :                      handle->log_callback) != FDB_RESULT_SUCCESS) {
     372                 :          0 :         _btreeblk_free_aligned_block(handle, block);
     373                 :          0 :         mempool_free(block);
     374                 :          0 :         return NULL;
     375                 :            :     }
     376                 :    7711684 :     _btreeblk_decode(handle, block);
     377                 :            : 
     378                 :    7712285 :     list_push_front(&handle->read_list, &block->le);
     379                 :            : #ifdef __BTREEBLK_READ_TREE
     380                 :            :     avl_insert(&handle->read_tree, &block->avl, _btreeblk_bid_cmp);
     381                 :            : #endif
     382                 :            : 
     383         [ +  + ]:    7712187 :     if (subblock) {
     384                 :            :         return (uint8_t *)block->addr +
     385                 :            :                (handle->nodesize) * offset +
     386                 :      12368 :                handle->sb[sb].sb_size * idx;
     387                 :            :     } else {
     388                 :  116300424 :         return (uint8_t *)block->addr + (handle->nodesize) * offset;
     389                 :            :     }
     390                 :            : }
     391                 :            : 
     392                 :  116170374 : void * btreeblk_read(void *voidhandle, bid_t bid)
     393                 :            : {
     394                 :  116170374 :     return _btreeblk_read(voidhandle, bid, -1);
     395                 :            : }
     396                 :            : 
     397                 :            : void btreeblk_set_dirty(void *voidhandle, bid_t bid);
     398                 :      36215 : void * btreeblk_move(void *voidhandle, bid_t bid, bid_t *new_bid)
     399                 :            : {
     400                 :      36215 :     struct btreeblk_handle *handle = (struct btreeblk_handle *)voidhandle;
     401                 :            :     void *old_addr, *new_addr;
     402                 :            :     bid_t _bid, _new_bid;
     403                 :            :     int i, subblock;
     404                 :            :     size_t sb, idx, new_idx;
     405                 :            : 
     406                 :      36215 :     old_addr = new_addr = NULL;
     407                 :      36215 :     sb = idx = 0;
     408                 :      36215 :     subbid2bid(bid, &sb, &idx, &_bid);
     409                 :      36215 :     subblock = is_subblock(bid);
     410                 :            : 
     411         [ +  + ]:      36215 :     if (!subblock) {
     412                 :            :         // normal block
     413                 :      34565 :         old_addr = btreeblk_read(voidhandle, bid);
     414                 :      34565 :         new_addr = btreeblk_alloc(voidhandle, new_bid);
     415                 :      34565 :         handle->nlivenodes--;
     416                 :            : 
     417                 :            :         // move
     418                 :      34565 :         memcpy(new_addr, old_addr, (handle->nodesize));
     419                 :            : 
     420                 :      34565 :         filemgr_invalidate_block(handle->file, bid);
     421                 :      34565 :         return new_addr;
     422                 :            :     } else {
     423                 :            :         // subblock
     424         [ +  + ]:       1650 :         if (handle->sb[sb].bid == _bid) {
     425                 :            :             //2 case 1
     426                 :            :             // current subblock set is not writable
     427                 :            :             // move all of them
     428                 :        836 :             old_addr = _btreeblk_read(voidhandle, _bid, sb);
     429                 :        836 :             new_addr = _btreeblk_alloc(voidhandle, &_new_bid, sb);
     430                 :        836 :             handle->nlivenodes--;
     431                 :        836 :             handle->sb[sb].bid = _new_bid;
     432                 :        836 :             bid2subbid(_new_bid, sb, idx, new_bid);
     433                 :            : 
     434                 :            :             // move
     435                 :        836 :             memcpy(new_addr, old_addr, (handle->nodesize));
     436                 :            : 
     437                 :        836 :             filemgr_invalidate_block(handle->file, _bid);
     438                 :        836 :             return (uint8_t*)new_addr + handle->sb[sb].sb_size * idx;
     439                 :            :         } else {
     440                 :            :             //2 case 2
     441                 :            :             // move only the target subblock
     442                 :            :             // into current subblock set (no allocation is required)
     443                 :        814 :             old_addr = _btreeblk_read(voidhandle, _bid, sb);
     444                 :            : 
     445                 :        814 :             new_idx = handle->sb[sb].nblocks;
     446         [ +  + ]:       4635 :             for (i=0;i<handle->sb[sb].nblocks;++i){
     447         [ +  + ]:       4556 :                 if (handle->sb[sb].bitmap[i] == 0) {
     448                 :        735 :                     new_idx = i;
     449                 :        735 :                     break;
     450                 :            :                 }
     451                 :            :             }
     452   [ +  +  +  + ]:       1549 :             if (new_idx == handle->sb[sb].nblocks ||
                 [ +  + ]
     453                 :        735 :                 !filemgr_is_writable(handle->file, handle->sb[sb].bid)) {
     454                 :            :                 // case 2-1
     455                 :            :                 // no free slot OR not writable
     456                 :            :                 // allocate new block
     457                 :        216 :                 new_addr = _btreeblk_alloc(voidhandle, &_new_bid, sb);
     458                 :        216 :                 handle->nlivenodes--;
     459                 :        216 :                 handle->sb[sb].bid = _new_bid;
     460                 :        216 :                 memset(handle->sb[sb].bitmap, 0, handle->sb[sb].nblocks);
     461                 :        216 :                 new_idx = 0;
     462                 :            :             } else {
     463                 :            :                 // case 2-2
     464                 :            :                 // append to the current block
     465                 :        598 :                 new_addr = _btreeblk_read(voidhandle, handle->sb[sb].bid, sb);
     466                 :        598 :                 btreeblk_set_dirty(voidhandle, handle->sb[sb].bid);
     467                 :            :             }
     468                 :            : 
     469                 :        814 :             handle->sb[sb].bitmap[new_idx] = 1;
     470                 :        814 :             bid2subbid(handle->sb[sb].bid, sb, new_idx, new_bid);
     471                 :            : 
     472                 :            :             // move
     473                 :       1628 :             memcpy((uint8_t*)new_addr + handle->sb[sb].sb_size * new_idx,
     474                 :        814 :                    (uint8_t*)old_addr + handle->sb[sb].sb_size * idx,
     475                 :       3256 :                    handle->sb[sb].sb_size);
     476                 :            : 
     477                 :      36215 :             return (uint8_t*)new_addr + handle->sb[sb].sb_size * new_idx;
     478                 :            :         }
     479                 :            :     }
     480                 :            : }
     481                 :            : 
     482                 :          0 : void btreeblk_remove(void *voidhandle, bid_t bid)
     483                 :            : {
     484                 :          0 :     struct btreeblk_handle *handle = (struct btreeblk_handle *)voidhandle;
     485                 :            :     bid_t _bid;
     486                 :            :     int i, subblock, nitems;
     487                 :            :     size_t sb, idx;
     488                 :            : 
     489                 :          0 :     sb = idx = 0;
     490                 :          0 :     subbid2bid(bid, &sb, &idx, &_bid);
     491                 :          0 :     subblock = is_subblock(bid);
     492                 :            : 
     493         [ #  # ]:          0 :     if (subblock) {
     494                 :            :         // subblock
     495         [ #  # ]:          0 :         if (handle->sb[sb].bid == _bid) {
     496                 :            :             // erase bitmap
     497                 :          0 :             handle->sb[sb].bitmap[idx] = 0;
     498                 :            :             // if all slots are empty, invalidate the block
     499                 :          0 :             nitems = 0;
     500         [ #  # ]:          0 :             for (i=0;i<handle->sb[sb].nblocks;++i){
     501         [ #  # ]:          0 :                 if (handle->sb[sb].bitmap) {
     502                 :          0 :                     nitems++;
     503                 :            :                 }
     504                 :            :             }
     505         [ #  # ]:          0 :             if (nitems == 0) {
     506                 :          0 :                 handle->sb[sb].bid = BLK_NOT_FOUND;
     507                 :          0 :                 handle->nlivenodes--;
     508                 :          0 :                 filemgr_invalidate_block(handle->file, _bid);
     509                 :            :             }
     510                 :            :         }
     511                 :            :     } else {
     512                 :            :         // normal block
     513                 :          0 :         handle->nlivenodes--;
     514                 :          0 :         filemgr_invalidate_block(handle->file, bid);
     515                 :            :     }
     516                 :          0 : }
     517                 :            : 
     518                 :    8636704 : int btreeblk_is_writable(void *voidhandle, bid_t bid)
     519                 :            : {
     520                 :    8636704 :     struct btreeblk_handle *handle = (struct btreeblk_handle *)voidhandle;
     521                 :            :     bid_t _bid;
     522                 :            :     bid_t filebid;
     523                 :            :     size_t sb, idx;
     524                 :            : 
     525                 :    8636704 :     sb = idx = 0;
     526                 :    8636704 :     subbid2bid(bid, &sb, &idx, &_bid);
     527                 :    8636703 :     filebid = _bid / handle->nnodeperblock;
     528                 :            : 
     529                 :    8636703 :     return filemgr_is_writable(handle->file, filebid);
     530                 :            : }
     531                 :            : 
     532                 :    8603092 : void btreeblk_set_dirty(void *voidhandle, bid_t bid)
     533                 :            : {
     534                 :    8603092 :     struct btreeblk_handle *handle = (struct btreeblk_handle *)voidhandle;
     535                 :            :     struct list_elem *e;
     536                 :            :     struct btreeblk_block *block;
     537                 :            :     bid_t _bid;
     538                 :            :     bid_t filebid;
     539                 :            :     size_t sb, idx;
     540                 :            : 
     541                 :    8603092 :     sb = idx = 0;
     542                 :    8603092 :     subbid2bid(bid, &sb, &idx, &_bid);
     543                 :    8603091 :     filebid = _bid / handle->nnodeperblock;
     544                 :            : 
     545                 :            : #ifdef __BTREEBLK_READ_TREE
     546                 :            :     // AVL-tree
     547                 :            :     struct btreeblk_block query;
     548                 :            :     query.bid = filebid;
     549                 :            :     struct avl_node *a;
     550                 :            :     a = avl_search(&handle->read_tree, &query.avl, _btreeblk_bid_cmp);
     551                 :            :     if (a) {
     552                 :            :         block = _get_entry(a, struct btreeblk_block, avl);
     553                 :            :         block->dirty = 1;
     554                 :            :     }
     555                 :            : #else
     556                 :            :     // list
     557                 :    8603091 :     e = list_begin(&handle->read_list);
     558         [ +  + ]:   32771639 :     while(e){
     559                 :   32769985 :         block = _get_entry(e, struct btreeblk_block, le);
     560         [ +  + ]:   32769985 :         if (block->bid == filebid) {
     561                 :    8601447 :             block->dirty = 1;
     562                 :    8601447 :             break;
     563                 :            :         }
     564                 :   24168538 :         e = list_next(e);
     565                 :            :     }
     566                 :            : #endif
     567                 :    8603101 : }
     568                 :            : 
     569                 :        160 : void _btreeblk_set_sb_no(void *voidhandle, bid_t bid, int sb_no)
     570                 :            : {
     571                 :        160 :     struct btreeblk_handle *handle = (struct btreeblk_handle *)voidhandle;
     572                 :            :     struct list_elem *e;
     573                 :            :     struct btreeblk_block *block;
     574                 :            :     bid_t _bid;
     575                 :            :     bid_t filebid;
     576                 :            :     size_t sb, idx;
     577                 :            : 
     578                 :        160 :     sb = idx = 0;
     579                 :        160 :     subbid2bid(bid, &sb, &idx, &_bid);
     580                 :        160 :     filebid = _bid / handle->nnodeperblock;
     581                 :            : 
     582                 :        160 :     e = list_begin(&handle->alc_list);
     583         [ +  + ]:        160 :     while(e){
     584                 :          5 :         block = _get_entry(e, struct btreeblk_block, le);
     585         [ +  - ]:          5 :         if (block->bid == filebid) {
     586                 :          5 :             block->sb_no = sb_no;
     587                 :          5 :             return;
     588                 :            :         }
     589                 :          0 :         e = list_next(e);
     590                 :            :     }
     591                 :            : 
     592                 :            : #ifdef __BTREEBLK_READ_TREE
     593                 :            :     // AVL-tree
     594                 :            :     struct btreeblk_block query;
     595                 :            :     query.bid = filebid;
     596                 :            :     struct avl_node *a;
     597                 :            :     a = avl_search(&handle->read_tree, &query.avl, _btreeblk_bid_cmp);
     598                 :            :     if (a) {
     599                 :            :         block = _get_entry(a, struct btreeblk_block, avl);
     600                 :            :         block->sb_no = sb_no;
     601                 :            :     }
     602                 :            : #else
     603                 :            :     // list
     604                 :        155 :     e = list_begin(&handle->read_list);
     605         [ +  - ]:        461 :     while(e){
     606                 :        301 :         block = _get_entry(e, struct btreeblk_block, le);
     607         [ +  + ]:        301 :         if (block->bid == filebid) {
     608                 :        155 :             block->sb_no = sb_no;
     609                 :        155 :             return;
     610                 :            :         }
     611                 :        146 :         e = list_next(e);
     612                 :            :     }
     613                 :            : #endif
     614                 :            : }
     615                 :            : 
     616                 :    8689388 : size_t btreeblk_get_size(void *voidhandle, bid_t bid)
     617                 :            : {
     618                 :            :     bid_t _bid;
     619                 :            :     size_t sb, idx;
     620                 :    8689388 :     struct btreeblk_handle *handle = (struct btreeblk_handle *)voidhandle;
     621                 :            : 
     622 [ +  + ][ +  + ]:    8689388 :     if (is_subblock(bid) && bid != BLK_NOT_FOUND) {
                 [ +  + ]
     623                 :      68182 :         subbid2bid(bid, &sb, &idx, &_bid);
     624                 :      68182 :         return handle->sb[sb].sb_size;
     625                 :            :     } else {
     626                 :    8689395 :         return handle->nodesize;
     627                 :            :     }
     628                 :            : }
     629                 :            : 
     630                 :       1999 : void * btreeblk_alloc_sub(void *voidhandle, bid_t *bid)
     631                 :            : {
     632                 :            :     int i;
     633                 :            :     void *addr;
     634                 :       1999 :     struct btreeblk_handle *handle = (struct btreeblk_handle *)voidhandle;
     635                 :            : 
     636         [ +  + ]:       1999 :     if (handle->nsb == 0) {
     637                 :          4 :         return btreeblk_alloc(voidhandle, bid);
     638                 :            :     }
     639                 :            : 
     640                 :            :     // check current block is available
     641         [ +  + ]:       1995 :     if (handle->sb[0].bid != BLK_NOT_FOUND) {
     642         [ +  + ]:       1821 :         if (filemgr_is_writable(handle->file, handle->sb[0].bid)) {
     643                 :            :             // check if there is an empty slot
     644         [ +  + ]:       6346 :             for (i=0;i<handle->sb[0].nblocks;++i){
     645         [ +  + ]:       6336 :                 if (handle->sb[0].bitmap[i] == 0) {
     646                 :            :                     // return subblock
     647                 :       1809 :                     handle->sb[0].bitmap[i] = 1;
     648                 :       1809 :                     bid2subbid(handle->sb[0].bid, 0, i, bid);
     649                 :       1809 :                     addr = _btreeblk_read(voidhandle, handle->sb[0].bid, 0);
     650                 :       1809 :                     btreeblk_set_dirty(voidhandle, handle->sb[0].bid);
     651                 :            :                     return (void*)
     652                 :            :                            ((uint8_t*)addr +
     653                 :       1809 :                             handle->sb[0].sb_size * i);
     654                 :            :                 }
     655                 :            :             }
     656                 :            :         }
     657                 :            :     }
     658                 :            : 
     659                 :            :     // existing subblock cannot be used .. give it up & allocate new one
     660                 :        186 :     addr = _btreeblk_alloc(voidhandle, &handle->sb[0].bid, 0);
     661                 :        186 :     memset(handle->sb[0].bitmap, 0, handle->sb[0].nblocks);
     662                 :        186 :     i = 0;
     663                 :        186 :     handle->sb[0].bitmap[i] = 1;
     664                 :        186 :     bid2subbid(handle->sb[0].bid, 0, i, bid);
     665                 :       1999 :     return (void*)((uint8_t*)addr + handle->sb[0].sb_size * i);
     666                 :            : }
     667                 :            : 
     668                 :       2576 : void * btreeblk_enlarge_node(void *voidhandle,
     669                 :            :                              bid_t old_bid,
     670                 :            :                              size_t req_size,
     671                 :            :                              bid_t *new_bid)
     672                 :            : {
     673                 :            :     int i;
     674                 :            :     bid_t bid;
     675                 :            :     size_t src_sb, src_idx, src_nitems;
     676                 :            :     size_t dst_sb, dst_idx, dst_nitems;
     677                 :            :     void *src_addr, *dst_addr;
     678                 :       2576 :     struct btreeblk_handle *handle = (struct btreeblk_handle *)voidhandle;
     679                 :            : 
     680         [ -  + ]:       2576 :     if (!is_subblock(old_bid)) {
     681                 :          0 :         return NULL;
     682                 :            :     }
     683                 :       2576 :     src_addr = dst_addr = NULL;
     684                 :       2576 :     subbid2bid(old_bid, &src_sb, &src_idx, &bid);
     685                 :            : 
     686                 :       2576 :     dst_sb = 0;
     687                 :            :     // find sublock that can accommodate req_size
     688         [ +  + ]:       3786 :     for (i=src_sb+1; i<handle->nsb; ++i){
     689         [ +  + ]:       3318 :         if (handle->sb[i].sb_size > req_size) {
     690                 :       2108 :             dst_sb = i;
     691                 :       2108 :             break;
     692                 :            :         }
     693                 :            :     }
     694                 :            : 
     695                 :       2576 :     src_nitems = 0;
     696         [ +  + ]:      61754 :     for (i=0;i<handle->sb[src_sb].nblocks;++i){
     697         [ +  + ]:      59178 :         if (handle->sb[src_sb].bitmap[i]) {
     698                 :       6993 :             src_nitems++;
     699                 :            :         }
     700                 :            :     }
     701                 :            : 
     702                 :       2576 :     dst_nitems = 0;
     703         [ +  + ]:       2576 :     if (dst_sb > 0) {
     704                 :       2108 :         dst_idx = handle->sb[dst_sb].nblocks;
     705         [ +  + ]:      26680 :         for (i=0;i<handle->sb[dst_sb].nblocks;++i){
     706         [ +  + ]:      24572 :             if (handle->sb[dst_sb].bitmap[i]) {
     707                 :       8133 :                 dst_nitems++;
     708         [ +  + ]:      16439 :             } else if (dst_idx == handle->sb[dst_sb].nblocks) {
     709                 :       2037 :                 dst_idx = i;
     710                 :            :             }
     711                 :            :         }
     712                 :            :     }
     713                 :            : 
     714         [ +  + ]:       2576 :     if (dst_nitems == 0) {
     715                 :            :         // destination block is empty
     716                 :       1080 :         dst_idx = 0;
     717         [ +  + ]:       1080 :         if (src_nitems == 1) {
     718                 :            :             //2 case 1
     719                 :            :             // if there's only one subblock in the source block,
     720                 :            :             // then switch source block to destination block
     721                 :        193 :             src_addr = _btreeblk_read(voidhandle, bid, src_sb);
     722 [ +  + ][ +  + ]:        193 :             if (filemgr_is_writable(handle->file, bid) &&
                 [ +  + ]
     723                 :        163 :                 bid == handle->sb[src_sb].bid) {
     724                 :            :                 // case 1-1
     725                 :        160 :                 dst_addr = src_addr;
     726         [ +  + ]:        160 :                 if (dst_sb > 0) {
     727                 :         74 :                     handle->sb[dst_sb].bid = handle->sb[src_sb].bid;
     728                 :            :                 } else {
     729                 :         86 :                     *new_bid = handle->sb[src_sb].bid;
     730                 :            :                 }
     731                 :        160 :                 btreeblk_set_dirty(voidhandle, handle->sb[src_sb].bid);
     732                 :            :                 // we MUST change block->sb_no value since subblock is switched.
     733                 :            :                 // dst_sb == 0: regular block, otherwise: sub-block
     734                 :        160 :                 _btreeblk_set_sb_no(voidhandle, handle->sb[src_sb].bid,
     735         [ +  + ]:        160 :                                     ((dst_sb)?(dst_sb):(-1)));
     736                 :            :             } else {
     737                 :            :                 // case 1-2
     738                 :            :                 // if the source block is not writable, allocate new one
     739         [ +  + ]:         33 :                 if (dst_sb > 0) {
     740                 :            :                     dst_addr = _btreeblk_alloc(voidhandle,
     741                 :         23 :                                                &handle->sb[dst_sb].bid, dst_sb);
     742                 :            :                 } else {
     743                 :            :                     // normal (whole) block
     744                 :         10 :                     dst_addr = btreeblk_alloc(voidhandle, new_bid);
     745                 :            :                 }
     746                 :            :             }
     747                 :            : 
     748 [ +  + ][ +  + ]:        193 :             if (src_idx > 0 || dst_addr != src_addr) {
     749                 :            :                 // move node to the beginning of the block
     750                 :            :                 memmove(dst_addr,
     751                 :         94 :                         (uint8_t*)src_addr + handle->sb[src_sb].sb_size * src_idx,
     752                 :         94 :                         handle->sb[src_sb].sb_size);
     753                 :            :             }
     754         [ +  + ]:        193 :             if (dst_sb > 0) {
     755                 :         97 :                 handle->sb[dst_sb].bitmap[dst_idx] = 1;
     756                 :            :             }
     757         [ +  + ]:        193 :             if (bid == handle->sb[src_sb].bid) {
     758                 :            :                 // remove existing source block info
     759                 :        186 :                 handle->sb[src_sb].bid = BLK_NOT_FOUND;
     760                 :        186 :                 memset(handle->sb[src_sb].bitmap, 0,
     761                 :        186 :                        handle->sb[src_sb].nblocks);
     762                 :            :             }
     763                 :            : 
     764                 :            :         } else {
     765                 :            :             //2 case 2
     766                 :            :             // if there are more than one slubblocks in the source block,
     767                 :            :             // then allocate destination block and move the target subblock
     768                 :        887 :             src_addr = _btreeblk_read(voidhandle, bid, src_sb);
     769                 :            : 
     770         [ +  + ]:        887 :             if (dst_sb > 0) {
     771                 :            :                 // case 2-1
     772                 :        515 :                 dst_addr = _btreeblk_alloc(voidhandle, &handle->sb[dst_sb].bid, dst_sb);
     773                 :       1030 :                 memcpy((uint8_t*)dst_addr + handle->sb[dst_sb].sb_size * dst_idx,
     774                 :        515 :                        (uint8_t*)src_addr + handle->sb[src_sb].sb_size * src_idx,
     775                 :       2060 :                        handle->sb[src_sb].sb_size);
     776                 :        515 :                 handle->sb[dst_sb].bitmap[dst_idx] = 1;
     777                 :            :             } else {
     778                 :            :                 // case 2-2: normal (whole) block
     779                 :        372 :                 dst_addr = btreeblk_alloc(voidhandle, new_bid);
     780                 :            :                 memcpy((uint8_t*)dst_addr,
     781                 :        372 :                        (uint8_t*)src_addr + handle->sb[src_sb].sb_size * src_idx,
     782                 :        372 :                        handle->sb[src_sb].sb_size);
     783                 :            :             }
     784         [ +  + ]:        887 :             if (bid == handle->sb[src_sb].bid) {
     785                 :        880 :                 handle->sb[src_sb].bitmap[src_idx] = 0;
     786                 :            :             }
     787                 :            :         }
     788                 :            :     } else {
     789                 :            :         //2 case 3
     790                 :            :         // destination block exists (always happens when subblock)
     791                 :       1496 :         src_addr = _btreeblk_read(voidhandle, bid, src_sb);
     792 [ +  + ][ +  + ]:       1496 :         if (filemgr_is_writable(handle->file, handle->sb[dst_sb].bid) &&
                 [ +  + ]
     793                 :       1482 :             dst_idx != handle->sb[dst_sb].nblocks) {
     794                 :            :             // case 3-1
     795                 :       1412 :             dst_addr = _btreeblk_read(voidhandle, handle->sb[dst_sb].bid, dst_sb);
     796                 :            :         } else {
     797                 :            :             // case 3-2: allocate new destination block
     798                 :         84 :             dst_addr = _btreeblk_alloc(voidhandle, &handle->sb[dst_sb].bid, dst_sb);
     799                 :         84 :             memset(handle->sb[dst_sb].bitmap, 0, handle->sb[dst_sb].nblocks);
     800                 :         84 :             dst_idx = 0;
     801                 :            :         }
     802                 :            : 
     803                 :       2992 :         memcpy((uint8_t*)dst_addr + handle->sb[dst_sb].sb_size * dst_idx,
     804                 :       1496 :                (uint8_t*)src_addr + handle->sb[src_sb].sb_size * src_idx,
     805                 :       5984 :                handle->sb[src_sb].sb_size);
     806                 :       1496 :         handle->sb[dst_sb].bitmap[dst_idx] = 1;
     807         [ +  + ]:       1496 :         if (bid == handle->sb[src_sb].bid) {
     808                 :       1470 :             handle->sb[src_sb].bitmap[src_idx] = 0;
     809                 :            :         }
     810                 :            :     }
     811                 :            : 
     812         [ +  + ]:       2576 :     if (dst_sb > 0) {
     813                 :            :         // sub block
     814                 :       2108 :         bid2subbid(handle->sb[dst_sb].bid, dst_sb, dst_idx, new_bid);
     815                 :       2108 :         return (uint8_t*)dst_addr + handle->sb[dst_sb].sb_size * dst_idx;
     816                 :            :     } else {
     817                 :            :         // whole block
     818                 :       2576 :         return dst_addr;
     819                 :            :     }
     820                 :            : }
     821                 :            : 
     822                 :    7801520 : INLINE void _btreeblk_free_dirty_block(struct btreeblk_handle *handle,
     823                 :            :                                        struct btreeblk_block *block)
     824                 :            : {
     825                 :    7801520 :     _btreeblk_free_aligned_block(handle, block);
     826                 :    7801003 :     mempool_free(block);
     827                 :    7801003 : }
     828                 :            : 
     829                 :    8688950 : INLINE fdb_status _btreeblk_write_dirty_block(struct btreeblk_handle *handle,
     830                 :            :                                         struct btreeblk_block *block)
     831                 :            : {
     832                 :            :     fdb_status status;
     833                 :            :     //2 MUST BE modified to support multiple nodes in a block
     834                 :            : 
     835                 :    8688950 :     _btreeblk_encode(handle, block);
     836                 :            :     status = filemgr_write(handle->file, block->bid, block->addr,
     837                 :    8688967 :                            handle->log_callback);
     838                 :    8688964 :     _btreeblk_decode(handle, block);
     839                 :    8688964 :     return status;
     840                 :            : }
     841                 :            : 
     842                 :   16491384 : fdb_status btreeblk_operation_end(void *voidhandle)
     843                 :            : {
     844                 :            :     // flush and write all items in allocation list
     845                 :   16491384 :     struct btreeblk_handle *handle = (struct btreeblk_handle *)voidhandle;
     846                 :            :     struct list_elem *e;
     847                 :            :     struct btreeblk_block *block;
     848                 :            :     int writable;
     849                 :   16491384 :     fdb_status status = FDB_RESULT_SUCCESS;
     850                 :            : 
     851                 :            :     // write and free items in allocation list
     852                 :   16491384 :     e = list_begin(&handle->alc_list);
     853         [ +  + ]:   16584058 :     while(e){
     854                 :      91775 :         block = _get_entry(e, struct btreeblk_block, le);
     855                 :      91775 :         writable = filemgr_is_writable(handle->file, block->bid);
     856         [ +  - ]:      91775 :         if (writable) {
     857                 :      91775 :             status = _btreeblk_write_dirty_block(handle, block);
     858         [ +  + ]:      91775 :             if (status != FDB_RESULT_SUCCESS) {
     859                 :          3 :                 return status;
     860                 :            :             }
     861                 :            :         }else{
     862                 :          0 :             assert(0);
     863                 :            :         }
     864                 :            : 
     865 [ +  + ][ -  + ]:      91772 :         if (block->pos + (handle->nodesize) > (handle->file->blocksize) || !writable) {
     866                 :            :             // remove from alc_list and insert into read list
     867                 :      91770 :             e = list_remove(&handle->alc_list, &block->le);
     868                 :      91770 :             block->dirty = 0;
     869                 :      91770 :             list_push_front(&handle->read_list, &block->le);
     870                 :            : #ifdef __BTREEBLK_READ_TREE
     871                 :            :             avl_insert(&handle->read_tree, &block->avl, _btreeblk_bid_cmp);
     872                 :            : #endif
     873                 :            :         }else {
     874                 :            :             // reserve the block when there is enough space and the block is writable
     875                 :          2 :             e = list_next(e);
     876                 :            :         }
     877                 :            :     }
     878                 :            : 
     879                 :            :     // free items in read list
     880                 :            : #ifdef __BTREEBLK_READ_TREE
     881                 :            :     // AVL-tree
     882                 :            :     struct avl_node *a;
     883                 :            :     a = avl_first(&handle->read_tree);
     884                 :            :     while (a) {
     885                 :            :         block = _get_entry(a, struct btreeblk_block, avl);
     886                 :            :         a = avl_next(a);
     887                 :            : 
     888                 :            :         if (block->dirty) {
     889                 :            :             // write back only when the block is modified
     890                 :            :             status = _btreeblk_write_dirty_block(handle, block);
     891                 :            :             if (status != FDB_RESULT_SUCCESS) {
     892                 :            :                 return status;
     893                 :            :             }
     894                 :            :             block->dirty = 0;
     895                 :            :         }
     896                 :            : 
     897                 :            :         if (block->age >= BTREEBLK_AGE_LIMIT) {
     898                 :            :             list_remove(&handle->read_list, &block->le);
     899                 :            :             avl_remove(&handle->read_tree, &block->avl);
     900                 :            :             _btreeblk_free_dirty_block(handle, block);
     901                 :            :         } else {
     902                 :            :             block->age++;
     903                 :            :         }
     904                 :            :     }
     905                 :            : #else
     906                 :            :     // list
     907                 :   16492283 :     e = list_begin(&handle->read_list);
     908         [ +  + ]:  168587078 :     while(e){
     909                 :  152095617 :         block = _get_entry(e, struct btreeblk_block, le);
     910                 :            : 
     911         [ +  + ]:  152095617 :         if (block->dirty) {
     912                 :            :             // write back only when the block is modified
     913                 :    8571738 :             status = _btreeblk_write_dirty_block(handle, block);
     914         [ -  + ]:    8597187 :             if (status != FDB_RESULT_SUCCESS) {
     915                 :          0 :                 return status;
     916                 :            :             }
     917                 :    8597187 :             block->dirty = 0;
     918                 :            :         }
     919                 :            : 
     920         [ +  + ]:  152121066 :         if (block->age >= BTREEBLK_AGE_LIMIT) {
     921                 :    7776530 :             e = list_remove(&handle->read_list, &block->le);
     922                 :    7777616 :             _btreeblk_free_dirty_block(handle, block);
     923                 :            :         } else {
     924                 :  144344536 :             block->age++;
     925                 :  144344536 :             e = list_next(e);
     926                 :            :         }
     927                 :            :     }
     928                 :            : #endif
     929                 :   16491464 :     return status;
     930                 :            : }
     931                 :            : 
     932                 :      18073 : void btreeblk_discard_blocks(struct btreeblk_handle *handle)
     933                 :            : {
     934                 :            :     // discard all writable blocks in the read list
     935                 :            :     struct list_elem *e;
     936                 :            :     struct btreeblk_block *block;
     937                 :            : 
     938                 :            :     // free items in read list
     939                 :            : #ifdef __BTREEBLK_READ_TREE
     940                 :            :     // AVL-tree
     941                 :            :     struct avl_node *a;
     942                 :            :     a = avl_first(&handle->read_tree);
     943                 :            :     while (a) {
     944                 :            :         block = _get_entry(a, struct btreeblk_block, avl);
     945                 :            :         a = avl_next(a);
     946                 :            : 
     947                 :            :         list_remove(&handle->read_list, &block->le);
     948                 :            :         avl_remove(&handle->read_tree, &block->avl);
     949                 :            :         _btreeblk_free_dirty_block(handle, block);
     950                 :            :     }
     951                 :            : #else
     952                 :            :     // list
     953                 :      18073 :     e = list_begin(&handle->read_list);
     954         [ +  + ]:      40482 :     while(e){
     955                 :      22409 :         block = _get_entry(e, struct btreeblk_block, le);
     956                 :      22409 :         e = list_next(&block->le);
     957                 :            : 
     958                 :      22409 :         list_remove(&handle->read_list, &block->le);
     959                 :      22409 :         _btreeblk_free_dirty_block(handle, block);
     960                 :            :     }
     961                 :            : #endif
     962                 :      18073 : }
     963                 :            : 
     964                 :            : #ifdef __BTREEBLK_SUBBLOCK
     965                 :            : struct btree_blk_ops btreeblk_ops = {
     966                 :            :     btreeblk_alloc,
     967                 :            :     btreeblk_alloc_sub,
     968                 :            :     btreeblk_enlarge_node,
     969                 :            :     btreeblk_read,
     970                 :            :     btreeblk_move,
     971                 :            :     btreeblk_remove,
     972                 :            :     btreeblk_is_writable,
     973                 :            :     btreeblk_get_size,
     974                 :            :     btreeblk_set_dirty,
     975                 :            :     NULL
     976                 :            : };
     977                 :            : #else
     978                 :            : struct btree_blk_ops btreeblk_ops = {
     979                 :            :     btreeblk_alloc,
     980                 :            :     NULL,
     981                 :            :     NULL,
     982                 :            :     btreeblk_read,
     983                 :            :     btreeblk_move,
     984                 :            :     btreeblk_remove,
     985                 :            :     btreeblk_is_writable,
     986                 :            :     btreeblk_get_size,
     987                 :            :     btreeblk_set_dirty,
     988                 :            :     NULL
     989                 :            : };
     990                 :            : #endif
     991                 :            : 
     992                 :        560 : struct btree_blk_ops *btreeblk_get_ops()
     993                 :            : {
     994                 :        560 :     return &btreeblk_ops;
     995                 :            : }
     996                 :            : 
     997                 :        611 : void btreeblk_init(struct btreeblk_handle *handle, struct filemgr *file, int nodesize)
     998                 :            : {
     999                 :            :     int i;
    1000                 :            :     uint32_t _nodesize;
    1001                 :            : 
    1002                 :        611 :     handle->file = file;
    1003                 :        611 :     handle->nodesize = nodesize;
    1004                 :        611 :     handle->nnodeperblock = handle->file->blocksize / handle->nodesize;
    1005                 :        611 :     handle->nlivenodes = 0;
    1006                 :            : 
    1007                 :        611 :     list_init(&handle->alc_list);
    1008                 :        611 :     list_init(&handle->read_list);
    1009                 :            : #ifdef __BTREEBLK_READ_TREE
    1010                 :            :     avl_init(&handle->read_tree, NULL);
    1011                 :            : #endif
    1012                 :            : 
    1013                 :            : #ifdef __BTREEBLK_BLOCKPOOL
    1014                 :        611 :     list_init(&handle->blockpool);
    1015                 :            : #endif
    1016                 :            : 
    1017                 :            : #ifdef __BTREEBLK_SUBBLOCK
    1018                 :            :     // compute # subblock sets
    1019                 :        611 :     _nodesize = BTREEBLK_MIN_SUBBLOCK;
    1020 [ +  + ][ +  - ]:       3628 :     for (i=0; (_nodesize < nodesize && i<5); ++i){
                 [ +  + ]
    1021                 :       3017 :         _nodesize = _nodesize << 1;
    1022                 :            :     }
    1023                 :        611 :     handle->nsb = i;
    1024         [ +  + ]:        611 :     if (i) {
    1025                 :            :         handle->sb = (struct btreeblk_subblocks*)
    1026                 :        608 :                      malloc(sizeof(struct btreeblk_subblocks) * handle->nsb);
    1027                 :            :         // initialize each subblock set
    1028                 :        608 :         _nodesize = BTREEBLK_MIN_SUBBLOCK;
    1029         [ +  + ]:       3625 :         for (i=0;i<handle->nsb;++i){
    1030                 :       3017 :             handle->sb[i].bid = BLK_NOT_FOUND;
    1031                 :       3017 :             handle->sb[i].sb_size = _nodesize;
    1032                 :       3017 :             handle->sb[i].nblocks = nodesize / _nodesize;
    1033                 :       3017 :             handle->sb[i].bitmap = (uint8_t*)malloc(handle->sb[i].nblocks);
    1034                 :       3017 :             memset(handle->sb[i].bitmap, 0, handle->sb[i].nblocks);
    1035                 :       3017 :             _nodesize = _nodesize << 1;
    1036                 :            :         }
    1037                 :            :     } else {
    1038                 :          3 :         handle->sb = NULL;
    1039                 :            :     }
    1040                 :            : #endif
    1041                 :        611 : }
    1042                 :            : 
    1043                 :            : // shutdown
    1044                 :        607 : void btreeblk_free(struct btreeblk_handle *handle)
    1045                 :            : {
    1046                 :            :     struct list_elem *e;
    1047                 :            :     struct btreeblk_block *block;
    1048                 :            : 
    1049                 :            :     // free all blocks in alc list
    1050                 :        607 :     e = list_begin(&handle->alc_list);
    1051         [ +  + ]:        613 :     while(e) {
    1052                 :          6 :         block = _get_entry(e, struct btreeblk_block, le);
    1053                 :          6 :         e = list_remove(&handle->alc_list, &block->le);
    1054                 :          6 :         _btreeblk_free_dirty_block(handle, block);
    1055                 :            :     }
    1056                 :            : 
    1057                 :            :     // free all blocks in read list
    1058                 :            : #ifdef __BTREEBLK_READ_TREE
    1059                 :            :     // AVL tree
    1060                 :            :     struct avl_node *a;
    1061                 :            :     a = avl_first(&handle->read_tree);
    1062                 :            :     while (a) {
    1063                 :            :         block = _get_entry(a, struct btreeblk_block, avl);
    1064                 :            :         a = avl_next(a);
    1065                 :            :         avl_remove(&handle->read_tree, &block->avl);
    1066                 :            :         _btreeblk_free_dirty_block(handle, block);
    1067                 :            :     }
    1068                 :            : #else
    1069                 :            :     // linked list
    1070                 :        607 :     e = list_begin(&handle->read_list);
    1071         [ +  + ]:       2165 :     while(e) {
    1072                 :       1558 :         block = _get_entry(e, struct btreeblk_block, le);
    1073                 :       1558 :         e = list_remove(&handle->read_list, &block->le);
    1074                 :       1558 :         _btreeblk_free_dirty_block(handle, block);
    1075                 :            :     }
    1076                 :            : #endif
    1077                 :            : 
    1078                 :            : #ifdef __BTREEBLK_BLOCKPOOL
    1079                 :            :     // free all blocks in the block pool
    1080                 :            :     struct btreeblk_addr *item;
    1081                 :            : 
    1082                 :        607 :     e = list_begin(&handle->blockpool);
    1083         [ +  + ]:       3817 :     while(e){
    1084                 :       3210 :         item = _get_entry(e, struct btreeblk_addr, le);
    1085                 :       3210 :         e = list_next(e);
    1086                 :            : 
    1087                 :       3210 :         free_align(item->addr);
    1088                 :       3210 :         mempool_free(item);
    1089                 :            :     }
    1090                 :            : #endif
    1091                 :            : 
    1092                 :            : #ifdef __BTREEBLK_SUBBLOCK
    1093                 :            :     int i;
    1094         [ +  + ]:       3618 :     for (i=0;i<handle->nsb;++i){
    1095                 :       3011 :         free(handle->sb[i].bitmap);
    1096                 :            :     }
    1097                 :        607 :     free(handle->sb);
    1098                 :            : #endif
    1099                 :        607 : }
    1100                 :            : 
    1101                 :   16492133 : fdb_status btreeblk_end(struct btreeblk_handle *handle)
    1102                 :            : {
    1103                 :            :     struct list_elem *e;
    1104                 :            :     struct btreeblk_block *block;
    1105                 :   16492133 :     fdb_status status = FDB_RESULT_SUCCESS;
    1106                 :            : 
    1107                 :            :     // flush all dirty items
    1108                 :   16492133 :     status = btreeblk_operation_end((void *)handle);
    1109         [ +  + ]:   16491362 :     if (status != FDB_RESULT_SUCCESS) {
    1110                 :          3 :         return status;
    1111                 :            :     }
    1112                 :            : 
    1113                 :            :     // remove all items in lists
    1114                 :   16491359 :     e = list_begin(&handle->alc_list);
    1115         [ +  + ]:   16490882 :     while(e) {
    1116                 :          2 :         block = _get_entry(e, struct btreeblk_block, le);
    1117                 :          2 :         e = list_remove(&handle->alc_list, &block->le);
    1118                 :            : 
    1119                 :          2 :         block->dirty = 0;
    1120                 :          2 :         list_push_front(&handle->read_list, &block->le);
    1121                 :            : #ifdef __BTREEBLK_READ_TREE
    1122                 :            :         avl_insert(&handle->read_tree, &block->avl, _btreeblk_bid_cmp);
    1123                 :            : #endif
    1124                 :            :     }
    1125                 :   16490883 :     return status;
    1126                 :            : }

Generated by: LCOV version 1.11