├── .gitignore ├── .version ├── AUTHORS ├── COPYING ├── Makefile.am ├── NOTICE ├── README.md ├── RELEASENOTES ├── autogen.sh ├── buildtools └── version-gen ├── configure.ac ├── docs └── examples │ ├── Makefile │ └── nvm_kv_sample.c ├── include ├── kv_macro.h ├── nvm_error.h └── nvm_kv.h ├── m4 ├── libtool.m4 ├── ltoptions.m4 ├── ltsugar.m4 ├── ltversion.m4 └── lt~obsolete.m4 ├── src ├── kv_async_expiry.cpp ├── kv_async_expiry.h ├── kv_cache.cpp ├── kv_cache.h ├── kv_common.h ├── kv_expiry_manager.cpp ├── kv_expiry_manager.h ├── kv_iterator.cpp ├── kv_iterator.h ├── kv_layout.cpp ├── kv_layout.h ├── kv_pool_del_manager.cpp ├── kv_pool_del_manager.h ├── kv_pool_manager.cpp ├── kv_pool_manager.h ├── kv_scanner.cpp ├── kv_scanner.h ├── kv_store.cpp ├── kv_store.h ├── kv_store_mgr.cpp ├── kv_store_mgr.h ├── kv_wrappers.cpp ├── kv_wrappers.h └── nvm_kv.cpp ├── test ├── README.md ├── nvm-kv.cpp ├── nvm-kv.h └── nvm-kv.xml └── util ├── kv_bitmap.cpp ├── kv_bitmap.h ├── kv_buffer_pool.cpp ├── kv_buffer_pool.h ├── kv_hash_func.cpp ├── kv_hash_func.h ├── kv_sync_list.cpp ├── kv_sync_list.h └── kv_util.h /.gitignore: -------------------------------------------------------------------------------- 1 | cscope.out 2 | tags 3 | .deps/* 4 | .libs/* 5 | lib/* 6 | bin/* 7 | autom4te.cache/* 8 | *.swp 9 | *.orig 10 | *.rej 11 | *.o 12 | *.lo 13 | config.* 14 | Makefile 15 | Makefile.in 16 | aclocal.m4 17 | ar-lib 18 | configure 19 | depcomp 20 | install-sh 21 | libtool 22 | ltmain.sh 23 | missing 24 | stamp-h1 25 | -------------------------------------------------------------------------------- /.version: -------------------------------------------------------------------------------- 1 | 1.2 2 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Names should be added to this file like so: 2 | # Name or Organization 3 | 4 | Fusion-io. 5 | 6 | # Initial version authors: 7 | Bharath Ramsundar 8 | Siddhi Tadpatrikar 9 | Sushma Devendrappa 10 | 11 | # Partial list of contributors: 12 | Akshita Jain 13 | Bruce Wood 14 | Chandra Mallarapu 15 | Devin Barbieri 16 | Jun Xie 17 | Leonardo Marmol 18 | Raveesh Ahuja 19 | Ravikant Malpani 20 | Sriram Ganesan 21 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | usrlib_execdir = .libs 2 | libdir = /usr/lib/nvm 3 | includedir = /usr/include/nvm 4 | bindir = /usr/bin 5 | docdir = /usr/share/doc/nvm/nvmkv 6 | 7 | ACLOCAL_AMFLAGS = -I m4 8 | AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir) @CXXFLAGS@ 9 | AM_LDFLAGS = @LDFLAGS@ 10 | 11 | lib_LTLIBRARIES = lib/libnvmkv.la 12 | lib_libnvmkv_la_SOURCES = src/kv_expiry_manager.cpp \ 13 | src/kv_wrappers.cpp \ 14 | src/kv_iterator.cpp \ 15 | src/kv_layout.cpp \ 16 | src/kv_pool_del_manager.cpp \ 17 | src/kv_pool_manager.cpp \ 18 | src/kv_scanner.cpp \ 19 | src/kv_store.cpp \ 20 | src/kv_store_mgr.cpp \ 21 | src/kv_async_expiry.cpp \ 22 | src/kv_cache.cpp \ 23 | src/nvm_kv.cpp \ 24 | util/kv_bitmap.cpp \ 25 | util/kv_buffer_pool.cpp \ 26 | util/kv_hash_func.cpp \ 27 | util/kv_sync_list.cpp 28 | 29 | include_HEADERS = include/nvm_error.h include/nvm_kv.h 30 | 31 | bin_PROGRAMS = bin/nvm-kv 32 | bin_nvm_kv_SOURCES = test/nvm-kv.cpp 33 | bin_nvm_kv_CPPFLAGS = $(AM_CPPFLAGS) -I/usr/include/libxml2 34 | bin_nvm_kv_LDFLAGS = $(AM_LDFLAGS) -lxml2 -static 35 | bin_nvm_kv_LDADD = $(lib_LTLIBRARIES) 36 | 37 | doc_DATA = docs/examples/nvm_kv_sample.c docs/examples/Makefile README.md test/nvm-kv.xml 38 | default: all 39 | 40 | all: $(lib_LTLIBRARIES) 41 | 42 | test: $(lib_LTLIBRARIES) $(bin_PROGRAMS) 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #WELCOME TO NVMKV 2 | 3 |
    4 |
  1. OVERVIEW
  2. 5 |
  3. GETTING STARTED WITH NVMKV
  4. 6 |
  5. NVMKV API REFERENCE
  6. 7 |
  7. NVMKV SAMPLE CODE
  8. 8 |
  9. NVMKV MAXIMUM SUPPORTED LIMITS
  10. 9 |
  11. NVMKV BENCHMARKING UTILITY
  12. 10 |
11 | 12 | ## 1. OVERVIEW 13 | 14 | A Key-Value (KV) store is a type of NoSQL database used in high-performance, data-intensive, and scale-out 15 | environments. Persistent KV stores today use flash as a block device and are unable to fully leverage powerful 16 | capabilities that a Flash Translation Layer (FTL) offers, such as dynamic mapping, transaction persistence, and autoexpiry. 17 | Additionally, non-FTL-aware KV stores maintain some of the same metadata that are maintained by the 18 | underlying FTL, resulting in wasted memory. 19 | 20 | The NVMKV library, as described in the API specification, is a lightweight user space library that provides basic key-value operations 21 | such as get, put, delete, and advanced operations such as batch put/get/delete, pools, iterator, and lookup. The library 22 | leverages highly-optimized primitives such as sparse addressing, atomic-writes, Persistent TRIM, etc., provided by the 23 | underlying FTL. The strong consistency guarantees of the underlying NVM Primitives allow KV to achieve high performance 24 | combined with ACID compliance. 25 | 26 | ## 2. GETTING STARTED WITH NVMKV 27 | 28 | See the 'DIY On-Premises -> NVMKV' section under http://opennvm.github.io/get-started.html 29 | 30 | ## 3. NVMKV API REFERENCE 31 | 32 | http://opennvm.github.io/nvmkv-documents/ 33 | 34 | ## 4. NVMKV SAMPLE CODE 35 | 36 | https://github.com/opennvm/nvmkv/tree/master/docs/examples/ 37 | 38 | ## 5. NVMKV MAXIMUM SUPPORTED LIMITS 39 | 40 | Maximum number of pools within a store, 1048576 41 | Maximum key size, 128 bytes. 42 | Maximum value size, 1 MiB - 1 KiB (1 MiB less 1 KiB). See NOTE below. 43 | Maximum number of iterators, 128. 44 | 45 | NOTE: NVMKV has been tested with VSL block sizes of 512 Bytes, 1 KiB, 2 KiB, and 4 KiB. If you are using 2 KiB or 4 KiB blocks, then the maximum value size will be 1 MiB - block size. 46 | 47 | ## 6. NVMKV BENCHMARKING UTILITY 48 | 49 | https://github.com/opennvm/nvmkv/tree/master/test 50 | -------------------------------------------------------------------------------- /RELEASENOTES: -------------------------------------------------------------------------------- 1 | 2 | Version 1.0.0 3 | ------------- 4 | 5 | - Added collision cache feature 6 | - Performance improvements for pools deletion and all keys deletion from KVStore 7 | - API change for nvm_kv_open, additional parameter has been added for collision cache 8 | - New API nvm_kv_batch_get added 9 | - Enhanced benchmarking tool to dump KVStore data on media 10 | - Requires NVM Primitives 1.0.0 in order to build. It can be downloaded from 11 | https://support.fusionio.com 12 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | ##---------------------------------------------------------------------------- 2 | ## NVMKV 3 | ## |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | ## This program is free software; you can redistribute it and/or modify it under 6 | ## the terms of the GNU General Public License version 2 as published by the Free 7 | ## Software Foundation; 8 | ## This program is distributed in the hope that it will be useful, but WITHOUT 9 | ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | ## FOR A PARTICULAR PURPOSE. See the GNU General 11 | ## Public License v2 for more details. 12 | ## A copy of the GNU General Public License v2 is provided with this package and 13 | ## can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | ## You should have received a copy of the GNU General Public License along with 15 | ## this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | ## Place, Suite 330, Boston, MA 02111-1307 USA. 17 | ##---------------------------------------------------------------------------- 18 | #!/bin/sh 19 | 20 | srcdir=$(dirname $0) 21 | 22 | currdir=$(pwd) 23 | cd $srcdir 24 | 25 | quit=0 26 | 27 | # check for required tools 28 | (autopoint --version) < /dev/null > /dev/null 2>&1 || { echo "You must have autopoint install"; quit=1; } 29 | (autoheader --version) < /dev/null > /dev/null 2>&1 || { echo "You must have autoheader install"; quit=1; } 30 | (autoconf --version) < /dev/null > /dev/null 2>&1 || { echo "You must have autoconf install"; quit=1; } 31 | (automake --version) < /dev/null > /dev/null 2>&1 || { echo "You must have automake install"; quit=1; } 32 | (libtool --version) < /dev/null > /dev/null 2>&1 || { echo "You must have libtool install"; quit=1; } 33 | # check for libtoolize version >= 2.x.x 34 | libtlz_ver=$(libtoolize --version | awk '/^libtoolize/ {print $4}') 35 | libtlz_ver=${libtlz_ver:-"missing"} 36 | 37 | if test "$quit" -eq 1; then 38 | exit 1 39 | fi 40 | 41 | rm -rf autom4te.cache 42 | 43 | aclocal 44 | # We support older versions with newer m4 files, so ignore the warnings if any 45 | libtoolize 2> /dev/null 46 | autoheader 47 | automake --force-missing --add-missing 48 | autoconf 49 | 50 | echo "Run ./configure and make to compile" 51 | 52 | cd $currdir 53 | -------------------------------------------------------------------------------- /buildtools/version-gen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "Usage: ${0##*/} " 1>&2 5 | exit 1 6 | fi 7 | 8 | version_file=$1 9 | version= 10 | if test -f $version_file; then 11 | version=`cat $version_file` 12 | case $version in 13 | [0-9]*) ;; 14 | *) version= ;; 15 | esac 16 | fi 17 | 18 | if test -z "$version"; then 19 | echo "${0##*/} is corrupted" 1>&2 20 | # from git tags now 21 | if version=`git describe --match='v*' HEAD 2> /dev/null` && 22 | case $v in 23 | v[0-9]*) ;; 24 | *) exit 1;; 25 | esac 26 | then 27 | version=`echo "$version" | sed 's/-.*//' | sed 's/^v//'` 28 | else 29 | version=UNKOWN 30 | fi 31 | fi 32 | 33 | echo $version | tr -d '\n' 34 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ(2.59) 5 | AC_INIT(fio-kv, m4_esyscmd([buildtools/version-gen .version]), sdevendrappa@fusionio.com) 6 | AC_CONFIG_SRCDIR([src/kv_store_mgr.cpp]) 7 | AC_LANG(C++) 8 | AC_CONFIG_MACRO_DIR([m4]) 9 | AC_CONFIG_HEADER([config.h]) 10 | AM_INIT_AUTOMAKE([-Wall -Werror foreign]) 11 | m4_pattern_allow([AM_PROG_AR]) 12 | AM_PROG_AR 13 | 14 | # Checks for programs. 15 | AC_PROG_CXXCPP 16 | AC_PROG_LIBTOOL 17 | 18 | AM_CONDITIONAL([LINUX], test "x$linux_os" = xyes) 19 | 20 | #---------------------------------------------------- 21 | MODE="-O2 -DNDEBUG" # Production mode 22 | #MODE="-O2 -g2 -DNDEBUG" # Profiling mode without debug symbols 23 | #MODE="-g2" # Debug mode with symbols 24 | #---------------------------------------------------- 25 | 26 | SHARED_CFLAGS="-fPIC -Wall -Werror -Wno-trigraphs -Wno-sign-compare -fno-strict-aliasing -fno-common -pipe -funit-at-a-time -std=c++0x -rdynamic" 27 | 28 | INCLUDE_PATH="-I/usr/include/nvm" 29 | 30 | LD_PATH="-L/usr/lib/nvm -L/usr/lib/fio" 31 | 32 | CXXFLAGS="$LD_PATH $SHARED_CFLAGS $INCLUDE_PATH $MODE" 33 | 34 | LIBS="-lrt" 35 | 36 | AC_C_INLINE 37 | AC_C_CONST 38 | 39 | # Check for c++0x 40 | AC_COMPILE_IFELSE([AC_LANG_SOURCE( 41 | [[template 42 | struct check 43 | { 44 | static_assert(sizeof(int) <= sizeof(T), "Not enough"); 45 | }; 46 | 47 | typedef check> right_angle_brackets; 48 | 49 | int a; 50 | decltype(a) b; 51 | 52 | typedef check check_type; 53 | check_type c; 54 | check_type&& cr = static_cast(c);]])],, 55 | AC_MSG_FAILURE(['$CXX $CXXFLAGS' does not accept ISO c++0x])) 56 | 57 | # Checks for header files. 58 | AC_HEADER_STDC 59 | AC_CHECK_HEADERS([aio.h\ 60 | assert.h\ 61 | ctype.h\ 62 | dlfcn.h\ 63 | errno.h\ 64 | fcntl.h\ 65 | float.h\ 66 | getopt.h\ 67 | linux/fs.h\ 68 | malloc.h\ 69 | map\ 70 | pthread.h\ 71 | set\ 72 | stdarg.h\ 73 | stdbool.h\ 74 | stdint.h\ 75 | stdio.h\ 76 | stdlib.h\ 77 | string\ 78 | string.h\ 79 | sys/ioctl.h\ 80 | sys/param.h\ 81 | sys/stat.h\ 82 | sys/types.h\ 83 | sys/uio.h\ 84 | time.h\ 85 | unistd.h\ 86 | vector],,AC_MSG_ERROR(["Missing header."])) 87 | 88 | # Checks for required libraries 89 | LIBS+=" -ldl" 90 | AC_CHECK_LIB([pthread], [pthread_create], [LIBS="-lpthread $LIBS"], AC_MSG_ERROR(["Missing pthread library"])) 91 | AC_CHECK_LIB([vsl], [vsl_open], [LIBS="-lvsl $LIBS"], AC_MSG_ERROR(["Missing vsl library"])) 92 | AC_CHECK_LIB([nvm-primitives], [nvm_get_version], [LIBS="-lnvm-primitives $LIBS"], AC_MSG_ERROR(["Missing nvm-primivites library"])) 93 | LDFLAGS+=" $LIBS" 94 | 95 | AC_CHECK_HEADERS([nvm_primitives.h\ 96 | nvm_types.h],,AC_MSG_ERROR(["Missing header."])) 97 | 98 | 99 | # Checks for library functions. 100 | AC_FUNC_MALLOC 101 | AC_FUNC_MEMCMP 102 | AC_CHECK_FUNCS([preadv pwritev ftruncate memset strerror clock_gettime],,AC_MSG_ERROR(["Missing function."])) 103 | 104 | AC_CONFIG_FILES([ 105 | Makefile 106 | ]) 107 | 108 | AC_OUTPUT 109 | -------------------------------------------------------------------------------- /docs/examples/Makefile: -------------------------------------------------------------------------------- 1 | #Assuming that libnvm-primitives.so and libnvmkv.so are in /usr/lib/nvm 2 | #Assuming that libvsl.so is in /usr/lib/fio 3 | #Assuming that public header files are in /usr/include/nvm 4 | #Assuming that device is /dev/fioa 5 | LDFLAGS= -L/usr/lib/nvm -L/usr/lib/fio -lvsl -lnvmkv -lnvm-primitives -ldl -lpthread 6 | 7 | CPPFLAGS=-std=gnu99 8 | 9 | all: nvm_kv_sample 10 | sudo LD_LIBRARY_PATH=/usr/lib/nvm ./nvm_kv_sample "/dev/fioa" 11 | 12 | nvm_kv_sample: nvm_kv_sample.o 13 | $(CC) -o $@ $< $(LDFLAGS) 14 | 15 | clean: 16 | rm -f *.o nvm_kv_sample 17 | -------------------------------------------------------------------------------- /include/kv_macro.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | /// \file kv_macro.h 19 | #ifndef KV_MACRO_H_ 20 | #define KV_MACRO_H_ 21 | 22 | // A macro to disallow the copy constructor and operator= functions 23 | #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ 24 | TypeName(const TypeName&); \ 25 | void operator=(const TypeName&); 26 | 27 | #endif //KV_MACRO_H_ 28 | -------------------------------------------------------------------------------- /include/nvm_error.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | /// \file nvm_error.h 19 | /// \brief NVMKV Error Codes Header File. 20 | 21 | #ifndef NVM_ERROR_H_ 22 | #define NVM_ERROR_H_ 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /// 29 | /// NVM Error Codes 30 | /// 31 | typedef enum 32 | { 33 | NVM_SUCCESS = 0, ///< SUCCESS 34 | NVM_ERR_INVALID_HANDLE = 1, ///< INVALID HANDLE 35 | NVM_ERR_DEVICE_NOT_FOUND = 2, ///< DEVICE NOT FOUND 36 | NVM_ERR_OUT_OF_MEMORY = 6, ///< OUT OF MEMORY 37 | NVM_ERR_INTERNAL_FAILURE = 11, ///< INTERNAL FAILURE 38 | NVM_ERR_CAPABILITIES_NOT_SUPPORTED = 17, ///< CAPABILITY NOT SUPPORTED 39 | NVM_ERR_NOT_IMPLEMENTED = 18, ///< NOT IMPLEMENTED 40 | NVM_ERR_FEATURE_NOT_SUPPORTED = 19, ///< FEATURE NOT SUPPORTED 41 | NVM_ERR_OPERATION_NOT_SUPPORTED = 25, ///< OPERATION NOT SUPPORTED 42 | NVM_ERR_OBJECT_EXISTS = 26, ///< OBJECT EXISTS 43 | NVM_ERR_IO = 35, ///< IO ERROR 44 | NVM_ERR_INVALID_INPUT = 36, ///< INVALID INPUT 45 | NVM_ERR_OBJECT_NOT_FOUND = 85, ///< OBJECT NOT FOUND 46 | NVM_ERR_MEMORY_NOT_ALIGNED = 86, ///< MEMORY NOT ALIGNED 47 | NVM_ERR_MAX_LIMIT_REACHED = 87, ///< MAX LIMIT REACHED 48 | } nvm_error_code_t; 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | #endif //NVM_ERROR_H_ 55 | -------------------------------------------------------------------------------- /m4/ltoptions.m4: -------------------------------------------------------------------------------- 1 | # Helper functions for option handling. -*- Autoconf -*- 2 | # 3 | # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, 4 | # Inc. 5 | # Written by Gary V. Vaughan, 2004 6 | # 7 | # This file is free software; the Free Software Foundation gives 8 | # unlimited permission to copy and/or distribute it, with or without 9 | # modifications, as long as this notice is preserved. 10 | 11 | # serial 7 ltoptions.m4 12 | 13 | # This is to help aclocal find these macros, as it can't see m4_define. 14 | AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) 15 | 16 | 17 | # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) 18 | # ------------------------------------------ 19 | m4_define([_LT_MANGLE_OPTION], 20 | [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) 21 | 22 | 23 | # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) 24 | # --------------------------------------- 25 | # Set option OPTION-NAME for macro MACRO-NAME, and if there is a 26 | # matching handler defined, dispatch to it. Other OPTION-NAMEs are 27 | # saved as a flag. 28 | m4_define([_LT_SET_OPTION], 29 | [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl 30 | m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), 31 | _LT_MANGLE_DEFUN([$1], [$2]), 32 | [m4_warning([Unknown $1 option `$2'])])[]dnl 33 | ]) 34 | 35 | 36 | # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) 37 | # ------------------------------------------------------------ 38 | # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. 39 | m4_define([_LT_IF_OPTION], 40 | [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) 41 | 42 | 43 | # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) 44 | # ------------------------------------------------------- 45 | # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME 46 | # are set. 47 | m4_define([_LT_UNLESS_OPTIONS], 48 | [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), 49 | [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), 50 | [m4_define([$0_found])])])[]dnl 51 | m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 52 | ])[]dnl 53 | ]) 54 | 55 | 56 | # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) 57 | # ---------------------------------------- 58 | # OPTION-LIST is a space-separated list of Libtool options associated 59 | # with MACRO-NAME. If any OPTION has a matching handler declared with 60 | # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about 61 | # the unknown option and exit. 62 | m4_defun([_LT_SET_OPTIONS], 63 | [# Set options 64 | m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), 65 | [_LT_SET_OPTION([$1], _LT_Option)]) 66 | 67 | m4_if([$1],[LT_INIT],[ 68 | dnl 69 | dnl Simply set some default values (i.e off) if boolean options were not 70 | dnl specified: 71 | _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no 72 | ]) 73 | _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no 74 | ]) 75 | dnl 76 | dnl If no reference was made to various pairs of opposing options, then 77 | dnl we run the default mode handler for the pair. For example, if neither 78 | dnl `shared' nor `disable-shared' was passed, we enable building of shared 79 | dnl archives by default: 80 | _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) 81 | _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) 82 | _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) 83 | _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) 84 | ]) 85 | ])# _LT_SET_OPTIONS 86 | 87 | 88 | ## --------------------------------- ## 89 | ## Macros to handle LT_INIT options. ## 90 | ## --------------------------------- ## 91 | 92 | # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) 93 | # ----------------------------------------- 94 | m4_define([_LT_MANGLE_DEFUN], 95 | [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) 96 | 97 | 98 | # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) 99 | # ----------------------------------------------- 100 | m4_define([LT_OPTION_DEFINE], 101 | [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl 102 | ])# LT_OPTION_DEFINE 103 | 104 | 105 | # dlopen 106 | # ------ 107 | LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes 108 | ]) 109 | 110 | AU_DEFUN([AC_LIBTOOL_DLOPEN], 111 | [_LT_SET_OPTION([LT_INIT], [dlopen]) 112 | AC_DIAGNOSE([obsolete], 113 | [$0: Remove this warning and the call to _LT_SET_OPTION when you 114 | put the `dlopen' option into LT_INIT's first parameter.]) 115 | ]) 116 | 117 | dnl aclocal-1.4 backwards compatibility: 118 | dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) 119 | 120 | 121 | # win32-dll 122 | # --------- 123 | # Declare package support for building win32 dll's. 124 | LT_OPTION_DEFINE([LT_INIT], [win32-dll], 125 | [enable_win32_dll=yes 126 | 127 | case $host in 128 | *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) 129 | AC_CHECK_TOOL(AS, as, false) 130 | AC_CHECK_TOOL(DLLTOOL, dlltool, false) 131 | AC_CHECK_TOOL(OBJDUMP, objdump, false) 132 | ;; 133 | esac 134 | 135 | test -z "$AS" && AS=as 136 | _LT_DECL([], [AS], [1], [Assembler program])dnl 137 | 138 | test -z "$DLLTOOL" && DLLTOOL=dlltool 139 | _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl 140 | 141 | test -z "$OBJDUMP" && OBJDUMP=objdump 142 | _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl 143 | ])# win32-dll 144 | 145 | AU_DEFUN([AC_LIBTOOL_WIN32_DLL], 146 | [AC_REQUIRE([AC_CANONICAL_HOST])dnl 147 | _LT_SET_OPTION([LT_INIT], [win32-dll]) 148 | AC_DIAGNOSE([obsolete], 149 | [$0: Remove this warning and the call to _LT_SET_OPTION when you 150 | put the `win32-dll' option into LT_INIT's first parameter.]) 151 | ]) 152 | 153 | dnl aclocal-1.4 backwards compatibility: 154 | dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) 155 | 156 | 157 | # _LT_ENABLE_SHARED([DEFAULT]) 158 | # ---------------------------- 159 | # implement the --enable-shared flag, and supports the `shared' and 160 | # `disable-shared' LT_INIT options. 161 | # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. 162 | m4_define([_LT_ENABLE_SHARED], 163 | [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl 164 | AC_ARG_ENABLE([shared], 165 | [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], 166 | [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], 167 | [p=${PACKAGE-default} 168 | case $enableval in 169 | yes) enable_shared=yes ;; 170 | no) enable_shared=no ;; 171 | *) 172 | enable_shared=no 173 | # Look at the argument we got. We use all the common list separators. 174 | lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," 175 | for pkg in $enableval; do 176 | IFS="$lt_save_ifs" 177 | if test "X$pkg" = "X$p"; then 178 | enable_shared=yes 179 | fi 180 | done 181 | IFS="$lt_save_ifs" 182 | ;; 183 | esac], 184 | [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) 185 | 186 | _LT_DECL([build_libtool_libs], [enable_shared], [0], 187 | [Whether or not to build shared libraries]) 188 | ])# _LT_ENABLE_SHARED 189 | 190 | LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) 191 | LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) 192 | 193 | # Old names: 194 | AC_DEFUN([AC_ENABLE_SHARED], 195 | [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) 196 | ]) 197 | 198 | AC_DEFUN([AC_DISABLE_SHARED], 199 | [_LT_SET_OPTION([LT_INIT], [disable-shared]) 200 | ]) 201 | 202 | AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) 203 | AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) 204 | 205 | dnl aclocal-1.4 backwards compatibility: 206 | dnl AC_DEFUN([AM_ENABLE_SHARED], []) 207 | dnl AC_DEFUN([AM_DISABLE_SHARED], []) 208 | 209 | 210 | 211 | # _LT_ENABLE_STATIC([DEFAULT]) 212 | # ---------------------------- 213 | # implement the --enable-static flag, and support the `static' and 214 | # `disable-static' LT_INIT options. 215 | # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. 216 | m4_define([_LT_ENABLE_STATIC], 217 | [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl 218 | AC_ARG_ENABLE([static], 219 | [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], 220 | [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], 221 | [p=${PACKAGE-default} 222 | case $enableval in 223 | yes) enable_static=yes ;; 224 | no) enable_static=no ;; 225 | *) 226 | enable_static=no 227 | # Look at the argument we got. We use all the common list separators. 228 | lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," 229 | for pkg in $enableval; do 230 | IFS="$lt_save_ifs" 231 | if test "X$pkg" = "X$p"; then 232 | enable_static=yes 233 | fi 234 | done 235 | IFS="$lt_save_ifs" 236 | ;; 237 | esac], 238 | [enable_static=]_LT_ENABLE_STATIC_DEFAULT) 239 | 240 | _LT_DECL([build_old_libs], [enable_static], [0], 241 | [Whether or not to build static libraries]) 242 | ])# _LT_ENABLE_STATIC 243 | 244 | LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) 245 | LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) 246 | 247 | # Old names: 248 | AC_DEFUN([AC_ENABLE_STATIC], 249 | [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) 250 | ]) 251 | 252 | AC_DEFUN([AC_DISABLE_STATIC], 253 | [_LT_SET_OPTION([LT_INIT], [disable-static]) 254 | ]) 255 | 256 | AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) 257 | AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) 258 | 259 | dnl aclocal-1.4 backwards compatibility: 260 | dnl AC_DEFUN([AM_ENABLE_STATIC], []) 261 | dnl AC_DEFUN([AM_DISABLE_STATIC], []) 262 | 263 | 264 | 265 | # _LT_ENABLE_FAST_INSTALL([DEFAULT]) 266 | # ---------------------------------- 267 | # implement the --enable-fast-install flag, and support the `fast-install' 268 | # and `disable-fast-install' LT_INIT options. 269 | # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. 270 | m4_define([_LT_ENABLE_FAST_INSTALL], 271 | [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl 272 | AC_ARG_ENABLE([fast-install], 273 | [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], 274 | [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], 275 | [p=${PACKAGE-default} 276 | case $enableval in 277 | yes) enable_fast_install=yes ;; 278 | no) enable_fast_install=no ;; 279 | *) 280 | enable_fast_install=no 281 | # Look at the argument we got. We use all the common list separators. 282 | lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," 283 | for pkg in $enableval; do 284 | IFS="$lt_save_ifs" 285 | if test "X$pkg" = "X$p"; then 286 | enable_fast_install=yes 287 | fi 288 | done 289 | IFS="$lt_save_ifs" 290 | ;; 291 | esac], 292 | [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) 293 | 294 | _LT_DECL([fast_install], [enable_fast_install], [0], 295 | [Whether or not to optimize for fast installation])dnl 296 | ])# _LT_ENABLE_FAST_INSTALL 297 | 298 | LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) 299 | LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) 300 | 301 | # Old names: 302 | AU_DEFUN([AC_ENABLE_FAST_INSTALL], 303 | [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) 304 | AC_DIAGNOSE([obsolete], 305 | [$0: Remove this warning and the call to _LT_SET_OPTION when you put 306 | the `fast-install' option into LT_INIT's first parameter.]) 307 | ]) 308 | 309 | AU_DEFUN([AC_DISABLE_FAST_INSTALL], 310 | [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) 311 | AC_DIAGNOSE([obsolete], 312 | [$0: Remove this warning and the call to _LT_SET_OPTION when you put 313 | the `disable-fast-install' option into LT_INIT's first parameter.]) 314 | ]) 315 | 316 | dnl aclocal-1.4 backwards compatibility: 317 | dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) 318 | dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) 319 | 320 | 321 | # _LT_WITH_PIC([MODE]) 322 | # -------------------- 323 | # implement the --with-pic flag, and support the `pic-only' and `no-pic' 324 | # LT_INIT options. 325 | # MODE is either `yes' or `no'. If omitted, it defaults to `both'. 326 | m4_define([_LT_WITH_PIC], 327 | [AC_ARG_WITH([pic], 328 | [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], 329 | [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], 330 | [lt_p=${PACKAGE-default} 331 | case $withval in 332 | yes|no) pic_mode=$withval ;; 333 | *) 334 | pic_mode=default 335 | # Look at the argument we got. We use all the common list separators. 336 | lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," 337 | for lt_pkg in $withval; do 338 | IFS="$lt_save_ifs" 339 | if test "X$lt_pkg" = "X$lt_p"; then 340 | pic_mode=yes 341 | fi 342 | done 343 | IFS="$lt_save_ifs" 344 | ;; 345 | esac], 346 | [pic_mode=default]) 347 | 348 | test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) 349 | 350 | _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl 351 | ])# _LT_WITH_PIC 352 | 353 | LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) 354 | LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) 355 | 356 | # Old name: 357 | AU_DEFUN([AC_LIBTOOL_PICMODE], 358 | [_LT_SET_OPTION([LT_INIT], [pic-only]) 359 | AC_DIAGNOSE([obsolete], 360 | [$0: Remove this warning and the call to _LT_SET_OPTION when you 361 | put the `pic-only' option into LT_INIT's first parameter.]) 362 | ]) 363 | 364 | dnl aclocal-1.4 backwards compatibility: 365 | dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) 366 | 367 | ## ----------------- ## 368 | ## LTDL_INIT Options ## 369 | ## ----------------- ## 370 | 371 | m4_define([_LTDL_MODE], []) 372 | LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], 373 | [m4_define([_LTDL_MODE], [nonrecursive])]) 374 | LT_OPTION_DEFINE([LTDL_INIT], [recursive], 375 | [m4_define([_LTDL_MODE], [recursive])]) 376 | LT_OPTION_DEFINE([LTDL_INIT], [subproject], 377 | [m4_define([_LTDL_MODE], [subproject])]) 378 | 379 | m4_define([_LTDL_TYPE], []) 380 | LT_OPTION_DEFINE([LTDL_INIT], [installable], 381 | [m4_define([_LTDL_TYPE], [installable])]) 382 | LT_OPTION_DEFINE([LTDL_INIT], [convenience], 383 | [m4_define([_LTDL_TYPE], [convenience])]) 384 | -------------------------------------------------------------------------------- /m4/ltsugar.m4: -------------------------------------------------------------------------------- 1 | # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- 2 | # 3 | # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. 4 | # Written by Gary V. Vaughan, 2004 5 | # 6 | # This file is free software; the Free Software Foundation gives 7 | # unlimited permission to copy and/or distribute it, with or without 8 | # modifications, as long as this notice is preserved. 9 | 10 | # serial 6 ltsugar.m4 11 | 12 | # This is to help aclocal find these macros, as it can't see m4_define. 13 | AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) 14 | 15 | 16 | # lt_join(SEP, ARG1, [ARG2...]) 17 | # ----------------------------- 18 | # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their 19 | # associated separator. 20 | # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier 21 | # versions in m4sugar had bugs. 22 | m4_define([lt_join], 23 | [m4_if([$#], [1], [], 24 | [$#], [2], [[$2]], 25 | [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) 26 | m4_define([_lt_join], 27 | [m4_if([$#$2], [2], [], 28 | [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) 29 | 30 | 31 | # lt_car(LIST) 32 | # lt_cdr(LIST) 33 | # ------------ 34 | # Manipulate m4 lists. 35 | # These macros are necessary as long as will still need to support 36 | # Autoconf-2.59 which quotes differently. 37 | m4_define([lt_car], [[$1]]) 38 | m4_define([lt_cdr], 39 | [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], 40 | [$#], 1, [], 41 | [m4_dquote(m4_shift($@))])]) 42 | m4_define([lt_unquote], $1) 43 | 44 | 45 | # lt_append(MACRO-NAME, STRING, [SEPARATOR]) 46 | # ------------------------------------------ 47 | # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. 48 | # Note that neither SEPARATOR nor STRING are expanded; they are appended 49 | # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). 50 | # No SEPARATOR is output if MACRO-NAME was previously undefined (different 51 | # than defined and empty). 52 | # 53 | # This macro is needed until we can rely on Autoconf 2.62, since earlier 54 | # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. 55 | m4_define([lt_append], 56 | [m4_define([$1], 57 | m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) 58 | 59 | 60 | 61 | # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) 62 | # ---------------------------------------------------------- 63 | # Produce a SEP delimited list of all paired combinations of elements of 64 | # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list 65 | # has the form PREFIXmINFIXSUFFIXn. 66 | # Needed until we can rely on m4_combine added in Autoconf 2.62. 67 | m4_define([lt_combine], 68 | [m4_if(m4_eval([$# > 3]), [1], 69 | [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl 70 | [[m4_foreach([_Lt_prefix], [$2], 71 | [m4_foreach([_Lt_suffix], 72 | ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, 73 | [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) 74 | 75 | 76 | # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) 77 | # ----------------------------------------------------------------------- 78 | # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited 79 | # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. 80 | m4_define([lt_if_append_uniq], 81 | [m4_ifdef([$1], 82 | [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], 83 | [lt_append([$1], [$2], [$3])$4], 84 | [$5])], 85 | [lt_append([$1], [$2], [$3])$4])]) 86 | 87 | 88 | # lt_dict_add(DICT, KEY, VALUE) 89 | # ----------------------------- 90 | m4_define([lt_dict_add], 91 | [m4_define([$1($2)], [$3])]) 92 | 93 | 94 | # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) 95 | # -------------------------------------------- 96 | m4_define([lt_dict_add_subkey], 97 | [m4_define([$1($2:$3)], [$4])]) 98 | 99 | 100 | # lt_dict_fetch(DICT, KEY, [SUBKEY]) 101 | # ---------------------------------- 102 | m4_define([lt_dict_fetch], 103 | [m4_ifval([$3], 104 | m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), 105 | m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) 106 | 107 | 108 | # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) 109 | # ----------------------------------------------------------------- 110 | m4_define([lt_if_dict_fetch], 111 | [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], 112 | [$5], 113 | [$6])]) 114 | 115 | 116 | # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) 117 | # -------------------------------------------------------------- 118 | m4_define([lt_dict_filter], 119 | [m4_if([$5], [], [], 120 | [lt_join(m4_quote(m4_default([$4], [[, ]])), 121 | lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), 122 | [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl 123 | ]) 124 | -------------------------------------------------------------------------------- /m4/ltversion.m4: -------------------------------------------------------------------------------- 1 | # ltversion.m4 -- version numbers -*- Autoconf -*- 2 | # 3 | # Copyright (C) 2004 Free Software Foundation, Inc. 4 | # Written by Scott James Remnant, 2004 5 | # 6 | # This file is free software; the Free Software Foundation gives 7 | # unlimited permission to copy and/or distribute it, with or without 8 | # modifications, as long as this notice is preserved. 9 | 10 | # @configure_input@ 11 | 12 | # serial 3337 ltversion.m4 13 | # This file is part of GNU Libtool 14 | 15 | m4_define([LT_PACKAGE_VERSION], [2.4.2]) 16 | m4_define([LT_PACKAGE_REVISION], [1.3337]) 17 | 18 | AC_DEFUN([LTVERSION_VERSION], 19 | [macro_version='2.4.2' 20 | macro_revision='1.3337' 21 | _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) 22 | _LT_DECL(, macro_revision, 0) 23 | ]) 24 | -------------------------------------------------------------------------------- /m4/lt~obsolete.m4: -------------------------------------------------------------------------------- 1 | # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- 2 | # 3 | # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. 4 | # Written by Scott James Remnant, 2004. 5 | # 6 | # This file is free software; the Free Software Foundation gives 7 | # unlimited permission to copy and/or distribute it, with or without 8 | # modifications, as long as this notice is preserved. 9 | 10 | # serial 5 lt~obsolete.m4 11 | 12 | # These exist entirely to fool aclocal when bootstrapping libtool. 13 | # 14 | # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) 15 | # which have later been changed to m4_define as they aren't part of the 16 | # exported API, or moved to Autoconf or Automake where they belong. 17 | # 18 | # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN 19 | # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us 20 | # using a macro with the same name in our local m4/libtool.m4 it'll 21 | # pull the old libtool.m4 in (it doesn't see our shiny new m4_define 22 | # and doesn't know about Autoconf macros at all.) 23 | # 24 | # So we provide this file, which has a silly filename so it's always 25 | # included after everything else. This provides aclocal with the 26 | # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything 27 | # because those macros already exist, or will be overwritten later. 28 | # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 29 | # 30 | # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. 31 | # Yes, that means every name once taken will need to remain here until 32 | # we give up compatibility with versions before 1.7, at which point 33 | # we need to keep only those names which we still refer to. 34 | 35 | # This is to help aclocal find these macros, as it can't see m4_define. 36 | AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) 37 | 38 | m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) 39 | m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) 40 | m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) 41 | m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) 42 | m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) 43 | m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) 44 | m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) 45 | m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) 46 | m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) 47 | m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) 48 | m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) 49 | m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) 50 | m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) 51 | m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) 52 | m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) 53 | m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) 54 | m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) 55 | m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) 56 | m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) 57 | m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) 58 | m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) 59 | m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) 60 | m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) 61 | m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) 62 | m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) 63 | m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) 64 | m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) 65 | m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) 66 | m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) 67 | m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) 68 | m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) 69 | m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) 70 | m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) 71 | m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) 72 | m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) 73 | m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) 74 | m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) 75 | m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) 76 | m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) 77 | m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) 78 | m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) 79 | m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) 80 | m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) 81 | m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) 82 | m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) 83 | m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) 84 | m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) 85 | m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) 86 | m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) 87 | m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) 88 | m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) 89 | m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) 90 | m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) 91 | m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) 92 | m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) 93 | m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) 94 | m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) 95 | m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) 96 | m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) 97 | m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) 98 | m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) 99 | -------------------------------------------------------------------------------- /src/kv_async_expiry.cpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #include 19 | #include "src/kv_async_expiry.h" 20 | #include "src/kv_store.h" 21 | #include "util/kv_sync_list.h" 22 | 23 | // 24 | //initializes the member variables for asynchronous deletion 25 | // 26 | NVM_KV_Async_Expiry::NVM_KV_Async_Expiry(int num_threads, NVM_KV_Store *kv_store) 27 | :NVM_KV_Scanner(num_threads, kv_store) 28 | { 29 | } 30 | // 31 | //destroys async expiry threads 32 | // 33 | NVM_KV_Async_Expiry::~NVM_KV_Async_Expiry() 34 | { 35 | while (!m_queue.empty()) 36 | { 37 | nvm_iovec_block_t *iov_blk = m_queue.front(); 38 | m_queue.pop(); 39 | delete iov_blk; 40 | } 41 | } 42 | // 43 | //function performs asynchronous deletion, it deletes 44 | //maximum number of iovecs which can be supported by the media 45 | //by using nvm_batch_atomic_operations 46 | // 47 | void* NVM_KV_Async_Expiry::start_thread() 48 | { 49 | uint64_t max_iovecs = get_store()->get_store_device()-> 50 | capabilities.nvm_max_num_iovs; 51 | nvm_iovec_block_t *iovec_block = NULL; 52 | nvm_iovec_t *iovec_entry = NULL; 53 | bool async_del = true; 54 | 55 | set_cancel_state(); 56 | //register function that needs to be called on thread cancellation 57 | pthread_cleanup_push(&NVM_KV_Scanner::scanner_cancel_routine, get_mutex()); 58 | 59 | while (async_del) 60 | { 61 | pthread_mutex_lock(get_mutex()); 62 | iovec_entry = NULL; 63 | 64 | //cancellation point 65 | pthread_testcancel(); 66 | //keep waiting till queue is not empty 67 | while (m_queue.empty() || m_queue.front()->iov_count < 68 | max_iovecs) 69 | { 70 | wait_for_trigger(); 71 | } 72 | 73 | iovec_block = m_queue.front(); 74 | iovec_entry = m_queue.front()->iovec_entry; 75 | m_queue.pop(); 76 | //unlock and start deleting 77 | pthread_mutex_unlock(get_mutex()); 78 | 79 | //deletion of iovecs dependent only on popping from queue 80 | //Insertion of iovec in the safe sync list 81 | if (get_store()->batch_delete_sync(iovec_entry, max_iovecs) != NVM_SUCCESS) 82 | { 83 | fprintf(stderr, "Error deleting expired keys at async expiry scanner\n"); 84 | } 85 | 86 | delete iovec_block->iovec_entry; 87 | delete iovec_block; 88 | } 89 | 90 | pthread_cleanup_pop(0); 91 | return NULL; 92 | } 93 | // 94 | //this function updates the queue with keys, which are expired, 95 | //this enables asynchronous, when the max number of iovecs that 96 | //are supported by media are reached, that particular block of 97 | //iovecs is handed over to start_thread function to perform deletion 98 | // 99 | int64_t NVM_KV_Async_Expiry::update_expiry_queue(uint64_t key_loc, 100 | nvm_kv_header_t *hdr) 101 | { 102 | bool iovec_present = false; 103 | int64_t ret_code = 0; 104 | uint64_t iov_count = 0; 105 | NVM_KV_Store *kv_store = get_store(); 106 | nvm_kv_store_capabilities_t cap = 107 | kv_store->get_store_device()->capabilities; 108 | uint64_t max_iovecs = cap.nvm_max_num_iovs; 109 | nvm_iovec_block_t *iovec_block = NULL; 110 | nvm_iovec_t *iovec_entry = NULL; 111 | uint64_t trim_len; 112 | uint32_t sector_size = cap.nvm_sector_size; 113 | 114 | pthread_mutex_lock(get_mutex()); 115 | 116 | if (m_queue.empty() || 117 | ((iovec_block = m_queue.back())->iov_count == max_iovecs)) 118 | { 119 | iovec_block = new(std::nothrow) nvm_iovec_block_t; 120 | if (iovec_block == NULL) 121 | { 122 | ret_code = -NVM_ERR_OUT_OF_MEMORY; 123 | pthread_mutex_unlock(get_mutex()); 124 | return ret_code; 125 | } 126 | 127 | iovec_block->iov_count = 0; 128 | iovec_block->iovec_entry = new(std::nothrow) nvm_iovec_t[max_iovecs]; 129 | if (iovec_block->iovec_entry == NULL) 130 | { 131 | ret_code = -NVM_ERR_OUT_OF_MEMORY; 132 | pthread_mutex_unlock(get_mutex()); 133 | delete iovec_block; 134 | return ret_code; 135 | } 136 | 137 | m_queue.push(iovec_block); 138 | } 139 | 140 | iovec_entry = iovec_block->iovec_entry; 141 | iov_count = iovec_block->iov_count; 142 | 143 | //check to ensure that same key is not inserted twice in the queue 144 | for (int j = 0; j < iov_count; j++) 145 | { 146 | if (iovec_entry[j].iov_lba == key_loc) 147 | { 148 | iovec_present = true; 149 | break; 150 | } 151 | } 152 | 153 | if (!iovec_present) 154 | { 155 | if ((trim_len = hdr->value_offset + hdr->value_len) <= sector_size) 156 | { 157 | trim_len = sector_size; 158 | } 159 | else 160 | { 161 | trim_len = nvm_kv_round_upto_blk(trim_len, sector_size); 162 | } 163 | 164 | iovec_entry[iov_count].iov_base = 0; 165 | iovec_entry[iov_count].iov_len = trim_len; 166 | iovec_entry[iov_count].iov_lba = key_loc; 167 | iovec_entry[iov_count].iov_opcode = NVM_IOV_TRIM; 168 | iovec_block->iov_count++; 169 | 170 | //starts deletion of iovec block from queue 171 | if (m_queue.front()->iov_count == max_iovecs) 172 | { 173 | restart_scanner_if_asleep(); 174 | } 175 | } 176 | 177 | pthread_mutex_unlock(get_mutex()); 178 | return 0; 179 | } 180 | -------------------------------------------------------------------------------- /src/kv_async_expiry.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_ASYNC_EXPIRY_H 19 | #define KV_ASYNC_EXPIRY_H 20 | #include 21 | #include "src/kv_wrappers.h" 22 | #include "src/kv_scanner.h" 23 | #include 24 | using namespace nvm_wrapper; 25 | 26 | class NVM_KV_Store; 27 | 28 | /// 29 | ///This class is responsible for doing asynchronous deletion of key value pairs 30 | ///If expiry is set to either global expiry or Arbitrary expiry, when the keys 31 | ///are accessed during API calls like kv_get, kv_get_current and if these keys 32 | ///are expired, they are opportunistically deleted. If deletion is done along 33 | ///with the API calls it will affect the performance of these APIs. 34 | ///Hence they are deleted asynchronously in this class. This class maintains 35 | ///a queue and threads which do API calls will submit the keys into this queue 36 | ///for deletion if the keys are expired. Worker threads spawned by this class 37 | ///reads the request from the queue and deletes them using 38 | ///nvm_batch_atomic_operations 39 | /// 40 | class NVM_KV_Async_Expiry : public NVM_KV_Scanner 41 | { 42 | public: 43 | /// 44 | ///Initialises mutex, conditional variable, trim length, 45 | ///kv_device and the thread. 46 | /// 47 | ///@param[in] num_threads number of async threads 48 | ///@param[in] kv_store KV store object associated with this scanner 49 | /// 50 | NVM_KV_Async_Expiry(int num_threads, NVM_KV_Store *kv_store); 51 | /// 52 | ///destroys async expiry threads 53 | /// 54 | ~NVM_KV_Async_Expiry(); 55 | /// 56 | ///function performs asynchronous deletion, it deletes 57 | ///maximum number of iovecs which can be supported by the media 58 | ///by using nvm_atomic_batch_operations 59 | /// 60 | ///@return none 61 | /// 62 | void* start_thread(); 63 | /// 64 | ///this function updates the queue with keys, which are expired, 65 | ///this enables asynchronous, when the max number of iovecs that 66 | ///are supported by media are reached, that particular block of 67 | ///iovecs is handed over to start_thread function to perform deletion 68 | /// 69 | ///@param[in] key_loc start loction of the key to be updated 70 | ///@param[in] kv_hdr pointer to the header of the KV pair 71 | /// 72 | ///@return returns 0 on success or return appropriate 73 | /// error 74 | /// 75 | int64_t update_expiry_queue(uint64_t key_loc, nvm_kv_header_t *kv_hdr); 76 | 77 | private: 78 | std::queue m_queue; ///< queue for storing blocks of iovecs 79 | 80 | }; 81 | 82 | #endif //KV_ASYNC_EXPIRY_H 83 | -------------------------------------------------------------------------------- /src/kv_cache.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2013-2014 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_CACHE_H_ 19 | #define KV_CACHE_H_ 20 | 21 | #include 22 | #include "include/kv_macro.h" 23 | #include "include/nvm_kv.h" 24 | #include "util/kv_hash_func.h" 25 | #include "src/kv_common.h" 26 | 27 | using namespace std; 28 | 29 | class NVM_KV_Store; 30 | 31 | /// 32 | ///This class holds implementation of collision cache, certain put workload 33 | ///makes two media calls, one for reading the key and the other for overwriting 34 | ///key if already exist. To avoid two media calls, collision cache can be used 35 | ///which stores the key-lba mapping in memory 36 | /// 37 | class NVM_KV_Cache 38 | { 39 | public: 40 | NVM_KV_Cache(NVM_KV_Store *kv_store); 41 | /// 42 | ///initializes the collision cache based on the cache_size 43 | /// 44 | ///@param[in] cache_size amount of memory (in bytes) used for 45 | /// collision cache 46 | /// 47 | ///@return return success or appropriate error code 48 | /// 49 | int initialize(uint64_t cache_size); 50 | /// 51 | ///destroys instance of NVM_KV_Hash_Func 52 | /// 53 | ~NVM_KV_Cache(); 54 | /// 55 | ///writes key-lba mapping into cache 56 | /// 57 | ///@param[in] key key that needs to be written into cache 58 | ///@param[in] key_len length of the key 59 | ///@param[in] pool_id Id of the pool to which the key belongs 60 | ///@param[in] value_len length of the value 61 | ///@param[in] abs_expiry absolute expiry time 62 | ///@param[in] gen_count generation count 63 | ///@param[in] lba LBA associated with key 64 | ///@param[in] cache_context pointer to the cache context 65 | /// 66 | ///@return NVM_SUCCESS on success 67 | /// appropriate error code on failure 68 | /// 69 | int kv_cache_put(nvm_kv_key_t *key, uint32_t key_len, 70 | int pool_id, uint32_t value_len, 71 | uint32_t abs_expiry, uint32_t gen_count, 72 | uint64_t lba, 73 | nvm_kv_cache_context *cache_context); 74 | /// 75 | ///reads the key-lba mapping if its exists in cache 76 | /// 77 | ///@param[in] key key that needs to be checked 78 | ///@param[in] key_len length of the key 79 | ///@param[in] pool_id Id of the pool to which the key belongs 80 | ///@param[out] cache_context pointer to the cache context 81 | /// 82 | ///@return NVM_SUCCESS on success 83 | /// appropriate error code on failure 84 | /// 85 | int kv_cache_get(nvm_kv_key_t *key, uint32_t key_len, 86 | int pool_id, nvm_kv_cache_context *cache_context); 87 | /// 88 | ///deletes key-lba mapping from cache 89 | /// 90 | ///@param[in] key key that needs to be deleted from cache 91 | ///@param[in] key_len length of the key 92 | ///@param[in] pool_id Id of the pool to which the key belongs 93 | ///@param[in,out] deleted_entry the cache entry gets deleted 94 | /// 95 | ///@return NVM_SUCCESS on success or appropriate error 96 | /// code on failure 97 | /// 98 | int kv_cache_delete(nvm_kv_key_t *key, uint32_t key_len, int pool_id, 99 | nvm_kv_cache_entry &deleted_entry); 100 | /// 101 | ///delete the cache entries for the given list of lba 102 | /// 103 | ///@param[in] lba_list lba list to be deleted from the cache 104 | /// 105 | void kv_cache_delete(const set& lba_list); 106 | /// 107 | ///deletes key-lba mapping for the given list of pools from the cache 108 | /// 109 | ///@param[in] list of pools to be deleted from the cache 110 | /// 111 | void kv_cache_delete_pools(const set& pool_ids); 112 | /// 113 | ///deletes cache entries of all pools except for the default pool 114 | /// 115 | void kv_cache_delete_all_pools(); 116 | /// 117 | ///delete all key-lba mapping entries from cache 118 | /// 119 | void kv_cache_delete_all(); 120 | /// 121 | ///acquire a write lock on the cache 122 | /// 123 | void kv_cache_acquire_wrlock(); 124 | /// 125 | ///release the lock on the cache 126 | /// 127 | void kv_cache_release_lock(); 128 | /// 129 | ///A comparator function to maintain an eviction map where the map is used in the 130 | ///ascending order of timestamps 131 | /// 132 | typedef struct kv_cache_eviction_comparator 133 | { 134 | bool operator () (time_t a, time_t b) 135 | { 136 | double diff = difftime(b, a); 137 | 138 | if (diff > 0) 139 | { 140 | return true; 141 | } 142 | else 143 | { 144 | return false; 145 | } 146 | } 147 | } kv_cache_eviction_comparator; 148 | /// 149 | ///get the size of the cache 150 | /// 151 | uint64_t kv_cache_get_size(); 152 | 153 | private: 154 | /// 155 | ///compare the cache entry with the given key and pool id 156 | /// 157 | ///@param[in] entry pointer to the cache entry 158 | ///@param[in] key pointer to the key to be compared 159 | ///@param[in] key_len length of the key 160 | ///@param[in] pool_id id of the pool to which the key belongs 161 | /// 162 | ///@return true, if the entry matches the key and pool id 163 | /// false, otherwise 164 | /// 165 | static bool kv_cache_entry_compare(const nvm_kv_cache_entry *entry, 166 | const nvm_kv_key_t *key, 167 | uint32_t key_len, 168 | uint32_t pool_id); 169 | /// 170 | ///compare the two cache entries 171 | /// 172 | ///@param[in] entry_one pointer to the first cache entry 173 | ///@param[in] entry_two pointer to the second cache entry 174 | /// 175 | ///@return true, if the two entry matches 176 | /// false, otherwise 177 | /// 178 | static bool kv_cache_entry_compare( 179 | const nvm_kv_cache_entry *entry_one, 180 | const nvm_kv_cache_entry *entry_two); 181 | /// 182 | ///populate the cache entry with the given content, except for the 183 | ///entry index 184 | /// 185 | ///@param[in] entry pointer to the cache entry 186 | ///@param[in] key pointer to the key to be compared 187 | ///@param[in] key_len length of the key 188 | ///@param[in] pool_id id of the pool to which the key belongs 189 | ///@param[in] value_len length of the value 190 | ///@param[in] abs_expiry absolute expiry time 191 | ///@param[in] gen_count generation count 192 | ///@param[in] lba lba of the key/value pair on the media 193 | ///@param[in] ts timestamp of storage of the entry in the cache 194 | /// 195 | static void kv_cache_entry_set( 196 | nvm_kv_cache_entry *entry, 197 | const nvm_kv_key_t *key, 198 | const uint32_t key_len, 199 | const uint32_t pool_id, 200 | const uint32_t value_len, 201 | const uint32_t abs_expiry, 202 | const uint32_t gen_count, 203 | const uint64_t lba, 204 | const time_t ts); 205 | 206 | static const uint64_t M_COLLISION_LIMIT = 8;///< number of times collision needs to be resolved 207 | 208 | //disable copy constructor and assignment operator 209 | DISALLOW_COPY_AND_ASSIGN(NVM_KV_Cache); 210 | 211 | NVM_KV_Store *m_kv_store; ///< KV store object 212 | pthread_rwlock_t m_cache_rwlock; ///< reader-writer lock for thread safety 213 | uint64_t m_cache_size; ///< amount of memory (in bytes) for cache 214 | uint64_t m_total_entries; ///< total number of cache entries 215 | uint32_t m_cache_addr_bits; ///< number of bits that represent the cache size 216 | NVM_KV_Hash_Func *m_hash_func; ///< hash functions used for collision cache 217 | nvm_kv_cache_entry **m_hash_table; ///< hash table of cache entries 218 | }; 219 | 220 | #endif //KV_CACHE_H_ 221 | -------------------------------------------------------------------------------- /src/kv_common.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_COMMON_H_ 19 | #define KV_COMMON_H_ 20 | #include "util/kv_util.h" 21 | #include "include/kv_macro.h" 22 | #include "include/nvm_kv.h" 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | using namespace std; 30 | 31 | /// 32 | ///KV store capabilities 33 | /// 34 | typedef struct 35 | { 36 | uint64_t nvm_max_num_iovs; ///< max number of atomic IOVs 37 | ///< supported by the device 38 | uint64_t nvm_atomic_write_multiplicity; ///< each atomic vector is a 39 | ///< multiple of this many bytes 40 | uint64_t nvm_max_write_size_per_iov; ///< max size of an atomic write 41 | ///< vector in units of 42 | ///< nvm_atomic_write_multiplicity 43 | uint64_t nvm_max_trim_size_per_iov; ///< max size of an atomic trim 44 | ///< vector in units of 45 | ///< nvm_atomic_write_multiplicity 46 | uint64_t nvm_sector_size; ///< sector size in bytes 47 | uint64_t nvm_max_num_logical_iter_ranges;///< max number of logical 48 | ///< iterator ranges 49 | uint64_t nvm_atomic_write_max_total_size;///< max total size of an atomic 50 | ///< write in bytes 51 | } nvm_kv_store_capabilities_t; 52 | static_assert((sizeof(nvm_kv_store_capabilities_t) % 8 == 0), 53 | "nvm_kv_store_capabilities_t is not byte aligned"); 54 | /// 55 | ///metadata associated with each key in KV store 56 | /// 57 | typedef struct __attribute__((packed)) 58 | { 59 | uint64_t num_key; ///< total number of keys in the KV store 60 | uint32_t gen_count;///< generation count 61 | uint32_t expiry; ///< expiry in seconds associated with each key 62 | } nvm_kv_key_metadata_t; 63 | 64 | static_assert((sizeof(nvm_kv_key_metadata_t) % 8 == 0), 65 | "nvm_kv_key_metadata_t is not byte aligned"); 66 | /// 67 | ///metadata associated with entire KV store 68 | /// 69 | typedef struct __attribute__((packed)) 70 | { 71 | uint64_t kv_store_id; ///< KV store id 72 | uint64_t kv_store_stamp;///< unique id used for verification 73 | uint64_t num_keys; ///< total number of keys on KV store 74 | uint32_t vsu_id; ///< vsu id associated with KV store 75 | uint32_t version; ///< customer store version 76 | uint32_t max_pools; ///< maximum number of pools that can be created in 77 | ///< KV store, this cannot be changed once KV store 78 | ///< is created. 79 | uint32_t max_key_size; ///< maximum key size supported 80 | uint32_t max_value_size;///< maximum value size supported 81 | uint32_t total_no_pools;///< total number of pools 82 | uint32_t kv_revision; ///< KV store API revision number 83 | uint32_t expiry_mode; ///< KV store expiry mode. Expected values are: 84 | ///< KV_DISABLE_EXPIRY(0) - Disable the expiry 85 | ///< KV_ARBITRARY_EXPIRY(1) - Arbitrary expiry 86 | ///< KV_GLOBAL_EXPIRY(2) - Global expiry 87 | uint32_t global_expiry; ///< Global expiry value 88 | uint32_t reserved; ///< reserved field for padding 89 | } nvm_kv_store_metadata_t; 90 | 91 | static_assert((sizeof(nvm_kv_store_metadata_t) % 8 == 0), 92 | "nvm_kv_store_metadata_t is not byte aligned"); 93 | 94 | /// 95 | ///header associated with each key 96 | /// 97 | typedef struct __attribute__((packed)) 98 | { 99 | uint32_t metadata_len; ///< length of KV key metadata in bytes 100 | uint32_t key_len; ///< length of the key in bytes 101 | uint32_t value_len; ///< length of the value in bytes 102 | uint32_t value_offset; ///< exact offset of value within entire 103 | ///< KV pair in bytes 104 | uint32_t pool_id; ///< pool id to which KV pair belong 105 | uint32_t reserved; ///< reserved field for padding 106 | nvm_kv_key_metadata_t metadata;///< metadata associated with the KV pair 107 | } nvm_kv_header_t; 108 | 109 | static_assert((sizeof(nvm_kv_header_t) % 8 == 0), 110 | "nvm_kv_header_t is not byte aligned"); 111 | 112 | /// 113 | ///stores fd and other device related information in memory 114 | /// 115 | typedef struct 116 | { 117 | uint32_t fd; ///< device fd 118 | nvm_handle_t nvm_handle; ///< NVM Handle to invoke 119 | ///< primitives 120 | nvm_kv_store_capabilities_t capabilities;///< KV store capabilities 121 | } nvm_kv_store_device_t; 122 | 123 | static_assert((sizeof(nvm_kv_store_device_t) % 8 == 0), 124 | "nvm_kv_store_device_t is not byte aligned"); 125 | /// 126 | ///entry to queue used for asynchronous deletes, 127 | ///stores maximum number of IOVs which media can support 128 | /// 129 | typedef struct 130 | { 131 | uint32_t iov_count; ///< number of IOVs in iovec_entry 132 | uint32_t reserved; ///< reserved field for padding 133 | nvm_iovec_t* iovec_entry; ///< array of IOVs 134 | } nvm_iovec_block_t; 135 | 136 | /// 137 | ///enum declarations for all KV API's 138 | /// 139 | enum nvm_kv_api 140 | { 141 | KVCREATE, 142 | KVPUT, 143 | KVGET, 144 | KVDELETE, 145 | KVPOOLCREATE, 146 | KVGETPOOLINFO, 147 | KVPOOLDELETE, 148 | KVDELETEALL, 149 | KVCLOSE, 150 | KVEXISTS, 151 | KVBATCHGET, 152 | KVBATCHPUT, 153 | KVBEGIN, 154 | KVNEXT, 155 | KVGETCURRENT, 156 | KVITEREND, 157 | KVGETSTOREINFO, 158 | KVGETKEYINFO, 159 | KVDELETEWRAPPER, 160 | KVGETVALLEN, 161 | KVSETEXPIRY, 162 | KVGETEXPIRY, 163 | KVGETPOOLMETADATA 164 | }; 165 | /// 166 | ///A private wrapper around nvm_logical_range_iter_t that allows tracking 167 | ///of current position in batch fetched iterator requests 168 | /// 169 | typedef struct 170 | { 171 | uint32_t pool_id; ///< pool for which this iterator is created 172 | uint32_t pool_hash; ///< pool hash for the given pool_id 173 | uint64_t num_ranges_found; ///< number of ranges found by the iterator 174 | uint64_t pos; ///< iterator position in fetched ranges 175 | nvm_logical_range_iter_t it;///< NVM iterator variable 176 | } kv_batch_iterator_t; 177 | /// 178 | ///NVMKV cache entry 179 | /// 180 | typedef struct 181 | { 182 | nvm_kv_key_t key[NVM_KV_MAX_KEY_SIZE]; ///< key that needs to be written in the cache 183 | uint32_t key_len; ///< length of the key 184 | uint32_t value_len; ///< length of the value 185 | uint32_t pool_id; ///< pool id associated with the key 186 | uint32_t expiry; ///< expiry in seconds 187 | uint32_t gen_count; ///< generation count 188 | uint32_t reserved; ///< reserved field 189 | uint64_t index; ///< index into the cache 190 | uint64_t lba; ///< LBA associated with the key 191 | time_t ts; ///< timestamp of when the entry was stored in 192 | ///< the cache 193 | } nvm_kv_cache_entry; 194 | /// 195 | ///NVMKV cache context state 196 | /// 197 | typedef enum nvm_kv_entry_state 198 | { 199 | CACHE_ENTRY_NOT_FOUND = 0, ///< cache entry not found 200 | CACHE_ENTRY_EMPTY, ///< an empty cache entry candidate 201 | CACHE_ENTRY_FOUND, ///< matching cache entry is found 202 | CACHE_ENTRY_DELETE ///< cache entry needs to be deleted 203 | } nvm_kv_entry_state; 204 | /// 205 | ///NVMKV cache context 206 | /// 207 | typedef struct 208 | { 209 | nvm_kv_cache_entry context_entry; ///< cache entry associated with the 210 | ///< context 211 | nvm_kv_entry_state context_state; ///< state of the cache entry 212 | bool expired; ///< whether entry is expired or not 213 | } nvm_kv_cache_context; 214 | /// 215 | ///enum declaration for iterator types 216 | /// 217 | typedef enum nvm_kv_iterator_type 218 | { 219 | KV_REGULAR_ITER = 1, ///< general KV store iterator 220 | KV_POOL_DEL_ITER, ///< pool deletion iterator 221 | KV_ARB_EXP_ITER, ///< arbitrary expiry iterator 222 | KV_GLB_EXP_ITER ///< global expiry iterator 223 | } nvm_kv_iterator_type_t; 224 | /// 225 | ///enum used in checking which input parameter needs to be 226 | ///validated for KV APIs 227 | /// 228 | typedef enum 229 | { 230 | KV_VALIDATE_ID = 1, ///< validate input id 231 | KV_VALIDATE_KEY = 2, ///< validate all key related params 232 | KV_VALIDATE_VALUE = 4, ///< validate all value related params 233 | KV_VALIDATE_BATCH = 8, ///< validate all params related to batch APIs 234 | KV_VALIDATE_POOL_ID = 16 ///< validate pool id 235 | } kv_validation_t; 236 | /// 237 | ///data structure type that holds pool tags 238 | /// 239 | typedef map kv_tags_map_t; 240 | #endif //KV_COMMON_H_ 241 | -------------------------------------------------------------------------------- /src/kv_expiry_manager.cpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #include 19 | #include 20 | #include 21 | #include "src/kv_store_mgr.h" 22 | #include "src/kv_expiry_manager.h" 23 | // 24 | //initialize expiry manager 25 | // 26 | NVM_KV_Expiry_Manager::NVM_KV_Expiry_Manager(int num_threads, 27 | NVM_KV_Store *kv_store) : NVM_KV_Scanner(num_threads, kv_store) 28 | { 29 | m_last_seen_capacity = 0.0; 30 | m_no_expire_count = 0; 31 | } 32 | // 33 | //destroys expiry manager 34 | // 35 | NVM_KV_Expiry_Manager::~NVM_KV_Expiry_Manager() 36 | { 37 | } 38 | // 39 | //routine that starts the scanner pass and discards 40 | //key-value pair that are expired 41 | // 42 | void* NVM_KV_Expiry_Manager::start_thread() 43 | { 44 | pthread_mutex_t *glb_mtx = 45 | get_store()->get_pool_mgr()->get_glb_mutex(); 46 | bool expiry = true; 47 | 48 | set_cancel_state(); 49 | //register function that needs to be called on thread cancellation 50 | pthread_cleanup_push(&NVM_KV_Scanner::scanner_cancel_routine, glb_mtx); 51 | //Global mutex is used to protect expiry manager 52 | //and pool delete manager from not deleting same addresses 53 | pthread_mutex_lock(glb_mtx); 54 | while (expiry) 55 | { 56 | //cancellation point 57 | pthread_testcancel(); 58 | while (get_store()->get_pool_mgr()->check_pool_del_status() 59 | || !expire_keys()) 60 | { 61 | wait_for_trigger(); 62 | } 63 | start_expiry(); 64 | } 65 | pthread_mutex_unlock(glb_mtx); 66 | pthread_cleanup_pop(0); 67 | return NULL; 68 | } 69 | // 70 | //start traversing through the complete range of keys 71 | //delete kv pairs that are expired 72 | // 73 | int NVM_KV_Expiry_Manager::start_expiry() 74 | { 75 | uint64_t key_loc = 0; 76 | uint64_t read_len = 0; 77 | uint64_t discard_len = 0; 78 | uint32_t iov_count = 0; 79 | nvm_iovec_t *iovec = get_iovec(); 80 | int ret_code = 0; 81 | NVM_KV_Store *kv_store = get_store(); 82 | nvm_kv_store_capabilities_t capabilities; 83 | uint64_t max_trim_size_per_iov = 0; 84 | 85 | capabilities = kv_store->get_store_device()->capabilities; 86 | max_trim_size_per_iov = 87 | capabilities.nvm_atomic_write_multiplicity * 88 | capabilities.nvm_max_trim_size_per_iov; 89 | 90 | while (!kv_store->get_pool_mgr()->check_pool_del_status() && 91 | ((ret_code = perform_scan(&key_loc, &read_len)) == NVM_SUCCESS)) 92 | { 93 | if (get_iter_type() != KV_GLB_EXP_ITER) 94 | { 95 | //check key if expired 96 | ret_code = is_valid_for_del(key_loc, NULL); 97 | if (ret_code < 0) 98 | { 99 | break; 100 | } 101 | else if (ret_code == 0) 102 | { 103 | continue; 104 | } 105 | } 106 | //check if read_len is greater than max_trim_size_per_iov 107 | discard_len = read_len * capabilities.nvm_sector_size; 108 | if (discard_len > max_trim_size_per_iov) 109 | { 110 | //there is some problem with length of key 111 | fprintf(stderr, "Error: Corrupted key\n"); 112 | ret_code = -NVM_ERR_INTERNAL_FAILURE; 113 | break; 114 | } 115 | else 116 | { 117 | //if expired, put in batch for discarding 118 | iovec[iov_count].iov_base = 0; 119 | iovec[iov_count].iov_len = discard_len; 120 | iovec[iov_count].iov_lba = key_loc; 121 | iovec[iov_count].iov_opcode = NVM_IOV_TRIM; 122 | iov_count++; 123 | } 124 | if (iov_count == capabilities.nvm_max_num_iovs) 125 | { 126 | if ((ret_code = kv_store->batch_delete_sync(iovec, iov_count)) 127 | != NVM_SUCCESS) 128 | { 129 | break; 130 | } 131 | iov_count = 0; 132 | } 133 | } 134 | 135 | if (ret_code == -NVM_ERR_OBJECT_NOT_FOUND) 136 | { 137 | ret_code = NVM_SUCCESS; 138 | } 139 | 140 | //issue discards on any of the keys in buffer 141 | //only when the end is reached 142 | if (iov_count && ret_code == NVM_SUCCESS) 143 | { 144 | ret_code = kv_store->batch_delete_sync(iovec, iov_count); 145 | } 146 | 147 | reset_iterator(); 148 | return ret_code; 149 | } 150 | // 151 | //expiry scanner checks for the heuristics to make sure expiry pass 152 | //needs to be started, if heuristics is met returns true else returns 153 | //false 154 | // 155 | bool NVM_KV_Expiry_Manager::expire_keys() 156 | { 157 | nvm_capacity_t capacity_info; 158 | int ret_code = 0; 159 | bool ret_val = false; 160 | double percent_used = 0; 161 | 162 | //check the % used of the physical capacity 163 | ret_code = nvm_get_capacity(get_store()->get_store_device()->nvm_handle, 164 | &capacity_info); 165 | if (ret_code >= 0) 166 | { 167 | percent_used = ((double)capacity_info.used_phys_capacity/ 168 | (double)capacity_info.total_phys_capacity) * 100; 169 | if (m_last_seen_capacity && (percent_used > m_last_seen_capacity)) 170 | { 171 | m_no_expire_count = 0; 172 | //if percentage is greater than M_TRIGGER_NEXT of last 173 | //triggering percentage, return true 174 | if ((percent_used - m_last_seen_capacity) > M_TRIGGER_NEXT) 175 | { 176 | ret_val = true; 177 | } 178 | } 179 | else if (percent_used == m_last_seen_capacity) 180 | { 181 | if (m_no_expire_count > M_NO_EXPIRY_LIMIT) 182 | { 183 | m_no_expire_count = 0; 184 | ret_val = false; 185 | } 186 | else 187 | { 188 | m_no_expire_count++; 189 | ret_val = true; 190 | } 191 | } 192 | else if (percent_used >= M_TRIGGER_PERCENT) 193 | { 194 | m_no_expire_count = 0; 195 | //if percentage is > M_TRIGGER_PERCENT 196 | ret_val = true; 197 | } 198 | } 199 | m_last_seen_capacity = percent_used; 200 | return ret_val; 201 | } 202 | // 203 | //expiry scanner goes on timed wait, it will be either 204 | //triggered by pool deletion manager or when it completes 205 | //sleep 206 | // 207 | void NVM_KV_Expiry_Manager::wait_for_trigger() 208 | { 209 | struct timespec ts; 210 | struct timeval tp; 211 | pthread_mutex_t *glb_mtx = get_store()->get_pool_mgr()-> 212 | get_glb_mutex(); 213 | pthread_cond_t *glb_cond_var = get_store()->get_pool_mgr()-> 214 | get_glb_cond_var(); 215 | 216 | gettimeofday(&tp, NULL); 217 | //convert from timeval to timespec 218 | ts.tv_sec = tp.tv_sec; 219 | ts.tv_nsec = tp.tv_usec * 1000; 220 | ts.tv_sec += M_TIME_INTERVAL; 221 | pthread_cond_timedwait(glb_cond_var, glb_mtx, &ts); 222 | return; 223 | } 224 | // 225 | //restarts expiry scanner if it is sleeping 226 | //on the conditional variable. 227 | // 228 | void NVM_KV_Expiry_Manager::restart_scanner_if_asleep() 229 | { 230 | pthread_cond_t *glb_cond_var = get_store()->get_pool_mgr()-> 231 | get_glb_cond_var(); 232 | 233 | pthread_cond_broadcast(glb_cond_var); 234 | } 235 | -------------------------------------------------------------------------------- /src/kv_expiry_manager.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_EXPIRY_MANAGER_H_ 19 | #define KV_EXPIRY_MANAGER_H_ 20 | 21 | #include 22 | #include "src/kv_scanner.h" 23 | 24 | /// 25 | ///class that defines a expiry thread object 26 | ///which is responsible for arbitrary expiry 27 | ///of keys in the KV store. This class 28 | ///inherits class KvScanner as most of the 29 | ///functionality done by expiry thread is common 30 | ///as that done by the scanner. 31 | /// 32 | class NVM_KV_Expiry_Manager : public NVM_KV_Scanner 33 | { 34 | public: 35 | /// 36 | ///initializes variable for KV store object 37 | /// 38 | ///@param[in] num_threads number of expiry threads 39 | ///@param[in] kv_store the KV store object associated with 40 | /// this expiry thread 41 | /// 42 | NVM_KV_Expiry_Manager(int num_threads, NVM_KV_Store *kv_store); 43 | // 44 | //destroys expiry manager allocations 45 | // 46 | ~NVM_KV_Expiry_Manager(); 47 | /// 48 | ///This function starts expiry thread 49 | /// 50 | void* start_thread(); 51 | /// 52 | ///starts traversing through the complete range of keys 53 | ///delete kv pairs that are expired 54 | /// 55 | int start_expiry(); 56 | /// 57 | ///expiry scanner checks for the heuristics to make sure expiry pass 58 | ///needs to be started, if heuristics is not met scanner will be put to 59 | ///sleep 60 | /// 61 | void wait_for_trigger(); 62 | /// 63 | ///restarts expiry scanner if it is sleeping 64 | /// 65 | void restart_scanner_if_asleep(); 66 | /// 67 | ///expiry scanner checks for the heuristics to make sure expiry pass 68 | ///needs to be started, if heuristics is met returns true else returns 69 | ///false 70 | /// 71 | ///@return returns true if scanner should start deleting expired keys 72 | /// else returns false 73 | /// 74 | bool expire_keys(); 75 | 76 | private: 77 | 78 | static const int M_NO_EXPIRY_LIMIT = 10; ///< limit on expiry not happening in contiguous expiry thread runs 79 | static const int M_TIME_INTERVAL = 86400; ///< Time interval to trigger expiry (in seconds) 80 | static const int M_TRIGGER_PERCENT = 25; ///< First trigger will be given after drive is 25% filled 81 | static const int M_TRIGGER_NEXT = 5; ///< Subsequent capacity triggers after 5% 82 | double m_last_seen_capacity; ///< Last seen percentage of capacity 83 | int m_no_expire_count; ///< counter which keeps track of no expiry done in contiguous expiry thread runs 84 | }; 85 | #endif //KV_EXPIRY_MANAGER_H_ 86 | -------------------------------------------------------------------------------- /src/kv_iterator.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_ITERATOR_H 19 | #define KV_ITERATOR_H 20 | 21 | #include "src/kv_layout.h" 22 | #include "src/kv_common.h" 23 | 24 | /// 25 | ///instance of this class represents iterator for a KV store. 26 | ///this class provides all functionality of iterator like: 27 | ///1. allocate iterator and initialize iterator params like 28 | /// search_range and search_length 29 | ///2. advance the iterator to next position in logical range 30 | ///3. fetches lba and data length at the current iterator position 31 | ///4. free up iterator index 32 | /// 33 | class NVM_KV_Iterator 34 | { 35 | public: 36 | /// 37 | ///KV store and other member variable are initialized 38 | /// 39 | ///@param[in] kv_store KV store object 40 | ///@param[in] pool_bits lsb that represents pool in LBA 41 | ///@param[in] max_pools maximum pools supported by KV store 42 | ///@param[in] all_poolid pool id that represents all pools 43 | /// 44 | NVM_KV_Iterator(NVM_KV_Store *kv_store, uint32_t pool_bits, 45 | uint32_t max_pools, int all_poolid); 46 | /// 47 | ///destroys all iterators with in KV store 48 | /// 49 | ~NVM_KV_Iterator(); 50 | /// 51 | ///initialization of the NVM_KV_Iterator object after it's created 52 | /// 53 | /// 54 | ///@return returns 0 on success or appropriate error 55 | /// 56 | int initialize(); 57 | /// 58 | ///allocate iterator, set the iterator at first available location 59 | ///within iterator list 60 | /// 61 | ///@param[in] iter_type type of the iterator that needs to be 62 | /// allocated 63 | ///@param[in] pool_id pool id to which iterator should be 64 | /// initialized 65 | ///@param[in] pool_hash pool hash of the pool id, default is set 66 | /// to 0 67 | ///@return returns index of the iterator within iterator 68 | /// list or returns error if the iterator list 69 | /// is full 70 | /// 71 | int alloc_iter(int iter_type, int pool_id, uint32_t pool_hash); 72 | /// 73 | ///initializes iterator param every time the function is called 74 | /// 75 | ///@param[in] it_id index of the iterator with in iterator 76 | /// list 77 | ///@param[in] search_base start location of the iterator 78 | ///@param[in] search_length search length of the iterator 79 | ///@param[in] iter_type type of the iterator, if it is regular 80 | /// one or iterator used by scanner 81 | ///@return returns 0 on success, or returns 82 | /// appropriate error code 83 | /// 84 | int init_iter(int it_id, uint64_t search_base, uint64_t search_length, 85 | int iter_type); 86 | /// 87 | ///get the iterator object for the given iterator type and id 88 | /// 89 | ///@param[in] iter_id unique identifier of iterator 90 | ///@param[in] iter_type type of the iterator, if it is regular 91 | /// one or iterator used by scanner 92 | ///@return returns pointer to kv_batch_iterator_t 93 | /// object or NULL if not found 94 | /// 95 | kv_batch_iterator_t* get_iter(int iter_id, int iter_type); 96 | /// 97 | ///sets iterator to next location with in a pool 98 | /// 99 | ///@param[in] it_id unique identifier of iterator 100 | ///@param[in] iter_type type of the iterator, if it is regular 101 | /// one or iterator used by scanner 102 | ///@return returns 0 on success or error on failure 103 | /// 104 | int iter_over_pool(int it_id, int iter_type); 105 | /// 106 | ///increment the given iterator forward one position on logical tree 107 | /// 108 | ///@param[in] it_id index of the iterator with in iterator 109 | /// list 110 | ///@param[in] iter_type type of the iterator, if it is regular 111 | /// one or iterator used by scanner 112 | ///@return returns 0 on success, or returns appropriate 113 | /// error code 114 | /// 115 | int iterate(int it_id, int iter_type); 116 | /// 117 | ///fetch iterator position on the logical tree and also retrieve data 118 | ///length 119 | /// 120 | ///@param[in] it_id unique iterator id 121 | ///@param[out] loc location of the iterator on logical tree(LBA) 122 | ///@param[out] len length of the data written on media 123 | /// represented by LBA 124 | ///@param[in] iter_type type of the iterator, if it is regular 125 | /// one or iterator used by scanner 126 | ///@return return 0 on success or return appropriate error 127 | /// 128 | int get_iter_loc(int it_id, uint64_t *lba, uint64_t *len, 129 | int iter_type); 130 | /// 131 | ///frees the iterator at index it_id in the iterator list 132 | /// 133 | ///@param[in] it_id index of the iterator with in iterator 134 | /// list 135 | ///@param[in] iter_type type of the iterator, if it is regular 136 | /// one or iterator used by scanner 137 | ///@return returns 0 on success or appropriate error 138 | /// 139 | int free_iterator(int it_id, int iter_type); 140 | /// 141 | ///count the number of contiguous ranges on the media 142 | /// 143 | ///@param[in] search_base start location for the search 144 | ///@param[in] search_length length to search 145 | ///@return returns number of contiguous ranges 146 | /// found with in the search length or 147 | /// returns appropriate error 148 | /// 149 | int64_t count_ranges(uint64_t search_base, uint64_t search_length); 150 | 151 | private: 152 | static const int M_NO_ITR = NVM_KV_MAX_ITERATORS + 3; ///< iterators 153 | ///< of KV store 154 | static const int M_POOL_DEL_ITR = NVM_KV_MAX_ITERATORS;///< pool 155 | ///< deletion 156 | ///< iterator 157 | ///< index 158 | static const int M_ARB_EXP_ITR = M_POOL_DEL_ITR + 1; ///< expiry 159 | ///< iterator 160 | ///< index 161 | static const int M_GLB_EXP_ITR = M_ARB_EXP_ITR + 1; ///< global 162 | ///< expiry 163 | ///< iterator 164 | ///< index 165 | static const uint32_t M_MAX_BUFFERS_IN_POOL = 128; ///< max number of 166 | ///< buffers in 167 | ///< buffer pool 168 | 169 | 170 | //disable copy constructor and assignment operator 171 | DISALLOW_COPY_AND_ASSIGN(NVM_KV_Iterator); 172 | /// 173 | ///fetch pool id from media at a given location 174 | /// 175 | ///@param[in] key_loc LBA of the entry 176 | ///@return returns pool_id on success, returns 177 | /// appropriate error code on error 178 | /// 179 | int get_poolid(uint64_t key_loc); 180 | /// 181 | ///validates iterator id, if iterator type is regular iterator id 182 | ///should be with in 0 - NVM_KV_MAX_ITERATORS, if iterator type is other 183 | ///than regular iterator id can be M_POOL_DEL_ITR or M_ARB_EXP_ITR 184 | /// 185 | ///@param[in] it_id iterator id 186 | ///@param[in] iter_type type of iterator 187 | ///@return 0 on valid iterator id or invalid error 188 | /// 189 | int validate_iter(int it_id, int iter_type); 190 | 191 | NVM_KV_Store *m_p_kv_store; ///< KV store object 192 | kv_batch_iterator_t *m_iter[M_NO_ITR];///< all iterators of KV store, 193 | ///< includes scanner iterators 194 | ///< as well 195 | pthread_mutex_t m_mtx_iter; ///< mutex for iterator list 196 | uint32_t m_pool_mask; ///< bit mask used to get pool 197 | ///< hash from lba 198 | uint32_t m_max_pools; ///< maximum pools supported by 199 | ///< KV store 200 | uint32_t m_pool_bits; ///< number of bits that 201 | ///< represents pools in lba 202 | uint32_t m_all_pool_id; ///< id that represents all pools 203 | 204 | NVM_KV_Buffer_Pool m_buffer_pool; ///< buffer pool 205 | bool m_initialized; ///< flag make sure the iterator 206 | ///< object is initialized only once 207 | }; 208 | #endif //KV_ITERATOR_H 209 | -------------------------------------------------------------------------------- /src/kv_layout.cpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #include 19 | #include "util/kv_bitmap.h" 20 | #include "src/kv_layout.h" 21 | #include "util/kv_util.h" 22 | // 23 | //initializes layout data like key bits, value bits 24 | // 25 | NVM_KV_Layout::NVM_KV_Layout(uint32_t sector_size, uint32_t sparse_addr_bits) 26 | { 27 | uint32_t max_value_in_sector = 0; 28 | m_valueBits = 0; 29 | m_keyBits = 0; 30 | m_sectBits = 0; 31 | 32 | m_sectorSize = sector_size; 33 | while ((sector_size = sector_size >> 1)) 34 | { 35 | m_sectBits++; 36 | } 37 | 38 | m_inUseBMLba = (nvm_kv_round_upto_blk(sizeof(nvm_kv_store_metadata_t), 39 | m_sectorSize) / m_sectorSize); 40 | max_value_in_sector = (M_KV_MAX_VALUE_RANGE / m_sectorSize); 41 | m_poolTagsLba = max_value_in_sector; 42 | m_maxValueSize = (M_KV_MAX_VALUE_RANGE / 2) - m_sectorSize; 43 | while ((max_value_in_sector = max_value_in_sector >> 1)) 44 | { 45 | m_valueBits++; 46 | } 47 | m_keyBits = (sparse_addr_bits - m_valueBits); 48 | m_poolBits = (m_valueBits - 1); 49 | m_kv_len = (1ULL << sparse_addr_bits); 50 | } 51 | // 52 | //destructor 53 | // 54 | NVM_KV_Layout::~NVM_KV_Layout() 55 | { 56 | } 57 | // 58 | //sets the number of records that will be used for metadata, including 59 | //KV store metadata, pool bitmaps, pool tags 60 | // 61 | void NVM_KV_Layout::set_md_rec(uint64_t md_recs) 62 | { 63 | uint64_t md_secs = 0; 64 | 65 | m_mdRecs = md_recs; 66 | md_secs = (md_recs * M_KV_MAX_VALUE_RANGE) / m_sectorSize; 67 | m_kvUserDataStartLba = md_secs; 68 | } 69 | // 70 | //sets pool deleted bitmap lba 71 | // 72 | void NVM_KV_Layout::set_del_bm_lba(uint32_t lba) 73 | { 74 | m_delBMLba = lba; 75 | } 76 | // 77 | // 78 | //gets LBA for KV store metadata 79 | // 80 | uint64_t NVM_KV_Layout::get_metadata_lba() 81 | { 82 | return M_KV_METADATA_LBA; 83 | } 84 | // 85 | //gets LBA for pool in-use bitmap 86 | // 87 | uint64_t NVM_KV_Layout::get_inuse_bm_lba() 88 | { 89 | return m_inUseBMLba; 90 | } 91 | // 92 | //gets LBA for pool tags on media 93 | // 94 | uint64_t NVM_KV_Layout::get_pool_tags_lba() 95 | { 96 | 97 | return m_poolTagsLba; 98 | } 99 | // 100 | //gets LBA for pool deleted bitmap 101 | // 102 | uint64_t NVM_KV_Layout::get_del_bm_lba() 103 | { 104 | return m_delBMLba; 105 | } 106 | // 107 | //gets user data start LBA 108 | // 109 | uint64_t NVM_KV_Layout::get_data_start_lba() 110 | { 111 | return m_kvUserDataStartLba; 112 | } 113 | // 114 | //gets number of bits that represents pool 115 | // 116 | uint32_t NVM_KV_Layout::get_pool_bits() 117 | { 118 | return m_poolBits; 119 | } 120 | // 121 | //gets number of bits that represents value 122 | // 123 | uint32_t NVM_KV_Layout::get_val_bits() 124 | { 125 | return m_valueBits; 126 | } 127 | // 128 | //gets number of bits that represents sector size 129 | // 130 | uint32_t NVM_KV_Layout::get_sect_bits() 131 | { 132 | return m_sectBits; 133 | } 134 | // 135 | //gets number of bits that represents key 136 | // 137 | uint32_t NVM_KV_Layout::get_key_bits() 138 | { 139 | return m_keyBits; 140 | } 141 | // 142 | //gets maximum value range 143 | // 144 | uint64_t NVM_KV_Layout::get_max_val_range() 145 | { 146 | return M_KV_MAX_VALUE_RANGE; 147 | } 148 | // 149 | //gets maximum search range in terms of sectors 150 | // 151 | uint32_t NVM_KV_Layout::get_max_search_range() 152 | { 153 | return (M_KV_MAX_VALUE_RANGE / m_sectorSize); 154 | } 155 | // 156 | //gets magic number used for verification 157 | // 158 | uint64_t NVM_KV_Layout::get_kv_stamp() 159 | { 160 | return M_KV_STAMP; 161 | } 162 | // 163 | //gets size of KV store 164 | // 165 | uint64_t NVM_KV_Layout::get_kv_len() 166 | { 167 | return m_kv_len; 168 | } 169 | -------------------------------------------------------------------------------- /src/kv_layout.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_LAYOUT_H_ 19 | #define KV_LAYOUT_H_ 20 | 21 | #include 22 | #include "src/kv_common.h" 23 | 24 | /// 25 | ///This class holds data regarding Logical layout of the KV store 26 | /// 27 | 28 | // 29 | // +-----------------------+ <- start 30 | // | kv_store_metadata_t | 31 | // +-----------------------+ <- end of 1 sector 32 | // | pool_bitmap_in_use | 33 | // +-----------------------+ 34 | // | pool_bitmap_deleted | 35 | // +-----------------------+ <-4096 sector 36 | // | pool tags | 37 | // +-----------------------+ 38 | // | . | 39 | // | . | 40 | // +-----------------------+ 41 | // | KV store user data | 42 | // | . | 43 | // | . | 44 | // | . | 45 | // +-----------------------+ <- end 46 | // 47 | class NVM_KV_Layout 48 | { 49 | public: 50 | /// 51 | ///initializes layout data like key bits, value bits 52 | /// 53 | NVM_KV_Layout(uint32_t sector_size, uint32_t sparse_addr_bits); 54 | /// 55 | ///destructor 56 | /// 57 | ~NVM_KV_Layout(); 58 | /// 59 | ///sets pool deleted bitmap LBA 60 | /// 61 | ///@param[in] lba deleted bitmap LBA 62 | /// 63 | ///@return none 64 | /// 65 | void set_del_bm_lba(uint32_t lba); 66 | /// 67 | ///gets LBA for KV store metadata 68 | /// 69 | ///@return returns KV store metadata LBA 70 | /// 71 | uint64_t get_metadata_lba(); 72 | /// 73 | ///gets LBA for pool in-use bitmap 74 | /// 75 | ///@return returns pool in-use bitmap LBA 76 | /// 77 | uint64_t get_inuse_bm_lba(); 78 | /// 79 | ///gets LBA for pool deleted bitmap 80 | /// 81 | ///@return returns pool deleted bitmap LBA 82 | /// 83 | uint64_t get_del_bm_lba(); 84 | /// 85 | ///gets LBA for pool tags on media 86 | /// 87 | ///@return returns pool tags LBA 88 | /// 89 | uint64_t get_pool_tags_lba(); 90 | /// 91 | ///gets user data start LBA 92 | /// 93 | ///@return returns user data start LBA 94 | /// 95 | uint64_t get_data_start_lba(); 96 | /// 97 | ///gets number of bits that represents pools 98 | /// 99 | ///@return returns number of bits 100 | /// 101 | uint32_t get_pool_bits(); 102 | /// 103 | ///gets number of bits that represents value 104 | /// 105 | ///@return returns number of bits 106 | /// 107 | uint32_t get_val_bits(); 108 | /// 109 | ///gets number of bits that represents key 110 | /// 111 | ///@return returns number of bits 112 | /// 113 | uint32_t get_key_bits(); 114 | /// 115 | ///gets number of bits that represents sector size 116 | /// 117 | ///@return returns number of bits that represents sector size 118 | /// 119 | uint32_t get_sect_bits(); 120 | /// 121 | ///gets maximum value range 122 | /// 123 | ///@return returns maximum value range 124 | /// 125 | uint64_t get_max_val_range(); 126 | /// 127 | ///gets maximum search range in sectors 128 | /// 129 | ///@return returns search range in sectors 130 | /// 131 | uint32_t get_max_search_range(); 132 | /// 133 | ///gets magic number used for verification 134 | /// 135 | ///@return - 64 bit stamp number 136 | /// 137 | uint64_t get_kv_stamp(); 138 | /// 139 | ///gets KV store size 140 | /// 141 | ///@return returns KV store size 142 | /// 143 | uint64_t get_kv_len(); 144 | /// 145 | ///sets the number of records that will be used for metadata, including 146 | ///KV store metadata, pool bitmaps, pool tags 147 | /// 148 | ///@param[in] md_recs number of records that is used for metadata 149 | /// 150 | ///@return none 151 | /// 152 | void set_md_rec(uint64_t md_recs); 153 | 154 | private: 155 | static const uint64_t M_KV_METADATA_LBA = 0; ///< KV store metadata LBA 156 | static const uint64_t M_KV_MAX_VALUE_RANGE = 2097152;///< maximum value size 157 | static const uint64_t M_KV_STAMP = 858623104131; ///< magic number used for KV store verification 158 | 159 | uint64_t m_inUseBMLba; ///< LBA for pool in-use bitmap 160 | uint64_t m_delBMLba; ///< LBA for pool deleted bitmap 161 | uint64_t m_poolTagsLba; ///< LBA associated with pool tags 162 | uint64_t m_kvUserDataStartLba;///< LBA pointing to start of user data 163 | uint32_t m_sectorSize; ///< sector size 164 | uint32_t m_sectBits; ///< bits representing sector size 165 | uint32_t m_valueBits; ///< LSB of LBA that represents value 166 | uint32_t m_keyBits; ///< MSB of LBA that represents key 167 | uint64_t m_maxValueSize; ///< maximum value size 168 | uint32_t m_poolBits; ///< LSB of LBA that represents pools 169 | uint64_t m_kv_len; ///< total size of KV store 170 | uint64_t m_mdRecs; ///< number of starting records that stores metadata 171 | }; 172 | 173 | #endif //KV_LAYOUT_H_ 174 | -------------------------------------------------------------------------------- /src/kv_pool_del_manager.cpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2014 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #include 19 | #include "src/kv_store_mgr.h" 20 | #include "src/kv_pool_del_manager.h" 21 | #include "src/kv_iterator.h" 22 | 23 | // 24 | //initializes pool deletion manager related data 25 | // 26 | NVM_KV_Pool_Del_Manager::NVM_KV_Pool_Del_Manager(int num_threads, 27 | NVM_KV_Store *kv_store) 28 | :NVM_KV_Scanner(num_threads, kv_store) 29 | { 30 | } 31 | // 32 | //destroys pool deletion manager threads 33 | // 34 | NVM_KV_Pool_Del_Manager::~NVM_KV_Pool_Del_Manager() 35 | { 36 | if (m_pools_to_delete) 37 | { 38 | bitmap_free(m_pools_to_delete); 39 | } 40 | } 41 | // 42 | //initializes the pool deletion manager 43 | // 44 | int NVM_KV_Pool_Del_Manager::initialize() 45 | { 46 | int ret_code = NVM_SUCCESS; 47 | NVM_KV_Store *kv_store = get_store(); 48 | nvm_kv_store_device_t *kv_device = kv_store->get_store_device(); 49 | NVM_KV_Layout *kv_layout = kv_store->get_layout(); 50 | uint32_t max_pools = kv_store->get_store_metadata()->max_pools; 51 | uint32_t sector_size = 52 | kv_store->get_store_device()->capabilities.nvm_sector_size; 53 | uint32_t pool_bits = kv_layout->get_pool_bits(); 54 | kv_batch_iterator_t *batch_iter = NULL; 55 | 56 | if ((ret_code = NVM_KV_Scanner::initialize(KV_POOL_DEL_ITER)) 57 | != NVM_SUCCESS) 58 | { 59 | return ret_code; 60 | } 61 | 62 | batch_iter = 63 | kv_store->get_iter()->get_iter(get_iter_id(), KV_POOL_DEL_ITER); 64 | m_iter = batch_iter->it; 65 | m_iter.max_ranges = 66 | kv_device->capabilities.nvm_max_num_logical_iter_ranges; 67 | m_iter.ranges = (nvm_block_range_t *) (batch_iter + 1); 68 | m_iter.reserved = 0; 69 | m_iter.filters.filter_mask = (1 << pool_bits) - 1; 70 | //disable the expiry 71 | m_iter.filters.filter_expiry = 0; 72 | 73 | m_pools_to_delete = bitmap_alloc_aligned(max_pools, sector_size); 74 | if (!m_pools_to_delete) 75 | { 76 | fprintf(stderr, "Error, pool in progress bitmap allocation failed!\n"); 77 | return -NVM_ERR_OUT_OF_MEMORY; 78 | } 79 | 80 | if (max_pools > (1 << pool_bits)) 81 | { 82 | m_validate_pool_id_on_media = true; 83 | } 84 | else 85 | { 86 | m_validate_pool_id_on_media = false; 87 | } 88 | 89 | m_usr_data_start_lba = kv_layout->get_data_start_lba(); 90 | m_usr_data_max_lba = kv_layout->get_kv_len() - m_usr_data_start_lba; 91 | 92 | return ret_code; 93 | } 94 | // 95 | //the routine for deleting keys in pool 96 | // 97 | void* NVM_KV_Pool_Del_Manager::start_thread() 98 | { 99 | pthread_mutex_t *glb_mtx = get_store()->get_pool_mgr()->get_glb_mutex(); 100 | NVM_KV_Store* kv_store = get_store(); 101 | NVM_KV_Pool_Mgr* pool_mgr = kv_store->get_pool_mgr(); 102 | bool delete_all_pools = false; 103 | int ret_code = NVM_SUCCESS; 104 | 105 | set_cancel_state(); 106 | //register function that needs to be called on thread cancellation 107 | pthread_cleanup_push(&NVM_KV_Scanner::scanner_cancel_routine, get_mutex()); 108 | pthread_cleanup_push(&NVM_KV_Scanner::scanner_cancel_routine, glb_mtx); 109 | while (true) 110 | { 111 | 112 | //cancellation point 113 | pthread_testcancel(); 114 | //check if the pool deletion map is empty, if not 115 | //return from the wait else start waiting for 116 | //external trigger 117 | pthread_mutex_lock(get_mutex()); 118 | while (!pool_mgr->has_pools_to_delete()) 119 | { 120 | wait_for_trigger(); 121 | } 122 | //copy out the pool deletion bitmap to m_pools_to_delete bitmap for 123 | //processing. This operation is protected by pool bitmap mutex. 124 | pool_mgr->get_pool_deletion_bitmap(m_pools_to_delete, delete_all_pools); 125 | pthread_mutex_unlock(get_mutex()); 126 | 127 | //to yield to pool deletion manager, pool deletion status is set right 128 | //away 129 | pool_mgr->set_pool_del_status(true); 130 | 131 | //acquire global lock to synchronize with expiry manager 132 | pthread_mutex_lock(glb_mtx); 133 | if ((ret_code = start_pool_delete(delete_all_pools)) != NVM_SUCCESS) 134 | { 135 | fprintf(stderr, "Pool deletion encounter error: %d\n", ret_code); 136 | } 137 | 138 | pool_mgr->set_pool_del_status(false); 139 | 140 | //trigger expiry thread 141 | if (get_store()->expiry_status()) 142 | { 143 | get_store()->get_expiry_thread()->restart_scanner_if_asleep(); 144 | } 145 | pthread_mutex_unlock(glb_mtx); 146 | } 147 | pthread_cleanup_pop(0); 148 | pthread_cleanup_pop(0); 149 | return NULL; 150 | } 151 | // 152 | //go through m_pools_to_delete bitmap to delete each pool 153 | // 154 | int NVM_KV_Pool_Del_Manager::start_pool_delete(bool delete_all_pools) 155 | { 156 | NVM_KV_Store *kv_store = get_store(); 157 | uint32_t max_pools = kv_store->get_store_metadata()->max_pools; 158 | int ret_code = NVM_SUCCESS; 159 | 160 | if (delete_all_pools) 161 | { 162 | if ((ret_code = delete_pool(-1, m_validate_pool_id_on_media)) 163 | != NVM_SUCCESS) 164 | { 165 | return ret_code; 166 | } 167 | if ((ret_code = 168 | kv_store->get_pool_mgr()->clear_pool_bitmaps(m_pools_to_delete)) 169 | != NVM_SUCCESS) 170 | { 171 | return ret_code; 172 | } 173 | } 174 | else 175 | { 176 | for (uint32_t i = 1; i < max_pools; i++) 177 | { 178 | if (bitmap_test(m_pools_to_delete, i)) 179 | { 180 | if ((ret_code = delete_pool(i, m_validate_pool_id_on_media)) 181 | != NVM_SUCCESS) 182 | { 183 | return ret_code; 184 | } 185 | if ((ret_code = 186 | kv_store->get_pool_mgr()->clear_pool_bitmaps(i)) 187 | != NVM_SUCCESS) 188 | { 189 | return ret_code; 190 | } 191 | } 192 | } 193 | } 194 | 195 | return ret_code; 196 | } 197 | // 198 | //delete all keys from the media for the given pool id 199 | // 200 | int NVM_KV_Pool_Del_Manager::delete_pool(int pool_id, 201 | bool validate_pool_id_on_media) 202 | { 203 | uint64_t max_trim_size_per_iov = 0; 204 | uint64_t trim_len = 0; 205 | uint32_t num_iovs = 0; 206 | nvm_block_range_t *current_range = NULL; 207 | uint32_t num_ranges_found = 0; 208 | uint32_t num_ranges = 0; 209 | uint32_t found_pool_id; 210 | NVM_KV_Store *kv_store = get_store(); 211 | nvm_kv_store_device_t *device = kv_store->get_store_device(); 212 | uint32_t pool_bits = kv_store->get_layout()->get_pool_bits(); 213 | uint32_t pool_mask = (1 << pool_bits) - 1; 214 | uint32_t pool_hash; 215 | uint32_t sector_size = device->capabilities.nvm_sector_size; 216 | int default_pool_id = kv_store->get_pool_mgr()->get_default_poolid(); 217 | nvm_iovec_t *iovec = get_iovec(); 218 | uint64_t iter_filter_mask = 0; 219 | int ret_code = NVM_SUCCESS; 220 | 221 | max_trim_size_per_iov = 222 | device->capabilities.nvm_atomic_write_multiplicity * 223 | device->capabilities.nvm_max_trim_size_per_iov; 224 | 225 | //setup the iterator parameters 226 | m_iter.range_to_iterate.start_lba = m_usr_data_start_lba; 227 | m_iter.range_to_iterate.length = m_usr_data_max_lba; 228 | if (pool_id == -1) 229 | { 230 | //if deleting all user created pools using pool id -1, 231 | //disable filter mask and filter pattern 232 | 233 | //save the old range iterator's filter mask value and 234 | //set the filter mask to 0 for now 235 | iter_filter_mask = m_iter.filters.filter_mask; 236 | m_iter.filters.filter_mask = 0; 237 | //set filter pattern to 0 as well 238 | m_iter.filters.filter_pattern = 0; 239 | } 240 | else 241 | { 242 | m_iter.filters.filter_pattern = 243 | kv_store->get_pool_mgr()->get_poolid_hash(pool_id); 244 | } 245 | 246 | //iterate through the whole user data area 247 | while (true) 248 | { 249 | ret_code = nvm_logical_range_iterator(device->nvm_handle, &m_iter); 250 | if (ret_code == -1) 251 | { 252 | ret_code = -NVM_ERR_INTERNAL_FAILURE; 253 | goto end_kv_delete_all_keys; 254 | } 255 | 256 | num_ranges_found = ret_code; 257 | if (num_ranges_found > 0) 258 | { 259 | num_ranges = 0; 260 | current_range = m_iter.ranges; 261 | while (num_ranges < num_ranges_found) 262 | { 263 | if (validate_pool_id_on_media) 264 | { 265 | ret_code = is_valid_for_del(current_range->start_lba, 266 | &found_pool_id); 267 | if (ret_code < 0) 268 | { 269 | goto end_kv_delete_all_keys; 270 | } 271 | else if ((pool_id != -1 && pool_id != found_pool_id) || 272 | (pool_id == -1 && found_pool_id == default_pool_id)) 273 | { 274 | //if pool id is not -1, skip the key that does not 275 | //belong to this pool 276 | //or if deleting all user created pools using pool id 277 | //-1, skip the key of the default pool 278 | num_ranges++; 279 | current_range++; 280 | continue; 281 | } 282 | } 283 | else 284 | { 285 | //if deleting all user pools, skip the key belong to the 286 | //default pool 287 | if (pool_id == -1) 288 | { 289 | pool_hash = current_range->start_lba & pool_mask; 290 | if (pool_hash == default_pool_id) 291 | { 292 | num_ranges++; 293 | current_range++; 294 | continue; 295 | } 296 | } 297 | } 298 | 299 | //check if trim length is greater than max_trim_size_per_iov 300 | trim_len = current_range->length * sector_size; 301 | if (trim_len > max_trim_size_per_iov) 302 | { 303 | fprintf(stderr, "Error: Corrupted key\n"); 304 | ret_code = -NVM_ERR_INTERNAL_FAILURE; 305 | goto end_kv_delete_all_keys; 306 | } 307 | 308 | iovec[num_iovs].iov_base = 0; 309 | iovec[num_iovs].iov_len = trim_len; 310 | iovec[num_iovs].iov_lba = current_range->start_lba; 311 | iovec[num_iovs].iov_opcode = NVM_IOV_TRIM; 312 | num_iovs++; 313 | num_ranges++; 314 | current_range++; 315 | 316 | //batch delete the keys once the iovec has been filled 317 | if (num_iovs == device->capabilities.nvm_max_num_iovs) 318 | { 319 | if ((ret_code = kv_store->batch_delete(iovec, num_iovs)) 320 | != NVM_SUCCESS) 321 | { 322 | goto end_kv_delete_all_keys; 323 | } 324 | num_iovs = 0; 325 | } 326 | } 327 | } 328 | 329 | if (num_ranges_found < m_iter.max_ranges) 330 | { 331 | if (num_iovs) 332 | { 333 | ret_code = kv_store->batch_delete(iovec, num_iovs); 334 | } 335 | goto end_kv_delete_all_keys; 336 | } 337 | } 338 | 339 | end_kv_delete_all_keys: 340 | 341 | if (pool_id == -1) 342 | { 343 | //reset the range iterator's filter mask back to original 344 | m_iter.filters.filter_mask = iter_filter_mask; 345 | } 346 | 347 | return ret_code; 348 | } 349 | -------------------------------------------------------------------------------- /src/kv_pool_del_manager.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_POOL_DEL_MANAGER_H_ 19 | #define KV_POOL_DEL_MANAGER_H_ 20 | 21 | #include "src/kv_scanner.h" 22 | #include "util/kv_bitmap.h" 23 | 24 | using namespace kv_bitmap; 25 | 26 | /// 27 | ///class that defines an object that will 28 | ///scan all key/values on the KV Store and perform 29 | ///deletion of keys in pools. This class inherits the 30 | ///scanner class 31 | /// 32 | class NVM_KV_Pool_Del_Manager: public NVM_KV_Scanner 33 | { 34 | public: 35 | /// 36 | ///initializes variable for KV store object 37 | /// 38 | ///@param[in] num_threads number of pool delete threads 39 | ///@param[in] kv_store KV store object associated with this scanner 40 | /// 41 | NVM_KV_Pool_Del_Manager(int num_threads, NVM_KV_Store *kv_store); 42 | // 43 | // 44 | // 45 | ~NVM_KV_Pool_Del_Manager(); 46 | /// 47 | ///initializes the pool deletion manager 48 | /// 49 | ///@return returns 0 on success or appropriate error 50 | /// 51 | int initialize(); 52 | /// 53 | ///the routine that starts pool deletion 54 | /// 55 | void* start_thread(); 56 | /// 57 | ///start traversing through the complete range of key 58 | ///delete kv pairs that belong to the pool in pool deletion map 59 | /// 60 | ///@param[in] flag if there's a request to delete all user created pools 61 | /// 62 | ///@return return success on successfully deleting keys from pools 63 | /// that are in delete map in one pass, returns object not 64 | /// found error when end of the key range is reached or 65 | /// other appropriate error is returned 66 | /// 67 | int start_pool_delete(bool delete_all_pools); 68 | 69 | private: 70 | /// 71 | ///delete all keys from the media for the given pool id 72 | /// 73 | ///@param[in] pool_id pool_id whose keys to be deleted 74 | ///@param[in] validate_pool_id_on_media check pool id from the media 75 | ///@return NVM_SUCCESS or appropriate error code 76 | /// 77 | int delete_pool(int pool_id, bool validate_pool_id_on_media); 78 | 79 | kv_bitmap_t *m_pools_to_delete; /// 19 | #include "src/kv_scanner.h" 20 | #include "src/kv_pool_manager.h" 21 | #include "src/kv_iterator.h" 22 | #include "src/kv_wrappers.h" 23 | #include "src/kv_layout.h" 24 | #include "src/kv_store.h" 25 | #include "util/kv_buffer_pool.h" 26 | #include 27 | #include 28 | #include 29 | using namespace nvm_wrapper; 30 | // 31 | //assigns KV store member variable 32 | // 33 | NVM_KV_Scanner::NVM_KV_Scanner(int num_threads, 34 | NVM_KV_Store *kv_store) 35 | { 36 | m_iovec = NULL; 37 | m_kv_store = kv_store; 38 | pthread_mutex_init(&m_cond_mtx, NULL); 39 | pthread_cond_init(&m_cond_var, NULL); 40 | m_num_threads = num_threads; 41 | m_thread = NULL; 42 | m_iter_id = -1; 43 | } 44 | // 45 | //destroys all scanner allocation 46 | // 47 | NVM_KV_Scanner::~NVM_KV_Scanner() 48 | { 49 | pthread_cond_destroy(&m_cond_var); 50 | pthread_mutex_destroy(&m_cond_mtx); 51 | if(m_iter_id >= 0) 52 | { 53 | m_kv_store->get_iter()->free_iterator(m_iter_id, m_iter_type); 54 | } 55 | delete[] m_iovec; 56 | delete[] m_thread; 57 | } 58 | // 59 | //does all necessary allocations and starts scanner 60 | // 61 | int NVM_KV_Scanner::initialize(int iter_type) 62 | { 63 | //allocate iterator and iovs 64 | if (iter_type > 0) 65 | { 66 | int ret_code = 0; 67 | int max_iovs = 68 | m_kv_store->get_store_device()->capabilities.nvm_max_num_iovs; 69 | int pool_id = m_kv_store->get_pool_mgr()->get_all_poolid(); 70 | 71 | ret_code = m_kv_store->get_iter()->alloc_iter(iter_type, pool_id, 0); 72 | if (ret_code < 0) 73 | { 74 | return ret_code; 75 | } 76 | m_iter_id = ret_code; 77 | m_iter_type = iter_type; 78 | 79 | //pool deletion iterator's initialization is different 80 | if (iter_type != KV_POOL_DEL_ITER) 81 | { 82 | reset_iterator(); 83 | } 84 | 85 | //allocate array of vectors for batch discard 86 | m_iovec = new(std::nothrow) nvm_iovec_t[max_iovs]; 87 | if (m_iovec == NULL) 88 | { 89 | return -NVM_ERR_OUT_OF_MEMORY; 90 | } 91 | } 92 | 93 | m_thread = new(std::nothrow) pthread_t[m_num_threads]; 94 | if (m_thread == NULL) 95 | { 96 | return -NVM_ERR_OUT_OF_MEMORY; 97 | } 98 | for (int i = 0; i < m_num_threads; i++) 99 | { 100 | pthread_create(&m_thread[i], NULL, 101 | &NVM_KV_Scanner::start_scanner_wrapper, this); 102 | } 103 | 104 | return NVM_SUCCESS; 105 | } 106 | // 107 | //sets scanner cancel state, type 108 | // 109 | void NVM_KV_Scanner::set_cancel_state() 110 | { 111 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 112 | } 113 | // 114 | //wrapper around start_thread that is passed to pthread_create 115 | // 116 | void* NVM_KV_Scanner::start_scanner_wrapper(void *param) 117 | { 118 | return ((NVM_KV_Scanner *) param)->start_thread(); 119 | } 120 | // 121 | //exits all threads spawned by the class 122 | // 123 | void NVM_KV_Scanner::cleanup_threads() 124 | { 125 | //send wakeup for all threads 126 | pthread_mutex_lock(&m_cond_mtx); 127 | pthread_cond_broadcast(&m_cond_var); 128 | pthread_mutex_unlock(&m_cond_mtx); 129 | 130 | for (int i = 0; i < m_num_threads; i++) 131 | { 132 | pthread_cancel(m_thread[i]); 133 | pthread_join(m_thread[i], NULL); 134 | } 135 | } 136 | // 137 | //cleanup routine that is called when scanner is cancelled 138 | // 139 | void NVM_KV_Scanner::scanner_cancel_routine(void *arg) 140 | { 141 | pthread_mutex_t *mutex = (pthread_mutex_t *) arg; 142 | 143 | pthread_mutex_unlock(mutex); 144 | return; 145 | } 146 | // 147 | //scans the drive and returns next key 148 | // 149 | int NVM_KV_Scanner::perform_scan(uint64_t *key_loc, uint64_t *read_len) 150 | { 151 | int ret_code = 0; 152 | 153 | ret_code = m_kv_store->get_iter()->iterate(m_iter_id, m_iter_type); 154 | if (ret_code == NVM_SUCCESS) 155 | { 156 | ret_code = m_kv_store->get_iter()->get_iter_loc(m_iter_id, key_loc, 157 | read_len, m_iter_type); 158 | } 159 | return ret_code; 160 | } 161 | // 162 | //resets the iterator to the front of the device. 163 | // 164 | int NVM_KV_Scanner::reset_iterator() 165 | { 166 | int retval = 0; 167 | uint64_t usr_data_lba = m_kv_store->get_layout()->get_data_start_lba(); 168 | uint64_t MAX_VALID_SECTOR = m_kv_store->get_layout()->get_kv_len() - 169 | usr_data_lba; 170 | retval = m_kv_store->get_iter()->init_iter(m_iter_id, usr_data_lba, 171 | MAX_VALID_SECTOR, m_iter_type); 172 | return retval; 173 | } 174 | // 175 | //checks if the key is expired and fill in pool id 176 | // 177 | int NVM_KV_Scanner::is_valid_for_del(uint64_t key_loc, uint32_t *pool_id) 178 | { 179 | uint32_t sector_size = m_kv_store->get_sector_size(); 180 | uint32_t ret_buf_size = 0; 181 | char *buf = NULL; 182 | uint32_t curtime = 0; 183 | int ret_code = 0; 184 | uint32_t expiry; 185 | int iov_cnt = 1; 186 | nvm_kv_header_t *hdr = NULL; 187 | nvm_iovec_t iovec; 188 | 189 | if ((ret_code = m_buffer_pool.initialize(M_MAX_BUFFERS_IN_POOL, 190 | sector_size, sector_size)) != NVM_SUCCESS) 191 | { 192 | return ret_code; 193 | } 194 | 195 | buf = m_buffer_pool.get_buf(sector_size, ret_buf_size); 196 | if (buf == NULL) 197 | { 198 | ret_code = -NVM_ERR_OUT_OF_MEMORY; 199 | goto key_del_exit; 200 | } 201 | 202 | //we just need to read the metadata of the key 203 | iovec.iov_base = (uint64_t)buf; 204 | iovec.iov_len = sector_size; 205 | iovec.iov_lba = key_loc; 206 | ret_code = nvm_readv(m_kv_store->get_store_device(), 207 | &iovec, iov_cnt); 208 | if (ret_code < 0) 209 | { 210 | goto key_del_exit; 211 | } 212 | 213 | //we need to restore ret_code in order to return 0 214 | //or 1 for key to be / not to be a candidate for delete 215 | //as read may set ret_code to > 0 for successful reading 216 | //of bytes 217 | ret_code = NVM_SUCCESS; 218 | 219 | hdr = (nvm_kv_header_t *) buf; 220 | if ((hdr->key_len == 0) || 221 | (hdr->key_len > NVM_KV_MAX_KEY_SIZE)) 222 | { 223 | ret_code = NVM_SUCCESS; 224 | goto key_del_exit; 225 | } 226 | 227 | expiry = hdr->metadata.expiry; 228 | 229 | //check if the key is expired 230 | curtime = time(NULL); 231 | if ((expiry != 0) && (curtime > expiry)) 232 | { 233 | ret_code = 1; 234 | } 235 | 236 | //store the pool id for scanner 237 | if (pool_id != NULL) 238 | { 239 | *pool_id = hdr->pool_id; 240 | } 241 | 242 | key_del_exit: 243 | if (buf) 244 | { 245 | m_buffer_pool.release_buf(buf, ret_buf_size); 246 | } 247 | 248 | return ret_code; 249 | } 250 | // 251 | //restarts scanner if it is sleeping 252 | //on the conditional variable. 253 | // 254 | void NVM_KV_Scanner::restart_scanner_if_asleep() 255 | { 256 | pthread_cond_broadcast(&m_cond_var); 257 | return; 258 | } 259 | // 260 | //waits on a trigger 261 | // 262 | void NVM_KV_Scanner::wait_for_trigger() 263 | { 264 | pthread_cond_wait(&m_cond_var, &m_cond_mtx); 265 | return; 266 | } 267 | // 268 | //gets mutex assosiated with scanner 269 | // 270 | pthread_mutex_t* NVM_KV_Scanner::get_mutex() 271 | { 272 | return &m_cond_mtx; 273 | } 274 | // 275 | //gets scanner condition variable 276 | // 277 | pthread_cond_t* NVM_KV_Scanner::get_cond_var() 278 | { 279 | return &m_cond_var; 280 | } 281 | // 282 | //gets scanner buffer pool 283 | // 284 | NVM_KV_Buffer_Pool* NVM_KV_Scanner::get_buf_pool() 285 | { 286 | return &m_buffer_pool; 287 | } 288 | // 289 | //gets scanner iovec member variable 290 | // 291 | nvm_iovec_t* NVM_KV_Scanner::get_iovec() 292 | { 293 | return m_iovec; 294 | } 295 | // 296 | //gets kvstore object 297 | // 298 | NVM_KV_Store* NVM_KV_Scanner::get_store() 299 | { 300 | return m_kv_store; 301 | } 302 | // 303 | //gets iterator type 304 | // 305 | int NVM_KV_Scanner::get_iter_type() 306 | { 307 | return m_iter_type; 308 | } 309 | // 310 | //gets iterator id 311 | // 312 | int NVM_KV_Scanner::get_iter_id() 313 | { 314 | return m_iter_id; 315 | } 316 | // 317 | //locks mutex 318 | // 319 | void NVM_KV_Scanner::lock_mutex() 320 | { 321 | pthread_mutex_lock(&m_cond_mtx); 322 | } 323 | // 324 | //unlocks mutex 325 | // 326 | void NVM_KV_Scanner::unlock_mutex() 327 | { 328 | pthread_mutex_unlock(&m_cond_mtx); 329 | } 330 | -------------------------------------------------------------------------------- /src/kv_scanner.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_SCANNER_H_ 19 | #define KV_SCANNER_H_ 20 | #include "src/kv_layout.h" 21 | #include "src/kv_wrappers.h" 22 | #include "util/kv_buffer_pool.h" 23 | #include 24 | 25 | class NVM_KV_Store; 26 | 27 | /// 28 | ///class that defines a scanner object that will 29 | ///scan all key/values on the KV Store and perform 30 | ///deletion of keys in pools. Initialize the pool 31 | ///deletion manager, expiry manager, and asynchronous 32 | ///expiry, start, create and exit threads of these classes 33 | /// 34 | class NVM_KV_Scanner 35 | { 36 | public: 37 | /// 38 | ///assigns KV store member variable 39 | /// 40 | ///@param[in] num_threads number of scanner threads 41 | /// that needs to be created 42 | ///@param[in] kv_store The KV store class object 43 | /// 44 | NVM_KV_Scanner(int num_threads, NVM_KV_Store *kv_store); 45 | /// 46 | ///destroys pthread mutex and thread condition variables 47 | /// 48 | virtual ~NVM_KV_Scanner(); 49 | /// 50 | ///does all necessary allocations and starts scanner 51 | ///thread by calling start_wrapper function 52 | /// 53 | ///@param[in] iter_type type of the iterator 54 | ///@return 0 on success or appropriate 55 | /// error 56 | /// 57 | int initialize(int iter_type); 58 | /// 59 | ///locks mutex 60 | /// 61 | void lock_mutex(); 62 | /// 63 | ///unlocks mutex 64 | /// 65 | void unlock_mutex(); 66 | /// 67 | ///signals the scanner to wake up if asleep 68 | /// 69 | virtual void restart_scanner_if_asleep(); 70 | /// 71 | ///virtual function which is overridden to exit threads by derived 72 | ///classes 73 | /// 74 | ///@return none 75 | /// 76 | void cleanup_threads(); 77 | /// 78 | ///gets kvstore object 79 | /// 80 | ///@return returns m_kv_store 81 | /// 82 | NVM_KV_Store* get_store(); 83 | 84 | protected: 85 | //disbale copy constructor and assignment operator 86 | DISALLOW_COPY_AND_ASSIGN(NVM_KV_Scanner); 87 | /// 88 | ///a wrapper around start_thread routine to pass to pthread_create 89 | /// 90 | ///@param[in] arg argument needed for thread handler 91 | /// 92 | ///@return none 93 | /// 94 | static void* start_scanner_wrapper(void *arg); 95 | /// 96 | ///virtual function which is overridden to start thread routines by 97 | ///derived classes 98 | /// 99 | ///@return none 100 | /// 101 | virtual void* start_thread() = 0; 102 | /// 103 | ///sets scanner cancel state, type 104 | /// 105 | void set_cancel_state(); 106 | /// 107 | ///routine that is called when scanner is cancelled 108 | /// 109 | ///@param[in] refrence to mutex 110 | /// 111 | static void scanner_cancel_routine(void *arg); 112 | /// 113 | ///scans drive for next available key 114 | /// 115 | ///@param[out] key_loc location of the key filled by the routine 116 | ///@param[out] read_len the length of the key filled by the routine 117 | ///@return returns 0 on success and fills the information, 118 | /// returns error on failure 119 | /// 120 | int perform_scan(uint64_t *key_loc, uint64_t *read_len); 121 | /// 122 | ///resets the iterator to the front of the drive 123 | /// 124 | ///@return Returns 0 on success and -1 on failure. 125 | /// 126 | int reset_iterator(); 127 | /// 128 | ///scanner waits on a conditional variable for the trigger 129 | /// 130 | virtual void wait_for_trigger(); 131 | 132 | /// 133 | ///gets scanner buffer pool 134 | /// 135 | ///@return returns m_buffer_pool 136 | /// 137 | NVM_KV_Buffer_Pool* get_buf_pool(); 138 | /// 139 | ///gets scanner iovec member variable 140 | /// 141 | ///@return returns m_iovec 142 | /// 143 | nvm_iovec_t* get_iovec(); 144 | /// 145 | ///gets iterator type 146 | /// 147 | ///@return returns m_iter_type 148 | /// 149 | int get_iter_type(); 150 | /// 151 | ///gets iterator id 152 | /// 153 | ///@return the id of the iterator used by the scanner 154 | /// 155 | int get_iter_id(); 156 | /// 157 | ///gets mutex associated with scanner 158 | /// 159 | ///@return returns m_cond_mtx 160 | /// 161 | pthread_mutex_t* get_mutex(); 162 | /// 163 | ///gets scanner condition variable 164 | /// 165 | ///@return returns m_cond_var 166 | /// 167 | pthread_cond_t* get_cond_var(); 168 | /// 169 | ///This function checks the key for its expiry as well as 170 | ///fills the pool id the key belongs to. This is used by 171 | ///both scanner and expiry threads 172 | /// 173 | ///@param[in] key_loc location of a particular key to be 174 | /// checked 175 | ///@param[out] pool_id pool id is needed by pool deletion thread 176 | /// to check if the key belongs to particular 177 | /// pool 178 | ///@return returns 0 if the key is not expired 179 | /// Returns 1 if the key is expired 180 | /// Returns -1 if any error 181 | /// 182 | int is_valid_for_del(uint64_t key_loc, uint32_t *pool_id); 183 | 184 | private: 185 | static const uint32_t M_MAX_BUFFERS_IN_POOL = 8; ///< maximum number of buffers in buffer pool 186 | 187 | int m_iter_id; ///< unique iterator id 188 | int m_iter_type; ///< iterator based on scanner type 189 | int m_expiry_mode; ///< expiry mode of the KV store 190 | pthread_cond_t m_cond_var; ///< scanner's conditional variable 191 | pthread_mutex_t m_cond_mtx; ///< mutex associated with scanner 192 | pthread_t *m_thread; ///< scanner thread 193 | NVM_KV_Store *m_kv_store; ///< KV store object 194 | nvm_iovec_t *m_iovec; ///< Array for batch discard 195 | NVM_KV_Buffer_Pool m_buffer_pool;///< buffer pool 196 | int m_num_threads; ///< number of scanner threads 197 | 198 | }; 199 | #endif //KV_SCANNER_H_ 200 | -------------------------------------------------------------------------------- /src/kv_store.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2014 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_STORE_H_ 19 | #define KV_STORE_H_ 20 | #include "src/kv_layout.h" 21 | #include "src/kv_pool_manager.h" 22 | #include "src/kv_cache.h" 23 | #include 24 | #include "util/kv_sync_list.h" 25 | 26 | class NVM_KV_Scanner; 27 | class NVM_KV_Iterator; 28 | 29 | /// 30 | ///Instance of this class represents a KV store on ioMemory 31 | ///This class holds all KV store related data set like layout, device 32 | ///info, poolManager, KV store metadata. 33 | /// 34 | class NVM_KV_Store 35 | { 36 | public: 37 | /// 38 | ///initializes KV store device 39 | /// 40 | NVM_KV_Store(); 41 | /// 42 | ///destroys memory allocated for expiry thread, pool manager, KV store layout 43 | /// 44 | ~NVM_KV_Store(); 45 | /// 46 | ///initializes KV store, creates store layout and poolManager 47 | /// 48 | ///@param[in] kv_id KV store id 49 | ///@param[in] handle nvm handle to invoke primitives 50 | ///@param[in] cap kv store capabilities 51 | ///@param[in] sparse_addr_bits sparse address bits for KV store 52 | ///@param[in] max_pools maximum number of pools that can be 53 | /// created 54 | ///@param[in] version KV store version passed by application 55 | ///@param[in] expiry Expiry support. Expected values: 56 | /// KV_DISABLE_EXPIRY(0) - Disable the expiry 57 | /// KV_ARBITRARY_EXPIRY(1) - Enable arbitraty expiry 58 | /// KV_GLOBAL_EXPIRY(2) - Enable global expiry 59 | ///@param[in] cache_size amount of memory (in bytes) to be 60 | /// allocated for the collision cache 61 | /// 62 | ///@return returns 0 on success or appropriate error 63 | /// 64 | int initialize(int kv_id, nvm_handle_t handle, nvm_kv_store_capabilities_t cap, 65 | uint32_t sparse_addr_bits, uint32_t max_pools, 66 | uint32_t version, uint32_t expiry, uint64_t cache_size); 67 | /// 68 | ///fetches the layout object 69 | /// 70 | ///@return address of layout object 71 | /// 72 | NVM_KV_Layout* get_layout(); 73 | /// 74 | ///returns hash function object 75 | /// 76 | ///@return returns m_pHashFunc 77 | /// 78 | NVM_KV_Hash_Func* get_hash_func(); 79 | /// 80 | ///fetches pool manager object 81 | /// 82 | ///@return address of pool manager object 83 | /// 84 | NVM_KV_Pool_Mgr* get_pool_mgr(); 85 | /// 86 | ///fetches collision cache object 87 | /// 88 | ///@return address of collision cache object 89 | /// 90 | NVM_KV_Cache* get_cache(); 91 | /// 92 | ///fetches the KV store device object 93 | /// 94 | ///@return address of KV store device object 95 | /// 96 | nvm_kv_store_device_t* get_store_device(); 97 | /// 98 | ///fetches KV store metadata 99 | /// 100 | ///@return address of KV store metadata 101 | /// 102 | nvm_kv_store_metadata_t* get_store_metadata(); 103 | /// 104 | ///get sector size of the KV store 105 | /// 106 | ///@return returns sector size 107 | /// 108 | uint32_t get_sector_size(); 109 | /// 110 | ///fetches maximum kv pairs that can fit in one 111 | ///batch operation 112 | /// 113 | ///@return maximum number of kv pairs that can 114 | /// fit in one batch request 115 | /// 116 | uint32_t get_max_batch_size(); 117 | /// 118 | ///checks if expiry threads are running 119 | /// 120 | ///@return true if expiry scanners are running 121 | /// 122 | bool expiry_status(); 123 | /// 124 | ///obtain the capability information from the device; validate 125 | // the capabilities are sufficient to support KV store; initialize the 126 | ///the internal capability structure 127 | /// 128 | ///@param[in] handle nvm handle. 129 | ///@param[in,out] cap pointer to the capability object. 130 | /// The object fields will be 131 | /// populated when function returns 132 | /// successfully. 133 | ///@return NVM_SUCCESS, 134 | /// -NVM_ERR_FEATURE_NOT_SUPPORTED, 135 | /// -NVM_ERR_INTERNAL_FAILURE 136 | /// 137 | static int initialize_capabilities(nvm_handle_t handle, 138 | nvm_kv_store_capabilities_t *cap); 139 | /// 140 | ///gets the mode of expiry for the KV store 141 | /// 142 | ///@return Returns the mode of expiry which can be: 143 | /// KV_DISABLE_EXPIRY(0) - Disable the expiry 144 | /// KV_ARBITRARY_EXPIRY(1) - Arbitrary expiry 145 | /// KV_GLOBAL_EXPIRY(2) - Global expiry 146 | /// 147 | uint32_t get_expiry(); 148 | /// 149 | ///fetches the number of sectors to be deleted based upon sector_size. 150 | /// 151 | ///@return number of sectors to be deleted 152 | /// 153 | uint64_t get_del_sec_count(); 154 | /// 155 | ///fetches iterator object which stores all iterators of KV store 156 | /// 157 | ///@return returns iterator object 158 | /// 159 | NVM_KV_Iterator* get_iter(); 160 | /// 161 | ///persists the KV store metadata 162 | /// 163 | ///@return returns -1 on error and 0 on success 164 | /// 165 | int persist_kv_metadata(); 166 | /// 167 | ///create and initialize expiry related scanners and pool deletion 168 | ///scanner 169 | /// 170 | ///@return returns 0 if successful, else -1 171 | /// 172 | int init_scanners(); 173 | /// 174 | ///getter function of asynchronous expiry instance 175 | /// 176 | ///@return returns m_pAsyncExpiry 177 | /// 178 | NVM_KV_Scanner* get_async_expiry_thread(); 179 | /// 180 | ///getter function of expiry instance 181 | /// 182 | ///@return returns m_pExpiryThread 183 | /// 184 | NVM_KV_Scanner* get_expiry_thread(); 185 | /// 186 | ///insert lba to the safe lba list 187 | /// 188 | ///@param[in] lba lba to be inserted 189 | ///@param[out] wait is set to true if thread waited while inserting 190 | ///@return returns true if entry got inserted successfully 191 | /// else returns false 192 | /// 193 | bool insert_lba_to_safe_list(uint64_t lba, bool *wait); 194 | /// 195 | ///deletes lba from the safe lba list 196 | /// 197 | ///@param[in] entry entry to be deleted 198 | ///@return returns true if entry got deleted successfully 199 | /// else returns false 200 | /// 201 | bool delete_lba_from_safe_list(uint64_t lba); 202 | /// 203 | ///delete all user data from the media and the cache 204 | /// 205 | ///@return NVM_SUCCESS or appropriate error code 206 | /// 207 | int delete_all(); 208 | /// 209 | ///delete the data blocks within the given range in a brute-force way 210 | ///from the media 211 | /// 212 | ///@param[in] start_lba lba that needs to be trimmed 213 | ///@param[in] delete_len value length that needs to be trimmed 214 | ///@return NVM_SUCCESS or appropriate error code 215 | /// 216 | int delete_range(uint64_t start_lba, uint64_t delete_len); 217 | /// 218 | ///delete all keys within the given range using logical range iterator 219 | ///from the media 220 | /// 221 | ///@param[in] start_lba starting lba of the range 222 | ///@param[in] delete_len length of the range 223 | ///@return NVM_SUCCESS or appropriate error code 224 | /// 225 | int delete_all_keys(uint64_t start_lba, uint64_t delete_len); 226 | /// 227 | ///batch delete protected by safe lba list. The default operation deletes 228 | ///the keys from both the media and the cache. 229 | /// 230 | ///@param[in] iovec array of keys to be deleted 231 | ///@param[in] iov_count number of keys which need to be deleted 232 | ///@param[in] delete_from_cache delete the keys from cache if the flag 233 | /// if the flag is true 234 | /// 235 | ///@return returns 0 if successful, else returns -1 236 | /// 237 | int batch_delete_sync(nvm_iovec_t *iovec, uint32_t iov_count, 238 | bool delete_from_cache = true); 239 | /// 240 | ///batch delete without safe lba list protection. The function deletes 241 | ///the keys from the media only. 242 | /// 243 | ///@param[in] iovec array of keys to be deleted 244 | ///@param[in] iov_count number of keys which need to be deleted 245 | /// 246 | ///@return returns 0 if successful, else returns -1 247 | /// 248 | int batch_delete(nvm_iovec_t *iovec, uint32_t iov_count); 249 | 250 | private: 251 | static const uint32_t M_KV_REVISION = 1; ///< internal revision of KV store 252 | static const uint32_t M_CAP_COUNT = 10; ///< number of NVM capabilities 253 | static const uint32_t M_MAX_BUFFERS_IN_POOL = 1; ///< max number of 254 | ///< buffers in buffer 255 | ///< pool 256 | 257 | //disable copy constructor and assignment operator 258 | DISALLOW_COPY_AND_ASSIGN(NVM_KV_Store); 259 | 260 | NVM_KV_Pool_Mgr *m_pPoolManager; ///< pool manager object 261 | NVM_KV_Layout *m_pKvLayout; ///< address of KV store layout object 262 | NVM_KV_Hash_Func *m_pHashFunc; ///< hash functions object 263 | NVM_KV_Cache *m_cache; ///< instance of collision cache 264 | nvm_kv_store_device_t *m_pKvDevice; ///< address of KV store device object 265 | nvm_kv_store_metadata_t *m_pStoreMetadata;///< metadata object for KV store 266 | uint32_t m_meta_data_buf_len; ///< length of the buffer holding the meta data 267 | NVM_KV_Scanner *m_pAsyncExpiry; ///< reference of async expiry object 268 | NVM_KV_Scanner *m_pExpiryThread; ///< reference of expiry object 269 | uint64_t m_deleteSectorCount; ///< number of sectors to be deleted per key 270 | NVM_KV_Iterator *m_iter; ///< all iterators in KV store 271 | NVM_KV_Buffer_Pool m_buffer_pool; ///< buffer pool used by kvstore to memory allocation 272 | NVM_KV_Sync_List m_safe_lba_list; ///< instance of safe LBA list 273 | bool m_exp_status; ///< status of expiry scanners 274 | }; 275 | #endif //KV_STORE_H_ 276 | -------------------------------------------------------------------------------- /src/kv_wrappers.cpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "src/kv_wrappers.h" 23 | using namespace nvm_wrapper; 24 | // 25 | //wrapper function which internally calls pwritev or 26 | //nvm_batch_atomic_operations based on the config for writing on 27 | //to ioMemory 28 | // 29 | int64_t nvm_wrapper::nvm_writev(nvm_kv_store_device_t *device, 30 | nvm_iovec_t *iovec, int iov_count, 31 | bool nvm_atomic_op) 32 | { 33 | int64_t ret_code = NVM_SUCCESS; 34 | uint32_t fd = device->fd; 35 | nvm_handle_t handle = device->nvm_handle; 36 | 37 | if (nvm_atomic_op) 38 | { 39 | ret_code = nvm_batch_atomic_operations(handle, iovec, iov_count, 0); 40 | } 41 | else 42 | { 43 | uint64_t offset = 0; 44 | int first_vector = 0; 45 | struct iovec *iovs = NULL; 46 | 47 | if (iov_count > device->capabilities.nvm_max_num_iovs) 48 | { 49 | return -NVM_ERR_INVALID_INPUT; 50 | } 51 | 52 | iovs = new(std::nothrow) 53 | struct iovec[device->capabilities.nvm_max_num_iovs]; 54 | if (iovs == NULL) 55 | { 56 | return -NVM_ERR_OUT_OF_MEMORY; 57 | } 58 | 59 | //first vector will have starting address from where data needs to be 60 | //written 61 | offset = iovec[first_vector].iov_lba * 62 | device->capabilities.nvm_sector_size; 63 | for (int k = 0; k < iov_count; k++) 64 | { 65 | iovs[k].iov_base = (void *) iovec[k].iov_base; 66 | iovs[k].iov_len = iovec[k].iov_len; 67 | } 68 | ret_code = pwritev(fd, iovs, iov_count, offset); 69 | delete[] iovs; 70 | } 71 | 72 | if (ret_code < 0) 73 | { 74 | ret_code = -NVM_ERR_IO; 75 | } 76 | return ret_code; 77 | } 78 | // 79 | //wrapper function which internally calls preadv 80 | // 81 | int64_t nvm_wrapper::nvm_readv(nvm_kv_store_device_t *device, 82 | nvm_iovec_t *iovec, 83 | int iov_count) 84 | { 85 | int64_t ret_code = NVM_SUCCESS; 86 | uint64_t offset = 0; 87 | int first_vector = 0; 88 | struct iovec *iovs = NULL; 89 | 90 | if (iov_count > device->capabilities.nvm_max_num_iovs) 91 | { 92 | return -NVM_ERR_INVALID_INPUT; 93 | } 94 | 95 | iovs = new(std::nothrow) 96 | struct iovec[device->capabilities.nvm_max_num_iovs]; 97 | if (iovs == NULL) 98 | { 99 | return -NVM_ERR_OUT_OF_MEMORY; 100 | } 101 | 102 | offset = iovec[first_vector].iov_lba * 103 | device->capabilities.nvm_sector_size; 104 | for (int k = 0; k < iov_count; k++) 105 | { 106 | //check if buffer memory is sector aligned if not 107 | //return error since preadv returns error if 108 | //memory is not sector aligned 109 | if (iovec[k].iov_base & 110 | (device->capabilities.nvm_sector_size -1)) 111 | { 112 | delete[] iovs; 113 | return -NVM_ERR_MEMORY_NOT_ALIGNED; 114 | } 115 | iovs[k].iov_base = (void *) iovec[k].iov_base; 116 | iovs[k].iov_len = iovec[k].iov_len; 117 | } 118 | ret_code = preadv(device->fd, iovs, iov_count, offset); 119 | delete[] iovs; 120 | 121 | if (ret_code < 0) 122 | { 123 | ret_code = -NVM_ERR_IO; 124 | } 125 | return ret_code; 126 | } 127 | -------------------------------------------------------------------------------- /src/kv_wrappers.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_WRAPPERS_H 19 | #define KV_WRAPPERS_H 20 | 21 | #include 22 | #include "src/kv_common.h" 23 | #include "nvm_kv.h" 24 | #include "nvm_error.h" 25 | #include 26 | #include 27 | 28 | namespace nvm_wrapper 29 | { 30 | /// 31 | ///wrapper function which internally calls pwritev or 32 | ///nvm_batch_atomic_operations based on the config for writing on 33 | ///to ioMemory 34 | /// 35 | ///@param[in] device pointer to the device object 36 | ///@param[in] iovec io vectors that holds vectored write data 37 | ///@param[in] iov_count number of io vectors passed in 38 | ///@param[in] nvm_batch_op if set to true nvm_batch_atomic_operations 39 | /// is called 40 | /// for writing else pwritev system call is made 41 | ///@return return 0 on success 42 | /// return error code on failure 43 | /// 44 | int64_t nvm_writev(nvm_kv_store_device_t *device, 45 | nvm_iovec_t *iov, int iov_count, 46 | bool nvm_batch_op); 47 | /// 48 | ///wrapper function which internally calls readv, could be enhanced to have 49 | ///nvm_read once supported 50 | /// 51 | ///@param[in] kv_device pointer to the device object 52 | ///@param[in,out] iovec io vectors that holds data read 53 | ///@param[in] iov_count number of io vectors passed in 54 | ///@return return 0 on success 55 | /// return error code on failure 56 | /// 57 | int64_t nvm_readv(nvm_kv_store_device_t *device, 58 | nvm_iovec_t *iov, int iov_count); 59 | } 60 | #endif //KV_WRAPPERS_H 61 | -------------------------------------------------------------------------------- /src/nvm_kv.cpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #include 19 | #include "src/kv_store_mgr.h" 20 | // 21 | //initializes KV store and writes KV store metadata if 22 | //necessary 23 | // 24 | int nvm_kv_open(int id, uint32_t version, uint32_t max_pools, 25 | uint32_t expiry, uint64_t cache_size) 26 | { 27 | try 28 | { 29 | return NVM_KV_Store_Mgr::instance(true)->kv_open(id, version, 30 | max_pools, 31 | expiry, 32 | cache_size); 33 | } 34 | catch (...) 35 | { 36 | errno = -NVM_ERR_INTERNAL_FAILURE; 37 | return -1; 38 | } 39 | } 40 | // 41 | //creates a new pool for the given KV store 42 | // 43 | int nvm_kv_pool_create(int id, nvm_kv_pool_tag_t *pool_tag) 44 | { 45 | try 46 | { 47 | return NVM_KV_Store_Mgr::instance()->kv_pool_create(id, pool_tag); 48 | } 49 | catch (...) 50 | { 51 | errno = -NVM_ERR_INTERNAL_FAILURE; 52 | return -1; 53 | } 54 | } 55 | // 56 | //returns information about a given pool in store 57 | // 58 | int nvm_kv_get_pool_info(int id, int pool_id, nvm_kv_pool_info_t *pool_info) 59 | { 60 | try 61 | { 62 | return NVM_KV_Store_Mgr::instance()->kv_get_pool_info(id, pool_id, 63 | pool_info); 64 | } 65 | catch (...) 66 | { 67 | errno = -NVM_ERR_INTERNAL_FAILURE; 68 | return -1; 69 | } 70 | } 71 | // 72 | //deletes a pool from the given KV store 73 | // 74 | int nvm_kv_pool_delete(int kv_id, int pool_id) 75 | { 76 | try 77 | { 78 | return NVM_KV_Store_Mgr::instance()->kv_pool_delete(kv_id, pool_id); 79 | } 80 | catch (...) 81 | { 82 | errno = -NVM_ERR_INTERNAL_FAILURE; 83 | return -1; 84 | } 85 | } 86 | // 87 | //deletes all the keys in the given KV store 88 | // 89 | int nvm_kv_delete_all(int kv_id) 90 | { 91 | try 92 | { 93 | return NVM_KV_Store_Mgr::instance()->kv_delete_all(kv_id); 94 | } 95 | catch (...) 96 | { 97 | errno = -NVM_ERR_INTERNAL_FAILURE; 98 | return -1; 99 | } 100 | } 101 | // 102 | //clean up in-memory data structures related to the KV store. 103 | //KV store data on the drive remains intact. 104 | // 105 | int nvm_kv_close(int kv_id) 106 | { 107 | try 108 | { 109 | return NVM_KV_Store_Mgr::instance()->kv_close(kv_id); 110 | } 111 | catch (...) 112 | { 113 | errno = -NVM_ERR_INTERNAL_FAILURE; 114 | return -1; 115 | } 116 | } 117 | // 118 | //puts key value pair in KV store 119 | // 120 | int nvm_kv_put(int id, int pool_id, nvm_kv_key_t *key, uint32_t key_len, 121 | void *value, uint32_t value_len, uint32_t expiry, bool replace, 122 | uint32_t gen_count) 123 | { 124 | try 125 | { 126 | return NVM_KV_Store_Mgr::instance()->kv_put(id, pool_id, key, key_len, 127 | value, value_len, expiry, 128 | replace, gen_count); 129 | } 130 | catch (...) 131 | { 132 | errno = -NVM_ERR_INTERNAL_FAILURE; 133 | return -1; 134 | } 135 | } 136 | // 137 | //gets key value pair in KV store 138 | // 139 | int nvm_kv_get (int id, int pool_id, nvm_kv_key_t *key, uint32_t key_len, 140 | void *value, uint32_t value_len, bool read_exact, 141 | nvm_kv_key_info_t *key_info) 142 | { 143 | try 144 | { 145 | return NVM_KV_Store_Mgr::instance()->kv_get(id, pool_id, key, key_len, 146 | value, value_len, 147 | read_exact, key_info); 148 | } 149 | catch (...) 150 | { 151 | errno = -NVM_ERR_INTERNAL_FAILURE; 152 | return -1; 153 | } 154 | 155 | } 156 | // 157 | //deletes key value pair in KV store 158 | // 159 | int nvm_kv_delete(int id, int pool_id, nvm_kv_key_t *key, uint32_t key_len) 160 | { 161 | try 162 | { 163 | return NVM_KV_Store_Mgr::instance()->kv_delete(id, pool_id, key, 164 | key_len); 165 | } 166 | catch (...) 167 | { 168 | errno = -NVM_ERR_INTERNAL_FAILURE; 169 | return -1; 170 | } 171 | } 172 | // 173 | //checks if key value pair exists in KV store 174 | // 175 | int nvm_kv_exists(int id, int pool_id, nvm_kv_key_t *key, uint32_t key_len, 176 | nvm_kv_key_info_t *key_info) 177 | { 178 | try 179 | { 180 | return NVM_KV_Store_Mgr::instance()->kv_exists(id, pool_id, key, 181 | key_len, key_info); 182 | } 183 | catch (...) 184 | { 185 | errno = -NVM_ERR_INTERNAL_FAILURE; 186 | return -1; 187 | } 188 | } 189 | // 190 | //returns approximate value length for the key 191 | // 192 | int nvm_kv_get_val_len(int id, int pool_id, nvm_kv_key_t *key, 193 | uint32_t key_len) 194 | { 195 | try 196 | { 197 | return NVM_KV_Store_Mgr::instance()->kv_get_val_len(id, pool_id, key, 198 | key_len); 199 | } 200 | catch (...) 201 | { 202 | errno = -NVM_ERR_INTERNAL_FAILURE; 203 | return -1; 204 | } 205 | } 206 | // 207 | //gets all KV pair in one batch operation 208 | // 209 | int nvm_kv_batch_get(int id, int pool_id, nvm_kv_iovec_t *kv_iov, 210 | uint32_t iov_count) 211 | { 212 | try 213 | { 214 | return NVM_KV_Store_Mgr::instance()->kv_batch_get(id, pool_id, kv_iov, 215 | iov_count); 216 | } 217 | catch (...) 218 | { 219 | errno = -NVM_ERR_INTERNAL_FAILURE; 220 | return -1; 221 | } 222 | } 223 | // 224 | //puts all KV pair in one batch operation 225 | // 226 | int nvm_kv_batch_put(int id, int pool_id, nvm_kv_iovec_t *kv_iov, 227 | uint32_t iov_count) 228 | { 229 | try 230 | { 231 | return NVM_KV_Store_Mgr::instance()->kv_batch_put(id, pool_id, kv_iov, 232 | iov_count); 233 | } 234 | catch (...) 235 | { 236 | errno = -NVM_ERR_INTERNAL_FAILURE; 237 | return -1; 238 | } 239 | } 240 | 241 | // 242 | //sets iterator to beginning of a given pool 243 | // 244 | int nvm_kv_begin(int id, int pool_id) 245 | { 246 | try 247 | { 248 | return NVM_KV_Store_Mgr::instance()->kv_begin(id, pool_id); 249 | } 250 | catch (...) 251 | { 252 | errno = -NVM_ERR_INTERNAL_FAILURE; 253 | return -1; 254 | } 255 | } 256 | 257 | // 258 | //sets iterator to the next location in given pool 259 | // 260 | int nvm_kv_next(int id, int it_id) 261 | { 262 | try 263 | { 264 | return NVM_KV_Store_Mgr::instance()->kv_next(id, it_id); 265 | } 266 | catch (...) 267 | { 268 | errno = -NVM_ERR_INTERNAL_FAILURE; 269 | return -1; 270 | } 271 | } 272 | // 273 | //retrieves key-value pair at current iterator location in pool 274 | // 275 | int nvm_kv_get_current(int id, int it_id, nvm_kv_key_t *key, 276 | uint32_t *key_len, void *value, uint32_t value_len, 277 | nvm_kv_key_info_t *key_info) 278 | { 279 | try 280 | { 281 | return NVM_KV_Store_Mgr::instance()->kv_get_current(id, it_id, key, 282 | key_len, value, 283 | value_len, 284 | key_info); 285 | } 286 | catch (...) 287 | { 288 | errno = -NVM_ERR_INTERNAL_FAILURE; 289 | return -1; 290 | } 291 | } 292 | // 293 | //ends iteration and releases the iterator id to free pool 294 | // 295 | int nvm_kv_iteration_end(int id, int it_id) 296 | { 297 | try 298 | { 299 | return NVM_KV_Store_Mgr::instance()->kv_iteration_end(id, it_id); 300 | } 301 | catch (...) 302 | { 303 | errno = -NVM_ERR_INTERNAL_FAILURE; 304 | return -1; 305 | } 306 | } 307 | // 308 | //retrieves metadata information about a KV store 309 | // 310 | int nvm_kv_get_store_info(int kv_id, nvm_kv_store_info_t *store_info) 311 | { 312 | try 313 | { 314 | return NVM_KV_Store_Mgr::instance()->kv_get_store_info(kv_id, 315 | store_info); 316 | } 317 | catch (...) 318 | { 319 | errno = -NVM_ERR_INTERNAL_FAILURE; 320 | return -1; 321 | } 322 | } 323 | // 324 | //retrieves metadata information about a specific key 325 | // 326 | int nvm_kv_get_key_info(int kv_id, int pool_id, nvm_kv_key_t *key, 327 | uint32_t key_len, nvm_kv_key_info_t *key_info) 328 | { 329 | try 330 | { 331 | return NVM_KV_Store_Mgr::instance()->kv_get_key_info(kv_id, pool_id, 332 | key, key_len, 333 | key_info); 334 | } 335 | catch (...) 336 | { 337 | errno = -NVM_ERR_INTERNAL_FAILURE; 338 | return -1; 339 | } 340 | } 341 | // 342 | //sets the global expiry value for KV store 343 | // 344 | int nvm_kv_set_global_expiry(int kv_id, uint32_t expiry) 345 | { 346 | try 347 | { 348 | return NVM_KV_Store_Mgr::instance()->kv_set_global_expiry(kv_id, 349 | expiry); 350 | } 351 | catch (...) 352 | { 353 | errno = -NVM_ERR_INTERNAL_FAILURE; 354 | return -1; 355 | } 356 | } 357 | // 358 | //fetches pool_id and associated tag iteratively for all the pools in a 359 | //KV store 360 | // 361 | int nvm_kv_get_pool_metadata(int kv_id, nvm_kv_pool_metadata_t *pool_md, 362 | uint32_t count, uint32_t start_count) 363 | { 364 | try 365 | { 366 | return NVM_KV_Store_Mgr::instance()->kv_get_pool_metadata(kv_id, 367 | pool_md, 368 | count, 369 | start_count); 370 | } 371 | catch (...) 372 | { 373 | errno = -NVM_ERR_INTERNAL_FAILURE; 374 | return -1; 375 | } 376 | } 377 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | #NVMKV UTILITY 2 | 3 | ## 1. BUILD 4 | 5 | Please issue the following steps in the repository root directory 6 | (repo-root-dir) 7 | 8 | (i) ./autogen.sh 9 | (ii) ./configure 10 | (iii) make 11 | 12 | If the build is successful, the nvm-kv binary should be generated under 13 | /bin/ 14 | 15 | ## 2. INPUT 16 | 17 | The input parameters to the utility can be provided using a XML file. 18 | A sample XML file (nvm-kv.xml) is provided in the current directory. 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | ## 3. EXPLANATION OF TAGS AND ATTRIBUTES 37 | 38 | (i) device tag: specifies properties of the device on which the benchmark is 39 | being performed 40 | name: specifies the name of the device 41 | 42 | (ii) test tag: specifies the type of test being performed 43 | smoke: runs a very basic suite of NVMKV APIs to check if basic 44 | functionality works 45 | perf: runs a performance test based on the parameters specified 46 | under the perf tag 47 | functional: runs a functional test (currently unused) 48 | dumpData: whether the data on media needs to be dumped to a file or not 49 | specified by the dumpData tag in (ix) 50 | 51 | (iii) perf tag: specifies parameters for the performance test 52 | 53 | (iv) io tag: specifies the various IO parameters for the performance test 54 | valueSize: size of the value that needs to be used for the test. The unit for this 55 | is specified by the valueUnits attribute 56 | kvCount: number of Key-Value pairs used for the performance test 57 | valueUnits: units for the value size. Currently this supports only "sector" 58 | batchSize: number of Key-Value pairs to be used in a batch for the batch APIs 59 | cacheSize: size of the collision cache (in bytes) 60 | 61 | (v) threads tag: specifies the properties of the threads used for the performance test 62 | count: number of threads used 63 | 64 | (vi) pools tag: specifies properties of the pools used for the test 65 | maxPools: maximum number of pools used for the test 66 | poolCount: number of pools used for the test 67 | getPoolInfo: whether to get information for the pool or not 68 | 69 | (vii) expiry tag: specifies expiry information for the test 70 | method: specifies expiry method. "0" will disable expiry, 71 | "1" will use arbitrary expiry and "2" will use global expiry 72 | expiryInSecs: specifies the expiry value in seconds 73 | 74 | (viii) jobs tag: specifies the APIs and other miscellaneous parameters 75 | jobString: specifies the APIs that need to be run in order 76 | verify: whether the test needs to verify the value that was returned 77 | after a nvm_kv_get call 78 | replacePuts: whether the test needs to replace the value for an existing 79 | key for a nvm_kv_put 80 | genCount: generation count for the store 81 | readExact: whether the length of the buffer passed in to get the value in 82 | nvm_kv_get specifies the expected length of the value or not 83 | 84 | (ix) dumpData tag: specifies properties for dumping NVMKV data present in media 85 | filename: name of the file in which the data needs to be dumped 86 | -------------------------------------------------------------------------------- /test/nvm-kv.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /util/kv_bitmap.cpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #include 19 | #include 20 | #include 21 | #include "util/kv_bitmap.h" 22 | #include "src/kv_common.h" 23 | #include "util/kv_util.h" 24 | using namespace kv_bitmap; 25 | // 26 | //allocate memory of bit maps 27 | // 28 | kv_bitmap_t* kv_bitmap::bitmap_alloc(uint32_t nbits) 29 | { 30 | kv_bitmap_t *pbm; 31 | 32 | pbm = (kv_bitmap_t *) calloc(bits_per_uint32(round32(nbits)), 33 | sizeof(kv_bitmap_t)); 34 | return pbm; 35 | } 36 | // 37 | //gets sector in which the pool id belongs 38 | // 39 | uint32_t kv_bitmap::bit_index_sector(uint32_t pool_id, uint32_t sector_bits) 40 | { 41 | //considering bytes 42 | sector_bits += 3; 43 | 44 | return (pool_id >> sector_bits); 45 | } 46 | 47 | // 48 | //allocate memory for bit maps which is sector aligned 49 | // 50 | kv_bitmap_t* kv_bitmap::bitmap_alloc_aligned(uint32_t nbits, 51 | uint32_t alignment) 52 | { 53 | kv_bitmap_t *pbm = NULL; 54 | uint32_t size ; 55 | 56 | size = nvm_kv_round_upto_blk(bits_per_uint8(round32(nbits)), alignment); 57 | if (posix_memalign((void **) &pbm, alignment, size) != 0) 58 | { 59 | return pbm; 60 | } 61 | //initially all bits are free 62 | memset(pbm, 0, size); 63 | return pbm; 64 | } 65 | // 66 | //deallocate memory allocated for bit map 67 | // 68 | void kv_bitmap::bitmap_free(kv_bitmap_t *pbm) 69 | { 70 | free(pbm); 71 | } 72 | // 73 | //set bit at given index 74 | // 75 | void kv_bitmap::bitmap_set(kv_bitmap_t *pbm, uint32_t index) 76 | { 77 | pbm[bits_per_uint32(index)] |= bit_mask(index); 78 | } 79 | // 80 | //clear bit at given index 81 | // 82 | void kv_bitmap::bitmap_clear(kv_bitmap_t *pbm, uint32_t index) 83 | { 84 | pbm[bits_per_uint32(index)] &= ~bit_mask(index); 85 | } 86 | // 87 | //test if the bit at given index is set 88 | // 89 | uint32_t kv_bitmap::bitmap_test(kv_bitmap_t *pbm, uint32_t index) 90 | { 91 | return pbm[bits_per_uint32(index)] & bit_mask(index); 92 | } 93 | // 94 | //walk the array of uint32_t checking 32bits at a time. 95 | // 96 | static int bitmap_helper(kv_bitmap_t *pbm, uint32_t nbits, 97 | unsigned char action) 98 | { 99 | uint32_t i = 0; 100 | uint32_t j = 0; 101 | uint32_t mask = 0; 102 | uint32_t is_set = 0; 103 | uint32_t idx = 0; 104 | uint32_t bm_unit_size = 1 << 5; 105 | unsigned char done = 0; 106 | uint32_t bm_array_idx_full = 0xffffffff; 107 | 108 | for (i = 0; i < bits_per_uint32(round32(nbits)); i++) 109 | { 110 | if (pbm[i] != bm_array_idx_full) 111 | { 112 | for (j = 0; j < bm_unit_size; j++) 113 | { 114 | mask = bit_mask(j); 115 | is_set = pbm[i] & mask; 116 | 117 | if (action == BM_FIND_FIRST_CLEAR && !is_set) 118 | { 119 | done = 1; 120 | break; 121 | } 122 | else if (action == BM_FIND_FIRST_SET && is_set) 123 | { 124 | done = 1; 125 | break; 126 | } 127 | else if (action == BM_FIND_FIRST_CLEAR_AND_SET && !is_set) 128 | { 129 | if ((idx = (i << 5) + j) < nbits) 130 | { 131 | pbm[i] |= mask; 132 | return idx; 133 | } 134 | else 135 | { 136 | return BM_FULL; 137 | } 138 | } 139 | } 140 | if (done) 141 | { 142 | break; 143 | } 144 | } 145 | else if (action == BM_FIND_FIRST_SET) 146 | { 147 | done = 1; 148 | break; 149 | } 150 | } 151 | 152 | idx = (i << 5) + j; 153 | return (done && (idx < nbits)) ? idx : BM_FULL; 154 | } 155 | // 156 | //walk through the bitmap to find first cleared bit 157 | // 158 | int kv_bitmap::bitmap_ffc(kv_bitmap_t *pbm, uint32_t nbits) 159 | { 160 | return bitmap_helper(pbm, nbits, BM_FIND_FIRST_CLEAR); 161 | } 162 | // 163 | //walk through the bitmap to find first set bit 164 | // 165 | int kv_bitmap::bitmap_ffs(kv_bitmap_t *pbm, uint32_t nbits) 166 | { 167 | return bitmap_helper(pbm, nbits, BM_FIND_FIRST_SET); 168 | } 169 | // 170 | //walk through the bitmap to find first available bit 171 | // 172 | int kv_bitmap::bitmap_ffa(kv_bitmap_t *pbm, uint32_t nbits) 173 | { 174 | return bitmap_helper(pbm, nbits, BM_FIND_FIRST_CLEAR_AND_SET); 175 | } 176 | -------------------------------------------------------------------------------- /util/kv_bitmap.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_BITMAP_H_ 19 | #define KV_BITMAP_H_ 20 | 21 | #include 22 | 23 | namespace kv_bitmap 24 | { 25 | enum 26 | { 27 | BM_FIND_FIRST_CLEAR = 1, 28 | BM_FIND_FIRST_SET = 2, 29 | BM_FIND_FIRST_CLEAR_AND_SET = 3 30 | }; 31 | 32 | typedef uint32_t kv_bitmap_t; 33 | /// 34 | ///gets sector in which the pool id belongs 35 | /// 36 | ///@param[in] pool_id unique id of the pool 37 | ///@param[in] sector_bits number of bits representing sector of the device 38 | /// 39 | ///@return sector number to which pool belongs 40 | /// 41 | uint32_t bit_index_sector(uint32_t pool_id, uint32_t sector_bits); 42 | /// 43 | ///allocates memory for bit map 44 | /// 45 | ///@param[in] nbits number of bits that needs to be allocated 46 | ///@return return address of bitmap 47 | /// 48 | kv_bitmap_t* bitmap_alloc(uint32_t nbits); 49 | /// 50 | ///allocate memory for bit maps along with alignment 51 | /// 52 | ///@param[in] nbits number of bits that needs to be allocated 53 | ///@param[in] alignment allocated memory needs to be aligned at this offset 54 | ///@return return address of bitmap 55 | /// 56 | kv_bitmap_t* bitmap_alloc_aligned(uint32_t nbits, uint32_t alignment); 57 | /// 58 | ///deallocate memory allocated for bit map 59 | /// 60 | ///@param[in] pbm address of the bit map that needs to be freed 61 | ///@return none 62 | /// 63 | void bitmap_free(kv_bitmap_t * pbm); 64 | /// 65 | ///test if the bit at given index is set 66 | /// 67 | ///@param[in] pbm address of the bit map 68 | ///@param[in] index location of the bit within bit map 69 | ///@return 0 if the bit is unset or 1 if bit is set 70 | /// 71 | uint32_t bitmap_test(kv_bitmap_t *pbm, uint32_t index); 72 | /// 73 | ///bitmap_set - set bit at given index 74 | /// 75 | ///@param[in] pbm address of the bit map 76 | ///@param[in] index location of the bit within bit map 77 | ///@return none 78 | /// 79 | void bitmap_set(kv_bitmap_t *pbm, uint32_t index); 80 | /// 81 | ///clear bit at given index 82 | /// 83 | ///@param[in] pbm address of the bit map 84 | ///@param[in] index location of the bit within bit map 85 | ///@return none 86 | /// 87 | void bitmap_clear(kv_bitmap_t *pbm, uint32_t index); 88 | /// 89 | ///walk through the bitmap to find first cleared bit 90 | /// 91 | ///@param[in] pbm address of bitmap 92 | ///@param[in] nbits number of bits in the bitmap 93 | ///@return index of the first bit cleared on success or 94 | /// -1 if bitmap is full 95 | /// 96 | int bitmap_ffc(kv_bitmap_t *pbm, uint32_t nbits); 97 | /// 98 | ///walk through the bitmap to find first set bit 99 | /// 100 | ///@param[in] pbm address of bitmap 101 | ///@param[in] nbits number of bits in the bitmap 102 | ///@return index of the first bit set on success or -1 if bitmap 103 | /// is full 104 | /// 105 | int bitmap_ffs(kv_bitmap_t *pbm, uint32_t nbits); 106 | /// 107 | ///walk through the bitmap to find first available bit 108 | /// 109 | ///@param[in] pbm address of bitmap 110 | ///@param[in] nbits number of bits in the bitmap 111 | ///@return index of the first bit available on success or -1 if 112 | /// bitmap is full 113 | /// 114 | int bitmap_ffa(kv_bitmap_t *pbm, uint32_t nbits); 115 | /// 116 | ///error value when bitmap is full 117 | /// 118 | const int BM_FULL = -1; 119 | } 120 | #endif //KV_BITMAP_H_ 121 | -------------------------------------------------------------------------------- /util/kv_buffer_pool.cpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #include 19 | #include "util/kv_buffer_pool.h" 20 | #include "nvm_error.h" 21 | 22 | //definition of static member variables 23 | const uint32_t NVM_KV_Buffer_Pool::M_BUFFER_LIMIT; 24 | // 25 | //NVM_KV_Buffer_Pool class definitions 26 | // 27 | 28 | // 29 | //creates pthread mutex and thread condition variables 30 | // 31 | NVM_KV_Buffer_Pool::NVM_KV_Buffer_Pool() 32 | { 33 | pthread_mutex_init(&m_mtx, NULL); 34 | pthread_cond_init(&m_condition_var, NULL); 35 | m_initialized = false; 36 | } 37 | // 38 | //destroys pre-allocated buffer 39 | // 40 | NVM_KV_Buffer_Pool::~NVM_KV_Buffer_Pool() 41 | { 42 | delete_all_buffers(); 43 | pthread_cond_destroy(&m_condition_var); 44 | pthread_mutex_destroy(&m_mtx); 45 | } 46 | // 47 | //allocates and initializes buffers 48 | // 49 | int NVM_KV_Buffer_Pool::initialize(uint32_t num_buffers, 50 | uint32_t buffer_limit, 51 | uint32_t buffer_alignment) 52 | { 53 | pthread_mutex_lock(&m_mtx); 54 | if (m_initialized) 55 | { 56 | pthread_mutex_unlock(&m_mtx); 57 | return NVM_SUCCESS; 58 | } 59 | 60 | if (num_buffers > M_MAX_BUFFERS) 61 | { 62 | pthread_mutex_unlock(&m_mtx); 63 | return -NVM_ERR_MAX_LIMIT_REACHED; 64 | } 65 | 66 | //allocate buffers with size buffer_limit 67 | //which are aligned to buffer_alignment 68 | for (int i = 0; i < num_buffers; ++i) 69 | { 70 | char *buffer = NULL; 71 | 72 | //pre-allocate buffer_alignment buffer 73 | if (posix_memalign((void **) &buffer, buffer_alignment, 74 | buffer_limit) != 0) 75 | { 76 | // delete all buffers allocated so far 77 | delete_all_buffers(); 78 | pthread_mutex_unlock(&m_mtx); 79 | return -NVM_ERR_OUT_OF_MEMORY; 80 | } 81 | m_buffers.push_back(buffer); 82 | m_buffer_sizes.push_back(buffer_limit); 83 | } 84 | m_num_buffers = num_buffers; 85 | m_buffer_limit = buffer_limit; 86 | m_buffer_alignment = buffer_alignment; 87 | m_initialized = true; 88 | pthread_mutex_unlock(&m_mtx); 89 | 90 | return NVM_SUCCESS; 91 | } 92 | // 93 | //returns buffer from the pool if there exists a buffer with 94 | //size equal to or greater than the requested size 95 | // 96 | char* NVM_KV_Buffer_Pool::get_buf(uint32_t size, uint32_t &ret_size) 97 | { 98 | char *buffer = NULL; 99 | char *new_buffer = NULL; 100 | int buffer_size = 0; 101 | 102 | pthread_mutex_lock(&m_mtx); 103 | 104 | while (m_buffers.empty()) 105 | { 106 | pthread_cond_wait(&m_condition_var, &m_mtx); 107 | } 108 | buffer = m_buffers.back(); 109 | buffer_size = m_buffer_sizes.back(); 110 | 111 | if (buffer_size < size) 112 | { 113 | // Can't reuse that buffer, it's too small. Try to allocate a buffer 114 | if (posix_memalign((void **) &new_buffer, m_buffer_alignment, size) != 0) 115 | { 116 | ret_size = 0; 117 | pthread_mutex_unlock(&m_mtx); 118 | return NULL; 119 | } 120 | // If allocation succeeds, free the current buffer in pool 121 | if (buffer) 122 | { 123 | free(buffer); 124 | buffer = NULL; 125 | } 126 | 127 | buffer = new_buffer; 128 | buffer_size = size; 129 | } 130 | 131 | m_buffers.pop_back(); 132 | m_buffer_sizes.pop_back(); 133 | 134 | pthread_mutex_unlock(&m_mtx); 135 | 136 | ret_size = buffer_size; 137 | return buffer; 138 | } 139 | // 140 | //buffer released to the pool 141 | // 142 | void NVM_KV_Buffer_Pool::release_buf(char *buff, uint32_t size) 143 | { 144 | bool isEmpty = false; 145 | pthread_mutex_lock(&m_mtx); 146 | 147 | if (m_buffers.empty()) 148 | { 149 | isEmpty = true; 150 | } 151 | m_buffers.push_back(buff); 152 | m_buffer_sizes.push_back(size); 153 | //signal only if buffer is empty 154 | //and is filled with one buffer now 155 | if (isEmpty) 156 | { 157 | pthread_cond_signal(&m_condition_var); 158 | } 159 | pthread_mutex_unlock(&m_mtx); 160 | } 161 | 162 | void NVM_KV_Buffer_Pool::delete_all_buffers() 163 | { 164 | for (std::vector::iterator it = m_buffers.begin(); 165 | it != m_buffers.end(); ++it) 166 | { 167 | if (*it != NULL) 168 | { 169 | free(*it); 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /util/kv_buffer_pool.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_BUFFER_POOL_H_ 19 | #define KV_BUFFER_POOL_H_ 20 | 21 | #include "include/kv_macro.h" 22 | #include 23 | #include 24 | #include 25 | /// 26 | ///class that maintains pool of buffer, buffer pool is used to 27 | ///prevent calling malloc for each KV store API calls like kv_get and kv_put requests 28 | /// 29 | class NVM_KV_Buffer_Pool 30 | { 31 | public: 32 | static const uint32_t M_MAX_BUFFERS = 4096; 33 | static const uint32_t M_BUFFER_LIMIT = 4096; 34 | static const uint32_t M_BUFFER_PAGE_ALIGN = 4096; 35 | 36 | /// 37 | ///creates pthread mutex and thread condition variables 38 | /// 39 | NVM_KV_Buffer_Pool(); 40 | /// 41 | ///destroys all pre-allocated buffer 42 | /// 43 | ~NVM_KV_Buffer_Pool(); 44 | /// 45 | ///pre-allocates and initialize buffers within buffer pool 46 | /// 47 | ///@param[in] num_buffers number of buffers that needs to be 48 | /// allocated in buffer pool 49 | ///@param[in] buffer_limit size of each buffer in buffer pool 50 | ///@param[in] buffer_align buffer is allocated with this alignmnet 51 | /// 52 | ///@return NVM_SUCCESS on successfully initializing 53 | /// buffers or return appropriate error code 54 | /// 55 | int initialize(uint32_t num_buffers, uint32_t buffer_limit, 56 | uint32_t buffer_align); 57 | ///returns buffer from the pool if there exists a 58 | ///buffer with size equal to or greater than the requested size 59 | /// 60 | ///@param[in] size requested size of the buffer 61 | ///@param[out] ret_size o/p, actual size of buffer provided to the 62 | /// requester 63 | ///@return pointer to the buffer 64 | /// 65 | char* get_buf(uint32_t size, uint32_t &ret_size); 66 | /// 67 | ///returns maximum size of the buffer 68 | /// 69 | ///@return maximum size of he buffer 70 | /// 71 | uint32_t get_buf_size_limit() 72 | { 73 | return m_buffer_limit; 74 | } 75 | /// 76 | ///buffer released to the pool 77 | /// 78 | ///@param[in] buff address of the buffer that was released 79 | ///@param[in] size actual size of the buffer that is released 80 | ///@return none 81 | /// 82 | void release_buf(char *buff, uint32_t size); 83 | 84 | private: 85 | //disbale copy constructor and assignment operator 86 | DISALLOW_COPY_AND_ASSIGN(NVM_KV_Buffer_Pool); 87 | /// 88 | ///delete all buffers in the pool 89 | /// 90 | void delete_all_buffers(); 91 | 92 | pthread_mutex_t m_mtx; 93 | pthread_cond_t m_condition_var; 94 | std::vector m_buffers; 95 | std::vector m_buffer_sizes; 96 | uint32_t m_num_buffers; 97 | uint32_t m_buffer_limit; 98 | uint32_t m_buffer_alignment; 99 | bool m_initialized; 100 | }; 101 | #endif //KV_BUFFER_POOL_H_ 102 | -------------------------------------------------------------------------------- /util/kv_hash_func.cpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #include "util/kv_hash_func.h" 19 | #include 20 | #include 21 | //static member variables defination 22 | // 23 | //creates instance of the class and initializes 24 | //member variables with default values 25 | // 26 | NVM_KV_Hash_Func::NVM_KV_Hash_Func() 27 | { 28 | //default values 29 | m_hashFunType = FNV1A; 30 | m_colHandletype = SEQUENTIAL_PROBE; 31 | m_alignmentAddr = 0; 32 | } 33 | // 34 | //destructor 35 | // 36 | NVM_KV_Hash_Func::~NVM_KV_Hash_Func() 37 | { 38 | } 39 | // 40 | //initializes hash function type, collision handling method 41 | // 42 | int NVM_KV_Hash_Func::initialize(hashtype_t hash_type, coltype_t col_type, 43 | uint32_t align_addr_bits, 44 | uint32_t slice_addr) 45 | { 46 | m_hashFunType = hash_type; 47 | m_colHandletype = col_type; 48 | m_alignmentAddr = align_addr_bits; 49 | m_sliceAddr = slice_addr; 50 | 51 | return NVM_SUCCESS; 52 | } 53 | // 54 | //hash for a key is computed based on the hash type set 55 | // 56 | uint64_t NVM_KV_Hash_Func::key_hash(uint8_t *key, uint32_t key_len, 57 | uint32_t pool_id, uint32_t hash_len, 58 | bool align) 59 | { 60 | uint64_t hash = 0; 61 | 62 | if (key == NULL || key_len == 0 || hash_len == 0) 63 | { 64 | return 0; 65 | } 66 | switch(m_hashFunType) 67 | { 68 | case FNV1A: 69 | hash = fnv1a(key, key_len, pool_id); 70 | break; 71 | default: 72 | return 0; 73 | } 74 | //generally hashing algorithms produce 32,64,128..power of 2 hashes 75 | //for hash value that are not power of two, xor fold to appropriate 76 | //bits 77 | if (hash_len) 78 | { 79 | if (hash_len > M_TINY_HASH_LEN) 80 | { 81 | hash = (hash >> hash_len) ^ 82 | (hash & (((uint64_t) 1 << hash_len) - 1)); 83 | } 84 | else 85 | { 86 | hash = ((hash >> hash_len) ^ hash) & 87 | (((uint64_t) 1 << hash_len) - 1); 88 | } 89 | } 90 | //converting to device/file address space 91 | if (align) 92 | { 93 | uint64_t align_left = m_alignmentAddr - hash_len; 94 | hash = (hash << align_left); 95 | } 96 | 97 | return hash; 98 | } 99 | // 100 | //info on fnv1a @ http://isthe.com/chongo/tech/comp/fnv/ 101 | // 102 | uint64_t NVM_KV_Hash_Func::fnv1a(uint8_t *key, uint32_t key_len, 103 | uint32_t pool_id) 104 | { 105 | uint64_t h = M_FNV_BASIS; 106 | uint32_t len = key_len; 107 | 108 | while (len > 0) 109 | { 110 | h ^= (uint8_t) *key; 111 | h *= M_FNV_PRIME; 112 | key++; 113 | len--; 114 | } 115 | //calculate hash including pool_id 116 | if (pool_id) 117 | { 118 | uint8_t *pool_id_addr = (uint8_t *) &pool_id; 119 | uint32_t pool_id_len = sizeof(pool_id); 120 | while (pool_id_len > 0) 121 | { 122 | h ^= (uint8_t) *pool_id_addr; 123 | h *= M_FNV_PRIME; 124 | pool_id_addr++; 125 | pool_id_len--; 126 | } 127 | } 128 | //redistributing hash if the key hashes within slice_addr 129 | if (h < m_sliceAddr) 130 | { 131 | h = h + m_sliceAddr; 132 | } 133 | return h; 134 | } 135 | // 136 | //resolves collision, calculate next hash after collision to 137 | //resolve collision 138 | // 139 | uint64_t NVM_KV_Hash_Func::resolve_coll(uint8_t *key, uint32_t key_len, 140 | uint32_t pool_id, uint64_t prev_hash, 141 | uint32_t ntimes, uint32_t hash_len, 142 | bool align) 143 | { 144 | uint64_t hash = 0; 145 | uint32_t align_left = 0; 146 | 147 | if (key == NULL || key_len == 0 || hash_len == 0) 148 | { 149 | return 0; 150 | } 151 | 152 | if (align) 153 | { 154 | align_left = m_alignmentAddr - hash_len; 155 | } 156 | 157 | switch(m_colHandletype) 158 | { 159 | case SEQUENTIAL_PROBE: 160 | hash = sequential_probe(prev_hash, ntimes, align_left); 161 | break; 162 | case POLYNOMIAL_PROBE: 163 | hash = polynom_probe(prev_hash, ntimes, align_left); 164 | break; 165 | } 166 | return hash; 167 | } 168 | 169 | // 170 | //resolve collision by sequential probing technique 171 | // 172 | uint64_t NVM_KV_Hash_Func::sequential_probe(uint64_t prev_hash, uint32_t ntimes, 173 | uint32_t align_left) 174 | { 175 | uint64_t hash = prev_hash + ((uint64_t) ntimes << align_left); 176 | 177 | hash = hash % ((uint64_t) 1 << (m_alignmentAddr - align_left)); 178 | return hash; 179 | } 180 | // 181 | //resolve collision by quadratic probing technique 182 | // 183 | uint64_t NVM_KV_Hash_Func::polynom_probe(uint64_t prev_hash, uint32_t ntimes, 184 | uint32_t align_left) 185 | { 186 | uint64_t hash = prev_hash + ( ((uint64_t) ntimes * ntimes) << align_left); 187 | 188 | hash = hash % ((uint64_t) 1 << (m_alignmentAddr - align_left)); 189 | return hash; 190 | } 191 | -------------------------------------------------------------------------------- /util/kv_hash_func.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_HASH_FUNC_H_ 19 | #define KV_HASH_FUNC_H_ 20 | 21 | #include 22 | #include "include/nvm_error.h" 23 | #include "include/kv_macro.h" 24 | /// 25 | ///enum for all hash types 26 | /// 27 | typedef enum 28 | { 29 | FNV1A, 30 | } hashtype_t; 31 | /// 32 | ///enum for all collision handling techniques 33 | /// 34 | typedef enum 35 | { 36 | SEQUENTIAL_PROBE, 37 | POLYNOMIAL_PROBE, 38 | } coltype_t; 39 | /// 40 | ///class that maintains definitions of hash 41 | ///functions FNV1a. 42 | /// 43 | class NVM_KV_Hash_Func 44 | { 45 | public: 46 | /// 47 | ///initializes member variables with default values 48 | /// 49 | NVM_KV_Hash_Func(); 50 | /// 51 | ///initializes hash function type and collision handling 52 | /// 53 | ///@param[in] hash_type type of the hash function that will be called 54 | /// by key_hash member function in order to 55 | /// calculate hash 56 | ///@param[in] col_type type of collision resolution technique that 57 | /// will be called by resolve_collision method. 58 | ///@param[in] hash_len xor fold 64 bit hash value to number of bits 59 | /// specified by hash_len 60 | ///@param[in] align_bits if align is true then align hash into 61 | /// m_alignmentAddr 62 | ///@param[in] slice_addr if the key hashed to slice address, 63 | /// redistribute the keys to different address, 64 | /// this is done to carve out first couple of LBAs 65 | /// to store metadata 66 | /// 67 | ///@return 0 on success or appropriate error code 68 | /// 69 | int initialize(hashtype_t hash_type, coltype_t col_type, 70 | uint32_t align_bits, uint32_t slice_addr); 71 | /// 72 | ///hash value for a key is computed using hash function 73 | ///that is set during initialization 74 | /// 75 | ///@param[in] key input key for which hash needs to be computed 76 | ///@param[in] key_len size of the input key 77 | ///@param[in] pool_id if non-zero pool id is used to calculate hash 78 | /// along with key 79 | ///@param[in] hash_len xor fold 64 bit hash value to number of bits 80 | /// specified by hash_len 81 | ///@param[in] align if true align the hash according to 82 | /// m_alignmentAddr 83 | ///@return returns appropriate error or 84 | /// 64 bit hash value for the input key 85 | /// 86 | uint64_t key_hash(uint8_t *key, uint32_t key_len, uint32_t pool_id, 87 | uint32_t hash_len, bool align); 88 | /// 89 | ///resolves collision, calculate next hash after 90 | ///collision to resolve collision 91 | /// 92 | ///@param[in] key input key for which hash needs to be computed 93 | ///@param[in] key_len size of the input key 94 | ///@param[in] pool_id pool_id 95 | ///@param[in] prev_hash previous hash value which formed collision 96 | ///@param[in] ntimes number of times collision resolutions is 97 | /// called on a key 98 | ///@param[in] hash_len xor fold 64 bit hash value to number of bits 99 | /// specified by hash_len 100 | ///@param[in] align if true align the hash according to 101 | /// m_alignmentAddr 102 | ///@return returns zero on error or 103 | /// 64 bit rehash value for the input key 104 | /// 105 | uint64_t resolve_coll(uint8_t *key, uint32_t key_len, uint32_t pool_id, 106 | uint64_t prev_hash, uint32_t ntimes, 107 | uint32_t hash_len, bool align); 108 | /// 109 | ///destroys instance of the class 110 | /// 111 | ~NVM_KV_Hash_Func(); 112 | 113 | protected: 114 | hashtype_t m_hashFunType; ///< type of hash functions 115 | coltype_t m_colHandletype;///< type of collision handling method 116 | uint32_t m_alignmentAddr; ///< align hash obtained 117 | uint32_t m_sliceAddr; ///< if key hashes to LBA within slice address redistribute the keys 118 | /// 119 | ///fnv1a hash function, info @ http://isthe.com/chongo/tech/comp/fnv/ 120 | /// 121 | ///@param[in] key input key for which hash needs to be computed 122 | ///@param[in] key_len size of the input key 123 | ///@param[in] pool_id if non-zero pool id is used to calculate hash 124 | /// along with key 125 | /// 126 | ///@return 64 bit hash value for the input key 127 | /// 128 | uint64_t fnv1a(uint8_t *key, uint32_t key_len, uint32_t pool_id); 129 | /// 130 | ///resolve collision by sequential probing technique 131 | /// 132 | ///@param[in] prev_hash previous hash value that resulted in collision 133 | ///@param[in] ntimes number of times collision occurred for a given 134 | /// key 135 | ///@param[in] align_left if non zero align the hash to align_left bits 136 | /// 137 | ///@return hash value after applying sequential probing 138 | /// concept 139 | /// 140 | uint64_t sequential_probe(uint64_t prev_hash, uint32_t ntimes, 141 | uint32_t align_left); 142 | /// 143 | ///resolve collision by quadratic probing technique 144 | /// 145 | ///@param[in] prev_hash previous hash value that resulted in collision 146 | ///@param[in] ntimes number of times collision occurred for a given 147 | /// key 148 | ///@param[in] align_left if non zero align the hash to align_left bits 149 | /// 150 | ///@return hash value after applying quadratic probing 151 | /// concept 152 | /// 153 | uint64_t polynom_probe(uint64_t prev_hash, uint32_t ntimes, 154 | uint32_t align_left); 155 | 156 | private: 157 | static const unsigned long long M_FNV_BASIS = 14695981039346656037ULL; 158 | ///< fnv1a magic number 159 | static const uint64_t M_FNV_PRIME = 1099511628211;///< magic number used by fnv1a 160 | static const uint32_t M_TINY_HASH_LEN = 32; ///< tiny hash length 161 | //disbale copy constructor and assignment operator 162 | DISALLOW_COPY_AND_ASSIGN(NVM_KV_Hash_Func); 163 | }; 164 | #endif //KV_HASH_FUNC_H_ 165 | -------------------------------------------------------------------------------- /util/kv_sync_list.cpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #include "util/kv_sync_list.h" 19 | 20 | // 21 | //NVM_KV_Sync_List class definitions 22 | // 23 | 24 | // 25 | //creates pthread mutex and thread condition variables 26 | // 27 | NVM_KV_Sync_List::NVM_KV_Sync_List() 28 | { 29 | pthread_mutex_init(&m_mtx, NULL); 30 | pthread_cond_init(&m_condition_var, NULL); 31 | } 32 | // 33 | //destroys pthread mutex and thread condition variables 34 | // 35 | NVM_KV_Sync_List::~NVM_KV_Sync_List() 36 | { 37 | pthread_cond_destroy(&m_condition_var); 38 | pthread_mutex_destroy(&m_mtx); 39 | } 40 | // 41 | //checks if the entry already exists in the list 42 | //if exists waits until entry gets deleted from the list 43 | //once deleted inserts the entry 44 | // 45 | bool NVM_KV_Sync_List::insert_entry(uint64_t entry, bool *wait) 46 | { 47 | bool ret_code = true; 48 | set::iterator itr; 49 | 50 | *wait = false; 51 | pthread_mutex_lock(&m_mtx); 52 | itr = m_list.find(entry); 53 | while (itr != m_list.end()) 54 | { 55 | *wait = true; 56 | pthread_cond_wait(&m_condition_var, &m_mtx); 57 | itr = m_list.find(entry); 58 | } 59 | m_list.insert(entry); 60 | pthread_mutex_unlock(&m_mtx); 61 | 62 | return ret_code; 63 | } 64 | // 65 | //deletes entry from the list and signal that entry is deleted 66 | // 67 | bool NVM_KV_Sync_List::delete_entry(uint64_t entry) 68 | { 69 | set::iterator itr; 70 | bool ret_code = true; 71 | 72 | pthread_mutex_lock(&m_mtx); 73 | itr = m_list.find(entry); 74 | if (itr == m_list.end()) 75 | { 76 | ret_code = false; 77 | } 78 | else 79 | { 80 | m_list.erase(itr); 81 | //signal only if the entry got deleted 82 | pthread_cond_broadcast(&m_condition_var); 83 | } 84 | pthread_mutex_unlock(&m_mtx); 85 | return ret_code; 86 | } 87 | -------------------------------------------------------------------------------- /util/kv_sync_list.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_SYNC_LIST_ 19 | #define KV_SYNC_LIST_ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | using namespace std; 26 | /// 27 | ///This class implements sychronized list which holds type uint64_t values 28 | ///It provides insert and delete functions on the list. 29 | ///Insert and Delete are thread safe. This class uses STL sets and adds 30 | ///thread safety on top of it 31 | /// 32 | class NVM_KV_Sync_List 33 | { 34 | public: 35 | /// 36 | ///creates pthread mutex and thread condition variables 37 | /// 38 | NVM_KV_Sync_List(); 39 | /// 40 | ///destroys pthread mutex and thread condition variables 41 | /// 42 | ~NVM_KV_Sync_List(); 43 | /// 44 | ///checks if the entry already exists in the list, if exists waits 45 | ///until entry gets deleted from the list, once deleted inserts 46 | ///the entry 47 | /// 48 | ///@param[in] entry entry to be inserted 49 | ///@param[out] wait is set to true if thread waited while inserting 50 | ///@return returns true if entry got inserted successfully 51 | /// else returns false 52 | /// 53 | bool insert_entry(uint64_t entry, bool *wait); 54 | /// 55 | ///deletes entry and signals that entry is deleted 56 | /// 57 | ///@param[in] entry entry to be deleted 58 | ///@return returns true if entry got deleted successfully 59 | /// else returns false 60 | /// 61 | bool delete_entry(uint64_t entry); 62 | 63 | private: 64 | //disable copy constructor and assignment operator 65 | DISALLOW_COPY_AND_ASSIGN(NVM_KV_Sync_List); 66 | 67 | pthread_mutex_t m_mtx; ///< pthread mutex for thread safety 68 | pthread_cond_t m_condition_var;///< pthread condition variable 69 | set m_list; ///< set that stores entry 70 | }; 71 | #endif //KV_SYNC_LIST_ 72 | -------------------------------------------------------------------------------- /util/kv_util.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // NVMKV 3 | // |- Copyright 2012-2013 Fusion-io, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or modify it under 6 | // the terms of the GNU General Public License version 2 as published by the Free 7 | // Software Foundation; 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General 11 | // Public License v2 for more details. 12 | // A copy of the GNU General Public License v2 is provided with this package and 13 | // can also be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 14 | // You should have received a copy of the GNU General Public License along with 15 | // this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 | // Place, Suite 330, Boston, MA 02111-1307 USA. 17 | //---------------------------------------------------------------------------- 18 | #ifndef KV_UTIL_H_ 19 | #define KV_UTIL_H_ 20 | 21 | #include 22 | 23 | /// 24 | ///utility function used to round up value to multiple of blk_size, if value 25 | ///is not multiple of blk_size 26 | /// 27 | ///@param[in] value input value that needs to be checked and rounded up 28 | ///@param[in] blk_size block size to which value is rounded up 29 | ///@return rounded up value, multiple of block size 30 | /// 31 | inline uint64_t nvm_kv_round_upto_blk(uint64_t value, uint64_t blk_size) 32 | { 33 | return ((value + (blk_size - 1)) & ~(blk_size - 1)); 34 | } 35 | /// 36 | ///utility function used to mask/clear lower order bits 37 | /// 38 | ///@param[in] value input value that needs to be masked 39 | ///@param[in] lsb number of lower order bits that needs to be masked 40 | ///@return value obtained after masking/clearing lower order bits 41 | /// 42 | inline uint64_t nvm_kv_mask_lsb(uint64_t value, uint32_t lsb) 43 | { 44 | return (value & ~(((uint64_t)1 << lsb) - 1)); 45 | } 46 | /// 47 | ///function facilitates rounding of input to 32 48 | /// 49 | ///@param[in] value input value that needs to be rounded 50 | ///@return input rounded to 32 51 | /// 52 | inline uint32_t round32(uint32_t value) 53 | { 54 | uint32_t round32_mask = (1 << 5) - 1; 55 | return ((value + round32_mask) & ~round32_mask); 56 | } 57 | /// 58 | ///function facilitates division by 8 59 | /// 60 | ///@param[in] value input value that needs to be divided 61 | ///@return input divided by 8 62 | /// 63 | inline uint32_t bits_per_uint8(uint32_t value) 64 | { 65 | return (value >> 3); 66 | } 67 | /// 68 | ///function facilitates division by 32 69 | /// 70 | ///@param[in] value input value that needs to be divided 71 | ///@return input divided by 32 72 | /// 73 | inline uint32_t bits_per_uint32(uint32_t value) 74 | { 75 | return (value >> 5); 76 | } 77 | /// 78 | ///function generates bit_mask to index into bit map 79 | /// 80 | ///@param[in] value position to be referred to in the bit map 81 | ///@return mask generated for indexing into bitmap 82 | /// 83 | inline uint32_t bit_mask(uint32_t value) 84 | { 85 | uint32_t bm_unit_size = 1 << 5; 86 | return (1 << (value % bm_unit_size)); 87 | } 88 | #endif //KV_UTIL_H_ 89 | --------------------------------------------------------------------------------