LCOV - code coverage report
Current view: top level - src - filemgr.cc (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 898 1005 89.4 %
Date: 2015-01-12 15:17:13 Functions: 66 68 97.1 %
Branches: 269 366 73.5 %

           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                 :            : #include <fcntl.h>
      22                 :            : #include <assert.h>
      23                 :            : #include <sys/stat.h>
      24                 :            : #include <stdarg.h>
      25                 :            : #if !defined(WIN32) && !defined(_WIN32)
      26                 :            : #include <sys/time.h>
      27                 :            : #endif
      28                 :            : 
      29                 :            : #include "filemgr.h"
      30                 :            : #include "filemgr_ops.h"
      31                 :            : #include "hash_functions.h"
      32                 :            : #include "blockcache.h"
      33                 :            : #include "wal.h"
      34                 :            : #include "list.h"
      35                 :            : #include "fdb_internal.h"
      36                 :            : #include "time_utils.h"
      37                 :            : 
      38                 :            : #include "memleak.h"
      39                 :            : 
      40                 :            : #ifdef __DEBUG
      41                 :            : #ifndef __DEBUG_FILEMGR
      42                 :            :     #undef DBG
      43                 :            :     #undef DBGCMD
      44                 :            :     #undef DBGSW
      45                 :            :     #define DBG(...)
      46                 :            :     #define DBGCMD(...)
      47                 :            :     #define DBGSW(n, ...)
      48                 :            : #endif
      49                 :            : #endif
      50                 :            : 
      51                 :            : // NBUCKET must be power of 2
      52                 :            : #define NBUCKET (1024)
      53                 :            : #define FILEMGR_MAGIC (UINT64_C(0xdeadcafebeefbeef))
      54                 :            : 
      55                 :            : // global static variables
      56                 :            : #ifdef SPIN_INITIALIZER
      57                 :            : static spin_t initial_lock = SPIN_INITIALIZER;
      58                 :            : #else
      59                 :            : static volatile unsigned int initial_lock_status = 0;
      60                 :            : static spin_t initial_lock;
      61                 :            : #endif
      62                 :            : 
      63                 :            : 
      64                 :            : static volatile uint8_t filemgr_initialized = 0;
      65                 :            : static struct filemgr_config global_config;
      66                 :            : static struct hash hash;
      67                 :            : static spin_t filemgr_openlock;
      68                 :            : 
      69                 :            : struct temp_buf_item{
      70                 :            :     void *addr;
      71                 :            :     struct list_elem le;
      72                 :            : };
      73                 :            : static struct list temp_buf;
      74                 :            : static spin_t temp_buf_lock;
      75                 :            : 
      76                 :            : static void _filemgr_free_func(struct hash_elem *h);
      77                 :            : 
      78                 :        248 : static void spin_init_wrap(void *lock) {
      79                 :        248 :     spin_init((spin_t*)lock);
      80                 :        248 : }
      81                 :            : 
      82                 :        247 : static void spin_destroy_wrap(void *lock) {
      83                 :        247 :     spin_destroy((spin_t*)lock);
      84                 :        247 : }
      85                 :            : 
      86                 :   15333019 : static void spin_lock_wrap(void *lock) {
      87                 :   15333019 :     spin_lock((spin_t*)lock);
      88                 :   15370980 : }
      89                 :            : 
      90                 :   15370980 : static void spin_unlock_wrap(void *lock) {
      91                 :   15370980 :     spin_unlock((spin_t*)lock);
      92                 :   15370971 : }
      93                 :            : 
      94                 :        103 : static void mutex_init_wrap(void *lock) {
      95                 :        103 :     mutex_init((mutex_t*)lock);
      96                 :        103 : }
      97                 :            : 
      98                 :        103 : static void mutex_destroy_wrap(void *lock) {
      99                 :        103 :     mutex_destroy((mutex_t*)lock);
     100                 :        103 : }
     101                 :            : 
     102                 :    7685490 : static void mutex_lock_wrap(void *lock) {
     103                 :    7685490 :     mutex_lock((mutex_t*)lock);
     104                 :    7685490 : }
     105                 :            : 
     106                 :    7685490 : static void mutex_unlock_wrap(void *lock) {
     107                 :    7685490 :     mutex_unlock((mutex_t*)lock);
     108                 :    7685490 : }
     109                 :            : 
     110                 :    4263923 : static int _block_is_overlapped(void *pbid1, void *pis_writer1,
     111                 :            :                                 void *pbid2, void *pis_writer2,
     112                 :            :                                 void *aux)
     113                 :            : {
     114                 :            :     (void)aux;
     115                 :            :     bid_t bid1, is_writer1, bid2, is_writer2;
     116                 :    4263923 :     bid1 = *(bid_t*)pbid1;
     117                 :    4263923 :     is_writer1 = *(bid_t*)pis_writer1;
     118                 :    4263923 :     bid2 = *(bid_t*)pbid2;
     119                 :    4263923 :     is_writer2 = *(bid_t*)pis_writer2;
     120                 :            : 
     121         [ +  + ]:    4263923 :     if (bid1 != bid2) {
     122                 :            :         // not overlapped
     123                 :    4261913 :         return 0;
     124                 :            :     } else {
     125                 :            :         // overlapped
     126 [ +  - ][ +  - ]:       2010 :         if (!is_writer1 && !is_writer2) {
     127                 :            :             // both are readers
     128                 :       2010 :             return 0;
     129                 :            :         } else {
     130                 :    4263923 :             return 1;
     131                 :            :         }
     132                 :            :     }
     133                 :            : }
     134                 :            : 
     135                 :       8433 : fdb_status fdb_log(err_log_callback *log_callback,
     136                 :            :                    fdb_status status,
     137                 :            :                    const char *format, ...)
     138                 :            : {
     139 [ +  + ][ +  + ]:       8433 :     if (log_callback && log_callback->callback) {
     140                 :            :         char msg[1024];
     141                 :            :         va_list args;
     142                 :          5 :         va_start(args, format);
     143                 :          5 :         vsprintf(msg, format, args);
     144                 :          5 :         va_end(args);
     145                 :          5 :         log_callback->callback(status, msg, log_callback->ctx_data);
     146                 :            :     }
     147                 :       8433 :     return status;
     148                 :            : }
     149                 :            : 
     150                 :     734455 : static void _log_errno_str(struct filemgr_ops *ops,
     151                 :            :                            err_log_callback *log_callback,
     152                 :            :                            fdb_status io_error,
     153                 :            :                            const char *what,
     154                 :            :                            const char *filename)
     155                 :            : {
     156         [ +  + ]:     734455 :     if (io_error < 0) {
     157                 :            :         char errno_msg[512];
     158                 :       7858 :         ops->get_errno_str(errno_msg, 512);
     159                 :            :         fdb_log(log_callback, io_error,
     160                 :       7858 :                 "Error in %s on a database file '%s', %s", what, filename, errno_msg);
     161                 :            :     }
     162                 :     734455 : }
     163                 :            : 
     164                 :       1162 : uint32_t _file_hash(struct hash *hash, struct hash_elem *e)
     165                 :            : {
     166                 :       1162 :     struct filemgr *file = _get_entry(e, struct filemgr, e);
     167                 :       1162 :     int len = strlen(file->filename);
     168                 :       1162 :     return chksum(file->filename, len) & ((unsigned)(NBUCKET-1));
     169                 :            : }
     170                 :            : 
     171                 :        629 : int _file_cmp(struct hash_elem *a, struct hash_elem *b)
     172                 :            : {
     173                 :            :     struct filemgr *aa, *bb;
     174                 :        629 :     aa = _get_entry(a, struct filemgr, e);
     175                 :        629 :     bb = _get_entry(b, struct filemgr, e);
     176                 :        629 :     return strcmp(aa->filename, bb->filename);
     177                 :            : }
     178                 :            : 
     179                 :        754 : void filemgr_init(struct filemgr_config *config)
     180                 :            : {
     181                 :            :     // global initialization
     182                 :            :     // initialized only once at first time
     183         [ +  + ]:        754 :     if (!filemgr_initialized) {
     184                 :            : #ifndef SPIN_INITIALIZER
     185                 :            :         // Note that only Windows passes through this routine
     186                 :            :         if (InterlockedCompareExchange(&initial_lock_status, 1, 0) == 0) {
     187                 :            :             // atomically initialize spin lock only once
     188                 :            :             spin_init(&initial_lock);
     189                 :            :             initial_lock_status = 2;
     190                 :            :         } else {
     191                 :            :             // the others .. wait until initializing 'initial_lock' is done
     192                 :            :             while (initial_lock_status != 2) {
     193                 :            :                 Sleep(1);
     194                 :            :             }
     195                 :            :         }
     196                 :            : #endif
     197                 :            : 
     198                 :        125 :         spin_lock(&initial_lock);
     199         [ +  - ]:        125 :         if (!filemgr_initialized) {
     200                 :        125 :             global_config = *config;
     201                 :            : 
     202         [ +  + ]:        125 :             if (global_config.ncacheblock > 0)
     203                 :         58 :                 bcache_init(global_config.ncacheblock, global_config.blocksize);
     204                 :            : 
     205                 :        125 :             hash_init(&hash, NBUCKET, _file_hash, _file_cmp);
     206                 :            : 
     207                 :            :             // initialize temp buffer
     208                 :        125 :             list_init(&temp_buf);
     209                 :        125 :             spin_init(&temp_buf_lock);
     210                 :            : 
     211                 :            :             // initialize global lock
     212                 :        125 :             spin_init(&filemgr_openlock);
     213                 :            : 
     214                 :            :             // set the initialize flag
     215                 :        125 :             filemgr_initialized = 1;
     216                 :            :         }
     217                 :        125 :         spin_unlock(&initial_lock);
     218                 :            :     }
     219                 :        754 : }
     220                 :            : 
     221                 :     224906 : void * _filemgr_get_temp_buf()
     222                 :            : {
     223                 :            :     struct list_elem *e;
     224                 :            :     struct temp_buf_item *item;
     225                 :            : 
     226                 :     224906 :     spin_lock(&temp_buf_lock);
     227                 :     224906 :     e = list_pop_front(&temp_buf);
     228         [ +  + ]:     224906 :     if (e) {
     229                 :     224781 :         item = _get_entry(e, struct temp_buf_item, le);
     230                 :            :     }else{
     231                 :            :         void *addr;
     232                 :            : 
     233                 :        125 :         malloc_align(addr, FDB_SECTOR_SIZE, global_config.blocksize + sizeof(struct temp_buf_item));
     234                 :            : 
     235                 :        125 :         item = (struct temp_buf_item *)((uint8_t *) addr + global_config.blocksize);
     236                 :        125 :         item->addr = addr;
     237                 :            :     }
     238                 :     224906 :     spin_unlock(&temp_buf_lock);
     239                 :            : 
     240                 :     224906 :     return item->addr;
     241                 :            : }
     242                 :            : 
     243                 :     224906 : void _filemgr_release_temp_buf(void *buf)
     244                 :            : {
     245                 :            :     struct temp_buf_item *item;
     246                 :            : 
     247                 :     224906 :     spin_lock(&temp_buf_lock);
     248                 :     224906 :     item = (struct temp_buf_item*)((uint8_t *)buf + global_config.blocksize);
     249                 :     224906 :     list_push_front(&temp_buf, &item->le);
     250                 :     224906 :     spin_unlock(&temp_buf_lock);
     251                 :     224906 : }
     252                 :            : 
     253                 :        123 : void _filemgr_shutdown_temp_buf()
     254                 :            : {
     255                 :            :     struct list_elem *e;
     256                 :            :     struct temp_buf_item *item;
     257                 :        123 :     size_t count=0;
     258                 :            : 
     259                 :        123 :     spin_lock(&temp_buf_lock);
     260                 :        123 :     e = list_begin(&temp_buf);
     261         [ +  + ]:        246 :     while(e){
     262                 :        123 :         item = _get_entry(e, struct temp_buf_item, le);
     263                 :        123 :         e = list_remove(&temp_buf, e);
     264                 :        123 :         free_align(item->addr);
     265                 :        123 :         count++;
     266                 :            :     }
     267                 :        123 :     spin_unlock(&temp_buf_lock);
     268                 :        123 : }
     269                 :            : 
     270                 :        251 : fdb_status _filemgr_read_header(struct filemgr *file)
     271                 :            : {
     272                 :            :     uint8_t marker[BLK_MARKER_SIZE];
     273                 :            :     filemgr_magic_t magic;
     274                 :            :     filemgr_header_len_t len;
     275                 :            :     uint8_t *buf;
     276                 :            :     uint32_t crc, crc_file;
     277                 :        251 :     fdb_status status = FDB_RESULT_SUCCESS;
     278                 :            : 
     279                 :            :     // get temp buffer
     280                 :        251 :     buf = (uint8_t *) _filemgr_get_temp_buf();
     281                 :            : 
     282         [ +  + ]:        251 :     if (file->pos > 0) {
     283                 :            :         // Crash Recovery Test 1: unaligned last block write
     284                 :         64 :         uint64_t remain = file->pos % file->blocksize;
     285         [ -  + ]:         64 :         if (remain) {
     286                 :          0 :             file->pos -= remain;
     287                 :          0 :             file->last_commit = file->pos;
     288                 :            :             DBG("Crash Detected: %llu non-block aligned bytes discarded\n",
     289                 :            :                 remain);
     290                 :            :         }
     291                 :            : 
     292         [ +  - ]:         16 :         do {
     293                 :            :             ssize_t rv = file->ops->pread(file->fd, buf, file->blocksize,
     294                 :         79 :                              file->pos - file->blocksize);
     295         [ +  + ]:         79 :             if (rv != file->blocksize) {
     296                 :          1 :                 status = FDB_RESULT_READ_FAIL;
     297                 :            :                 DBG("Unable to read file %s blocksize %llu\n",
     298                 :            :                     file->filename, file->blocksize);
     299                 :          1 :                 break;
     300                 :            :             }
     301                 :         78 :             memcpy(marker, buf + file->blocksize - BLK_MARKER_SIZE,
     302                 :         78 :                    BLK_MARKER_SIZE);
     303                 :            : 
     304         [ +  + ]:         78 :             if (marker[0] == BLK_MARKER_DBHEADER) {
     305                 :            :                 // possible need for byte conversions here
     306                 :            :                 memcpy(&magic,
     307                 :         63 :                        buf + file->blocksize - BLK_MARKER_SIZE - sizeof(magic),
     308                 :         63 :                        sizeof(magic));
     309                 :         63 :                 magic = _endian_decode(magic);
     310                 :            : 
     311         [ +  - ]:         63 :                 if (magic == FILEMGR_MAGIC) {
     312                 :            :                     memcpy(&len,
     313                 :            :                            buf + file->blocksize - BLK_MARKER_SIZE -
     314                 :         63 :                            sizeof(magic) - sizeof(len),
     315                 :         63 :                            sizeof(len));
     316                 :         63 :                     len = _endian_decode(len);
     317                 :            : 
     318                 :         63 :                     crc = chksum(buf, len - sizeof(crc));
     319                 :         63 :                     memcpy(&crc_file, buf + len - sizeof(crc), sizeof(crc));
     320                 :         63 :                     crc_file = _endian_decode(crc_file);
     321         [ +  - ]:         63 :                     if (crc == crc_file) {
     322                 :         63 :                         file->header.data = (void *)malloc(len);
     323                 :            : 
     324                 :         63 :                         memcpy(file->header.data, buf, len);
     325                 :            :                         memcpy(&file->header.revnum, buf + len,
     326                 :         63 :                                sizeof(filemgr_header_revnum_t));
     327                 :            :                         memcpy((void *) &file->header.seqnum,
     328                 :         63 :                                 buf + len + sizeof(filemgr_header_revnum_t),
     329                 :         63 :                                 sizeof(fdb_seqnum_t));
     330                 :            :                         file->header.revnum =
     331                 :         63 :                             _endian_decode(file->header.revnum);
     332                 :            :                         file->header.seqnum =
     333                 :         63 :                             _endian_decode(file->header.seqnum);
     334                 :         63 :                         file->header.size = len;
     335                 :         63 :                         file->header.bid = (file->pos / file->blocksize) - 1;
     336                 :            : 
     337                 :         63 :                         file->header.dirty_idtree_root = BLK_NOT_FOUND;
     338                 :         63 :                         file->header.dirty_seqtree_root = BLK_NOT_FOUND;
     339                 :         63 :                         memset(&file->header.stat, 0x0, sizeof(file->header.stat));
     340                 :            : 
     341                 :            :                         // release temp buffer
     342                 :         63 :                         _filemgr_release_temp_buf(buf);
     343                 :            : 
     344                 :         63 :                         return FDB_RESULT_SUCCESS;
     345                 :            :                     } else {
     346                 :          0 :                         status = FDB_RESULT_CHECKSUM_ERROR;
     347                 :            :                         DBG("Crash Detected: CRC on disk %u != %u\n",
     348                 :            :                                 crc_file, crc);
     349                 :            :                     }
     350                 :            :                 } else {
     351                 :          0 :                     status = FDB_RESULT_FILE_CORRUPTION;
     352                 :            :                     DBG("Crash Detected: Wrong Magic %llu != %llu\n", magic,
     353                 :            :                             FILEMGR_MAGIC);
     354                 :            :                 }
     355                 :            :             } else {
     356                 :         15 :                 status = FDB_RESULT_FILE_CORRUPTION;
     357                 :            :                 DBG("Crash Detected: Last Block not DBHEADER %0.01x\n",
     358                 :            :                         marker[0]);
     359                 :            :             }
     360                 :            : 
     361                 :         15 :             file->pos -= file->blocksize;
     362                 :         15 :             file->last_commit = file->pos;
     363                 :            :         } while (file->pos);
     364                 :            :     }
     365                 :            : 
     366                 :            :     // release temp buffer
     367                 :        188 :     _filemgr_release_temp_buf(buf);
     368                 :            : 
     369                 :        188 :     file->header.size = 0;
     370                 :        188 :     file->header.revnum = 0;
     371                 :        188 :     file->header.seqnum = 0;
     372                 :        188 :     file->header.data = NULL;
     373                 :        188 :     file->header.dirty_idtree_root = BLK_NOT_FOUND;
     374                 :        188 :     file->header.dirty_seqtree_root = BLK_NOT_FOUND;
     375                 :        188 :     memset(&file->header.stat, 0x0, sizeof(file->header.stat));
     376                 :        251 :     return status;
     377                 :            : }
     378                 :            : 
     379                 :          5 : size_t filemgr_get_ref_count(struct filemgr *file)
     380                 :            : {
     381                 :          5 :     size_t ret = 0;
     382                 :          5 :     spin_lock(&file->lock);
     383                 :          5 :     ret = file->ref_count;
     384                 :          5 :     spin_unlock(&file->lock);
     385                 :          5 :     return ret;
     386                 :            : }
     387                 :            : 
     388                 :            : struct filemgr_prefetch_args {
     389                 :            :     struct filemgr *file;
     390                 :            :     uint64_t duration;
     391                 :            :     void *aux;
     392                 :            : };
     393                 :            : 
     394                 :         60 : void *_filemgr_prefetch_thread(void *voidargs)
     395                 :            : {
     396                 :         60 :     struct filemgr_prefetch_args *args = (struct filemgr_prefetch_args*)voidargs;
     397                 :         60 :     uint8_t *buf = alca(uint8_t, args->file->blocksize);
     398                 :         60 :     uint64_t cur_pos = 0, i;
     399                 :            :     uint64_t bcache_free_space;
     400                 :            :     bid_t bid;
     401                 :         60 :     bool terminate = false;
     402                 :            :     struct timeval begin, cur, gap;
     403                 :            : 
     404                 :         60 :     spin_lock(&args->file->lock);
     405                 :         60 :     cur_pos = args->file->last_commit;
     406                 :         60 :     spin_unlock(&args->file->lock);
     407         [ +  + ]:         60 :     if (cur_pos < FILEMGR_PREFETCH_UNIT) {
     408                 :         43 :         terminate = true;
     409                 :            :     } else {
     410                 :         17 :         cur_pos -= FILEMGR_PREFETCH_UNIT;
     411                 :            :     }
     412                 :            :     // read backwards from the end of the file, in the unit of FILEMGR_PREFETCH_UNIT
     413                 :         60 :     gettimeofday(&begin, NULL);
     414         [ +  + ]:        154 :     while (!terminate) {
     415         [ +  + ]:      95348 :         for (i = cur_pos;
     416                 :            :              i < cur_pos + FILEMGR_PREFETCH_UNIT;
     417                 :            :              i += args->file->blocksize) {
     418                 :            : 
     419                 :      95255 :             gettimeofday(&cur, NULL);
     420                 :      95255 :             gap = _utime_gap(begin, cur);
     421                 :      95255 :             bcache_free_space = bcache_get_num_free_blocks();
     422                 :      95255 :             bcache_free_space *= args->file->blocksize;
     423                 :            : 
     424 [ +  - ][ +  - ]:      95255 :             if (args->file->prefetch_status == FILEMGR_PREFETCH_ABORT ||
         [ -  + ][ -  + ]
     425                 :            :                 gap.tv_sec >= args->duration ||
     426                 :            :                 bcache_free_space < FILEMGR_PREFETCH_UNIT) {
     427                 :            :                 // terminate thread when
     428                 :            :                 // 1. got abort signal
     429                 :            :                 // 2. time out
     430                 :            :                 // 3. not enough free space in block cache
     431                 :          0 :                 terminate = true;
     432                 :          0 :                 break;
     433                 :            :             } else {
     434                 :      95255 :                 bid = i / args->file->blocksize;
     435         [ +  + ]:      95255 :                 if (filemgr_read(args->file, bid, buf, NULL)
     436                 :            :                         != FDB_RESULT_SUCCESS) {
     437                 :            :                     // 4. read failure
     438                 :          1 :                     terminate = true;
     439                 :          1 :                     break;
     440                 :            :                 }
     441                 :            :             }
     442                 :            :         }
     443                 :            : 
     444         [ +  + ]:         94 :         if (cur_pos >= FILEMGR_PREFETCH_UNIT) {
     445                 :         78 :             cur_pos -= FILEMGR_PREFETCH_UNIT;
     446                 :            :         } else {
     447                 :            :             // remaining space is less than FILEMGR_PREFETCH_UNIT
     448                 :         16 :             terminate = true;
     449                 :            :         }
     450                 :            :     }
     451                 :            : 
     452                 :         60 :     args->file->prefetch_status = FILEMGR_PREFETCH_IDLE;
     453                 :         60 :     free(args);
     454                 :         60 :     return NULL;
     455                 :            : }
     456                 :            : 
     457                 :            : // prefetch the given DB file
     458                 :        217 : void filemgr_prefetch(struct filemgr *file,
     459                 :            :                       struct filemgr_config *config)
     460                 :            : {
     461                 :            :     uint64_t bcache_free_space;
     462                 :            : 
     463                 :        217 :     bcache_free_space = bcache_get_num_free_blocks();
     464                 :        217 :     bcache_free_space *= file->blocksize;
     465                 :            : 
     466                 :            :     // block cache should have free space larger than FILEMGR_PREFETCH_UNIT
     467                 :        217 :     spin_lock(&file->lock);
     468 [ +  + ][ +  + ]:        217 :     if (file->last_commit > 0 &&
     469                 :            :         bcache_free_space >= FILEMGR_PREFETCH_UNIT) {
     470                 :            :         // invoke prefetch thread
     471                 :            :         struct filemgr_prefetch_args *args;
     472                 :            :         args = (struct filemgr_prefetch_args *)
     473                 :         60 :                calloc(1, sizeof(struct filemgr_prefetch_args));
     474                 :         60 :         args->file = file;
     475                 :         60 :         args->duration = config->prefetch_duration;
     476                 :            : 
     477                 :         60 :         file->prefetch_status = FILEMGR_PREFETCH_RUNNING;
     478                 :         60 :         thread_create(&file->prefetch_tid, _filemgr_prefetch_thread, args);
     479                 :            :     }
     480                 :        217 :     spin_unlock(&file->lock);
     481                 :        217 : }
     482                 :            : 
     483                 :        644 : filemgr_open_result filemgr_open(char *filename, struct filemgr_ops *ops,
     484                 :            :                                  struct filemgr_config *config,
     485                 :            :                                  err_log_callback *log_callback)
     486                 :            : {
     487                 :        644 :     struct filemgr *file = NULL;
     488                 :            :     struct filemgr query;
     489                 :        644 :     struct hash_elem *e = NULL;
     490                 :        644 :     bool create = config->options & FILEMGR_CREATE;
     491                 :        644 :     int file_flag = 0x0;
     492                 :        644 :     int fd = -1;
     493                 :            :     fdb_status status;
     494                 :        644 :     filemgr_open_result result = {NULL, FDB_RESULT_OPEN_FAIL};
     495                 :            : 
     496                 :        644 :     filemgr_init(config);
     497                 :            : 
     498                 :            :     // check whether file is already opened or not
     499                 :        644 :     query.filename = filename;
     500                 :        644 :     spin_lock(&filemgr_openlock);
     501                 :        644 :     e = hash_find(&hash, &query.e);
     502                 :            : 
     503         [ +  + ]:        644 :     if (e) {
     504                 :            :         // already opened (return existing structure)
     505                 :        380 :         file = _get_entry(e, struct filemgr, e);
     506                 :            : 
     507                 :        380 :         spin_lock(&file->lock);
     508                 :        380 :         file->ref_count++;
     509                 :            : 
     510         [ +  + ]:        380 :         if (file->status == FILE_CLOSED) { // if file was closed before
     511                 :          5 :             file_flag = O_RDWR;
     512         [ +  + ]:          5 :             if (create) {
     513                 :          4 :                 file_flag |= O_CREAT;
     514                 :            :             }
     515                 :          5 :             *file->config = *config;
     516                 :          5 :             file->config->blocksize = global_config.blocksize;
     517                 :          5 :             file->config->ncacheblock = global_config.ncacheblock;
     518                 :          5 :             file_flag |= config->flag;
     519                 :          5 :             file->fd = file->ops->open(file->filename, file_flag, 0666);
     520         [ +  + ]:          5 :             if (file->fd < 0) {
     521         [ +  - ]:          1 :                 if (file->fd == FDB_RESULT_NO_SUCH_FILE) {
     522                 :            :                     // A database file was manually deleted by the user.
     523                 :            :                     // Clean up global hash table, WAL index, and buffer cache.
     524                 :            :                     // Then, retry it with a create option below IFF it is not
     525                 :            :                     // a read-only open attempt
     526                 :            :                     struct hash_elem *ret;
     527                 :          1 :                     spin_unlock(&file->lock);
     528                 :          1 :                     ret = hash_remove(&hash, &file->e);
     529         [ -  + ]:          1 :                     assert(ret);
     530                 :          1 :                     _filemgr_free_func(&file->e);
     531         [ +  - ]:          1 :                     if (!create) {
     532                 :            :                         _log_errno_str(ops, log_callback,
     533                 :          1 :                                 FDB_RESULT_NO_SUCH_FILE, "OPEN", filename);
     534                 :          1 :                         spin_unlock(&filemgr_openlock);
     535                 :          1 :                         result.rv = FDB_RESULT_NO_SUCH_FILE;
     536                 :          1 :                         return result;
     537                 :            :                     }
     538                 :            :                 } else {
     539                 :            :                     _log_errno_str(file->ops, log_callback,
     540                 :          0 :                                   (fdb_status)file->fd, "OPEN", filename);
     541                 :          0 :                     file->ref_count--;
     542                 :          0 :                     spin_unlock(&file->lock);
     543                 :          0 :                     spin_unlock(&filemgr_openlock);
     544                 :          0 :                     result.rv = file->fd;
     545                 :          0 :                     return result;
     546                 :            :                 }
     547                 :            :             } else { // Reopening the closed file is succeed.
     548                 :          4 :                 file->status = FILE_NORMAL;
     549         [ +  - ]:          4 :                 if (config->options & FILEMGR_SYNC) {
     550                 :          4 :                     file->fflags |= FILEMGR_SYNC;
     551                 :            :                 } else {
     552                 :          0 :                     file->fflags &= ~FILEMGR_SYNC;
     553                 :            :                 }
     554                 :          4 :                 spin_unlock(&file->lock);
     555                 :          4 :                 spin_unlock(&filemgr_openlock);
     556                 :          4 :                 result.file = file;
     557                 :          4 :                 result.rv = FDB_RESULT_SUCCESS;
     558                 :          4 :                 return result;
     559                 :            :             }
     560                 :            :         } else { // file is already opened.
     561                 :            : 
     562         [ +  + ]:        375 :             if (config->options & FILEMGR_SYNC) {
     563                 :        372 :                 file->fflags |= FILEMGR_SYNC;
     564                 :            :             } else {
     565                 :          3 :                 file->fflags &= ~FILEMGR_SYNC;
     566                 :            :             }
     567                 :            : 
     568                 :        375 :             spin_unlock(&file->lock);
     569                 :        375 :             spin_unlock(&filemgr_openlock);
     570                 :        375 :             result.file = file;
     571                 :        375 :             result.rv = FDB_RESULT_SUCCESS;
     572                 :        375 :             return result;
     573                 :            :         }
     574                 :            :     }
     575                 :            : 
     576                 :        264 :     file_flag = O_RDWR;
     577         [ +  + ]:        264 :     if (create) {
     578                 :        234 :         file_flag |= O_CREAT;
     579                 :            :     }
     580                 :        264 :     file_flag |= config->flag;
     581                 :        264 :     fd = ops->open(filename, file_flag, 0666);
     582         [ +  + ]:        264 :     if (fd < 0) {
     583                 :         15 :         _log_errno_str(ops, log_callback, (fdb_status)fd, "OPEN", filename);
     584                 :         15 :         spin_unlock(&filemgr_openlock);
     585                 :         15 :         result.rv = fd;
     586                 :         15 :         return result;
     587                 :            :     }
     588                 :        249 :     file = (struct filemgr*)calloc(1, sizeof(struct filemgr));
     589                 :        249 :     file->filename_len = strlen(filename);
     590                 :        249 :     file->filename = (char*)malloc(file->filename_len + 1);
     591                 :        249 :     strcpy(file->filename, filename);
     592                 :            : 
     593                 :        249 :     file->ref_count = 1;
     594                 :            : 
     595                 :        249 :     file->wal = (struct wal *)calloc(1, sizeof(struct wal));
     596                 :        249 :     file->wal->flag = 0;
     597                 :            : 
     598                 :        249 :     file->ops = ops;
     599                 :        249 :     file->blocksize = global_config.blocksize;
     600                 :        249 :     file->status = FILE_NORMAL;
     601                 :        249 :     file->config = (struct filemgr_config*)malloc(sizeof(struct filemgr_config));
     602                 :        249 :     *file->config = *config;
     603                 :        249 :     file->config->blocksize = global_config.blocksize;
     604                 :        249 :     file->config->ncacheblock = global_config.ncacheblock;
     605                 :        249 :     file->new_file = NULL;
     606                 :        249 :     file->old_filename = NULL;
     607                 :        249 :     file->fd = fd;
     608                 :            : 
     609                 :        249 :     cs_off_t offset = file->ops->goto_eof(file->fd);
     610         [ -  + ]:        249 :     if (offset == FDB_RESULT_SEEK_FAIL) {
     611                 :          0 :         _log_errno_str(file->ops, log_callback, FDB_RESULT_SEEK_FAIL, "SEEK_END", filename);
     612                 :          0 :         free(file->wal);
     613                 :          0 :         free(file->filename);
     614                 :          0 :         free(file->config);
     615                 :          0 :         free(file);
     616                 :          0 :         spin_unlock(&filemgr_openlock);
     617                 :          0 :         result.rv = FDB_RESULT_SEEK_FAIL;
     618                 :          0 :         return result;
     619                 :            :     }
     620                 :        249 :     file->pos = file->last_commit = offset;
     621                 :            : 
     622                 :        249 :     file->bcache = NULL;
     623                 :        249 :     file->in_place_compaction = false;
     624                 :        249 :     file->kv_header = NULL;
     625                 :        249 :     file->prefetch_status = FILEMGR_PREFETCH_IDLE;
     626                 :            : 
     627                 :        249 :     status = _filemgr_read_header(file);
     628         [ +  + ]:        249 :     if (status != FDB_RESULT_SUCCESS) {
     629                 :          1 :         _log_errno_str(file->ops, log_callback, status, "READ", filename);
     630                 :          1 :         free(file->wal);
     631                 :          1 :         free(file->filename);
     632                 :          1 :         free(file->config);
     633                 :          1 :         free(file);
     634                 :          1 :         spin_unlock(&filemgr_openlock);
     635                 :          1 :         result.rv = status;
     636                 :          1 :         return result;
     637                 :            :     }
     638                 :            : 
     639                 :        248 :     spin_init(&file->lock);
     640                 :            : 
     641                 :            : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
     642                 :            :     struct plock_ops pops;
     643                 :            :     struct plock_config pconfig;
     644                 :            : 
     645                 :        248 :     pops.init_user = mutex_init_wrap;
     646                 :        248 :     pops.lock_user = mutex_lock_wrap;
     647                 :        248 :     pops.unlock_user = mutex_unlock_wrap;
     648                 :        248 :     pops.destroy_user = mutex_destroy_wrap;
     649                 :        248 :     pops.init_internal = spin_init_wrap;
     650                 :        248 :     pops.lock_internal = spin_lock_wrap;
     651                 :        248 :     pops.unlock_internal = spin_unlock_wrap;
     652                 :        248 :     pops.destroy_internal = spin_destroy_wrap;
     653                 :        248 :     pops.is_overlapped = _block_is_overlapped;
     654                 :            : 
     655                 :        248 :     memset(&pconfig, 0x0, sizeof(pconfig));
     656                 :        248 :     pconfig.ops = &pops;
     657                 :        248 :     pconfig.sizeof_lock_internal = sizeof(spin_t);
     658                 :        248 :     pconfig.sizeof_lock_user = sizeof(mutex_t);
     659                 :        248 :     pconfig.sizeof_range = sizeof(bid_t);
     660                 :        248 :     pconfig.aux = NULL;
     661                 :        248 :     plock_init(&file->plock, &pconfig);
     662                 :            : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
     663                 :            :     int i;
     664                 :            :     for (i=0;i<DLOCK_MAX;++i) {
     665                 :            :         mutex_init(&file->data_mutex[i]);
     666                 :            :     }
     667                 :            : #else
     668                 :            :     int i;
     669                 :            :     for (i=0;i<DLOCK_MAX;++i) {
     670                 :            :         spin_init(&file->data_spinlock[i]);
     671                 :            :     }
     672                 :            : #endif //__FILEMGR_DATA_PARTIAL_LOCK
     673                 :            : 
     674                 :            : #ifdef __FILEMGR_MUTEX_LOCK
     675                 :        248 :     mutex_init(&file->mutex);
     676                 :            : #else
     677                 :            :     spin_init(&file->mutex);
     678                 :            : #endif
     679                 :            : 
     680                 :            :     // initialize WAL
     681         [ +  - ]:        248 :     if (!wal_is_initialized(file)) {
     682                 :        248 :         wal_init(file, FDB_WAL_NBUCKET);
     683                 :            :     }
     684                 :            : 
     685                 :            :     // init global transaction for the file
     686                 :            :     file->global_txn.wrapper = (struct wal_txn_wrapper*)
     687                 :        248 :                                malloc(sizeof(struct wal_txn_wrapper));
     688                 :        248 :     file->global_txn.wrapper->txn = &file->global_txn;
     689                 :        248 :     file->global_txn.handle = NULL;
     690         [ +  + ]:        248 :     if (file->pos > 0) {
     691                 :         61 :         file->global_txn.prev_hdr_bid = (file->pos / file->blocksize)-1;
     692                 :            :     } else {
     693                 :        187 :         file->global_txn.prev_hdr_bid = BLK_NOT_FOUND;
     694                 :            :     }
     695                 :        248 :     file->global_txn.items = (struct list *)malloc(sizeof(struct list));
     696                 :        248 :     list_init(file->global_txn.items);
     697                 :        248 :     file->global_txn.isolation = FDB_ISOLATION_READ_COMMITTED;
     698                 :        248 :     wal_add_transaction(file, &file->global_txn);
     699                 :            : 
     700                 :        248 :     hash_insert(&hash, &file->e);
     701         [ +  + ]:        248 :     if (config->prefetch_duration > 0) {
     702                 :        217 :         filemgr_prefetch(file, config);
     703                 :            :     }
     704                 :        248 :     spin_unlock(&filemgr_openlock);
     705                 :            : 
     706         [ +  + ]:        248 :     if (config->options & FILEMGR_SYNC) {
     707                 :        226 :         file->fflags |= FILEMGR_SYNC;
     708                 :            :     } else {
     709                 :         22 :         file->fflags &= ~FILEMGR_SYNC;
     710                 :            :     }
     711                 :            : 
     712                 :        248 :     result.file = file;
     713                 :        248 :     result.rv = FDB_RESULT_SUCCESS;
     714                 :        644 :     return result;
     715                 :            : }
     716                 :            : 
     717                 :      13762 : uint64_t filemgr_update_header(struct filemgr *file, void *buf, size_t len)
     718                 :            : {
     719                 :            :     uint64_t ret;
     720                 :            : 
     721                 :      13762 :     spin_lock(&file->lock);
     722                 :            : 
     723         [ +  + ]:      13762 :     if (file->header.data == NULL) {
     724                 :        162 :         file->header.data = (void *)malloc(len);
     725         [ +  + ]:      13600 :     }else if (file->header.size < len){
     726                 :         54 :         file->header.data = (void *)realloc(file->header.data, len);
     727                 :            :     }
     728                 :      13762 :     memcpy(file->header.data, buf, len);
     729                 :      13762 :     file->header.size = len;
     730                 :      13762 :     ++(file->header.revnum);
     731                 :      13762 :     ret = file->header.revnum;
     732                 :            : 
     733                 :      13762 :     spin_unlock(&file->lock);
     734                 :            : 
     735                 :      13762 :     return ret;
     736                 :            : }
     737                 :            : 
     738                 :    3534784 : filemgr_header_revnum_t filemgr_get_header_revnum(struct filemgr *file)
     739                 :            : {
     740                 :            :     filemgr_header_revnum_t ret;
     741                 :    3534784 :     spin_lock(&file->lock);
     742                 :    3536189 :     ret = file->header.revnum;
     743                 :    3536189 :     spin_unlock(&file->lock);
     744                 :    3535748 :     return ret;
     745                 :            : }
     746                 :            : 
     747                 :            : // 'filemgr_get_seqnum' & 'filemgr_set_seqnum' have to be protected by
     748                 :            : // 'filemgr_mutex_lock' & 'filemgr_mutex_unlock'.
     749                 :    2438383 : fdb_seqnum_t filemgr_get_seqnum(struct filemgr *file)
     750                 :            : {
     751                 :    2438383 :     return file->header.seqnum;
     752                 :            : }
     753                 :            : 
     754                 :    2435185 : void filemgr_set_seqnum(struct filemgr *file, fdb_seqnum_t seqnum)
     755                 :            : {
     756                 :    2435185 :     file->header.seqnum = seqnum;
     757                 :    2435185 : }
     758                 :            : 
     759                 :          0 : char* filemgr_get_filename_ptr(struct filemgr *file, char **filename, uint16_t *len)
     760                 :            : {
     761                 :          0 :     spin_lock(&file->lock);
     762                 :          0 :     *filename = file->filename;
     763                 :          0 :     *len = file->filename_len;
     764                 :          0 :     spin_unlock(&file->lock);
     765                 :          0 :     return *filename;
     766                 :            : }
     767                 :            : 
     768                 :       2990 : bid_t filemgr_get_header_bid(struct filemgr *file)
     769                 :            : {
     770         [ +  + ]:       2990 :     if (file->header.size > 0) {
     771                 :       2863 :         return file->header.bid;
     772                 :            :     } else {
     773                 :       2990 :         return BLK_NOT_FOUND;
     774                 :            :     }
     775                 :            : }
     776                 :            : 
     777                 :       3014 : void* filemgr_get_header(struct filemgr *file, void *buf, size_t *len)
     778                 :            : {
     779                 :       3014 :     spin_lock(&file->lock);
     780                 :            : 
     781         [ +  + ]:       3014 :     if (file->header.size > 0) {
     782         [ +  + ]:       2887 :         if (buf == NULL) {
     783                 :       2468 :             buf = (void*)malloc(file->header.size);
     784                 :            :         }
     785                 :       2887 :         memcpy(buf, file->header.data, file->header.size);
     786                 :            :     }
     787                 :       3014 :     *len = file->header.size;
     788                 :            : 
     789                 :       3014 :     spin_unlock(&file->lock);
     790                 :            : 
     791                 :       3014 :     return buf;
     792                 :            : }
     793                 :            : 
     794                 :          2 : fdb_status filemgr_fetch_header(struct filemgr *file, uint64_t bid,
     795                 :            :                                 void *buf, size_t *len,
     796                 :            :                                 err_log_callback *log_callback)
     797                 :            : {
     798                 :            :     uint8_t *_buf;
     799                 :            :     uint8_t marker[BLK_MARKER_SIZE];
     800                 :            :     filemgr_header_len_t hdr_len;
     801                 :            :     filemgr_magic_t magic;
     802                 :          2 :     fdb_status status = FDB_RESULT_SUCCESS;
     803                 :            : 
     804 [ +  - ][ -  + ]:          2 :     if (!bid || bid == BLK_NOT_FOUND) {
     805                 :          0 :         *len = 0; // No other header available
     806                 :          0 :         return FDB_RESULT_SUCCESS;
     807                 :            :     }
     808                 :          2 :     _buf = (uint8_t *)_filemgr_get_temp_buf();
     809                 :            : 
     810                 :          2 :     status = filemgr_read(file, (bid_t)bid, _buf, log_callback);
     811                 :            : 
     812         [ -  + ]:          2 :     if (status != FDB_RESULT_SUCCESS) {
     813                 :          0 :         _filemgr_release_temp_buf(_buf);
     814                 :          0 :         return status;
     815                 :            :     }
     816                 :          2 :     memcpy(marker, _buf + file->blocksize - BLK_MARKER_SIZE,
     817                 :          2 :             BLK_MARKER_SIZE);
     818                 :            : 
     819         [ -  + ]:          2 :     if (marker[0] != BLK_MARKER_DBHEADER) {
     820                 :          0 :         _filemgr_release_temp_buf(_buf);
     821                 :          0 :         return FDB_RESULT_READ_FAIL;
     822                 :            :     }
     823                 :            :     memcpy(&magic,
     824                 :          2 :             _buf + file->blocksize - BLK_MARKER_SIZE - sizeof(magic),
     825                 :          2 :             sizeof(magic));
     826                 :          2 :     magic = _endian_decode(magic);
     827         [ -  + ]:          2 :     if (magic != FILEMGR_MAGIC) {
     828                 :          0 :         _filemgr_release_temp_buf(_buf);
     829                 :          0 :         return FDB_RESULT_READ_FAIL;
     830                 :            :     }
     831                 :            :     memcpy(&hdr_len,
     832                 :            :             _buf + file->blocksize - BLK_MARKER_SIZE - sizeof(magic) -
     833                 :          2 :             sizeof(hdr_len), sizeof(hdr_len));
     834                 :          2 :     hdr_len = _endian_decode(hdr_len);
     835                 :            : 
     836                 :          2 :     memcpy(buf, _buf, hdr_len);
     837                 :          2 :     *len = hdr_len;
     838                 :            : 
     839                 :          2 :     _filemgr_release_temp_buf(_buf);
     840                 :            : 
     841                 :          2 :     return status;
     842                 :            : }
     843                 :            : 
     844                 :        138 : uint64_t filemgr_fetch_prev_header(struct filemgr *file, uint64_t bid,
     845                 :            :                                    void *buf, size_t *len, fdb_seqnum_t *seqnum,
     846                 :            :                                    err_log_callback *log_callback)
     847                 :            : {
     848                 :            :     uint8_t *_buf;
     849                 :            :     uint8_t marker[BLK_MARKER_SIZE];
     850                 :            :     fdb_seqnum_t _seqnum;
     851                 :            :     filemgr_header_revnum_t _revnum;
     852                 :            :     filemgr_header_len_t hdr_len;
     853                 :            :     filemgr_magic_t magic;
     854                 :        138 :     int found = 0;
     855                 :            : 
     856 [ +  - ][ -  + ]:        138 :     if (!bid || bid == BLK_NOT_FOUND) {
     857                 :          0 :         *len = 0; // No other header available
     858                 :          0 :         return bid;
     859                 :            :     }
     860                 :        138 :     _buf = (uint8_t *)_filemgr_get_temp_buf();
     861                 :            : 
     862                 :        138 :     bid--;
     863                 :            :     // Reverse scan the file for a previous DB header
     864         [ +  - ]:      11175 :     do {
     865         [ -  + ]:      11313 :         if (filemgr_read(file, (bid_t)bid, _buf, log_callback)
     866                 :            :              != FDB_RESULT_SUCCESS) {
     867                 :          0 :             break;
     868                 :            :         }
     869                 :      11313 :         memcpy(marker, _buf + file->blocksize - BLK_MARKER_SIZE,
     870                 :      11313 :                 BLK_MARKER_SIZE);
     871                 :            : 
     872         [ +  + ]:      11313 :         if (marker[0] != BLK_MARKER_DBHEADER) {
     873                 :      11175 :             continue;
     874                 :            :         }
     875                 :            :         memcpy(&magic,
     876                 :        138 :                _buf + file->blocksize - BLK_MARKER_SIZE - sizeof(magic),
     877                 :        138 :                sizeof(magic));
     878                 :        138 :         magic = _endian_decode(magic);
     879         [ -  + ]:        138 :         if (magic != FILEMGR_MAGIC) {
     880                 :          0 :             continue;
     881                 :            :         }
     882                 :            :         memcpy(&hdr_len,
     883                 :            :                _buf + file->blocksize - BLK_MARKER_SIZE - sizeof(magic) -
     884                 :        138 :                sizeof(hdr_len), sizeof(hdr_len));
     885                 :        138 :         hdr_len = _endian_decode(hdr_len);
     886                 :            : 
     887                 :        138 :         memcpy(buf, _buf, hdr_len);
     888                 :            :         memcpy(&_revnum, _buf + hdr_len,
     889                 :        138 :                sizeof(filemgr_header_revnum_t));
     890                 :            :         memcpy(&_seqnum,
     891                 :        138 :                _buf + hdr_len + sizeof(filemgr_header_revnum_t),
     892                 :        138 :                sizeof(fdb_seqnum_t));
     893                 :        138 :         *seqnum = _endian_decode(_seqnum);
     894                 :        138 :         *len = hdr_len;
     895                 :        138 :         found = 1;
     896                 :        138 :         break;
     897                 :            :     } while (bid--); // scan even the first block 0
     898                 :            : 
     899         [ -  + ]:        138 :     if (!found) { // no other header found till end of file
     900                 :          0 :         *len = 0;
     901                 :            :     }
     902                 :            : 
     903                 :        138 :     _filemgr_release_temp_buf(_buf);
     904                 :            : 
     905                 :        138 :     return bid;
     906                 :            : }
     907                 :            : 
     908                 :        625 : fdb_status filemgr_close(struct filemgr *file, bool cleanup_cache_onclose,
     909                 :            :                          const char *orig_file_name,
     910                 :            :                          err_log_callback *log_callback)
     911                 :            : {
     912                 :        625 :     int rv = FDB_RESULT_SUCCESS;
     913                 :            : 
     914                 :        625 :     spin_lock(&filemgr_openlock); // Grab the filemgr lock to avoid the race with
     915                 :            :                                   // filemgr_open() because file->lock won't
     916                 :            :                                   // prevent the race condition.
     917                 :            : 
     918                 :            :     // remove filemgr structure if no thread refers to the file
     919                 :        625 :     spin_lock(&file->lock);
     920         [ +  + ]:        625 :     if (--(file->ref_count) == 0) {
     921                 :        250 :         spin_unlock(&file->lock);
     922         [ +  + ]:        250 :         if (global_config.ncacheblock > 0) {
     923                 :            :             // discard all dirty blocks belonged to this file
     924                 :        121 :             bcache_remove_dirty_blocks(file);
     925                 :            :         }
     926                 :            : 
     927         [ +  - ]:        250 :         if (wal_is_initialized(file)) {
     928                 :        250 :             wal_close(file);
     929                 :            :         }
     930                 :            : 
     931                 :        250 :         spin_lock(&file->lock);
     932                 :        250 :         rv = file->ops->close(file->fd);
     933         [ +  + ]:        250 :         if (file->status == FILE_REMOVED_PENDING) {
     934                 :         54 :             _log_errno_str(file->ops, log_callback, (fdb_status)rv, "CLOSE", file->filename);
     935                 :            :             // remove file
     936                 :         54 :             remove(file->filename);
     937                 :            :             // we can release lock becuase no one will open this file
     938                 :         54 :             spin_unlock(&file->lock);
     939                 :         54 :             struct hash_elem *ret = hash_remove(&hash, &file->e);
     940         [ -  + ]:         54 :             assert(ret);
     941                 :         54 :             spin_unlock(&filemgr_openlock);
     942                 :         54 :             _filemgr_free_func(&file->e);
     943                 :         54 :             return (fdb_status) rv;
     944                 :            :         } else {
     945         [ +  + ]:        196 :             if (cleanup_cache_onclose) {
     946                 :        191 :                 _log_errno_str(file->ops, log_callback, (fdb_status)rv, "CLOSE", file->filename);
     947 [ +  + ][ +  - ]:        191 :                 if (file->in_place_compaction && orig_file_name) {
     948                 :          6 :                     struct hash_elem *elem = NULL;
     949                 :            :                     struct filemgr query;
     950                 :          6 :                     query.filename = (char *)orig_file_name;
     951                 :          6 :                     elem = hash_find(&hash, &query.e);
     952 [ +  + ][ -  + ]:          6 :                     if (!elem && rename(file->filename, orig_file_name) < 0) {
                 [ -  + ]
     953                 :            :                         // Note that the renaming failure is not a critical
     954                 :            :                         // issue because the last compacted file will be automatically
     955                 :            :                         // identified and opened in the next fdb_open call.
     956                 :            :                         _log_errno_str(file->ops, log_callback, FDB_RESULT_FILE_RENAME_FAIL,
     957                 :          0 :                                        "CLOSE", file->filename);
     958                 :            :                     }
     959                 :            :                 }
     960                 :        191 :                 spin_unlock(&file->lock);
     961                 :            :                 // Clean up global hash table, WAL index, and buffer cache.
     962                 :        191 :                 struct hash_elem *ret = hash_remove(&hash, &file->e);
     963         [ -  + ]:        191 :                 assert(ret);
     964                 :        191 :                 spin_unlock(&filemgr_openlock);
     965                 :        191 :                 _filemgr_free_func(&file->e);
     966                 :        191 :                 return (fdb_status) rv;
     967                 :            :             } else {
     968                 :          5 :                 file->status = FILE_CLOSED;
     969                 :            :             }
     970                 :            :         }
     971                 :            :     }
     972                 :            : 
     973                 :        380 :     _log_errno_str(file->ops, log_callback, (fdb_status)rv, "CLOSE", file->filename);
     974                 :            : 
     975                 :        380 :     spin_unlock(&file->lock);
     976                 :        380 :     spin_unlock(&filemgr_openlock);
     977                 :        625 :     return (fdb_status) rv;
     978                 :            : }
     979                 :            : 
     980                 :        247 : static void _filemgr_free_func(struct hash_elem *h)
     981                 :            : {
     982                 :        247 :     struct filemgr *file = _get_entry(h, struct filemgr, e);
     983                 :            : 
     984                 :        247 :     spin_lock(&file->lock);
     985         [ +  + ]:        247 :     if (file->prefetch_status == FILEMGR_PREFETCH_RUNNING) {
     986                 :            :         // prefetch thread is running
     987                 :            :         void *ret;
     988                 :          1 :         file->prefetch_status = FILEMGR_PREFETCH_ABORT;
     989                 :          1 :         spin_unlock(&file->lock);
     990                 :            :         // wait
     991                 :          1 :         thread_join(file->prefetch_tid, &ret);
     992                 :            :     } else {
     993                 :        246 :         spin_unlock(&file->lock);
     994                 :            :     }
     995                 :            : 
     996                 :            :     // remove all cached blocks
     997         [ +  + ]:        247 :     if (global_config.ncacheblock > 0) {
     998                 :        121 :         bcache_remove_dirty_blocks(file);
     999                 :        121 :         bcache_remove_clean_blocks(file);
    1000                 :        121 :         bcache_remove_file(file);
    1001                 :            :     }
    1002                 :            : 
    1003         [ +  + ]:        247 :     if (file->kv_header) {
    1004                 :            :         // multi KV intance mode & KV header exists
    1005                 :        225 :         file->free_kv_header(file);
    1006                 :            :     }
    1007                 :            : 
    1008                 :            :     // free global transaction
    1009                 :        247 :     wal_remove_transaction(file, &file->global_txn);
    1010                 :        247 :     free(file->global_txn.items);
    1011                 :        247 :     free(file->global_txn.wrapper);
    1012                 :            : 
    1013                 :            :     // destroy WAL
    1014         [ +  - ]:        247 :     if (wal_is_initialized(file)) {
    1015                 :        247 :         wal_shutdown(file);
    1016                 :        247 :         hash_free(&file->wal->hash_bykey);
    1017                 :        247 :         hash_free(&file->wal->hash_byseq);
    1018                 :        247 :         spin_destroy(&file->wal->lock);
    1019                 :            :     }
    1020                 :        247 :     free(file->wal);
    1021                 :            : 
    1022                 :            :     // free filename and header
    1023                 :        247 :     free(file->filename);
    1024         [ +  + ]:        247 :     if (file->header.data) free(file->header.data);
    1025                 :            :     // free old filename if any
    1026                 :        247 :     free(file->old_filename);
    1027                 :            : 
    1028                 :            :     // destroy locks
    1029                 :        247 :     spin_destroy(&file->lock);
    1030                 :            : 
    1031                 :            : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
    1032                 :        247 :     plock_destroy(&file->plock);
    1033                 :            : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
    1034                 :            :     int i;
    1035                 :            :     for (i=0;i<DLOCK_MAX;++i) {
    1036                 :            :         mutex_destroy(&file->data_mutex[i]);
    1037                 :            :     }
    1038                 :            : #else
    1039                 :            :     int i;
    1040                 :            :     for (i=0;i<DLOCK_MAX;++i) {
    1041                 :            :         spin_destroy(&file->data_spinlock[i]);
    1042                 :            :     }
    1043                 :            : #endif //__FILEMGR_DATA_PARTIAL_LOCK
    1044                 :            : 
    1045                 :            : #ifdef __FILEMGR_MUTEX_LOCK
    1046                 :        247 :     mutex_destroy(&file->mutex);
    1047                 :            : #else
    1048                 :            :     spin_destroy(&file->mutex);
    1049                 :            : #endif
    1050                 :            : 
    1051                 :            :     // free file structure
    1052                 :        247 :     free(file->config);
    1053                 :        247 :     free(file);
    1054                 :        247 : }
    1055                 :            : 
    1056                 :            : // permanently remove file from cache (not just close)
    1057                 :          0 : void filemgr_remove_file(struct filemgr *file)
    1058                 :            : {
    1059                 :            :     struct hash_elem *ret;
    1060                 :            : 
    1061         [ #  # ]:          0 :     assert(file);
    1062         [ #  # ]:          0 :     assert(file->ref_count <= 0);
    1063                 :            : 
    1064                 :            :     // remove from global hash table
    1065                 :          0 :     spin_lock(&filemgr_openlock);
    1066                 :          0 :     ret = hash_remove(&hash, &file->e);
    1067         [ #  # ]:          0 :     assert(ret);
    1068                 :          0 :     spin_unlock(&filemgr_openlock);
    1069                 :            : 
    1070                 :          0 :     _filemgr_free_func(&file->e);
    1071                 :          0 : }
    1072                 :            : 
    1073                 :        123 : void filemgr_shutdown()
    1074                 :            : {
    1075         [ +  - ]:        123 :     if (filemgr_initialized) {
    1076                 :        123 :         spin_lock(&initial_lock);
    1077                 :            : 
    1078                 :        123 :         hash_free_active(&hash, _filemgr_free_func);
    1079         [ +  + ]:        123 :         if (global_config.ncacheblock > 0) {
    1080                 :         56 :             bcache_shutdown();
    1081                 :            :         }
    1082                 :        123 :         filemgr_initialized = 0;
    1083                 :            : #ifndef SPIN_INITIALIZER
    1084                 :            :         initial_lock_status = 0;
    1085                 :            :         spin_destroy(&initial_lock);
    1086                 :            : #else
    1087                 :        123 :         initial_lock = SPIN_INITIALIZER;
    1088                 :            : #endif
    1089                 :        123 :         _filemgr_shutdown_temp_buf();
    1090                 :            : 
    1091                 :        123 :         spin_unlock(&initial_lock);
    1092                 :            :     }
    1093                 :        123 : }
    1094                 :            : 
    1095                 :      13594 : bid_t filemgr_get_next_alloc_block(struct filemgr *file)
    1096                 :            : {
    1097                 :      13594 :     spin_lock(&file->lock);
    1098                 :      13594 :     bid_t bid = file->pos / file->blocksize;
    1099                 :      13594 :     spin_unlock(&file->lock);
    1100                 :      13594 :     return bid;
    1101                 :            : }
    1102                 :            : 
    1103                 :     105791 : bid_t filemgr_alloc(struct filemgr *file, err_log_callback *log_callback)
    1104                 :            : {
    1105                 :     105791 :     spin_lock(&file->lock);
    1106                 :     105791 :     bid_t bid = file->pos / file->blocksize;
    1107                 :     105791 :     file->pos += file->blocksize;
    1108                 :            : 
    1109         [ +  + ]:     105791 :     if (global_config.ncacheblock <= 0) {
    1110                 :            :         // if block cache is turned off, write the allocated block before use
    1111                 :      16927 :         uint8_t _buf = 0x0;
    1112                 :      16927 :         ssize_t rv = file->ops->pwrite(file->fd, &_buf, 1, file->pos-1);
    1113                 :      16927 :         _log_errno_str(file->ops, log_callback, (fdb_status) rv, "WRITE", file->filename);
    1114                 :            :     }
    1115                 :     105791 :     spin_unlock(&file->lock);
    1116                 :            : 
    1117                 :     105791 :     return bid;
    1118                 :            : }
    1119                 :            : 
    1120                 :       3150 : void filemgr_alloc_multiple(struct filemgr *file, int nblock, bid_t *begin,
    1121                 :            :                             bid_t *end, err_log_callback *log_callback)
    1122                 :            : {
    1123                 :       3150 :     spin_lock(&file->lock);
    1124                 :       3150 :     *begin = file->pos / file->blocksize;
    1125                 :       3150 :     *end = *begin + nblock - 1;
    1126                 :       3150 :     file->pos += file->blocksize * nblock;
    1127                 :            : 
    1128         [ +  + ]:       3150 :     if (global_config.ncacheblock <= 0) {
    1129                 :            :         // if block cache is turned off, write the allocated block before use
    1130                 :       2187 :         uint8_t _buf = 0x0;
    1131                 :       2187 :         ssize_t rv = file->ops->pwrite(file->fd, &_buf, 1, file->pos-1);
    1132                 :       2187 :         _log_errno_str(file->ops, log_callback, (fdb_status) rv, "WRITE", file->filename);
    1133                 :            :     }
    1134                 :       3150 :     spin_unlock(&file->lock);
    1135                 :       3150 : }
    1136                 :            : 
    1137                 :            : // atomically allocate NBLOCK blocks only when current file position is same to nextbid
    1138                 :     221763 : bid_t filemgr_alloc_multiple_cond(struct filemgr *file, bid_t nextbid, int nblock,
    1139                 :            :                                   bid_t *begin, bid_t *end,
    1140                 :            :                                   err_log_callback *log_callback)
    1141                 :            : {
    1142                 :            :     bid_t bid;
    1143                 :     221763 :     spin_lock(&file->lock);
    1144                 :     221763 :     bid = file->pos / file->blocksize;
    1145         [ +  + ]:     221763 :     if (bid == nextbid) {
    1146                 :     218613 :         *begin = file->pos / file->blocksize;
    1147                 :     218613 :         *end = *begin + nblock - 1;
    1148                 :     218613 :         file->pos += file->blocksize * nblock;
    1149                 :            : 
    1150         [ +  + ]:     218613 :         if (global_config.ncacheblock <= 0) {
    1151                 :            :             // if block cache is turned off, write the allocated block before use
    1152                 :      11607 :             uint8_t _buf = 0x0;
    1153                 :      11607 :             ssize_t rv = file->ops->pwrite(file->fd, &_buf, 1, file->pos-1);
    1154                 :      11607 :             _log_errno_str(file->ops, log_callback, (fdb_status) rv, "WRITE", file->filename);
    1155                 :            :         }
    1156                 :            :     }else{
    1157                 :       3150 :         *begin = BLK_NOT_FOUND;
    1158                 :       3150 :         *end = BLK_NOT_FOUND;
    1159                 :            :     }
    1160                 :     221763 :     spin_unlock(&file->lock);
    1161                 :     221763 :     return bid;
    1162                 :            : }
    1163                 :            : 
    1164                 :            : #ifdef __CRC32
    1165                 :     228538 : INLINE fdb_status _filemgr_crc32_check(struct filemgr *file, void *buf)
    1166                 :            : {
    1167         [ +  + ]:     228538 :     if ( *((uint8_t*)buf + file->blocksize-1) == BLK_MARKER_BNODE ) {
    1168                 :            :         uint32_t crc_file, crc;
    1169                 :      48467 :         memcpy(&crc_file, (uint8_t *) buf + BTREE_CRC_OFFSET, sizeof(crc_file));
    1170                 :      48467 :         crc_file = _endian_decode(crc_file);
    1171                 :      48467 :         memset((uint8_t *) buf + BTREE_CRC_OFFSET, 0xff, BTREE_CRC_FIELD_LEN);
    1172                 :      48467 :         crc = chksum(buf, file->blocksize);
    1173         [ -  + ]:      48463 :         if (crc != crc_file) {
    1174                 :          0 :             return FDB_RESULT_CHECKSUM_ERROR;
    1175                 :            :         }
    1176                 :            :     }
    1177                 :     228534 :     return FDB_RESULT_SUCCESS;
    1178                 :            : }
    1179                 :            : #endif
    1180                 :            : 
    1181                 :      35401 : void filemgr_invalidate_block(struct filemgr *file, bid_t bid)
    1182                 :            : {
    1183         [ +  + ]:      35401 :     if (global_config.ncacheblock > 0) {
    1184                 :      33427 :         bcache_invalidate_block(file, bid);
    1185                 :            :     }
    1186                 :      35401 : }
    1187                 :            : 
    1188                 :   11062602 : fdb_status filemgr_read(struct filemgr *file, bid_t bid, void *buf,
    1189                 :            :                   err_log_callback *log_callback)
    1190                 :            : {
    1191                 :            :     size_t lock_no;
    1192                 :            :     ssize_t r;
    1193                 :   11062602 :     uint64_t pos = bid * file->blocksize;
    1194                 :   11062602 :     fdb_status status = FDB_RESULT_SUCCESS;
    1195         [ -  + ]:   11062602 :     assert(pos < file->pos);
    1196                 :            : 
    1197         [ +  + ]:   11062602 :     if (global_config.ncacheblock > 0) {
    1198                 :   10944802 :         lock_no = bid % DLOCK_MAX;
    1199                 :            :         (void)lock_no;
    1200                 :            : 
    1201                 :            : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
    1202                 :   10944802 :         plock_entry_t *plock_entry = NULL;
    1203                 :   10944802 :         bid_t is_writer = 0;
    1204                 :            : #endif
    1205                 :   10944802 :         bool locked = false;
    1206                 :            :         // Note: we don't need to grab lock for committed blocks
    1207                 :            :         // because they are immutable so that no writer will interfere and
    1208                 :            :         // overwrite dirty data
    1209         [ +  + ]:   10944802 :         if (filemgr_is_writable(file, bid)) {
    1210                 :            : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
    1211                 :    7685415 :             plock_entry = plock_lock(&file->plock, &bid, &is_writer);
    1212                 :            : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
    1213                 :            :             mutex_lock(&file->data_mutex[lock_no]);
    1214                 :            : #else
    1215                 :            :             spin_lock(&file->data_spinlock[lock_no]);
    1216                 :            : #endif //__FILEMGR_DATA_PARTIAL_LOCK
    1217                 :    7681533 :             locked = true;
    1218                 :            :         }
    1219                 :            : 
    1220                 :   10968167 :         r = bcache_read(file, bid, buf);
    1221         [ +  + ]:   10944745 :         if (r == 0) {
    1222                 :            :             // cache miss
    1223                 :            :             // if normal file, just read a block
    1224                 :     110836 :             r = file->ops->pread(file->fd, buf, file->blocksize, pos);
    1225         [ +  + ]:     110764 :             if (r != file->blocksize) {
    1226                 :            :                 _log_errno_str(file->ops, log_callback,
    1227                 :          1 :                                (fdb_status) r, "READ", file->filename);
    1228         [ -  + ]:          1 :                 if (locked) {
    1229                 :            : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
    1230                 :          0 :                     plock_unlock(&file->plock, plock_entry);
    1231                 :            : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
    1232                 :            :                     mutex_unlock(&file->data_mutex[lock_no]);
    1233                 :            : #else
    1234                 :            :                     spin_unlock(&file->data_spinlock[lock_no]);
    1235                 :            : #endif //__FILEMGR_DATA_PARTIAL_LOCK
    1236                 :            :                 }
    1237                 :          1 :                 return (fdb_status)r;
    1238                 :            :             }
    1239                 :            : #ifdef __CRC32
    1240                 :     110763 :             status = _filemgr_crc32_check(file, buf);
    1241         [ -  + ]:     110720 :             if (status != FDB_RESULT_SUCCESS) {
    1242                 :            :                 _log_errno_str(file->ops, log_callback, status, "READ",
    1243                 :          0 :                         file->filename);
    1244                 :          0 :                 return status;
    1245                 :            :             }
    1246                 :            : #endif
    1247                 :     110720 :             r = bcache_write(file, bid, buf, BCACHE_REQ_CLEAN);
    1248         [ -  + ]:     110808 :             if (r != global_config.blocksize) {
    1249                 :            :                 _log_errno_str(file->ops, log_callback,
    1250                 :          0 :                                (fdb_status) r, "WRITE", file->filename);
    1251                 :          0 :                 return FDB_RESULT_WRITE_FAIL;
    1252                 :            :             }
    1253                 :            :         }
    1254         [ +  + ]:   10944717 :         if (locked) {
    1255                 :            : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
    1256                 :    7674708 :             plock_unlock(&file->plock, plock_entry);
    1257                 :            : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
    1258                 :            :             mutex_unlock(&file->data_mutex[lock_no]);
    1259                 :            : #else
    1260                 :            :             spin_unlock(&file->data_spinlock[lock_no]);
    1261                 :            : #endif //__FILEMGR_DATA_PARTIAL_LOCK
    1262                 :            :         }
    1263                 :            :     } else {
    1264                 :     117800 :         r = file->ops->pread(file->fd, buf, file->blocksize, pos);
    1265         [ +  + ]:     117800 :         if (r != file->blocksize) {
    1266                 :            :             _log_errno_str(file->ops, log_callback, (fdb_status) r, "READ",
    1267                 :          1 :                            file->filename);
    1268                 :          1 :             return (fdb_status)r;
    1269                 :            :         }
    1270                 :            : 
    1271                 :            : #ifdef __CRC32
    1272                 :     117799 :         status = _filemgr_crc32_check(file, buf);
    1273         [ -  + ]:     117799 :         if (status != FDB_RESULT_SUCCESS) {
    1274                 :            :             _log_errno_str(file->ops, log_callback, status, "READ",
    1275                 :          0 :                            file->filename);
    1276                 :          0 :             return status;
    1277                 :            :         }
    1278                 :            : #endif
    1279                 :            :     }
    1280                 :   11070995 :     return status;
    1281                 :            : }
    1282                 :            : 
    1283                 :   18051487 : fdb_status filemgr_write_offset(struct filemgr *file, bid_t bid,
    1284                 :            :                                 uint64_t offset, uint64_t len, void *buf,
    1285                 :            :                                 err_log_callback *log_callback)
    1286                 :            : {
    1287         [ -  + ]:   18051487 :     assert(offset + len <= file->blocksize);
    1288                 :            : 
    1289                 :            :     size_t lock_no;
    1290                 :   18051487 :     ssize_t r = 0;
    1291                 :   18051487 :     uint64_t pos = bid * file->blocksize + offset;
    1292         [ -  + ]:   18051487 :     assert(pos >= file->last_commit);
    1293                 :            : 
    1294         [ +  + ]:   18051487 :     if (global_config.ncacheblock > 0) {
    1295                 :   17379527 :         lock_no = bid % DLOCK_MAX;
    1296                 :            :         (void)lock_no;
    1297                 :            : 
    1298         [ +  + ]:   17379527 :         if (len == file->blocksize) {
    1299                 :            :             // write entire block .. we don't need to read previous block
    1300                 :    8378411 :             r = bcache_write(file, bid, buf, BCACHE_REQ_DIRTY);
    1301         [ -  + ]:    8378411 :             if (r != global_config.blocksize) {
    1302                 :            :                 _log_errno_str(file->ops, log_callback,
    1303                 :          0 :                                (fdb_status) r, "WRITE", file->filename);
    1304                 :          0 :                 return FDB_RESULT_WRITE_FAIL;
    1305                 :            :             }
    1306                 :            :         } else {
    1307                 :            :             // partially write buffer cache first
    1308                 :    9001116 :             r = bcache_write_partial(file, bid, buf, offset, len);
    1309         [ +  + ]:    9001116 :             if (r == 0) {
    1310                 :            :                 // cache miss
    1311                 :            :                 // write partially .. we have to read previous contents of the block
    1312                 :     210755 :                 uint64_t cur_file_pos = file->ops->goto_eof(file->fd);
    1313                 :     210755 :                 bid_t cur_file_last_bid = cur_file_pos / file->blocksize;
    1314                 :     210755 :                 bool locked = false;
    1315                 :            : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
    1316                 :            :                 plock_entry_t *plock_entry;
    1317                 :            : #endif
    1318                 :     210755 :                 void *_buf = _filemgr_get_temp_buf();
    1319                 :            : 
    1320         [ -  + ]:     210755 :                 if (bid >= cur_file_last_bid) {
    1321                 :            :                     // this is the first time to write this block
    1322                 :            :                     // we don't need to read previous block from file
    1323                 :            :                     // and also we don't need to grab lock
    1324                 :            :                 } else {
    1325                 :            : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
    1326                 :          0 :                     bid_t is_writer = 1;
    1327                 :          0 :                     plock_entry = plock_lock(&file->plock, &bid, &is_writer);
    1328                 :            : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
    1329                 :            :                     mutex_lock(&file->data_mutex[lock_no]);
    1330                 :            : #else
    1331                 :            :                     spin_lock(&file->data_spinlock[lock_no]);
    1332                 :            : #endif //__FILEMGR_DATA_PARTIAL_LOCK
    1333                 :          0 :                     locked = true;
    1334                 :            : 
    1335                 :            :                     r = file->ops->pread(file->fd, _buf, file->blocksize,
    1336                 :          0 :                                          bid * file->blocksize);
    1337         [ #  # ]:          0 :                     if (r != file->blocksize) {
    1338                 :          0 :                         _filemgr_release_temp_buf(_buf);
    1339                 :            :                         _log_errno_str(file->ops, log_callback, (fdb_status) r,
    1340                 :          0 :                                        "READ", file->filename);
    1341                 :          0 :                         return FDB_RESULT_READ_FAIL;
    1342                 :            :                     }
    1343                 :            :                 }
    1344                 :     210755 :                 memcpy((uint8_t *)_buf + offset, buf, len);
    1345                 :     210755 :                 r = bcache_write(file, bid, _buf, BCACHE_REQ_DIRTY);
    1346         [ -  + ]:     210755 :                 if (r != global_config.blocksize) {
    1347                 :          0 :                     _filemgr_release_temp_buf(_buf);
    1348                 :            :                     _log_errno_str(file->ops, log_callback,
    1349                 :          0 :                             (fdb_status) r, "WRITE", file->filename);
    1350                 :          0 :                     return FDB_RESULT_WRITE_FAIL;
    1351                 :            :                 }
    1352                 :            : 
    1353         [ -  + ]:     210755 :                 if (locked) {
    1354                 :            : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
    1355                 :          0 :                     plock_unlock(&file->plock, plock_entry);
    1356                 :            : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
    1357                 :            :                     mutex_unlock(&file->data_mutex[lock_no]);
    1358                 :            : #else
    1359                 :            :                     spin_unlock(&file->data_spinlock[lock_no]);
    1360                 :            : #endif //__FILEMGR_DATA_PARTIAL_LOCK
    1361                 :            :                 }
    1362                 :            : 
    1363                 :     210755 :                 _filemgr_release_temp_buf(_buf);
    1364                 :            :             }
    1365                 :            :         }
    1366                 :            :     } else {
    1367                 :            : 
    1368                 :            : #ifdef __CRC32
    1369         [ +  + ]:     671960 :         if (len == file->blocksize) {
    1370                 :     310564 :             uint8_t marker = *((uint8_t*)buf + file->blocksize - 1);
    1371         [ +  + ]:     310564 :             if (marker == BLK_MARKER_BNODE) {
    1372                 :     310148 :                 memset((uint8_t *)buf + BTREE_CRC_OFFSET, 0xff, BTREE_CRC_FIELD_LEN);
    1373                 :     310148 :                 uint32_t crc32 = chksum(buf, file->blocksize);
    1374                 :     310119 :                 crc32 = _endian_encode(crc32);
    1375                 :     310119 :                 memcpy((uint8_t *)buf + BTREE_CRC_OFFSET, &crc32, sizeof(crc32));
    1376                 :            :             }
    1377                 :            :         }
    1378                 :            : #endif
    1379                 :            : 
    1380                 :     671931 :         r = file->ops->pwrite(file->fd, buf, len, pos);
    1381                 :     671976 :         _log_errno_str(file->ops, log_callback, (fdb_status) r, "WRITE", file->filename);
    1382         [ +  + ]:     671960 :         if (r != len) {
    1383                 :       3921 :             return FDB_RESULT_READ_FAIL;
    1384                 :            :         }
    1385                 :            :     }
    1386                 :   18051506 :     return FDB_RESULT_SUCCESS;
    1387                 :            : }
    1388                 :            : 
    1389                 :    8688976 : fdb_status filemgr_write(struct filemgr *file, bid_t bid, void *buf,
    1390                 :            :                    err_log_callback *log_callback)
    1391                 :            : {
    1392                 :            :     return filemgr_write_offset(file, bid, 0, file->blocksize, buf,
    1393                 :    8688976 :                                 log_callback);
    1394                 :            : }
    1395                 :            : 
    1396                 :   27379467 : int filemgr_is_writable(struct filemgr *file, bid_t bid)
    1397                 :            : {
    1398                 :   27379467 :     spin_lock(&file->lock);
    1399                 :   27444614 :     uint64_t pos = bid * file->blocksize;
    1400 [ +  + ][ +  + ]:   27444614 :     int cond = (pos >= file->last_commit && pos < file->pos);
    1401                 :   27444614 :     spin_unlock(&file->lock);
    1402                 :            : 
    1403                 :   27443151 :     return cond;
    1404                 :            : }
    1405                 :            : 
    1406                 :      15304 : fdb_status filemgr_commit(struct filemgr *file,
    1407                 :            :                           err_log_callback *log_callback)
    1408                 :            : {
    1409                 :      15304 :     uint16_t header_len = file->header.size;
    1410                 :            :     uint16_t _header_len;
    1411                 :            :     fdb_seqnum_t _seqnum;
    1412                 :            :     filemgr_header_revnum_t _revnum;
    1413                 :      15304 :     int result = FDB_RESULT_SUCCESS;
    1414                 :      15304 :     filemgr_magic_t magic = FILEMGR_MAGIC;
    1415                 :            :     filemgr_magic_t _magic;
    1416                 :            : 
    1417         [ +  + ]:      15304 :     if (global_config.ncacheblock > 0) {
    1418                 :       2669 :         result = bcache_flush(file);
    1419         [ -  + ]:       2669 :         if (result != FDB_RESULT_SUCCESS) {
    1420                 :            :             _log_errno_str(file->ops, log_callback, (fdb_status) result,
    1421                 :          0 :                            "WRITE", file->filename);
    1422                 :          0 :             return (fdb_status)result;
    1423                 :            :         }
    1424                 :            :     }
    1425                 :            : 
    1426                 :      15304 :     spin_lock(&file->lock);
    1427                 :            : 
    1428 [ +  + ][ +  - ]:      15304 :     if (file->header.size > 0 && file->header.data) {
    1429                 :      13760 :         void *buf = _filemgr_get_temp_buf();
    1430                 :            :         uint8_t marker[BLK_MARKER_SIZE];
    1431                 :            : 
    1432                 :            :         // <-------------------------- block size --------------------------->
    1433                 :            :         // <-  len -><---  8 ---><-  8 ->             <-- 2 --><- 8 -><-  1 ->
    1434                 :            :         // [hdr data][hdr revnum][seqnum] ..(empty).. [hdr len][magic][marker]
    1435                 :            : 
    1436                 :            :         // header data
    1437                 :      13760 :         memcpy(buf, file->header.data, header_len);
    1438                 :            :         // header rev number
    1439                 :      13760 :         _revnum = _endian_encode(file->header.revnum);
    1440                 :      13760 :         memcpy((uint8_t *)buf + header_len, &_revnum,
    1441                 :      27520 :                sizeof(filemgr_header_revnum_t));
    1442                 :            :         // file's sequence number
    1443                 :      13760 :         _seqnum = _endian_encode(file->header.seqnum);
    1444                 :      13760 :         memcpy((uint8_t *)buf + header_len + sizeof(filemgr_header_revnum_t),
    1445                 :      13760 :                &_seqnum, sizeof(fdb_seqnum_t));
    1446                 :            : 
    1447                 :            :         // header length
    1448                 :      13760 :         _header_len = _endian_encode(header_len);
    1449                 :            :         memcpy((uint8_t *)buf + (file->blocksize - sizeof(filemgr_magic_t)
    1450                 :      13760 :                - sizeof(header_len) - BLK_MARKER_SIZE),
    1451                 :      13760 :                &_header_len, sizeof(header_len));
    1452                 :            :         // magic number
    1453                 :      13760 :         _magic = _endian_encode(magic);
    1454                 :            :         memcpy((uint8_t *)buf + (file->blocksize - sizeof(filemgr_magic_t)
    1455                 :      13760 :                - BLK_MARKER_SIZE), &_magic, sizeof(magic));
    1456                 :            : 
    1457                 :            :         // marker
    1458                 :      13760 :         memset(marker, BLK_MARKER_DBHEADER, BLK_MARKER_SIZE);
    1459                 :      13760 :         memcpy((uint8_t *)buf + file->blocksize - BLK_MARKER_SIZE,
    1460                 :      13760 :                marker, BLK_MARKER_SIZE);
    1461                 :            : 
    1462                 :      13760 :         ssize_t rv = file->ops->pwrite(file->fd, buf, file->blocksize, file->pos);
    1463                 :      13760 :         _log_errno_str(file->ops, log_callback, (fdb_status) rv, "WRITE", file->filename);
    1464         [ -  + ]:      13760 :         if (rv != file->blocksize) {
    1465                 :          0 :             _filemgr_release_temp_buf(buf);
    1466                 :          0 :             spin_unlock(&file->lock);
    1467                 :          0 :             return FDB_RESULT_WRITE_FAIL;
    1468                 :            :         }
    1469                 :      13760 :         file->header.bid = file->pos / file->blocksize;
    1470                 :      13760 :         file->pos += file->blocksize;
    1471                 :            : 
    1472                 :      13760 :         file->header.dirty_idtree_root = BLK_NOT_FOUND;
    1473                 :      13760 :         file->header.dirty_seqtree_root = BLK_NOT_FOUND;
    1474                 :            : 
    1475                 :      13760 :         _filemgr_release_temp_buf(buf);
    1476                 :            :     }
    1477                 :            :     // race condition?
    1478                 :      15304 :     file->last_commit = file->pos;
    1479                 :            : 
    1480                 :      15304 :     spin_unlock(&file->lock);
    1481                 :            : 
    1482         [ +  + ]:      15304 :     if (file->fflags & FILEMGR_SYNC) {
    1483                 :      13757 :         result = file->ops->fsync(file->fd);
    1484                 :      13757 :         _log_errno_str(file->ops, log_callback, (fdb_status)result, "FSYNC", file->filename);
    1485                 :            :     }
    1486                 :      15304 :     return (fdb_status) result;
    1487                 :            : }
    1488                 :            : 
    1489                 :       3615 : fdb_status filemgr_sync(struct filemgr *file, err_log_callback *log_callback)
    1490                 :            : {
    1491                 :       3615 :     fdb_status result = FDB_RESULT_SUCCESS;
    1492         [ +  + ]:       3615 :     if (global_config.ncacheblock > 0) {
    1493                 :       1089 :         result = bcache_flush(file);
    1494         [ -  + ]:       1089 :         if (result != FDB_RESULT_SUCCESS) {
    1495                 :            :             _log_errno_str(file->ops, log_callback, (fdb_status) result,
    1496                 :          0 :                            "WRITE", file->filename);
    1497                 :          0 :             return result;
    1498                 :            :         }
    1499                 :            :     }
    1500                 :            : 
    1501         [ +  - ]:       3615 :     if (file->fflags & FILEMGR_SYNC) {
    1502                 :       3615 :         int rv = file->ops->fsync(file->fd);
    1503                 :       3615 :         _log_errno_str(file->ops, log_callback, (fdb_status)rv, "FSYNC", file->filename);
    1504                 :       3615 :         return (fdb_status) rv;
    1505                 :            :     }
    1506                 :       3615 :     return result;
    1507                 :            : }
    1508                 :            : 
    1509                 :        139 : int filemgr_update_file_status(struct filemgr *file, file_status_t status,
    1510                 :            :                                 char *old_filename)
    1511                 :            : {
    1512                 :        139 :     int ret = 1;
    1513                 :        139 :     spin_lock(&file->lock);
    1514                 :        139 :     file->status = status;
    1515         [ +  + ]:        139 :     if (old_filename) {
    1516         [ +  + ]:         86 :         if (!file->old_filename) {
    1517                 :         63 :             file->old_filename = old_filename;
    1518                 :            :         } else {
    1519                 :         23 :             ret = 0;
    1520         [ -  + ]:         23 :             assert(file->ref_count);
    1521                 :         23 :             free(old_filename);
    1522                 :            :         }
    1523                 :            :     }
    1524                 :        139 :     spin_unlock(&file->lock);
    1525                 :        139 :     return ret;
    1526                 :            : }
    1527                 :            : 
    1528                 :         53 : void filemgr_set_compaction_old(struct filemgr *old_file, struct filemgr *new_file)
    1529                 :            : {
    1530         [ -  + ]:         53 :     assert(new_file);
    1531                 :            : 
    1532                 :         53 :     spin_lock(&old_file->lock);
    1533                 :         53 :     old_file->new_file = new_file;
    1534                 :         53 :     old_file->status = FILE_COMPACT_OLD;
    1535                 :         53 :     spin_unlock(&old_file->lock);
    1536                 :         53 : }
    1537                 :            : 
    1538                 :         55 : void filemgr_remove_pending(struct filemgr *old_file, struct filemgr *new_file)
    1539                 :            : {
    1540         [ -  + ]:         55 :     assert(new_file);
    1541                 :            : 
    1542                 :         55 :     spin_lock(&old_file->lock);
    1543         [ +  - ]:         55 :     if (old_file->ref_count > 0) {
    1544                 :            :         // delay removing
    1545                 :         55 :         old_file->new_file = new_file;
    1546                 :         55 :         old_file->status = FILE_REMOVED_PENDING;
    1547                 :         55 :         spin_unlock(&old_file->lock);
    1548                 :            :     }else{
    1549                 :            :         // immediatly remove
    1550                 :          0 :         spin_unlock(&old_file->lock);
    1551                 :          0 :         remove(old_file->filename);
    1552                 :          0 :         filemgr_remove_file(old_file);
    1553                 :            :     }
    1554                 :         55 : }
    1555                 :            : 
    1556                 :            : // Note: filemgr_openlock should be held before calling this function.
    1557                 :          6 : fdb_status filemgr_destroy_file(char *filename,
    1558                 :            :                                 struct filemgr_config *config,
    1559                 :            :                                 struct hash *destroy_file_set)
    1560                 :            : {
    1561                 :          6 :     struct filemgr *file = NULL;
    1562                 :            :     struct hash to_destroy_files;
    1563                 :            :     struct hash *destroy_set = (destroy_file_set ? destroy_file_set :
    1564         [ +  + ]:          6 :                                                   &to_destroy_files);
    1565                 :            :     struct filemgr query;
    1566                 :          6 :     struct hash_elem *e = NULL;
    1567                 :          6 :     fdb_status status = FDB_RESULT_SUCCESS;
    1568                 :          6 :     char *old_filename = NULL;
    1569                 :            : 
    1570         [ +  + ]:          6 :     if (!destroy_file_set) { // top level or non-recursive call
    1571                 :          5 :         hash_init(destroy_set, NBUCKET, _file_hash, _file_cmp);
    1572                 :            :     }
    1573                 :            : 
    1574                 :          6 :     query.filename = filename;
    1575                 :            :     // check whether file is already being destroyed in parent recursive call
    1576                 :          6 :     e = hash_find(destroy_set, &query.e);
    1577         [ -  + ]:          6 :     if (e) { // Duplicate filename found, nothing to be done in this call
    1578         [ #  # ]:          0 :         if (!destroy_file_set) { // top level or non-recursive call
    1579                 :          0 :             hash_free(destroy_set);
    1580                 :            :         }
    1581                 :          0 :         return status;
    1582                 :            :     } else {
    1583                 :            :         // Remember file. Stack value ok IFF single direction recursion
    1584                 :          6 :         hash_insert(destroy_set, &query.e);
    1585                 :            :     }
    1586                 :            : 
    1587                 :            :     // check global list of known files to see if it is already opened or not
    1588                 :          6 :     e = hash_find(&hash, &query.e);
    1589         [ +  + ]:          6 :     if (e) {
    1590                 :            :         // already opened (return existing structure)
    1591                 :          2 :         file = _get_entry(e, struct filemgr, e);
    1592                 :            : 
    1593                 :          2 :         spin_lock(&file->lock);
    1594         [ +  - ]:          2 :         if (file->ref_count) {
    1595                 :          2 :             spin_unlock(&file->lock);
    1596                 :          2 :             status = FDB_RESULT_FILE_IS_BUSY;
    1597         [ +  - ]:          2 :             if (!destroy_file_set) { // top level or non-recursive call
    1598                 :          2 :                 hash_free(destroy_set);
    1599                 :            :             }
    1600                 :          2 :             return status;
    1601                 :            :         }
    1602                 :          0 :         spin_unlock(&file->lock);
    1603         [ #  # ]:          0 :         if (file->old_filename) {
    1604                 :            :             status = filemgr_destroy_file(file->old_filename, config,
    1605                 :          0 :                                           destroy_set);
    1606         [ #  # ]:          0 :             if (status != FDB_RESULT_SUCCESS) {
    1607         [ #  # ]:          0 :                 if (!destroy_file_set) { // top level or non-recursive call
    1608                 :          0 :                     hash_free(destroy_set);
    1609                 :            :                 }
    1610                 :          0 :                 return status;
    1611                 :            :             }
    1612                 :            :         }
    1613                 :            : 
    1614                 :            :         // Cleanup file from in-memory as well as on-disk
    1615                 :          0 :         e = hash_remove(&hash, &file->e);
    1616         [ #  # ]:          0 :         assert(e);
    1617                 :          0 :         _filemgr_free_func(&file->e);
    1618         [ #  # ]:          0 :         if (remove(filename)) {
    1619                 :          0 :             status = FDB_RESULT_FILE_REMOVE_FAIL;
    1620                 :            :         }
    1621                 :            :     } else { // file not in memory, read on-disk to destroy older versions..
    1622                 :          4 :         file = (struct filemgr *)alca(struct filemgr, 1);
    1623                 :          4 :         file->filename = filename;
    1624                 :          4 :         file->ops = get_filemgr_ops();
    1625                 :          4 :         file->fd = file->ops->open(file->filename, O_RDWR, 0666);
    1626                 :          4 :         file->blocksize = global_config.blocksize;
    1627         [ +  + ]:          4 :         if (file->fd < 0) {
    1628         [ -  + ]:          2 :             if (file->fd != FDB_RESULT_NO_SUCH_FILE) {
    1629         [ #  # ]:          0 :                 if (!destroy_file_set) { // top level or non-recursive call
    1630                 :          0 :                     hash_free(destroy_set);
    1631                 :            :                 }
    1632                 :          0 :                 return FDB_RESULT_OPEN_FAIL;
    1633                 :            :             }
    1634                 :            :         } else { // file successfully opened, seek to end to get DB header
    1635                 :          2 :             cs_off_t offset = file->ops->goto_eof(file->fd);
    1636         [ -  + ]:          2 :             if (offset == FDB_RESULT_SEEK_FAIL) {
    1637         [ #  # ]:          0 :                 if (!destroy_file_set) { // top level or non-recursive call
    1638                 :          0 :                     hash_free(destroy_set);
    1639                 :            :                 }
    1640                 :          0 :                 return FDB_RESULT_SEEK_FAIL;
    1641                 :            :             } else { // Need to read DB header which contains old filename
    1642                 :          2 :                 file->pos = offset;
    1643                 :          2 :                 status = _filemgr_read_header(file);
    1644         [ -  + ]:          2 :                 if (status != FDB_RESULT_SUCCESS) {
    1645         [ #  # ]:          0 :                     if (!destroy_file_set) { // top level or non-recursive call
    1646                 :          0 :                         hash_free(destroy_set);
    1647                 :            :                     }
    1648                 :          0 :                     return status;
    1649                 :            :                 }
    1650         [ +  - ]:          2 :                 if (file->header.data) {
    1651                 :            :                     uint16_t *new_filename_len_ptr = (uint16_t *)((char *)
    1652                 :          2 :                                                      file->header.data + 64);
    1653                 :            :                     uint16_t new_filename_len =
    1654                 :          2 :                                       _endian_decode(*new_filename_len_ptr);
    1655                 :            :                     uint16_t *old_filename_len_ptr = (uint16_t *)((char *)
    1656                 :          2 :                                                      file->header.data + 66);
    1657                 :            :                     uint16_t old_filename_len =
    1658                 :          2 :                                       _endian_decode(*old_filename_len_ptr);
    1659                 :            :                     old_filename = (char *)file->header.data + 68
    1660                 :          2 :                                    + new_filename_len;
    1661         [ +  + ]:          2 :                     if (old_filename_len) {
    1662                 :            :                         status = filemgr_destroy_file(old_filename, config,
    1663                 :          1 :                                                       destroy_set);
    1664                 :            :                     }
    1665                 :          2 :                     free(file->header.data);
    1666                 :            :                 }
    1667         [ +  - ]:          2 :                 if (status == FDB_RESULT_SUCCESS) {
    1668         [ -  + ]:          2 :                     if (remove(filename)) {
    1669                 :          0 :                         status = FDB_RESULT_FILE_REMOVE_FAIL;
    1670                 :            :                     }
    1671                 :            :                 }
    1672                 :            :             }
    1673                 :          2 :             file->ops->close(file->fd);
    1674                 :            :         }
    1675                 :            :     }
    1676                 :            : 
    1677         [ +  + ]:          4 :     if (!destroy_file_set) { // top level or non-recursive call
    1678                 :          3 :         hash_free(destroy_set);
    1679                 :            :     }
    1680                 :            : 
    1681                 :          6 :     return status;
    1682                 :            : }
    1683                 :            : 
    1684                 :   45460186 : file_status_t filemgr_get_file_status(struct filemgr *file)
    1685                 :            : {
    1686                 :   45460186 :     spin_lock(&file->lock);
    1687                 :   45487325 :     file_status_t status = file->status;
    1688                 :   45487325 :     spin_unlock(&file->lock);
    1689                 :   45486681 :     return status;
    1690                 :            : }
    1691                 :            : 
    1692                 :   13202328 : uint64_t filemgr_get_pos(struct filemgr *file)
    1693                 :            : {
    1694                 :   13202328 :     spin_lock(&file->lock);
    1695                 :   13262548 :     uint64_t pos = file->pos;
    1696                 :   13262548 :     spin_unlock(&file->lock);
    1697                 :   13260977 :     return pos;
    1698                 :            : }
    1699                 :            : 
    1700                 :    2471039 : bool filemgr_is_rollback_on(struct filemgr *file)
    1701                 :            : {
    1702                 :    2471039 :     spin_lock(&file->lock);
    1703                 :    2471039 :     bool rv = (file->fflags & FILEMGR_ROLLBACK_IN_PROG);
    1704                 :    2471039 :     spin_unlock(&file->lock);
    1705                 :    2471039 :     return rv;
    1706                 :            : }
    1707                 :            : 
    1708                 :         50 : void filemgr_set_rollback(struct filemgr *file, uint8_t new_val)
    1709                 :            : {
    1710                 :         50 :     spin_lock(&file->lock);
    1711         [ +  + ]:         50 :     if (new_val) {
    1712                 :         25 :         file->fflags |= FILEMGR_ROLLBACK_IN_PROG;
    1713                 :            :     } else {
    1714                 :         25 :         file->fflags &= ~FILEMGR_ROLLBACK_IN_PROG;
    1715                 :            :     }
    1716                 :         50 :     spin_unlock(&file->lock);
    1717                 :         50 : }
    1718                 :            : 
    1719                 :         53 : void filemgr_set_in_place_compaction(struct filemgr *file,
    1720                 :            :                                      bool in_place_compaction) {
    1721                 :         53 :     spin_lock(&file->lock);
    1722                 :         53 :     file->in_place_compaction = in_place_compaction;
    1723                 :         53 :     spin_unlock(&file->lock);
    1724                 :         53 : }
    1725                 :            : 
    1726                 :          5 : void filemgr_mutex_openlock(struct filemgr_config *config)
    1727                 :            : {
    1728                 :          5 :     filemgr_init(config);
    1729                 :            : 
    1730                 :          5 :     spin_lock(&filemgr_openlock);
    1731                 :          5 : }
    1732                 :            : 
    1733                 :          5 : void filemgr_mutex_openunlock(void)
    1734                 :            : {
    1735                 :          5 :     spin_unlock(&filemgr_openlock);
    1736                 :          5 : }
    1737                 :            : 
    1738                 :    2542918 : void filemgr_mutex_lock(struct filemgr *file)
    1739                 :            : {
    1740                 :            : #ifdef __FILEMGR_MUTEX_LOCK
    1741                 :    2542918 :     mutex_lock(&file->mutex);
    1742                 :            : #else
    1743                 :            :     spin_lock(&file->mutex);
    1744                 :            : #endif
    1745                 :    2542917 : }
    1746                 :            : 
    1747                 :    2542918 : void filemgr_mutex_unlock(struct filemgr *file)
    1748                 :            : {
    1749                 :            : #ifdef __FILEMGR_MUTEX_LOCK
    1750                 :    2542918 :     mutex_unlock(&file->mutex);
    1751                 :            : #else
    1752                 :            :     spin_unlock(&file->mutex);
    1753                 :            : #endif
    1754                 :    2542918 : }
    1755                 :            : 
    1756                 :        603 : void filemgr_set_dirty_root(struct filemgr *file,
    1757                 :            :                             bid_t dirty_idtree_root,
    1758                 :            :                             bid_t dirty_seqtree_root)
    1759                 :            : {
    1760                 :        603 :     spin_lock(&file->lock);
    1761                 :        603 :     file->header.dirty_idtree_root = dirty_idtree_root;
    1762                 :        603 :     file->header.dirty_seqtree_root = dirty_seqtree_root;
    1763                 :        603 :     spin_unlock(&file->lock);
    1764                 :        603 : }
    1765                 :            : 
    1766                 :    2412659 : void filemgr_get_dirty_root(struct filemgr *file,
    1767                 :            :                             bid_t *dirty_idtree_root,
    1768                 :            :                             bid_t *dirty_seqtree_root)
    1769                 :            : {
    1770                 :    2412659 :     spin_lock(&file->lock);
    1771                 :    2412659 :     *dirty_idtree_root = file->header.dirty_idtree_root;
    1772                 :    2412659 :     *dirty_seqtree_root= file->header.dirty_seqtree_root;
    1773                 :    2412659 :     spin_unlock(&file->lock);
    1774                 :    2412659 : }
    1775                 :            : 
    1776                 :     150300 : static int _kvs_stat_cmp(struct avl_node *a, struct avl_node *b, void *aux)
    1777                 :            : {
    1778                 :            :     struct kvs_node *aa, *bb;
    1779                 :     150300 :     aa = _get_entry(a, struct kvs_node, avl_id);
    1780                 :     150300 :     bb = _get_entry(b, struct kvs_node, avl_id);
    1781                 :            : 
    1782         [ +  + ]:     150300 :     if (aa->id < bb->id) {
    1783                 :      41667 :         return -1;
    1784         [ +  + ]:     108633 :     } else if (aa->id > bb->id) {
    1785                 :       8021 :         return 1;
    1786                 :            :     } else {
    1787                 :     150300 :         return 0;
    1788                 :            :     }
    1789                 :            : }
    1790                 :            : 
    1791                 :        469 : void _kvs_stat_set(struct filemgr *file,
    1792                 :            :                    fdb_kvs_id_t kv_id,
    1793                 :            :                    struct kvs_stat stat)
    1794                 :            : {
    1795         [ +  + ]:        469 :     if (kv_id == 0) {
    1796                 :        365 :         spin_lock(&file->lock);
    1797                 :        365 :         file->header.stat = stat;
    1798                 :        365 :         spin_unlock(&file->lock);
    1799                 :            :     } else {
    1800                 :            :         struct avl_node *a;
    1801                 :            :         struct kvs_node query, *node;
    1802                 :        104 :         struct kvs_header *kv_header = file->kv_header;
    1803                 :            : 
    1804                 :        104 :         spin_lock(&kv_header->lock);
    1805                 :        104 :         query.id = kv_id;
    1806                 :        104 :         a = avl_search(kv_header->idx_id, &query.avl_id, _kvs_stat_cmp);
    1807         [ +  - ]:        104 :         if (a) {
    1808                 :        104 :             node = _get_entry(a, struct kvs_node, avl_id);
    1809                 :        104 :             node->stat = stat;
    1810                 :            :         }
    1811                 :        104 :         spin_unlock(&kv_header->lock);
    1812                 :            :     }
    1813                 :        469 : }
    1814                 :            : 
    1815                 :   20874796 : void _kvs_stat_update_attr(struct filemgr *file,
    1816                 :            :                            fdb_kvs_id_t kv_id,
    1817                 :            :                            kvs_stat_attr_t attr,
    1818                 :            :                            int delta)
    1819                 :            : {
    1820                 :   20874796 :     spin_t *lock = NULL;
    1821                 :            :     struct kvs_stat *stat;
    1822                 :            : 
    1823         [ +  + ]:   20874796 :     if (kv_id == 0) {
    1824                 :   20790772 :         stat = &file->header.stat;
    1825                 :   20790772 :         lock = &file->lock;
    1826                 :   20790772 :         spin_lock(lock);
    1827                 :            :     } else {
    1828                 :            :         struct avl_node *a;
    1829                 :            :         struct kvs_node query, *node;
    1830                 :      84024 :         struct kvs_header *kv_header = file->kv_header;
    1831                 :            : 
    1832                 :      84024 :         lock = &kv_header->lock;
    1833                 :      84024 :         spin_lock(lock);
    1834                 :      84024 :         query.id = kv_id;
    1835                 :      84024 :         a = avl_search(kv_header->idx_id, &query.avl_id, _kvs_stat_cmp);
    1836         [ +  + ]:      84024 :         if (!a) {
    1837                 :            :             // KV instance corresponding to the kv_id is already removed
    1838                 :          4 :             spin_unlock(lock);
    1839                 :   20874851 :             return;
    1840                 :            :         }
    1841                 :      84020 :         node = _get_entry(a, struct kvs_node, avl_id);
    1842                 :      84020 :         stat = &node->stat;
    1843                 :            :     }
    1844                 :            : 
    1845         [ +  + ]:   20874890 :     if (attr == KVS_STAT_DATASIZE) {
    1846                 :    4269028 :         stat->datasize += delta;
    1847         [ +  + ]:   16605862 :     } else if (attr == KVS_STAT_NDOCS) {
    1848                 :    3768955 :         stat->ndocs += delta;
    1849         [ +  + ]:   12836907 :     } else if (attr == KVS_STAT_NLIVENODES) {
    1850                 :    4269029 :         stat->nlivenodes += delta;
    1851         [ +  + ]:    8567878 :     } else if (attr == KVS_STAT_WAL_NDELETES) {
    1852                 :       1462 :         stat->wal_ndeletes += delta;
    1853         [ +  - ]:    8566416 :     } else if (attr == KVS_STAT_WAL_NDOCS) {
    1854                 :    8566417 :         stat->wal_ndocs += delta;
    1855                 :            :     }
    1856                 :   20874890 :     spin_unlock(lock);
    1857                 :            : }
    1858                 :            : 
    1859                 :      16490 : int _kvs_stat_get_kv_header(struct kvs_header *kv_header,
    1860                 :            :                             fdb_kvs_id_t kv_id,
    1861                 :            :                             struct kvs_stat *stat)
    1862                 :            : {
    1863                 :      16490 :     int ret = 0;
    1864                 :            :     struct avl_node *a;
    1865                 :            :     struct kvs_node query, *node;
    1866                 :            : 
    1867                 :      16490 :     query.id = kv_id;
    1868                 :      16490 :     a = avl_search(kv_header->idx_id, &query.avl_id, _kvs_stat_cmp);
    1869         [ +  + ]:      16490 :     if (a) {
    1870                 :      16488 :         node = _get_entry(a, struct kvs_node, avl_id);
    1871                 :      16488 :         *stat = node->stat;
    1872                 :            :     } else {
    1873                 :          2 :         ret = -1;
    1874                 :            :     }
    1875                 :      16490 :     return ret;
    1876                 :            : }
    1877                 :            : 
    1878                 :    4283558 : int _kvs_stat_get(struct filemgr *file,
    1879                 :            :                   fdb_kvs_id_t kv_id,
    1880                 :            :                   struct kvs_stat *stat)
    1881                 :            : {
    1882                 :    4283558 :     int ret = 0;
    1883                 :            : 
    1884         [ +  + ]:    4283558 :     if (kv_id == 0) {
    1885                 :    4267172 :         spin_lock(&file->lock);
    1886                 :    4267176 :         *stat = file->header.stat;
    1887                 :    4267176 :         spin_unlock(&file->lock);
    1888                 :            :     } else {
    1889                 :      16386 :         struct kvs_header *kv_header = file->kv_header;
    1890                 :            : 
    1891                 :      16386 :         spin_lock(&kv_header->lock);
    1892                 :      16386 :         ret = _kvs_stat_get_kv_header(kv_header, kv_id, stat);
    1893                 :      16386 :         spin_unlock(&kv_header->lock);
    1894                 :            :     }
    1895                 :            : 
    1896                 :    4283562 :     return ret;
    1897                 :            : }
    1898                 :            : 
    1899                 :       5503 : uint64_t _kvs_stat_get_sum(struct filemgr *file,
    1900                 :            :                            kvs_stat_attr_t attr)
    1901                 :            : {
    1902                 :            :     struct avl_node *a;
    1903                 :            :     struct kvs_node *node;
    1904                 :       5503 :     struct kvs_header *kv_header = file->kv_header;
    1905                 :            : 
    1906                 :       5503 :     uint64_t ret = 0;
    1907                 :       5503 :     spin_lock(&file->lock);
    1908         [ +  + ]:       5503 :     if (attr == KVS_STAT_DATASIZE) {
    1909                 :       1115 :         ret += file->header.stat.datasize;
    1910         [ +  + ]:       4388 :     } else if (attr == KVS_STAT_NDOCS) {
    1911                 :       1091 :         ret += file->header.stat.ndocs;
    1912         [ +  + ]:       3297 :     } else if (attr == KVS_STAT_NLIVENODES) {
    1913                 :       1115 :         ret += file->header.stat.nlivenodes;
    1914         [ +  + ]:       2182 :     } else if (attr == KVS_STAT_WAL_NDELETES) {
    1915                 :       1091 :         ret += file->header.stat.wal_ndeletes;
    1916         [ +  - ]:       1091 :     } else if (attr == KVS_STAT_WAL_NDOCS) {
    1917                 :       1091 :         ret += file->header.stat.wal_ndocs;
    1918                 :            :     }
    1919                 :       5503 :     spin_unlock(&file->lock);
    1920                 :            : 
    1921         [ +  - ]:       5503 :     if (kv_header) {
    1922                 :       5503 :         spin_lock(&kv_header->lock);
    1923                 :       5503 :         a = avl_first(kv_header->idx_id);
    1924         [ +  + ]:       5533 :         while (a) {
    1925                 :         30 :             node = _get_entry(a, struct kvs_node, avl_id);
    1926                 :         30 :             a = avl_next(&node->avl_id);
    1927                 :            : 
    1928         [ +  + ]:         30 :             if (attr == KVS_STAT_DATASIZE) {
    1929                 :          6 :                 ret += node->stat.datasize;
    1930         [ +  + ]:         24 :             } else if (attr == KVS_STAT_NDOCS) {
    1931                 :          6 :                 ret += node->stat.ndocs;
    1932         [ +  + ]:         18 :             } else if (attr == KVS_STAT_NLIVENODES) {
    1933                 :          6 :                 ret += node->stat.nlivenodes;
    1934         [ +  + ]:         12 :             } else if (attr == KVS_STAT_WAL_NDELETES) {
    1935                 :          6 :                 ret += node->stat.wal_ndeletes;
    1936         [ +  - ]:          6 :             } else if (attr == KVS_STAT_WAL_NDOCS) {
    1937                 :          6 :                 ret += node->stat.wal_ndocs;
    1938                 :            :             }
    1939                 :            :         }
    1940                 :       5503 :         spin_unlock(&kv_header->lock);
    1941                 :            :     }
    1942                 :            : 
    1943                 :       5503 :     return ret;
    1944                 :            : }
    1945                 :            : 

Generated by: LCOV version 1.11