LCOV - code coverage report
Current view: top level - src - snapshot.cc (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 121 135 89.6 %
Date: 2015-01-12 15:17:13 Functions: 9 9 100.0 %
Branches: 41 66 62.1 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
       2                 :            : /*
       3                 :            :  *     Copyright 2010 Couchbase, Inc
       4                 :            :  *
       5                 :            :  *   Licensed under the Apache License, Version 2.0 (the "License");
       6                 :            :  *   you may not use this file except in compliance with the License.
       7                 :            :  *   You may obtain a copy of the License at
       8                 :            :  *
       9                 :            :  *       http://www.apache.org/licenses/LICENSE-2.0
      10                 :            :  *
      11                 :            :  *   Unless required by applicable law or agreed to in writing, software
      12                 :            :  *   distributed under the License is distributed on an "AS IS" BASIS,
      13                 :            :  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14                 :            :  *   See the License for the specific language governing permissions and
      15                 :            :  *   limitations under the License.
      16                 :            :  */
      17                 :            : 
      18                 :            : #include <stdlib.h>
      19                 :            : #include <string.h>
      20                 :            : #include <assert.h>
      21                 :            : #include <stdint.h>
      22                 :            : 
      23                 :            : #include "common.h"
      24                 :            : #include "avltree.h"
      25                 :            : #include "snapshot.h"
      26                 :            : 
      27                 :            : #include "memleak.h"
      28                 :            : 
      29                 :            : #ifdef __DEBUG
      30                 :            : #ifndef __DEBUG_SNAP
      31                 :            :     #undef DBG
      32                 :            :     #undef DBGCMD
      33                 :            :     #undef DBGSW
      34                 :            :     #define DBG(...)
      35                 :            :     #define DBGCMD(...)
      36                 :            :     #define DBGSW(n, ...)
      37                 :            : #endif
      38                 :            : #endif
      39                 :            : 
      40                 :            : // lexicographically compares two variable-length binary streams
      41                 :       1928 : int _snp_keycmp(void *key1, size_t keylen1, void *key2, size_t keylen2)
      42                 :            : {
      43         [ +  + ]:       1928 :     if (keylen1 == keylen2) {
      44                 :       1926 :         return memcmp(key1, key2, keylen1);
      45                 :            :     }else {
      46         [ +  - ]:          2 :         size_t len = MIN(keylen1, keylen2);
      47                 :          2 :         int cmp = memcmp(key1, key2, len);
      48         [ +  - ]:          2 :         if (cmp != 0) return cmp;
      49                 :            :         else {
      50                 :       1928 :             return (int)((int)keylen1 - (int)keylen2);
      51                 :            :         }
      52                 :            :     }
      53                 :            : }
      54                 :            : 
      55                 :       1407 : int _snp_seqnum_cmp(struct avl_node *a, struct avl_node *b, void *aux)
      56                 :            : {
      57                 :            :     struct snap_wal_entry *aa, *bb;
      58                 :       1407 :     aa = _get_entry(a, struct snap_wal_entry, avl_seq);
      59                 :       1407 :     bb = _get_entry(b, struct snap_wal_entry, avl_seq);
      60                 :       1407 :     return (aa->seqnum - bb->seqnum);
      61                 :            : }
      62                 :            : 
      63                 :       3753 : int _snp_wal_cmp(struct avl_node *a, struct avl_node *b, void *aux)
      64                 :            : {
      65                 :       3753 :     struct _fdb_key_cmp_info *info = (struct _fdb_key_cmp_info*)aux;
      66                 :            :     struct snap_wal_entry *aa, *bb;
      67                 :       3753 :     aa = _get_entry(a, struct snap_wal_entry, avl);
      68                 :       3753 :     bb = _get_entry(b, struct snap_wal_entry, avl);
      69                 :            : 
      70         [ +  + ]:       3753 :     if (info->kvs_config.custom_cmp) {
      71                 :            :         // custom compare function for variable-length key
      72         [ +  - ]:       1825 :         if (info->kvs) {
      73                 :            :             // multi KV instance mode
      74                 :            :             // KV ID should be compared separately
      75                 :       1825 :             size_t size_id = sizeof(fdb_kvs_id_t);
      76                 :            :             fdb_kvs_id_t a_id, b_id, _a_id, _b_id;
      77                 :       1825 :             _a_id = *(fdb_kvs_id_t*)aa->key;
      78                 :       1825 :             _b_id = *(fdb_kvs_id_t*)bb->key;
      79                 :       1825 :             a_id = _endian_decode(_a_id);
      80                 :       1825 :             b_id = _endian_decode(_b_id);
      81                 :            : 
      82         [ -  + ]:       1825 :             if (a_id < b_id) {
      83                 :          0 :                 return -1;
      84         [ -  + ]:       1825 :             } else if (a_id > b_id) {
      85                 :          0 :                 return 1;
      86                 :            :             } else {
      87                 :            :                 return info->kvs_config.custom_cmp(
      88                 :       1825 :                             (uint8_t*)aa->key + size_id, aa->keylen - size_id,
      89                 :       1825 :                             (uint8_t*)bb->key + size_id, bb->keylen - size_id);
      90                 :            :             }
      91                 :            :         } else {
      92                 :            :             return info->kvs_config.custom_cmp(aa->key, aa->keylen,
      93                 :          0 :                                                bb->key, bb->keylen);
      94                 :            :         }
      95                 :            :     } else {
      96                 :       3753 :         return _snp_keycmp(aa->key, aa->keylen, bb->key, bb->keylen);
      97                 :            :     }
      98                 :            : }
      99                 :            : 
     100                 :            : 
     101                 :         33 : fdb_status snap_init(struct snap_handle *shandle, fdb_kvs_handle *handle)
     102                 :            : {
     103                 :         33 :     shandle->key_tree = (struct avl_tree *) malloc(sizeof(struct avl_tree));
     104         [ -  + ]:         33 :     if (!shandle->key_tree) {
     105                 :          0 :         return FDB_RESULT_ALLOC_FAIL;
     106                 :            :     }
     107                 :         33 :     shandle->cmp_info.kvs_config = handle->kvs_config;
     108                 :         33 :     shandle->cmp_info.kvs = handle->kvs;
     109                 :            : 
     110                 :         33 :     avl_init(shandle->key_tree, (void *)&shandle->cmp_info);
     111                 :         33 :     shandle->seq_tree = (struct avl_tree *) malloc(sizeof(struct avl_tree));
     112         [ -  + ]:         33 :     if (!shandle->seq_tree) {
     113                 :          0 :         return FDB_RESULT_ALLOC_FAIL;
     114                 :            :     }
     115                 :         33 :     avl_init(shandle->seq_tree, NULL);
     116                 :         33 :     spin_init(&shandle->lock);
     117                 :         33 :     shandle->ref_cnt = 1;
     118                 :         33 :     return FDB_RESULT_SUCCESS;
     119                 :            : }
     120                 :            : 
     121                 :        227 : fdb_status snap_insert(struct snap_handle *shandle, fdb_doc *doc,
     122                 :            :                         uint64_t offset)
     123                 :            : {
     124                 :            :     struct snap_wal_entry query;
     125                 :            :     struct snap_wal_entry *item;
     126                 :            :     struct avl_node *node;
     127                 :        227 :     memset(&query, 0, sizeof(snap_wal_entry));
     128                 :        227 :     query.key = doc->key;
     129                 :        227 :     query.keylen = doc->keylen;
     130                 :        227 :     node = avl_search(shandle->key_tree, &query.avl, _snp_wal_cmp);
     131                 :            : 
     132         [ +  + ]:        227 :     if (!node) {
     133                 :        225 :         item = (struct snap_wal_entry *) malloc(sizeof(struct snap_wal_entry));
     134                 :        225 :         item->keylen = doc->keylen;
     135                 :        225 :         item->key = doc->key;
     136                 :        225 :         item->seqnum = doc->seqnum;
     137         [ -  + ]:        225 :         item->action = doc->deleted ? WAL_ACT_LOGICAL_REMOVE : WAL_ACT_INSERT;
     138                 :        225 :         item->offset = offset;
     139                 :        225 :         item->flag = 0;
     140                 :        225 :         avl_insert(shandle->key_tree, &item->avl, _snp_wal_cmp);
     141                 :        225 :         avl_insert(shandle->seq_tree, &item->avl_seq, _snp_seqnum_cmp);
     142                 :            : 
     143                 :            :         // Note: same logic in wal_commit
     144                 :        225 :         shandle->stat.wal_ndocs++;
     145         [ -  + ]:        225 :         if (doc->deleted) {
     146                 :          0 :             shandle->stat.wal_ndeletes++;
     147                 :            :         }
     148                 :            :     } else {
     149                 :            :         // replace existing node with new values so there are no duplicates
     150                 :          2 :         item = _get_entry(node, struct snap_wal_entry, avl);
     151                 :          2 :         free(item->key);
     152                 :          2 :         item->keylen = doc->keylen;
     153                 :          2 :         item->key = doc->key;
     154         [ +  - ]:          2 :         if (item->seqnum != doc->seqnum) { // Re-index duplicate into seqtree
     155                 :          2 :             item->seqnum = doc->seqnum;
     156                 :          2 :             avl_remove(shandle->seq_tree, &item->avl_seq);
     157                 :          2 :             avl_insert(shandle->seq_tree, &item->avl_seq, _snp_seqnum_cmp);
     158                 :            :         }
     159                 :            : 
     160                 :            :         // Note: same logic in wal_commit
     161 [ +  - ][ -  + ]:          2 :         if (item->action == WAL_ACT_INSERT &&
     162                 :            :             doc->deleted) {
     163                 :          0 :             shandle->stat.wal_ndeletes++;
     164 [ -  + ][ #  # ]:          2 :         } else if (item->action == WAL_ACT_LOGICAL_REMOVE &&
     165                 :          0 :                    !doc->deleted) {
     166                 :          0 :             shandle->stat.wal_ndeletes--;
     167                 :            :         }
     168                 :            : 
     169         [ -  + ]:          2 :         item->action = doc->deleted ? WAL_ACT_LOGICAL_REMOVE : WAL_ACT_INSERT;
     170                 :          2 :         item->offset = offset;
     171                 :            :     }
     172                 :            : 
     173                 :        227 :     return FDB_RESULT_SUCCESS;
     174                 :            : }
     175                 :            : 
     176                 :     359724 : fdb_status snap_find(struct snap_handle *shandle, fdb_doc *doc,
     177                 :            :                       uint64_t *offset)
     178                 :            : {
     179                 :            :     struct snap_wal_entry query;
     180                 :            :     struct avl_node *node;
     181                 :     359724 :     memset(&query, 0, sizeof(snap_wal_entry));
     182 [ +  + ][ +  # ]:     359724 :     if (doc->seqnum == SEQNUM_NOT_USED || (doc->key && doc->keylen > 0)) {
                 [ +  + ]
     183         [ -  + ]:     359723 :         if (!shandle->key_tree) {
     184                 :          0 :             return FDB_RESULT_KEY_NOT_FOUND;
     185                 :            :         }
     186                 :            :         // search by key
     187                 :     359723 :         query.key = doc->key;
     188                 :     359723 :         query.keylen = doc->keylen;
     189                 :     359723 :         node = avl_search(shandle->key_tree, &query.avl, _snp_wal_cmp);
     190         [ +  + ]:     359774 :         if (!node) {
     191                 :     359573 :             return FDB_RESULT_KEY_NOT_FOUND;
     192                 :            :         } else {
     193                 :            :             struct snap_wal_entry *item;
     194                 :        201 :             item = _get_entry(node, struct snap_wal_entry, avl);
     195                 :        201 :             *offset = item->offset;
     196         [ +  - ]:        201 :             if (item->action == WAL_ACT_INSERT) {
     197                 :        201 :                 doc->deleted = false;
     198                 :            :             } else {
     199                 :          0 :                 doc->deleted = true;
     200                 :            :             }
     201                 :        201 :             return FDB_RESULT_SUCCESS;
     202                 :            :         }
     203                 :            :     } else {
     204         [ -  + ]:          1 :         if (!shandle->seq_tree) {
     205                 :          0 :             return FDB_RESULT_KEY_NOT_FOUND;
     206                 :            :         }
     207                 :            :         // search by sequence number
     208                 :          1 :         query.seqnum = doc->seqnum;
     209                 :          1 :         node = avl_search(shandle->seq_tree, &query.avl_seq, _snp_seqnum_cmp);
     210         [ -  + ]:          1 :         if (!node) {
     211                 :          0 :             return FDB_RESULT_KEY_NOT_FOUND;
     212                 :            :         } else {
     213                 :            :             struct snap_wal_entry *item;
     214                 :          1 :             item = _get_entry(node, struct snap_wal_entry, avl_seq);
     215                 :          1 :             *offset = item->offset;
     216         [ +  - ]:          1 :             if (item->action == WAL_ACT_INSERT) {
     217                 :          1 :                 doc->deleted = false;
     218                 :            :             } else {
     219                 :          0 :                 doc->deleted = true;
     220                 :            :             }
     221                 :     359775 :             return FDB_RESULT_SUCCESS;
     222                 :            :         }
     223                 :            :     }
     224                 :            :     return FDB_RESULT_KEY_NOT_FOUND;
     225                 :            : }
     226                 :            : 
     227                 :          2 : fdb_status snap_clone(struct snap_handle *shandle_in, fdb_seqnum_t in_seqnum,
     228                 :            :                       struct snap_handle **shandle, fdb_seqnum_t snap_seqnum)
     229                 :            : {
     230 [ +  + ][ +  - ]:          2 :     if (snap_seqnum == FDB_SNAPSHOT_INMEM ||
     231                 :            :         in_seqnum == snap_seqnum) {
     232                 :          2 :         spin_lock(&shandle_in->lock);
     233                 :          2 :         shandle_in->ref_cnt++;
     234                 :          2 :         spin_unlock(&shandle_in->lock);
     235                 :          2 :         *shandle = shandle_in;
     236                 :          2 :         return FDB_RESULT_SUCCESS;
     237                 :            :     }
     238                 :            : 
     239                 :          2 :     return FDB_RESULT_INVALID_ARGS;
     240                 :            : }
     241                 :            : 
     242                 :         35 : fdb_status snap_close(struct snap_handle *shandle)
     243                 :            : {
     244                 :            :     struct avl_node *a;
     245                 :            :     struct snap_wal_entry *snap_item;
     246                 :            : 
     247                 :         35 :     spin_lock(&shandle->lock);
     248         [ -  + ]:         35 :     assert(shandle->ref_cnt);
     249                 :            : 
     250         [ +  + ]:         35 :     if (--shandle->ref_cnt == 0) {
     251         [ +  - ]:         33 :         if (shandle->key_tree) {
     252                 :         33 :             a = avl_first(shandle->key_tree);
     253         [ +  + ]:        258 :             while (a) {
     254                 :        225 :                 snap_item = _get_entry(a, struct snap_wal_entry, avl);
     255                 :        225 :                 a = avl_next(a);
     256                 :        225 :                 avl_remove(shandle->key_tree, &snap_item->avl);
     257                 :        225 :                 free(snap_item->key);
     258                 :        225 :                 free(snap_item);
     259                 :            :             }
     260                 :         33 :             free(shandle->key_tree);
     261                 :         33 :             free(shandle->seq_tree);
     262                 :            :         }
     263                 :         33 :         spin_unlock(&shandle->lock);
     264                 :         33 :         free(shandle);
     265                 :            :     } else {
     266                 :          2 :         spin_unlock(&shandle->lock);
     267                 :            :     }
     268                 :            : 
     269                 :         35 :     return FDB_RESULT_SUCCESS;
     270                 :            : }
     271                 :            : 
     272                 :          6 : fdb_status snap_get_stat(struct snap_handle *shandle, struct kvs_stat *stat)
     273                 :            : {
     274                 :          6 :     *stat = shandle->stat;
     275                 :          6 :     return FDB_RESULT_SUCCESS;
     276                 :            : }
     277                 :            : 

Generated by: LCOV version 1.11