├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── README.md ├── build └── .placeholder ├── script └── setup.sh └── src └── mica ├── alloc ├── hugetlbfs_shm.cc └── hugetlbfs_shm.h ├── common.h ├── test ├── test_atomics.cc ├── test_tsc_sync.cc ├── test_tx.cc ├── test_tx.json ├── test_tx_conf.h ├── test_tx_conf_org.h ├── test_tx_index.cc └── test_zipf.cc ├── transaction ├── btree_index.h ├── btree_index_impl │ ├── check.h │ ├── fixup.h │ ├── gather.h │ ├── init.h │ ├── insert.h │ ├── lookup.h │ ├── node.h │ ├── prefetch.h │ └── remove.h ├── context.h ├── context_gc.h ├── db.h ├── db_impl.h ├── db_print_stats.h ├── hash_index.h ├── hash_index_impl │ ├── bucket.h │ ├── init.h │ ├── insert.h │ ├── lookup.h │ ├── prefetch.h │ └── remove.h ├── list.h ├── list_impl.h ├── logging.h ├── page_pool.h ├── row.h ├── row_access.h ├── row_version_pool.h ├── stats.h ├── table.h ├── table_impl.h ├── timestamp.cc ├── timestamp.h ├── transaction.h └── transaction_impl │ ├── commit.h │ ├── init.h │ └── operation.h └── util ├── SafeInt ├── SafeInt3.hpp └── SafeInt3_mod.hpp ├── barrier.h ├── cityhash ├── city.cc ├── city.h ├── city_mod.cc ├── citycrc.h └── citycrc_mod.h ├── config.cc ├── config.h ├── hash.h ├── latency.h ├── lcore.cc ├── lcore.h ├── memcpy.h ├── pcg ├── include │ ├── pcg_extras.hpp │ ├── pcg_random.hpp │ └── pcg_uint128.hpp ├── pcg_extras.hpp ├── pcg_random.hpp └── pcg_uint128.hpp ├── philox └── philox_random.h ├── queue.h ├── rand.h ├── rand_pcg.h ├── rand_philox.h ├── rapidjson ├── allocators.h ├── document.h ├── encodedstream.h ├── encodings.h ├── error │ ├── en.h │ └── error.h ├── filereadstream.h ├── filewritestream.h ├── internal │ ├── biginteger.h │ ├── diyfp.h │ ├── dtoa.h │ ├── ieee754.h │ ├── itoa.h │ ├── meta.h │ ├── pow10.h │ ├── stack.h │ ├── strfunc.h │ ├── strtod.h │ └── swap.h ├── memorybuffer.h ├── memorystream.h ├── msinttypes │ ├── inttypes.h │ └── stdint.h ├── pointer.h ├── prettywriter.h ├── rapidjson.h ├── reader.h ├── stringbuffer.h └── writer.h ├── rate_limiter.h ├── roundup.h ├── rte_memcpy ├── rte_memcpy.h └── rte_memcpy_mod.h ├── safe_cast.h ├── siphash └── siphash24.c ├── stopwatch.cc ├── stopwatch.h ├── tsc.h ├── type_traits.h ├── zipf.cc └── zipf.h /.clang-format: -------------------------------------------------------------------------------- 1 | # 2 | # https://google-styleguide.googlecode.com/svn/trunk/cppguide.html 3 | # 4 | # Exceptions: 5 | # * Allow the Interface postfix for a class if the class does not define any methods or member variables. 6 | # * Allow rvalue references to express universal references. 7 | # * Use #pragma once in addition to the include guards. 8 | # * Allow using variable-length arrays if each is guaranteed <= 1 KiB. 9 | # * Do not reflow comments; do it manually. 10 | # 11 | 12 | BasedOnStyle: Google 13 | 14 | Language: Cpp 15 | DerivePointerAlignment: false 16 | PointerAlignment: Left 17 | PointerBindsToType: true 18 | 19 | # Requires clang-format v4.0+ 20 | ReflowComments: false 21 | SortIncludes: false 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | 3 | .tags* 4 | tags 5 | .ycm_extra_conf.py 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 2 | 3 | PROJECT(MICA) 4 | 5 | 6 | SET(CMAKE_CXX_COMPILER g++-5) 7 | SET(CMAKE_C_LINK_EXECUTABLE g++-5) 8 | 9 | 10 | 11 | OPTION(DEBUG "Enable debugging" OFF) 12 | OPTION(LTO "Use link time optimization" OFF) 13 | 14 | # OPTION(AVX2 "Enable AVX2" ON) 15 | 16 | 17 | 18 | INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src) 19 | SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build) 20 | SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build) 21 | SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build) 22 | 23 | 24 | 25 | ADD_DEFINITIONS(-std=c++14) 26 | 27 | ADD_DEFINITIONS(-Wall -Wextra) 28 | ADD_DEFINITIONS(-Wzero-as-null-pointer-constant) 29 | ADD_DEFINITIONS(-Wsign-conversion) 30 | ADD_DEFINITIONS(-Wconversion) 31 | ADD_DEFINITIONS(-Winline) 32 | 33 | ADD_DEFINITIONS(-Wno-unused-function) 34 | 35 | ADD_DEFINITIONS(-march=native) 36 | ADD_DEFINITIONS(-pthread) 37 | 38 | ADD_DEFINITIONS(-g) 39 | 40 | 41 | 42 | IF(DEBUG) 43 | 44 | MESSAGE(WARNING "Debugging is ENABLED (to disable, run `cmake .. -DDEBUG=OFF`). Performance will be low.") 45 | ADD_DEFINITIONS(-Og) 46 | # ADD_DEFINITIONS(-O0) 47 | 48 | ELSE(DEBUG) 49 | 50 | MESSAGE(STATUS "Debugging is disabled (to enable, run `cmake .. -DDEBUG=ON`)") 51 | ADD_DEFINITIONS(-DNDEBUG) 52 | ADD_DEFINITIONS(-O3) 53 | # ADD_DEFINITIONS(--param inline-unit-growth=200 --param large-function-growth=500) 54 | 55 | ENDIF(DEBUG) 56 | 57 | 58 | IF(LTO) 59 | 60 | MESSAGE(STATUS "Link time optimization is enabled (to disable, run `cmake .. -DLTO=OFF`)") 61 | ADD_DEFINITIONS(-flto) 62 | SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto") 63 | 64 | ELSE(LTO) 65 | 66 | MESSAGE(WARNING "Link time optimization is DISABLED (to enable, run `cmake .. -DLTO=ON`). Performance will be low.") 67 | 68 | ENDIF(LTO) 69 | 70 | 71 | # IF(AVX2) 72 | 73 | # MESSAGE(STATUS "AVX2 is enabled (to disable, run `cmake .. -DAVX2=OFF`)") 74 | # ADD_DEFINITIONS(-mavx2) 75 | # SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -mavx2") 76 | 77 | # ELSE(LTO) 78 | 79 | # MESSAGE(WARNING "AVX2 is DISABLED (to enable, run `cmake .. -DAVX2=ON`). Performance will be low.") 80 | 81 | # ENDIF(AVX2) 82 | 83 | 84 | 85 | SET(SOURCES ${SOURCES} src/mica/alloc/hugetlbfs_shm.cc) 86 | SET(SOURCES ${SOURCES} src/mica/transaction/timestamp.cc) 87 | SET(SOURCES ${SOURCES} src/mica/util/config.cc) 88 | SET(SOURCES ${SOURCES} src/mica/util/cityhash/city_mod.cc) 89 | SET(SOURCES ${SOURCES} src/mica/util/siphash/siphash24.c) 90 | SET_SOURCE_FILES_PROPERTIES(src/mica/util/siphash/siphash24.c PROPERTIES LANGUAGE CXX) 91 | SET(SOURCES ${SOURCES} src/mica/util/lcore.cc) 92 | SET(SOURCES ${SOURCES} src/mica/util/stopwatch.cc) 93 | SET(SOURCES ${SOURCES} src/mica/util/zipf.cc) 94 | 95 | SET(LIBRARIES ${LIBRARIES} rt numa pthread) 96 | 97 | 98 | 99 | IF(LTO) 100 | 101 | ADD_EXECUTABLE(test_atomics src/mica/test/test_atomics.cc ${SOURCES}) 102 | TARGET_LINK_LIBRARIES(test_atomics ${LIBRARIES}) 103 | 104 | ADD_EXECUTABLE(test_tsc_sync src/mica/test/test_tsc_sync.cc ${SOURCES}) 105 | TARGET_LINK_LIBRARIES(test_tsc_sync ${LIBRARIES}) 106 | 107 | ADD_EXECUTABLE(test_tx src/mica/test/test_tx.cc ${SOURCES}) 108 | TARGET_LINK_LIBRARIES(test_tx ${LIBRARIES}) 109 | 110 | ADD_EXECUTABLE(test_tx_index src/mica/test/test_tx_index.cc ${SOURCES}) 111 | TARGET_LINK_LIBRARIES(test_tx_index ${LIBRARIES}) 112 | 113 | ELSE(LTO) 114 | 115 | ADD_LIBRARY(common ${SOURCES}) 116 | 117 | ADD_EXECUTABLE(test_atomics src/mica/test/test_atomics.cc ${SOURCES}) 118 | TARGET_LINK_LIBRARIES(test_atomics ${LIBRARIES}) 119 | 120 | ADD_EXECUTABLE(test_tsc_sync src/mica/test/test_tsc_sync.cc ${SOURCES}) 121 | TARGET_LINK_LIBRARIES(test_tsc_sync ${LIBRARIES}) 122 | 123 | ADD_EXECUTABLE(test_tx src/mica/test/test_tx.cc ${SOURCES}) 124 | TARGET_LINK_LIBRARIES(test_tx ${LIBRARIES}) 125 | 126 | ADD_EXECUTABLE(test_tx_index src/mica/test/test_tx_index.cc ${SOURCES}) 127 | TARGET_LINK_LIBRARIES(test_tx_index ${LIBRARIES}) 128 | 129 | ENDIF(LTO) 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Cicada 2 | ====== 3 | 4 | Dependably fast multi-core in-memory transactions 5 | 6 | Requirements 7 | ------------ 8 | 9 | * Linux x86\_64 >= 3.0 10 | * Intel CPU >= Haswell 11 | * Hugepage (2 GiB) support 12 | 13 | Dependencies for compilation 14 | ---------------------------- 15 | 16 | * g++ >= 5.3 17 | * cmake >= 2.8 18 | * make >= 3.81 19 | * libnuma-dev >= 2.0 20 | 21 | Dependencies for execution 22 | -------------------------- 23 | 24 | * bash >= 4.0 25 | * python >= 3.4 26 | 27 | Compiling Cicada 28 | ---------------- 29 | 30 | * cd cicada-core/build 31 | * cmake .. 32 | * make -j 33 | 34 | Setting up the general environment 35 | ---------------------------------- 36 | 37 | * cd cicada-core/build 38 | * ln -s src/mica/test/*.json . 39 | * ../script/setup.sh 16384 16384 # 2 NUMA nodes, 32 Ki pages (64 GiB) 40 | 41 | Running microbench 42 | ------------------ 43 | 44 | * cd cicada-core/build 45 | * sudo ./test_tx 10000000 16 0.95 0.99 200000 28 46 | 47 | Note 48 | ---- 49 | * The main namespace is mica for historical reasons. This may change in the future. 50 | * Some code (e.g., memory pool allocation) needs to be modified for many-core (> 64 cores) non-dual-socket systems. 51 | * NUMA-aware parts are tested on a dual-socket system that assigns even-numbered lcore IDs to CPU 0 cores and odd-numbered lcore IDs to CPU 1 cores. 52 | * The system expects a full memory bandwidth configuration (e.g., all 4 channels are active). 53 | * Busy-waiting in contention regulation can be inefficient if hyperthreading is enabled. 54 | * StaticConfig::kPairwiseSleeping can be enabled to reduce wasted cycles on hyperthreading (experimental). 55 | * Backoff is currently using only RDTSC for spinning, which can add an excessive delay upon VM live migration. 56 | 57 | Authors 58 | ------- 59 | 60 | Hyeontaek Lim (hl@cs.cmu.edu) 61 | 62 | License 63 | ------- 64 | 65 | Copyright 2014, 2015, 2016, 2017 Carnegie Mellon University 66 | 67 | Licensed under the Apache License, Version 2.0 (the "License"); 68 | you may not use this file except in compliance with the License. 69 | You may obtain a copy of the License at 70 | 71 | http://www.apache.org/licenses/LICENSE-2.0 72 | 73 | Unless required by applicable law or agreed to in writing, software 74 | distributed under the License is distributed on an "AS IS" BASIS, 75 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 76 | See the License for the specific language governing permissions and 77 | limitations under the License. 78 | 79 | -------------------------------------------------------------------------------- /build/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/efficient/cicada-engine/af469679d67a59a89536de634216d349af577d3a/build/.placeholder -------------------------------------------------------------------------------- /script/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Modified from Intel DPDK's tools/setup.sh 4 | 5 | # BSD LICENSE 6 | # 7 | # Copyright(c) 2010-2013 Intel Corporation. All rights reserved. 8 | # All rights reserved. 9 | # 10 | # Redistribution and use in source and binary forms, with or without 11 | # modification, are permitted provided that the following conditions 12 | # are met: 13 | # 14 | # * Redistributions of source code must retain the above copyright 15 | # notice, this list of conditions and the following disclaimer. 16 | # * Redistributions in binary form must reproduce the above copyright 17 | # notice, this list of conditions and the following disclaimer in 18 | # the documentation and/or other materials provided with the 19 | # distribution. 20 | # * Neither the name of Intel Corporation nor the names of its 21 | # contributors may be used to endorse or promote products derived 22 | # from this software without specific prior written permission. 23 | # 24 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | mnthuge=/mnt/huge 37 | 38 | disable_oom_kills() 39 | { 40 | echo "Disabling OOM kills" 41 | sudo sysctl -q -w vm.overcommit_memory=1 42 | 43 | # This is OK for [8192, 8192] page configuration. 44 | sudo sysctl -q -w kernel.shmmax=34359738368 45 | sudo sysctl -q -w kernel.shmall=34359738368 46 | } 47 | 48 | drop_shm() 49 | { 50 | echo "Dropping SHM entries" 51 | 52 | for i in $(ipcs -m | awk '{ print $1; }'); do 53 | if [[ $i =~ 0x.* ]]; then 54 | sudo ipcrm -M $i 2>/dev/null 55 | fi 56 | done 57 | } 58 | 59 | drop_cache() 60 | { 61 | echo "Dropping the page cache" 62 | 63 | echo "echo 3 > /proc/sys/vm/drop_caches" > .echo_tmp 64 | sudo sh .echo_tmp 65 | rm -f .echo_tmp 66 | } 67 | 68 | setup_mmap_limits() 69 | { 70 | sudo sysctl -q -w vm.max_map_count=2147483647 71 | } 72 | 73 | remove_mnt_huge() 74 | { 75 | #echo "Unmounting $mnthuge and removing directory" 76 | 77 | #grep -s $mnthuge /proc/mounts > /dev/null 78 | #if [ $? -eq 0 ] ; then 79 | # sudo umount $mnthuge 80 | #fi 81 | 82 | #if [ -d $mnthuge ] ; then 83 | # sudo rm -R $mnthuge 84 | #fi 85 | 86 | echo "Unmounting hugetlbfs" 87 | for target in `mount -t hugetlbfs | awk '{ print $3 }'`; do 88 | sudo umount $target 89 | if [ -d $target ] ; then 90 | sudo rm -R $target 91 | fi 92 | done 93 | } 94 | 95 | clear_huge_pages() 96 | { 97 | echo "Removing currently reserved hugepages" 98 | 99 | echo > .echo_tmp 100 | for d in /sys/devices/system/node/node? ; do 101 | echo "echo 0 > $d/hugepages/hugepages-2048kB/nr_hugepages" >> .echo_tmp 102 | done 103 | sudo sh .echo_tmp 104 | rm -f .echo_tmp 105 | 106 | remove_mnt_huge 107 | } 108 | 109 | create_mnt_huge() 110 | { 111 | echo "Creating $mnthuge and mounting as hugetlbfs" 112 | 113 | sudo mkdir -p $mnthuge 114 | 115 | grep -s $mnthuge /proc/mounts > /dev/null 116 | if [ $? -ne 0 ] ; then 117 | sudo mount -t hugetlbfs nodev $mnthuge 118 | fi 119 | } 120 | 121 | set_numa_pages() 122 | { 123 | clear_huge_pages 124 | 125 | echo "Reserving hugepages" 126 | 127 | for d in /sys/devices/system/node/node? ; do 128 | echo > .echo_tmp 129 | node=$(basename $d) 130 | Pages=$1 131 | echo -n "Number of pages for $node: $Pages requested, " 132 | shift 133 | echo "echo $Pages > $d/hugepages/hugepages-2048kB/nr_hugepages" >> .echo_tmp 134 | sudo sh .echo_tmp 135 | echo "$(cat "$d/hugepages/hugepages-2048kB/nr_hugepages") actual" 136 | done 137 | rm -f .echo_tmp 138 | 139 | create_mnt_huge 140 | } 141 | 142 | 143 | setup_mmap_limits 144 | disable_oom_kills 145 | drop_shm 146 | drop_cache 147 | 148 | set_numa_pages $* 149 | 150 | echo Done! 151 | -------------------------------------------------------------------------------- /src/mica/alloc/hugetlbfs_shm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_ALLOC_HUGETLB_SHM_H_ 3 | #define MICA_ALLOC_HUGETLB_SHM_H_ 4 | 5 | #include 6 | #include 7 | #include "mica/common.h" 8 | #include "mica/util/config.h" 9 | #include "mica/util/roundup.h" 10 | 11 | // Configuration file entries for HugeTLBFS_SHM: 12 | // 13 | // * hugetlbfs_path (string): The HugeTLBFS directory. 14 | // Default = "/mnt/huge" 15 | // * filename_prefix (string): The prefix of the filenames on HugeTLBFS. 16 | // Default = "mica_shm_" 17 | // * num_pages_to_init (integer): The maximum number of pages to initialize 18 | // across all NUMA domains. This is recommended to be set high because it 19 | // may not possible to find a sufficient number of free pages on each NUMA 20 | // domain if this number is too small. Default = 1048576 (virtually all 21 | // available pages) 22 | // * num_pages_to_free (array of integers): The number of pages to free for 23 | // other applications in each NUMA domain (e.g., Intel DPDK). Default = [0, 24 | // ..., 0] 25 | // * num_pages_to_reserve (array of integers): The number of pages to reserve 26 | // for use by HugeTLBFS_SHM. This actually does nothing in the 27 | // initialization process, but it shows a warning if HugeTLBFS_SHM is not 28 | // given that number of pages after initialization. Default = [0, ..., 0] 29 | // * clean_files_on_init (bool): If true, delete all files whose filename 30 | // starts with filename_prefix. Creating the files again takes some time, so 31 | // enable this only when the old memory state must be discarded. Default = 32 | // false 33 | // * clean_other_files_on_init (bool): Similar to clean_files_on_init, but 34 | // delete all files whose filename does not starts with filename_prefix. 35 | // This is required to make num_pages_to_free work. Default = true 36 | // * verbose (bool): Print verbose messages. Default = false 37 | 38 | namespace mica { 39 | namespace alloc { 40 | class HugeTLBFS_SHM { 41 | public: 42 | HugeTLBFS_SHM(const ::mica::util::Config& config); 43 | ~HugeTLBFS_SHM(); 44 | 45 | static constexpr size_t kInvalidId = std::numeric_limits::max(); 46 | 47 | static size_t roundup(size_t size) { 48 | return ::mica::util::roundup<2 * 1048576>(size); 49 | } 50 | 51 | void* find_free_address(size_t size); 52 | 53 | size_t alloc(size_t length, size_t numa_node); 54 | bool schedule_release(size_t entry_id); 55 | 56 | bool map(size_t entry_id, void* ptr, size_t offset, size_t length); 57 | bool unmap(void* ptr); 58 | 59 | size_t get_memuse() const { return used_memory_; } 60 | void dump_page_info(); 61 | 62 | void* malloc_contiguous(size_t size, size_t numa_node); 63 | void* malloc_contiguous_local(size_t size); 64 | void free_contiguous(void* ptr); 65 | 66 | void* malloc_striped(size_t size); 67 | void free_striped(void* ptr); 68 | 69 | private: 70 | void initialize(); 71 | 72 | void clean_files(); 73 | void clean_other_files(); 74 | void make_path(size_t page_id, char* out_path); 75 | 76 | void lock(); 77 | void unlock(); 78 | 79 | void check_release(size_t entry_id); 80 | 81 | void* malloc_contiguous_any(size_t size); 82 | 83 | static constexpr size_t kPageSize = 2 * 1048576; 84 | 85 | struct Page { 86 | size_t file_id; // ID used for path generation. 87 | void* addr; 88 | void* paddr; 89 | size_t numa_node; 90 | bool in_use; 91 | }; 92 | 93 | struct Entry { 94 | size_t refcount; // reference by mapping 95 | bool to_remove; // remove entry when refcount == 0 96 | size_t length; 97 | size_t num_pages; 98 | std::vector page_ids; 99 | }; 100 | 101 | struct Mapping { 102 | size_t entry_id; 103 | void* addr; 104 | size_t length; 105 | size_t page_offset; 106 | size_t num_pages; 107 | }; 108 | 109 | ::mica::util::Config config_; 110 | 111 | std::string hugetlbfs_path_; 112 | std::string filename_prefix_; 113 | size_t num_numa_nodes_; 114 | size_t num_pages_to_init_; 115 | std::vector num_pages_to_free_; 116 | std::vector num_pages_to_reserve_; 117 | bool clean_files_on_init_; 118 | bool clean_other_files_on_init_; 119 | bool verbose_; 120 | 121 | uint64_t state_lock_; 122 | std::vector pages_; 123 | std::vector entries_; 124 | std::vector mappings_; 125 | size_t used_memory_; 126 | }; 127 | } 128 | } 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /src/mica/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_COMMON_H_ 3 | #define MICA_COMMON_H_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/mica/test/test_tsc_sync.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mica/util/lcore.h" 4 | #include "mica/util/stopwatch.h" 5 | #include "mica/util/barrier.h" 6 | 7 | static ::mica::util::Stopwatch sw; 8 | static volatile uint16_t running_threads; 9 | static volatile uint16_t finished_threads; 10 | static volatile uint8_t stop; 11 | 12 | static const int kQueueDepth = 512; 13 | 14 | volatile uint64_t sync_target; 15 | volatile uint64_t master_tsc; 16 | volatile uint64_t slave_tsc; 17 | volatile int64_t slave_adjust; 18 | 19 | struct Task { 20 | uint16_t lcore_id; 21 | uint16_t master_lcore_id; 22 | uint16_t num_threads; 23 | } __attribute__((aligned(128))); 24 | 25 | int worker_proc(void* arg) { 26 | auto task = reinterpret_cast(arg); 27 | 28 | ::mica::util::lcore.pin_thread(task->lcore_id); 29 | 30 | // printf("worker running on lcore %" PRIu16 "\n", task->lcore_id); 31 | 32 | __sync_add_and_fetch(&running_threads, 1); 33 | while (running_threads < task->num_threads) ::mica::util::pause(); 34 | 35 | uint64_t start_t = sw.now(); 36 | 37 | int64_t diff_sum = 0; 38 | int64_t diff_cnt = 0; 39 | int64_t latency = 9999999; 40 | 41 | if (task->lcore_id == task->master_lcore_id) { 42 | uint64_t next_sync_target; 43 | if (task->master_lcore_id == 0) 44 | next_sync_target = 1; 45 | else 46 | next_sync_target = 0; 47 | 48 | uint64_t duration = sw.c_1_sec() * 6; 49 | while (true) { 50 | uint64_t now = sw.now(); 51 | if (now - start_t > duration) break; 52 | 53 | master_tsc = now; 54 | slave_tsc = 0; 55 | ::mica::util::memory_barrier(); 56 | sync_target = next_sync_target; 57 | 58 | ::mica::util::memory_barrier(); 59 | while (slave_tsc == 0) { 60 | now = sw.now(); 61 | if (now - start_t > duration) break; 62 | ::mica::util::pause(); 63 | } 64 | if (now - start_t > duration) break; 65 | ::mica::util::memory_barrier(); 66 | 67 | uint64_t master_tsc2 = sw.now(); 68 | // printf("%" PRId64 " %" PRId64 "\n", master_tsc, slave_tsc); 69 | slave_adjust = (static_cast(master_tsc) + 70 | static_cast(master_tsc2)) / 71 | 2 - 72 | static_cast(slave_tsc); 73 | // slave_adjust = 1; 74 | // printf("%" PRId64 "\n", slave_adjust); 75 | 76 | if (latency > 77 | static_cast(master_tsc2) - static_cast(master_tsc)) 78 | latency = static_cast(master_tsc2) - 79 | static_cast(master_tsc); 80 | 81 | ::mica::util::memory_barrier(); 82 | while (slave_adjust != 0) ::mica::util::pause(); 83 | ::mica::util::memory_barrier(); 84 | 85 | next_sync_target++; 86 | while (true) { 87 | if (next_sync_target == task->num_threads) 88 | next_sync_target = 0; 89 | else if (next_sync_target == task->master_lcore_id) 90 | next_sync_target++; 91 | else 92 | break; 93 | } 94 | } 95 | 96 | while (finished_threads != task->lcore_id) ::mica::util::pause(); 97 | 98 | printf("one-way latency: %+6.2lf (%+7.1lf ns)\n", 99 | static_cast(latency) / 2., 100 | static_cast(latency) / 2. / 101 | static_cast(sw.c_1_sec()) * 1000. * 1000 * 1000.); 102 | 103 | __sync_add_and_fetch(&finished_threads, 1); 104 | } else { 105 | int64_t tsc_offset = 0; 106 | uint64_t duration = sw.c_1_sec() * 5; 107 | 108 | while (true) { 109 | uint64_t now = sw.now(); 110 | if (now - start_t > duration) break; 111 | 112 | ::mica::util::memory_barrier(); 113 | while (sync_target != task->lcore_id) ::mica::util::pause(); 114 | sync_target = task->master_lcore_id; 115 | ::mica::util::memory_barrier(); 116 | 117 | now = sw.now(); 118 | slave_tsc = now + static_cast(tsc_offset); 119 | 120 | ::mica::util::memory_barrier(); 121 | while (slave_adjust == 0) ::mica::util::pause(); 122 | ::mica::util::memory_barrier(); 123 | 124 | int64_t adjust = slave_adjust; 125 | slave_adjust = 0; 126 | // printf("%" PRId64 "\n", adjust); 127 | 128 | tsc_offset += adjust * 1 / 50; 129 | 130 | diff_sum += adjust; 131 | diff_cnt++; 132 | } 133 | 134 | while (finished_threads != task->lcore_id) ::mica::util::pause(); 135 | 136 | printf("thread %2" PRIu16 ": offset = %+5" PRId64 137 | " (%+7.1lf ns), avg_jitter = %+6.2lf (%+7.1lf ns)\n", 138 | task->lcore_id, tsc_offset, 139 | static_cast(tsc_offset) / static_cast(sw.c_1_sec()) * 140 | 1000. * 1000 * 1000., 141 | static_cast(diff_sum) / static_cast(diff_cnt), 142 | static_cast(diff_sum) / static_cast(diff_cnt) / 143 | static_cast(sw.c_1_sec()) * 1000. * 1000 * 1000.); 144 | 145 | __sync_add_and_fetch(&finished_threads, 1); 146 | } 147 | return 0; 148 | } 149 | 150 | int main(int argc, const char* argv[]) { 151 | if (argc != 3) { 152 | printf("%s MASTER-LCORE-ID THREAD-COUNT\n", argv[0]); 153 | return EXIT_FAILURE; 154 | } 155 | 156 | ::mica::util::lcore.pin_thread(0); 157 | 158 | sw.init_start(); 159 | sw.init_end(); 160 | 161 | uint16_t master_lcore_id = static_cast(atoi(argv[1])); 162 | uint16_t num_threads = static_cast(atoi(argv[2])); 163 | assert(num_threads <= 164 | static_cast(::mica::util::lcore.lcore_count())); 165 | printf("master_lcore_id: %hu\n", master_lcore_id); 166 | printf("num_threads: %hu\n", num_threads); 167 | printf("\n"); 168 | 169 | std::vector tasks(num_threads); 170 | for (uint16_t lcore_id = 0; lcore_id < num_threads; lcore_id++) { 171 | tasks[lcore_id].lcore_id = lcore_id; 172 | tasks[lcore_id].master_lcore_id = master_lcore_id; 173 | tasks[lcore_id].num_threads = num_threads; 174 | } 175 | 176 | running_threads = 0; 177 | finished_threads = 0; 178 | stop = 0; 179 | 180 | sync_target = master_lcore_id; 181 | 182 | ::mica::util::memory_barrier(); 183 | 184 | std::vector threads; 185 | for (size_t thread_id = 1; thread_id < num_threads; thread_id++) 186 | threads.emplace_back(worker_proc, &tasks[thread_id]); 187 | worker_proc(&tasks[0]); 188 | 189 | while (threads.size() > 0) { 190 | threads.back().join(); 191 | threads.pop_back(); 192 | } 193 | 194 | return EXIT_SUCCESS; 195 | } -------------------------------------------------------------------------------- /src/mica/test/test_tx.json: -------------------------------------------------------------------------------- 1 | { 2 | "alloc": { 3 | /*"clean_files_on_init": true, 4 | "verbose": true*/ 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/mica/test/test_tx_conf.h: -------------------------------------------------------------------------------- 1 | 2 | // For compatibility. 3 | 4 | #define WORKLOAD YCSB 5 | #define WARMUP 2000000 6 | #define MAX_TXN_PER_PART 2000000 7 | #define INIT_PARALLELISM 2 8 | #define MAX_TUPLE_SIZE 100 9 | #define SYNTH_TABLE_SIZE 10000000 10 | #define REQ_PER_QUERY 1 11 | #define READ_PERC 0.5 12 | #define WRITE_PERC 0.5 13 | #define SCAN_PERC 0 14 | #define ZIPF_THETA 0.99 15 | #define THREAD_CNT 28 16 | #define PART_CNT 1 17 | #define IDX_HASH 1 18 | #define IDX_MICA 2 19 | 20 | #define CC_ALG MICA 21 | #define ISOLATION_LEVEL SERIALIZABLE 22 | #define VALIDATION_LOCK "no-wait" 23 | #define PRE_ABORT "true" 24 | #define RCU_ALLOC false 25 | #define RCU_ALLOC_SIZE 20401094656UL 26 | 27 | #define MICA_COLUMN_COUNT 1 28 | 29 | #define INDEX_STRUCT IDX_MICA 30 | #define MICA_FULLINDEX false 31 | 32 | #define MICA_USE_SCAN false 33 | #define MICA_USE_FULL_TABLE_SCAN false 34 | #define MICA_MAX_SCAN_LEN 100 35 | 36 | #define MICA_NO_TSC false 37 | #define MICA_NO_PRE_VALIDATION false 38 | #define MICA_NO_INSERT_NEWEST_VERSION_ONLY false 39 | #define MICA_NO_SORT_WRITE_SET_BY_CONTENTION false 40 | #define MICA_NO_STRAGGLER_AVOIDANCE false 41 | #define MICA_NO_WAIT_FOR_PENDING false 42 | #define MICA_NO_INLINING false 43 | #define MICA_NO_BACKOFF false 44 | 45 | #define MICA_USE_FIXED_BACKOFF false 46 | #define MICA_FIXED_BACKOFF 0. 47 | 48 | #define MICA_USE_SLOW_GC false 49 | #define MICA_SLOW_GC 10 50 | 51 | template 52 | class VerificationLogger; 53 | 54 | struct DBConfig : public ::mica::transaction::BasicDBConfig { 55 | // static constexpr bool kVerbose = true; 56 | 57 | #if MICA_NO_PRE_VALIDATION 58 | static constexpr bool kPreValidation = false; 59 | #endif 60 | #if MICA_NO_INSERT_NEWEST_VERSION_ONLY 61 | static constexpr bool kInsertNewestVersionOnly = false; 62 | #endif 63 | #if MICA_NO_SORT_WRITE_SET_BY_CONTENTION 64 | static constexpr bool kSortWriteSetByContention = false; 65 | #endif 66 | #if MICA_NO_STRAGGLER_AVOIDANCE 67 | static constexpr bool kStragglerAvoidance = false; 68 | #endif 69 | #if MICA_NO_WAIT_FOR_PENDING 70 | static constexpr bool kNoWaitForPending = true; 71 | #endif 72 | #if MICA_NO_INLINING 73 | static constexpr bool kInlinedRowVersion = false; 74 | #endif 75 | 76 | #if MICA_NO_BACKOFF 77 | static constexpr bool kBackoff = false; 78 | #endif 79 | 80 | // static constexpr bool kPrintBackoff = true; 81 | // static constexpr bool kPairwiseSleeping = true; 82 | 83 | #if MICA_USE_FIXED_BACKOFF 84 | static constexpr double kBackoffMin = MICA_FIXED_BACKOFF; 85 | static constexpr double kBackoffMax = MICA_FIXED_BACKOFF; 86 | #endif 87 | 88 | #if MICA_USE_SLOW_GC 89 | static constexpr int64_t kMinQuiescenceInterval = MICA_SLOW_GC; 90 | #endif 91 | 92 | // typedef ::mica::transaction::WideTimestamp Timestamp; 93 | // typedef ::mica::transaction::WideConcurrentTimestamp ConcurrentTimestamp; 94 | #if MICA_NO_TSC 95 | typedef ::mica::transaction::CentralizedTimestamp Timestamp; 96 | typedef ::mica::transaction::CentralizedConcurrentTimestamp 97 | ConcurrentTimestamp; 98 | #endif 99 | 100 | // static constexpr bool kCollectCommitStats = false; 101 | // static constexpr bool kCollectProcessingStats = true; 102 | // typedef ::mica::transaction::ActiveTiming Timing; 103 | 104 | // Switch this for verification. 105 | typedef ::mica::transaction::NullLogger Logger; 106 | // typedef VerificationLogger Logger; 107 | }; 108 | 109 | // Debugging 110 | static constexpr bool kVerbose = DBConfig::kVerbose; 111 | static constexpr bool kShowPoolStats = true; 112 | // static constexpr bool kShowPoolStats = false; 113 | static constexpr bool kRunPerf = false; 114 | // static constexpr bool kRunPerf = true; 115 | 116 | // Workload generation. 117 | // static constexpr bool kReadModifyWriteRatio = 0.0; 118 | // static constexpr bool kReadModifyWriteRatio = 0.5; 119 | static constexpr bool kReadModifyWriteRatio = 1.0; 120 | 121 | #if 1 122 | 123 | // HashIndex 124 | #if INDEX_STRUCT == IDX_MICA 125 | static constexpr bool kUseHashIndex = true; 126 | #else 127 | static constexpr bool kUseHashIndex = false; 128 | #endif 129 | static constexpr bool kUseBTreeIndex = false; 130 | 131 | #else 132 | 133 | // BTreeIndex 134 | static constexpr bool kUseHashIndex = false; 135 | #if INDEX_STRUCT == IDX_MICA 136 | static constexpr bool kUseBTreeIndex = true; 137 | #else 138 | static constexpr bool kUseBTreeIndex = false; 139 | #endif 140 | 141 | #endif 142 | 143 | #if MICA_FULLINDEX 144 | static constexpr bool kSkipValidationForIndexAccess = false; 145 | #else 146 | static constexpr bool kSkipValidationForIndexAccess = true; 147 | #endif 148 | 149 | // static constexpr bool kUseSnapshot = false; 150 | static constexpr bool kUseSnapshot = true; 151 | 152 | static constexpr bool kUseContendedSet = false; 153 | // static constexpr bool kUseContendedSet = true; 154 | static constexpr uint64_t kContendedSetSize = 64; 155 | static constexpr uint64_t kContendedReqPerTX = 2; 156 | // static constexpr uint64_t kContendedSetSize = 1048576; 157 | // static constexpr uint64_t kContendedReqPerTX = 1; 158 | // static constexpr uint64_t kContendedSetSize = 10; 159 | // static constexpr uint64_t kContendedReqPerTX = 1; 160 | 161 | // static constexpr uint64_t kDataSize = 8; 162 | // static constexpr uint64_t kColumnSize = 8; 163 | // static constexpr uint64_t kDataSize = 10; 164 | // static constexpr uint64_t kColumnSize = 10; 165 | // static constexpr uint64_t kDataSize = 16; 166 | // static constexpr uint64_t kColumnSize = 16; 167 | // static constexpr uint64_t kDataSize = 100; 168 | // static constexpr uint64_t kColumnSize = 100; 169 | // static constexpr uint64_t kDataSize = 1000; 170 | // static constexpr uint64_t kColumnSize = 100; 171 | // static constexpr uint64_t kDataSize = 1000; 172 | // static constexpr uint64_t kColumnSize = 1000; 173 | static constexpr uint64_t kDataSize = MAX_TUPLE_SIZE; 174 | static constexpr uint64_t kColumnSize = MAX_TUPLE_SIZE / MICA_COLUMN_COUNT; 175 | 176 | #if !MICA_USE_SCAN 177 | static constexpr bool kUseScan = false; 178 | #else 179 | static constexpr bool kUseScan = true; 180 | #endif 181 | static constexpr uint32_t kMaxScanLen = MICA_MAX_SCAN_LEN; 182 | 183 | #if !MICA_USE_FULL_TABLE_SCAN 184 | static constexpr bool kUseFullTableScan = false; 185 | #else 186 | static constexpr bool kUseFullTableScan = true; 187 | #endif 188 | -------------------------------------------------------------------------------- /src/mica/test/test_tx_conf_org.h: -------------------------------------------------------------------------------- 1 | 2 | // For compatibility. 3 | 4 | #define WORKLOAD YCSB 5 | #define WARMUP 2000000 6 | #define MAX_TXN_PER_PART 2000000 7 | #define INIT_PARALLELISM 2 8 | #define MAX_TUPLE_SIZE 100 9 | #define SYNTH_TABLE_SIZE 10000000 10 | #define REQ_PER_QUERY 1 11 | #define READ_PERC 0.5 12 | #define WRITE_PERC 0.5 13 | #define SCAN_PERC 0 14 | #define ZIPF_THETA 0.99 15 | #define THREAD_CNT 28 16 | #define PART_CNT 1 17 | #define IDX_HASH 1 18 | #define IDX_MICA 2 19 | 20 | #define CC_ALG MICA 21 | #define ISOLATION_LEVEL SERIALIZABLE 22 | #define VALIDATION_LOCK "no-wait" 23 | #define PRE_ABORT "true" 24 | #define RCU_ALLOC false 25 | #define RCU_ALLOC_SIZE 20401094656UL 26 | 27 | #define MICA_COLUMN_COUNT 1 28 | 29 | #define INDEX_STRUCT IDX_MICA 30 | #define MICA_FULLINDEX false 31 | 32 | #define MICA_USE_SCAN false 33 | #define MICA_USE_FULL_TABLE_SCAN false 34 | #define MICA_MAX_SCAN_LEN 100 35 | 36 | #define MICA_NO_TSC false 37 | #define MICA_NO_PRE_VALIDATION false 38 | #define MICA_NO_INSERT_NEWEST_VERSION_ONLY false 39 | #define MICA_NO_SORT_WRITE_SET_BY_CONTENTION false 40 | #define MICA_NO_STRAGGLER_AVOIDANCE false 41 | #define MICA_NO_WAIT_FOR_PENDING false 42 | #define MICA_NO_INLINING false 43 | #define MICA_NO_BACKOFF false 44 | 45 | #define MICA_USE_FIXED_BACKOFF false 46 | #define MICA_FIXED_BACKOFF 0. 47 | 48 | #define MICA_USE_SLOW_GC false 49 | #define MICA_SLOW_GC 10 50 | 51 | template 52 | class VerificationLogger; 53 | 54 | struct DBConfig : public ::mica::transaction::BasicDBConfig { 55 | // static constexpr bool kVerbose = true; 56 | 57 | #if MICA_NO_PRE_VALIDATION 58 | static constexpr bool kPreValidation = false; 59 | #endif 60 | #if MICA_NO_INSERT_NEWEST_VERSION_ONLY 61 | static constexpr bool kInsertNewestVersionOnly = false; 62 | #endif 63 | #if MICA_NO_SORT_WRITE_SET_BY_CONTENTION 64 | static constexpr bool kSortWriteSetByContention = false; 65 | #endif 66 | #if MICA_NO_STRAGGLER_AVOIDANCE 67 | static constexpr bool kStragglerAvoidance = false; 68 | #endif 69 | #if MICA_NO_WAIT_FOR_PENDING 70 | static constexpr bool kNoWaitForPending = true; 71 | #endif 72 | #if MICA_NO_INLINING 73 | static constexpr bool kInlinedRowVersion = false; 74 | #endif 75 | 76 | #if MICA_NO_BACKOFF 77 | static constexpr bool kBackoff = false; 78 | #endif 79 | 80 | // static constexpr bool kPrintBackoff = true; 81 | // static constexpr bool kPairwiseSleeping = true; 82 | 83 | #if MICA_USE_FIXED_BACKOFF 84 | static constexpr double kBackoffMin = MICA_FIXED_BACKOFF; 85 | static constexpr double kBackoffMax = MICA_FIXED_BACKOFF; 86 | #endif 87 | 88 | #if MICA_USE_SLOW_GC 89 | static constexpr int64_t kMinQuiescenceInterval = MICA_SLOW_GC; 90 | #endif 91 | 92 | // typedef ::mica::transaction::WideTimestamp Timestamp; 93 | // typedef ::mica::transaction::WideConcurrentTimestamp ConcurrentTimestamp; 94 | #if MICA_NO_TSC 95 | typedef ::mica::transaction::CentralizedTimestamp Timestamp; 96 | typedef ::mica::transaction::CentralizedConcurrentTimestamp 97 | ConcurrentTimestamp; 98 | #endif 99 | 100 | // static constexpr bool kCollectCommitStats = false; 101 | // static constexpr bool kCollectProcessingStats = true; 102 | // typedef ::mica::transaction::ActiveTiming Timing; 103 | 104 | // Switch this for verification. 105 | typedef ::mica::transaction::NullLogger Logger; 106 | // typedef VerificationLogger Logger; 107 | }; 108 | 109 | // Debugging 110 | static constexpr bool kVerbose = DBConfig::kVerbose; 111 | static constexpr bool kShowPoolStats = true; 112 | // static constexpr bool kShowPoolStats = false; 113 | static constexpr bool kRunPerf = false; 114 | // static constexpr bool kRunPerf = true; 115 | 116 | // Workload generation. 117 | // static constexpr bool kReadModifyWriteRatio = 0.0; 118 | // static constexpr bool kReadModifyWriteRatio = 0.5; 119 | static constexpr bool kReadModifyWriteRatio = 1.0; 120 | 121 | #if 1 122 | 123 | // HashIndex 124 | #if INDEX_STRUCT == IDX_MICA 125 | static constexpr bool kUseHashIndex = true; 126 | #else 127 | static constexpr bool kUseHashIndex = false; 128 | #endif 129 | static constexpr bool kUseBTreeIndex = false; 130 | 131 | #else 132 | 133 | // BTreeIndex 134 | static constexpr bool kUseHashIndex = false; 135 | #if INDEX_STRUCT == IDX_MICA 136 | static constexpr bool kUseBTreeIndex = true; 137 | #else 138 | static constexpr bool kUseBTreeIndex = false; 139 | #endif 140 | 141 | #endif 142 | 143 | #if MICA_FULLINDEX 144 | static constexpr bool kSkipValidationForIndexAccess = false; 145 | #else 146 | static constexpr bool kSkipValidationForIndexAccess = true; 147 | #endif 148 | 149 | // static constexpr bool kUseSnapshot = false; 150 | static constexpr bool kUseSnapshot = true; 151 | 152 | static constexpr bool kUseContendedSet = false; 153 | // static constexpr bool kUseContendedSet = true; 154 | static constexpr uint64_t kContendedSetSize = 64; 155 | static constexpr uint64_t kContendedReqPerTX = 2; 156 | // static constexpr uint64_t kContendedSetSize = 1048576; 157 | // static constexpr uint64_t kContendedReqPerTX = 1; 158 | // static constexpr uint64_t kContendedSetSize = 10; 159 | // static constexpr uint64_t kContendedReqPerTX = 1; 160 | 161 | // static constexpr uint64_t kDataSize = 8; 162 | // static constexpr uint64_t kColumnSize = 8; 163 | // static constexpr uint64_t kDataSize = 10; 164 | // static constexpr uint64_t kColumnSize = 10; 165 | // static constexpr uint64_t kDataSize = 16; 166 | // static constexpr uint64_t kColumnSize = 16; 167 | // static constexpr uint64_t kDataSize = 100; 168 | // static constexpr uint64_t kColumnSize = 100; 169 | // static constexpr uint64_t kDataSize = 1000; 170 | // static constexpr uint64_t kColumnSize = 100; 171 | // static constexpr uint64_t kDataSize = 1000; 172 | // static constexpr uint64_t kColumnSize = 1000; 173 | static constexpr uint64_t kDataSize = MAX_TUPLE_SIZE; 174 | static constexpr uint64_t kColumnSize = MAX_TUPLE_SIZE / MICA_COLUMN_COUNT; 175 | 176 | #if !MICA_USE_SCAN 177 | static constexpr bool kUseScan = false; 178 | #else 179 | static constexpr bool kUseScan = true; 180 | #endif 181 | static constexpr uint32_t kMaxScanLen = MICA_MAX_SCAN_LEN; 182 | 183 | #if !MICA_USE_FULL_TABLE_SCAN 184 | static constexpr bool kUseFullTableScan = false; 185 | #else 186 | static constexpr bool kUseFullTableScan = true; 187 | #endif 188 | -------------------------------------------------------------------------------- /src/mica/test/test_zipf.cc: -------------------------------------------------------------------------------- 1 | #include "mica/util/zipf.h" 2 | #include 3 | 4 | int main() { 5 | ::mica::util::ZipfGen::test(-1.); 6 | ::mica::util::ZipfGen::test(0.0); 7 | ::mica::util::ZipfGen::test(0.99); 8 | ::mica::util::ZipfGen::test(40.); 9 | 10 | return EXIT_SUCCESS; 11 | } 12 | -------------------------------------------------------------------------------- /src/mica/transaction/btree_index_impl/fixup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_BTREE_INDEX_IMPL_FIXUP_H_ 3 | #define MICA_TRANSACTION_BTREE_INDEX_IMPL_FIXUP_H_ 4 | 5 | namespace mica { 6 | namespace transaction { 7 | // We exploit the fact that a leaf node's min key never becomes smaller; 8 | // we only need to take the next pointer as in B-link-tree. 9 | 10 | template 11 | template 12 | bool BTreeIndex::fixup_internal( 13 | RowAccessHandleT& rah, const Node*& node_b, const Key& key) const { 14 | auto node = as_internal(node_b); 15 | 16 | if (RightOpen) (void)key; 17 | 18 | // Ensure key < node->max_key. 19 | uint64_t fixup_len = 0; 20 | while (node->next != kNullRowID) { 21 | if (RightOpen) 22 | ; 23 | else if (RightExclusive) { 24 | if (comp_le(key, node->max_key)) break; 25 | } else { 26 | if (comp_lt(key, node->max_key)) break; 27 | } 28 | 29 | if (kPrefetchNode) prefetch_row(rah, node->next); 30 | 31 | rah.reset(); 32 | node_b = get_node(rah, node->next); 33 | if (!node_b) return false; 34 | 35 | node = as_internal(node_b); 36 | 37 | if ((kVerbose & VerboseFlag::kFixup)) fixup_len++; 38 | } 39 | 40 | if (!comp_le(node->min_key, key)) return false; 41 | 42 | if ((kVerbose & VerboseFlag::kFixup)) 43 | if (fixup_len > 100) 44 | printf("BTreeIndex::fixup_internal(): key=%" PRIu64 " fixup_len=%" PRIu64 45 | "\n", 46 | key_info(key), fixup_len); 47 | 48 | return true; 49 | } 50 | 51 | template 52 | template 53 | bool BTreeIndex::fixup_leaf( 54 | RowAccessHandleT& rah, const Node*& node_b, const Key& key) const { 55 | auto node = as_leaf(node_b); 56 | 57 | // Ensure key < node->max_key. 58 | uint64_t fixup_len = 0; 59 | 60 | if (!RightOpen) { 61 | while (node->prev != kNullRowID) { 62 | if (RightExclusive) { 63 | if (comp_lt(node->min_key, key)) break; 64 | } else { 65 | if (comp_le(node->min_key, key)) break; 66 | } 67 | 68 | if (kPrefetchNode) prefetch_row(rah, node->prev); 69 | 70 | rah.reset(); 71 | node_b = get_node(rah, node->prev); 72 | if (!node_b) return false; 73 | 74 | node = as_leaf(node_b); 75 | 76 | if ((kVerbose & VerboseFlag::kFixup)) fixup_len++; 77 | } 78 | } 79 | 80 | while (node->next != kNullRowID) { 81 | if (RightOpen) 82 | ; 83 | else if (RightExclusive) { 84 | if (comp_le(key, node->max_key)) break; 85 | } else { 86 | if (comp_lt(key, node->max_key)) break; 87 | } 88 | 89 | if (kPrefetchNode) prefetch_row(rah, node->next); 90 | 91 | rah.reset(); 92 | node_b = get_node(rah, node->next); 93 | if (!node_b) return false; 94 | 95 | node = as_leaf(node_b); 96 | 97 | if ((kVerbose & VerboseFlag::kFixup)) fixup_len++; 98 | } 99 | 100 | if (!comp_le(node->min_key, key)) return false; 101 | 102 | if ((kVerbose & VerboseFlag::kFixup)) 103 | if (fixup_len > 100) 104 | printf("BTreeIndex::fixup_leaf(): key=%" PRIu64 " fixup_len=%" PRIu64 105 | "\n", 106 | key_info(key), fixup_len); 107 | 108 | return true; 109 | } 110 | } 111 | } 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /src/mica/transaction/btree_index_impl/init.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_BTREE_INDEX_IMPL_INIT_H_ 3 | #define MICA_TRANSACTION_BTREE_INDEX_IMPL_INIT_H_ 4 | 5 | namespace mica { 6 | namespace transaction { 7 | template 8 | BTreeIndex::BTreeIndex( 9 | DB* db, Table* main_tbl, 10 | Table* idx_tbl, const Compare& comp) 11 | : db_(db), main_tbl_(main_tbl), idx_tbl_(idx_tbl), comp_(comp) { 12 | static_assert(sizeof(InternalNode) <= sizeof(LeafNode), "invalid node size"); 13 | static_assert(std::is_trivially_copyable::value, 14 | "trivially copyable keys required"); 15 | } 16 | 17 | template 18 | bool BTreeIndex::init(Transaction* tx) { 19 | Timing t(tx->context()->timing_stack(), &Stats::index_write); 20 | 21 | bool ret = tx->begin(); 22 | if (!ret) return false; 23 | 24 | RowAccessHandle rah_head(tx); 25 | auto head = make_internal_node(rah_head); 26 | if (!head || rah_head.row_id() != 0) { 27 | printf("failed to create head\n"); 28 | return false; 29 | } 30 | 31 | RowAccessHandle rah_root(tx); 32 | auto root = make_leaf_node(rah_root); 33 | if (!root) { 34 | printf("failed to create root\n"); 35 | return false; 36 | } 37 | 38 | head->count = 0; 39 | head->child_row_id(0) = rah_root.row_id(); 40 | head->next = kNullRowID; 41 | head->min_key = Key{}; 42 | head->max_key = Key{}; 43 | 44 | root->count = 0; 45 | root->prev = kNullRowID; 46 | root->next = kNullRowID; 47 | root->min_key = Key{}; 48 | root->max_key = Key{}; 49 | 50 | if (!tx->commit()) { 51 | printf("failed to initialize a new BTreeIndex\n"); 52 | return false; 53 | } 54 | // printf("BTreeIndex::init()\n"); 55 | return true; 56 | } 57 | } 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/mica/transaction/btree_index_impl/prefetch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_BTREE_INDEX_IMPL_PREFETCH_H_ 3 | #define MICA_TRANSACTION_BTREE_INDEX_IMPL_PREFETCH_H_ 4 | 5 | namespace mica { 6 | namespace transaction { 7 | template 8 | void BTreeIndex::prefetch( 9 | Transaction* tx, const Key& key) { 10 | // Prefetching is not meaningfull in a tree. 11 | (void)tx; 12 | (void)key; 13 | } 14 | } 15 | } 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/mica/transaction/context_gc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_CONTEXT_GC_H_ 3 | #define MICA_TRANSACTION_CONTEXT_GC_H_ 4 | 5 | namespace mica { 6 | namespace transaction { 7 | template 8 | void Context::schedule_gc( 9 | /*uint64_t gc_epoch,*/ const Timestamp& wts, Table* tbl, 10 | uint16_t cf_id, uint8_t deleted, uint64_t row_id, 11 | RowHead* head, RowVersion* write_rv) { 12 | // We need to store Timestamp separately from write_rv because write_rv may be 13 | // gone when we check the timestamp. 14 | 15 | // gc_items_.push({gc_epoch, wts, tbl, row_id, head, write_rv}); 16 | gc_items_.push({wts, tbl, cf_id, deleted, row_id, head, write_rv}); 17 | 18 | // if (gc_items_.full()) { 19 | // fprintf(stderr, "Error: GC queue is full\n"); 20 | // return; 21 | // } 22 | // auto& tail = gc_items_.tail(); 23 | // tail.wts = wts; 24 | // tail.tbl = tbl; 25 | // tail.cf_id = cf_id; 26 | // tail.deleted = deleted; 27 | // tail.row_id = row_id; 28 | // tail.head = head; 29 | // tail.write_rv = write_rv; 30 | // gc_items_.push_tail(); 31 | 32 | __builtin_prefetch(tbl->gc_info(cf_id, row_id), 0, 3); 33 | } 34 | 35 | template 36 | void Context::gc(bool forced) { 37 | Timing t(timing_stack(), &Stats::gc); 38 | 39 | auto gc_row = [this](auto& ts, auto tbl, auto cf_id, auto deleted, 40 | auto row_id, auto head, auto write_rv) { 41 | uint64_t dealloc_chain_len; 42 | if (StaticConfig::kCollectProcessingStats) { 43 | dealloc_chain_len = 0; 44 | } 45 | 46 | auto gc_info = tbl->gc_info(cf_id, row_id); 47 | 48 | { 49 | auto gc_ts = gc_info->gc_ts.get(); 50 | // write_rv is invalid (dangling) now. 51 | if (gc_ts >= ts) return true; 52 | } 53 | 54 | if (!deleted) { 55 | if (gc_info->gc_lock == 1 || 56 | __sync_lock_test_and_set(&gc_info->gc_lock, 1) == 1) { 57 | // Some other thread is GCing this row already. 58 | // Just give up on this row; maybe that thread will clean up almost 59 | // everything. 60 | return true; 61 | } 62 | 63 | // Read gc_ts again because it may have been changed before locking. 64 | { 65 | auto gc_ts = gc_info->gc_ts.get(); 66 | if (gc_ts >= ts) { 67 | __sync_lock_release(&gc_info->gc_lock); 68 | return true; 69 | } 70 | } 71 | } else { 72 | // We do not give up locking if the GC was invoked by deletion. 73 | while (__sync_lock_test_and_set(&gc_info->gc_lock, 1) == 1) 74 | ::mica::util::pause(); 75 | 76 | // There must be no more commits for deleted rows; we can omit the 77 | // checking usually. 78 | assert(gc_info->gc_ts.get() < ts); 79 | } 80 | 81 | if (StaticConfig::kVerbose) 82 | printf("gc: thread_id=%2hu min_rts=%" PRIu64 " begin prev_gc_ts=%" PRIu64 83 | "\n", 84 | thread_id_, db_->min_rts().t2, gc_info->gc_ts.get().t2); 85 | 86 | gc_info->gc_ts.write(ts); 87 | 88 | if (StaticConfig::kVerbose) 89 | printf("gc: thread_id=%2hu min_rts=%" PRIu64 " write_rv %p (wts=%" PRIu64 90 | ")\n", 91 | thread_id_, db_->min_rts().t2, write_rv, write_rv->wts.t2); 92 | 93 | assert(write_rv->status >= RowVersionStatus::kCommitted); 94 | assert(write_rv->wts < db_->min_rts()); 95 | 96 | RowVersion* rv; 97 | bool delete_rv; 98 | 99 | if (write_rv->status == RowVersionStatus::kDeleted && 100 | head->older_rv == write_rv) { 101 | // Delete the row if this row version was a "deleted" version and the row 102 | // has this version only. 103 | 104 | // This will not reclaim a deleted row if there is any aborted 105 | // version before a "deleted" version. 106 | // 107 | // However, with StaticConfig::kSkipPending == false, there will be no 108 | // newer version installed after any older pending or deleted version, so 109 | // it is guaranteed to have a deleted version as the first version in the 110 | // version list. 111 | 112 | // Actual row deletion (row ID deallocation) is done at bit later because 113 | // we are still holding a GC lock for this row. 114 | delete_rv = true; 115 | 116 | // We will deallocate this "deleted" version as well. 117 | rv = write_rv; 118 | head->older_rv = nullptr; 119 | } else { 120 | delete_rv = false; 121 | 122 | // Take the rest of row versions from the version chain. 123 | rv = write_rv->older_rv; 124 | write_rv->older_rv = nullptr; 125 | } 126 | 127 | // We can now release the lock because we have modified any shared data, and 128 | // the rest will not be visible to other threads. Other threads can do 129 | // parallel GCing this row. 130 | __sync_lock_release(&gc_info->gc_lock); 131 | 132 | while (rv != nullptr) { 133 | // If this test fails, some bad thing is going on (accessing a GC'ed 134 | // row version). 135 | assert(rv->status != RowVersionStatus::kInvalid); 136 | assert(rv->wts < db_->min_rts() || 137 | (delete_rv && rv->wts <= db_->min_rts())); 138 | 139 | if (StaticConfig::kCollectProcessingStats) dealloc_chain_len++; 140 | 141 | auto older_rv = rv->older_rv; 142 | __builtin_prefetch(older_rv, 0, 0); 143 | 144 | if (StaticConfig::kVerbose) 145 | printf("gc: thread_id=%2hu min_rts=%" PRIu64 146 | " delete %p (wts=%" PRIu64 ")\n", 147 | thread_id_, db_->min_rts().t2, rv, rv->wts.t2); 148 | 149 | deallocate_version(rv); 150 | 151 | rv = older_rv; 152 | } 153 | 154 | if (delete_rv && cf_id == 0) { 155 | // Deleting the first column family implies the whole row deletion. 156 | deallocate_row(tbl, row_id); 157 | } 158 | 159 | if (StaticConfig::kCollectProcessingStats) { 160 | if (stats_.max_gc_dealloc_chain_len < dealloc_chain_len) 161 | stats_.max_gc_dealloc_chain_len = dealloc_chain_len; 162 | } 163 | 164 | // TODO: Reclaim aborted row versions that appear before the latest 165 | // committed row versions. Maybe we can do slow scanning to reinsert any 166 | // committed version if it is not the first one. 167 | 168 | if (StaticConfig::kVerbose) 169 | printf("gc: thread_id=%2hu min_rts=%" PRIu64 " end\n", thread_id_, 170 | db_->min_rts().t2); 171 | 172 | return true; 173 | }; 174 | 175 | // auto gc_epoch = db_->gc_epoch(); 176 | auto min_rts = db_->min_rts(); 177 | 178 | while (!gc_items_.empty() && /*gc_epoch - gc_items_.front().gc_epoch >= 2 &&*/ 179 | min_rts > gc_items_.front().wts) { 180 | auto& item = gc_items_.front(); 181 | if (!gc_row(item.wts, item.tbl, item.cf_id, item.deleted, item.row_id, 182 | item.head, item.write_rv)) 183 | break; 184 | gc_items_.pop(); 185 | } 186 | 187 | // while (!gc_items_.empty() && min_rts > gc_items_.head().wts) { 188 | // auto& item = gc_items_.head(); 189 | // if (!gc_row(item.wts, item.tbl, item.cf_id, item.deleted, item.row_id, 190 | // item.head, item.write_rv)) 191 | // break; 192 | // gc_items_.pop_head(); 193 | // } 194 | 195 | if (StaticConfig::kCollectProcessingStats) { 196 | if (forced) 197 | stats_.gc_forced_count++; 198 | else 199 | stats_.gc_inc_count++; 200 | } 201 | } 202 | } 203 | } 204 | 205 | #endif 206 | -------------------------------------------------------------------------------- /src/mica/transaction/hash_index.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_HASH_INDEX_H_ 3 | #define MICA_TRANSACTION_HASH_INDEX_H_ 4 | 5 | #include "mica/common.h" 6 | #include "mica/util/type_traits.h" 7 | 8 | namespace mica { 9 | namespace transaction { 10 | template , class KeyEqual = std::equal_to> 12 | class HashIndex; 13 | 14 | template , class KeyEqual = std::equal_to> 16 | class HashIndexBucketCopier { 17 | public: 18 | typedef HashIndex HashIndexT; 19 | typedef typename HashIndexT::Bucket Bucket; 20 | 21 | bool operator()(uint16_t cf_id, RowVersion* dest, 22 | const RowVersion* src) const { 23 | (void)cf_id; 24 | if (dest->data_size == 0) return true; 25 | 26 | auto dest_bucket = reinterpret_cast(dest->data); 27 | auto src_bucket = reinterpret_cast(src->data); 28 | 29 | dest_bucket->next = src_bucket->next; 30 | 31 | ::mica::util::memcpy(dest_bucket->keys, src_bucket->keys, 32 | sizeof(Bucket::keys)); 33 | if (Bucket::kBucketSize == 1) { 34 | for (size_t i = 0; i < Bucket::kBucketSize; i++) 35 | dest_bucket->values[i] = src_bucket->values[i]; 36 | } else { 37 | ::mica::util::memcpy(dest_bucket->values, src_bucket->values, 38 | sizeof(Bucket::values)); 39 | } 40 | return true; 41 | } 42 | }; 43 | 44 | template 46 | class HashIndex { 47 | public: 48 | typedef HashIndexBucketCopier 49 | DataCopier; 50 | 51 | typedef typename StaticConfig::Timing Timing; 52 | typedef ::mica::transaction::RowAccessHandle RowAccessHandle; 53 | typedef ::mica::transaction::RowAccessHandlePeekOnly 54 | RowAccessHandlePeekOnly; 55 | typedef ::mica::transaction::Transaction Transaction; 56 | 57 | struct Bucket { 58 | // static constexpr size_t kBucketSize = 13; // (216 - 8) / 16 59 | // static constexpr size_t kBucketSize = 9; // (152 - 8) / 16 60 | // static constexpr size_t kBucketSize = 5; // (88 - 8) / 16 61 | static constexpr size_t kBucketSize = 1; // (24 - 8) / 16 62 | 63 | uint64_t next; 64 | 65 | Key keys[kBucketSize]; 66 | uint64_t values[kBucketSize]; 67 | }; 68 | static constexpr uint64_t kDataSize = sizeof(Bucket); 69 | 70 | static constexpr uint64_t kNullRowID = static_cast(-1); 71 | 72 | static constexpr uint64_t kHaveToAbort = static_cast(-1); 73 | 74 | // hash_index_impl/init.h 75 | HashIndex(DB* db, Table* main_tbl, 76 | Table* idx_tbl, uint64_t expected_num_rows, 77 | const Hash& hash = Hash(), const KeyEqual& key_equal = KeyEqual()); 78 | 79 | bool init(Transaction* tx); 80 | 81 | // hash_index_impl/insert.h 82 | uint64_t insert(Transaction* tx, const Key& key, uint64_t value); 83 | 84 | // hash_index_impl/remove.h 85 | uint64_t remove(Transaction* tx, const Key& key, uint64_t value); 86 | 87 | // hash_index_impl/lookup.h 88 | template 89 | uint64_t lookup(Transaction* tx, const Key& key, bool skip_validation, 90 | const Func& func); 91 | 92 | // hash_index_impl/prefetch.h 93 | void prefetch(Transaction* tx, const Key& key); 94 | 95 | Table* main_table() { return main_tbl_; } 96 | const Table* main_table() const { return main_tbl_; } 97 | 98 | Table* index_table() { return idx_tbl_; } 99 | const Table* index_table() const { return idx_tbl_; } 100 | 101 | uint64_t expected_num_rows() const { return expected_num_rows_; } 102 | 103 | private: 104 | DB* db_; 105 | Table* main_tbl_; 106 | Table* idx_tbl_; 107 | uint64_t expected_num_rows_; 108 | Hash hash_; 109 | KeyEqual key_equal_; 110 | 111 | DataCopier data_copier_; 112 | 113 | uint64_t bucket_count_; 114 | uint64_t bucket_count_mask_; 115 | 116 | // hash_index_impl/bucket.h 117 | uint64_t get_bucket_id(const Key& key) const; 118 | }; 119 | } 120 | } 121 | 122 | #include "hash_index_impl/init.h" 123 | #include "hash_index_impl/bucket.h" 124 | #include "hash_index_impl/insert.h" 125 | #include "hash_index_impl/remove.h" 126 | #include "hash_index_impl/lookup.h" 127 | #include "hash_index_impl/prefetch.h" 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /src/mica/transaction/hash_index_impl/bucket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_HASH_INDEX_IMPL_BUCKET_H_ 3 | #define MICA_TRANSACTION_HASH_INDEX_IMPL_BUCKET_H_ 4 | 5 | namespace mica { 6 | namespace transaction { 7 | template 9 | uint64_t HashIndex::get_bucket_id(const Key& key) const { 11 | // Constant from CityHash. 12 | return (hash_(key) * 0x9ddfea08eb382d69ULL) & bucket_count_mask_; 13 | // return (key * 0x9ddfea08eb382d69ULL) % bucket_count_; 14 | } 15 | } 16 | } 17 | 18 | #endif -------------------------------------------------------------------------------- /src/mica/transaction/hash_index_impl/init.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_HASH_INDEX_IMPL_INIT_H_ 3 | #define MICA_TRANSACTION_HASH_INDEX_IMPL_INIT_H_ 4 | 5 | namespace mica { 6 | namespace transaction { 7 | template 9 | HashIndex::HashIndex( 10 | DB* db, Table* main_tbl, 11 | Table* idx_tbl, uint64_t expected_num_rows, const Hash& hash, 12 | const KeyEqual& key_equal) 13 | : db_(db), 14 | main_tbl_(main_tbl), 15 | idx_tbl_(idx_tbl), 16 | expected_num_rows_(expected_num_rows), 17 | hash_(hash), 18 | key_equal_(key_equal) { 19 | static_assert(std::is_trivially_copyable::value, 20 | "trivially copyable keys required"); 21 | 22 | // bucket_count_ = expected_num_rows * 11 / 10 / 23 | // Bucket::kBucketSize; // 10% provisioning 24 | bucket_count_ = 25 | expected_num_rows * 12 / 10 / Bucket::kBucketSize; // 20% provisioning 26 | // bucket_count_ = expected_num_rows * 15 / 10 / 27 | // Bucket::kBucketSize; // 50% provisioning 28 | 29 | bucket_count_ = ::mica::util::next_power_of_two(bucket_count_); 30 | bucket_count_mask_ = bucket_count_ - 1; 31 | } 32 | 33 | template 35 | bool HashIndex::init( 36 | Transaction* tx) { 37 | Timing t(tx->context()->timing_stack(), &Stats::index_write); 38 | 39 | const uint64_t kBatchSize = 16; 40 | for (uint64_t i = 0; i < bucket_count_; i++) { 41 | if (i % kBatchSize == 0) { 42 | bool ret = tx->begin(); 43 | if (!ret) return false; 44 | } 45 | 46 | RowAccessHandle rah(tx); 47 | if (!rah.new_row(idx_tbl_, 0, Transaction::kNewRowID, true, kDataSize)) { 48 | printf("failed to insert buckets\n"); 49 | return false; 50 | } 51 | if (rah.row_id() != i) { 52 | printf("failed to insert buckets\n"); 53 | return false; 54 | } 55 | 56 | auto new_bkt = reinterpret_cast(rah.data()); 57 | for (uint64_t j = 0; j < Bucket::kBucketSize; j++) 58 | new_bkt->values[j] = kNullRowID; 59 | new_bkt->next = kNullRowID; 60 | 61 | if (i % kBatchSize == kBatchSize - 1 || i == bucket_count_ - 1) { 62 | if (!tx->commit()) { 63 | printf("failed to insert buckets\n"); 64 | return false; 65 | } 66 | } 67 | } 68 | // printf("HashIndex::init()\n"); 69 | return true; 70 | } 71 | } 72 | } 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /src/mica/transaction/hash_index_impl/insert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_HASH_INDEX_IMPL_INSERT_H_ 3 | #define MICA_TRANSACTION_HASH_INDEX_IMPL_INSERT_H_ 4 | 5 | namespace mica { 6 | namespace transaction { 7 | template 9 | uint64_t HashIndex::insert( 10 | Transaction* tx, const Key& key, uint64_t value) { 11 | Timing t(tx->context()->timing_stack(), &Stats::index_write); 12 | 13 | auto bkt_id = get_bucket_id(key); 14 | RowAccessHandle rah(tx); 15 | 16 | if (!rah.peek_row(idx_tbl_, 0, bkt_id, true, true, false) || 17 | !rah.read_row(data_copier_)) 18 | return kHaveToAbort; 19 | // printf("HashIndex::insert() 1\n"); 20 | auto cbkt = reinterpret_cast(rah.cdata()); 21 | 22 | // Find any duplicate key or the last bucket in the chain. 23 | while (true) { 24 | if (UniqueKey) { 25 | for (uint64_t j = 0; j < Bucket::kBucketSize; j++) 26 | if (cbkt->values[j] != kNullRowID && key_equal_(cbkt->keys[j], key)) { 27 | // A duplicate key has been found. Do not insert anything. 28 | return 0; 29 | } 30 | } 31 | 32 | if (cbkt->next == kNullRowID) break; 33 | bkt_id = cbkt->next; 34 | 35 | rah.reset(); 36 | if (!rah.peek_row(idx_tbl_, 0, bkt_id, true, true, false) || 37 | !rah.read_row(data_copier_)) 38 | return kHaveToAbort; 39 | // printf("HashIndex::insert() 2\n"); 40 | cbkt = reinterpret_cast(rah.cdata()); 41 | } 42 | 43 | // Note that we did not specify write_hint earlier before calling 44 | // write_row(). It may have better or worse insert speed, but it is totally 45 | // safe to do so. 46 | rah.write_row(kDataSize, data_copier_); 47 | // printf("HashIndex::insert() 3\n"); 48 | auto bkt = reinterpret_cast(rah.data()); 49 | 50 | uint64_t j; 51 | for (j = 0; j < Bucket::kBucketSize; j++) 52 | if (bkt->values[j] == kNullRowID) break; 53 | 54 | if (j == Bucket::kBucketSize) { 55 | RowAccessHandle new_rah(tx); 56 | if (!new_rah.new_row(idx_tbl_, 0, Transaction::kNewRowID, true, kDataSize)) 57 | return kHaveToAbort; 58 | 59 | // printf("HashIndex::insert() 4\n"); 60 | 61 | auto new_bkt = reinterpret_cast(new_rah.data()); 62 | for (j = 0; j < Bucket::kBucketSize; j++) new_bkt->values[j] = kNullRowID; 63 | new_bkt->next = kNullRowID; 64 | j = 0; 65 | 66 | bkt->next = new_rah.row_id(); 67 | bkt = new_bkt; 68 | } 69 | 70 | bkt->keys[j] = key; 71 | bkt->values[j] = value; 72 | // printf("HashIndex::insert() 5\n"); 73 | return 1; 74 | } 75 | } 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /src/mica/transaction/hash_index_impl/lookup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_HASH_INDEX_IMPL_LOOKUP_H_ 3 | #define MICA_TRANSACTION_HASH_INDEX_IMPL_LOOKUP_H_ 4 | 5 | namespace mica { 6 | namespace transaction { 7 | template 9 | template 10 | uint64_t HashIndex::lookup( 11 | Transaction* tx, const Key& key, bool skip_validation, const Func& func) { 12 | Timing t(tx->context()->timing_stack(), &Stats::index_read); 13 | 14 | uint64_t chain_len; 15 | 16 | if (StaticConfig::kCollectProcessingStats) chain_len = 0; 17 | 18 | uint64_t found = 0; 19 | 20 | const Bucket* bkt; 21 | auto bkt_id = get_bucket_id(key); 22 | 23 | while (true) { 24 | if (StaticConfig::kCollectProcessingStats) chain_len++; 25 | 26 | if (skip_validation) { 27 | RowAccessHandlePeekOnly rah(tx); 28 | if (!rah.peek_row(idx_tbl_, 0, bkt_id, false, false, false)) 29 | return kHaveToAbort; 30 | bkt = reinterpret_cast(rah.cdata()); 31 | } else { 32 | RowAccessHandle rah(tx); 33 | if (!rah.peek_row(idx_tbl_, 0, bkt_id, true, true, false) || 34 | !rah.read_row(data_copier_)) 35 | return kHaveToAbort; 36 | bkt = reinterpret_cast(rah.cdata()); 37 | } 38 | 39 | for (size_t j = 0; j < Bucket::kBucketSize; j++) { 40 | // printf("HashIndex::lookup() key=%" PRIu64 " bucket_key=%" PRIu64 41 | // " value=%" PRIu64 "\n", 42 | // key, bkt->keys[i], bkt->values[i]); 43 | if (!key_equal_(bkt->keys[j], key)) continue; 44 | 45 | if (bkt->values[j] == kNullRowID) continue; 46 | 47 | auto value = bkt->values[j]; 48 | 49 | if (StaticConfig::kCollectProcessingStats) { 50 | if (tx->context()->stats().max_hash_index_chain_len < chain_len) 51 | tx->context()->stats().max_hash_index_chain_len = chain_len; 52 | } 53 | 54 | found++; 55 | if (!func(bkt->keys[j], value)) return found; 56 | if (UniqueKey) { 57 | // There will be no matching key. 58 | return found; 59 | } 60 | 61 | // To omit checking j if the bucket has only one item. 62 | if (Bucket::kBucketSize == 1) break; 63 | } 64 | 65 | bkt_id = bkt->next; 66 | if (bkt_id == kNullRowID) { 67 | if (StaticConfig::kCollectProcessingStats) { 68 | if (tx->context()->stats().max_hash_index_chain_len < chain_len) 69 | tx->context()->stats().max_hash_index_chain_len = chain_len; 70 | } 71 | return found; 72 | } 73 | } 74 | } 75 | } 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /src/mica/transaction/hash_index_impl/prefetch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_HASH_INDEX_IMPL_PREFETCH_H_ 3 | #define MICA_TRANSACTION_HASH_INDEX_IMPL_PREFETCH_H_ 4 | 5 | namespace mica { 6 | namespace transaction { 7 | template 9 | void HashIndex::prefetch( 10 | Transaction* tx, const Key& key) { 11 | Timing t(tx->context()->timing_stack(), &Stats::index_read); 12 | 13 | auto bkt_id = get_bucket_id(key); 14 | 15 | RowAccessHandlePeekOnly rah(tx); 16 | rah.prefetch_row(idx_tbl_, 0, bkt_id, 0, sizeof(Bucket)); 17 | } 18 | } 19 | } 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/mica/transaction/hash_index_impl/remove.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_HASH_INDEX_IMPL_REMOVE_H_ 3 | #define MICA_TRANSACTION_HASH_INDEX_IMPL_REMOVE_H_ 4 | 5 | namespace mica { 6 | namespace transaction { 7 | template 9 | uint64_t HashIndex::remove( 10 | Transaction* tx, const Key& key, uint64_t value) { 11 | Timing t(tx->context()->timing_stack(), &Stats::index_write); 12 | 13 | auto bkt_id = get_bucket_id(key); 14 | RowAccessHandle rah(tx); 15 | RowAccessHandle rah_prev(tx); 16 | 17 | if (!rah.peek_row(idx_tbl_, 0, bkt_id, true, true, false) || 18 | !rah.read_row(data_copier_)) 19 | return kHaveToAbort; 20 | // printf("HashIndex::remove() 1\n"); 21 | auto cbkt = reinterpret_cast(rah.cdata()); 22 | 23 | // Find the existing key. 24 | uint64_t existing_key_j = Bucket::kBucketSize; 25 | while (true) { 26 | for (uint64_t j = 0; j < Bucket::kBucketSize; j++) 27 | if (cbkt->values[j] == value && key_equal_(cbkt->keys[j], key)) { 28 | existing_key_j = j; 29 | break; 30 | } 31 | if (existing_key_j != Bucket::kBucketSize) break; 32 | 33 | if (cbkt->next == kNullRowID) break; 34 | bkt_id = cbkt->next; 35 | 36 | rah_prev = rah; 37 | rah.reset(); 38 | if (!rah.peek_row(idx_tbl_, 0, bkt_id, true, true, false) || 39 | !rah.read_row(data_copier_)) 40 | return kHaveToAbort; 41 | // printf("HashIndex::remove() 2\n"); 42 | cbkt = reinterpret_cast(rah.cdata()); 43 | } 44 | 45 | // No existing key found. 46 | if (existing_key_j == Bucket::kBucketSize) return 0; 47 | 48 | // If this is not the last bucket in the chain, find a key from the last bucket to fill the slot of this deleted key. 49 | 50 | if (cbkt->next != kNullRowID) { 51 | if (!rah.write_row(kDataSize, data_copier_)) return kHaveToAbort; 52 | auto filled_in_bkt = reinterpret_cast(rah.data()); 53 | 54 | while (cbkt->next != kNullRowID) { 55 | bkt_id = cbkt->next; 56 | 57 | rah_prev = rah; 58 | rah.reset(); 59 | if (!rah.peek_row(idx_tbl_, 0, bkt_id, true, true, false) || 60 | !rah.read_row(data_copier_)) 61 | return kHaveToAbort; 62 | cbkt = reinterpret_cast(rah.cdata()); 63 | } 64 | 65 | uint64_t last_j = Bucket::kBucketSize; 66 | for (uint64_t j = 0; j < Bucket::kBucketSize; j++) 67 | if (cbkt->values[j] != kNullRowID) { 68 | if (last_j == Bucket::kBucketSize) { 69 | last_j = j; 70 | break; 71 | } 72 | } 73 | assert(last_j != Bucket::kBucketSize); 74 | 75 | // Fill the slot. 76 | filled_in_bkt->keys[existing_key_j] = cbkt->keys[last_j]; 77 | filled_in_bkt->values[existing_key_j] = cbkt->values[last_j]; 78 | 79 | // Pretend that we deleted some key from the last bucket. 80 | existing_key_j = last_j; 81 | } 82 | 83 | // Delete the last bucket if we have removed the last key from it. 84 | bool will_delete_bucket; 85 | if (!rah_prev) 86 | will_delete_bucket = false; 87 | else { 88 | will_delete_bucket = true; 89 | for (uint64_t j = 0; j < Bucket::kBucketSize; j++) 90 | if (cbkt->values[j] != kNullRowID) { 91 | if (j == existing_key_j) 92 | continue; 93 | else { 94 | will_delete_bucket = false; 95 | break; 96 | } 97 | } 98 | } 99 | 100 | if (!will_delete_bucket) { 101 | // Simply make the slot as empty. 102 | if (!rah.write_row(kDataSize, data_copier_)) return kHaveToAbort; 103 | auto bkt = reinterpret_cast(rah.data()); 104 | bkt->values[existing_key_j] = kNullRowID; 105 | } else { 106 | // Unlink this bucket from the previous bucket. 107 | if (!rah_prev.write_row(0, data_copier_)) return kHaveToAbort; 108 | auto prev_bkt = reinterpret_cast(rah.data()); 109 | 110 | prev_bkt->next = kNullRowID; 111 | 112 | // Delete this bucket. 113 | if (!rah.delete_row()) return kHaveToAbort; 114 | } 115 | 116 | return 1; 117 | } 118 | } 119 | } 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /src/mica/transaction/list.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_LIST_H_ 3 | #define MICA_TRANSACTION_LIST_H_ 4 | 5 | #include "mica/common.h" 6 | 7 | namespace mica { 8 | namespace transaction { 9 | template 10 | class List { 11 | public: 12 | typedef typename StaticConfig::Timing Timing; 13 | 14 | static constexpr uint64_t kDataSize = sizeof(uint64_t) * 2; 15 | 16 | static constexpr uint64_t kNullRowID = static_cast(-1); 17 | 18 | List(uint64_t off, uint64_t neg_infty = 0, uint64_t pos_infty = 1); 19 | 20 | uint64_t neg_infty() const { return neg_infty_; } 21 | uint64_t pos_infty() const { return pos_infty_; } 22 | 23 | const uint64_t& prev(const char* data) const; 24 | const uint64_t& next(const char* data) const; 25 | 26 | bool is_adjacent(const char* left, const char* right) const; 27 | 28 | void init_infty(char* left, char* right); 29 | 30 | void set_prev(char* data, uint64_t prev); 31 | void set_next(char* data, uint64_t next); 32 | 33 | bool insert(uint64_t row_id, char* data, char* left, char* right); 34 | bool remove(char* data, char* left, char* right); 35 | 36 | private: 37 | uint64_t off_; 38 | uint64_t neg_infty_; 39 | uint64_t pos_infty_; 40 | }; 41 | } 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/mica/transaction/list_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_LIST_IMPL_H_ 3 | #define MICA_TRANSACTION_LIST_IMPL_H_ 4 | 5 | namespace mica { 6 | namespace transaction { 7 | template 8 | List::List(uint64_t off, uint64_t neg_infty, uint64_t pos_infty) 9 | : off_(off), neg_infty_(neg_infty), pos_infty_(pos_infty) { 10 | if (off % sizeof(uint64_t) != 0) { 11 | fprintf(stderr, "error: off must be a multiple of sizeof(uint64_t)\n"); 12 | assert(false); 13 | return; 14 | } 15 | } 16 | 17 | template 18 | const uint64_t& List::prev(const char* data) const { 19 | return *static_cast(data + off_); 20 | } 21 | 22 | template 23 | const uint64_t& List::next(const char* data) const { 24 | return *static_cast(data + off_ + sizeof(uint64_t)); 25 | } 26 | 27 | template 28 | bool List::is_adjacent(const char* left, 29 | const char* right) const { 30 | return next(left) == prev(right); 31 | } 32 | 33 | template 34 | void List::init_infty(char* left, char* right) { 35 | set_prev(rah_neg_infty, kNullRowID); 36 | set_next(rah_neg_infty, pos_infty_); 37 | 38 | set_prev(rah_pos_infty, neg_infty_); 39 | set_next(rah_pos_infty, kNullRowID); 40 | } 41 | 42 | template 43 | void List::set_prev(char* data, uint64_t prev) { 44 | *static_cast(data + off_) = prev; 45 | } 46 | 47 | template 48 | void List::set_next(char* data, uint64_t next) { 49 | *static_cast(data + off_ + sizeof(uint64_)) = next; 50 | } 51 | 52 | template 53 | bool List::insert(uint64_t row_id, char* data, char* left, 54 | char* right) { 55 | if (!is_adjacent(left, right)) return false; 56 | 57 | set_prev(data, prev(right)); 58 | set_next(data, next(left)); 59 | 60 | set_next(left, row_id); 61 | set_prev(right, row_id); 62 | 63 | return true; 64 | } 65 | 66 | template 67 | bool List::remove(char* data, char* left, char* right) { 68 | if (!is_adjacent(left, data)) return false; 69 | if (!is_adjacent(data, right)) return false; 70 | 71 | set_next(rah_left, next(data)); 72 | set_prev(rah_right, prev(data)); 73 | 74 | return true; 75 | } 76 | } 77 | } 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/mica/transaction/logging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_LOGGING_H_ 3 | #define MICA_TRANSACTION_LOGGING_H_ 4 | 5 | #include "mica/common.h" 6 | #include "mica/transaction/db.h" 7 | #include "mica/transaction/row.h" 8 | #include "mica/transaction/row_version_pool.h" 9 | #include "mica/transaction/context.h" 10 | #include "mica/transaction/transaction.h" 11 | 12 | namespace mica { 13 | namespace transaction { 14 | template 15 | class LoggerInterface { 16 | public: 17 | bool log(const Transaction* tx); 18 | }; 19 | 20 | template 21 | class NullLogger : public LoggerInterface { 22 | public: 23 | bool log(const Transaction* tx) { 24 | (void)tx; 25 | return true; 26 | } 27 | }; 28 | } 29 | } 30 | 31 | #endif -------------------------------------------------------------------------------- /src/mica/transaction/page_pool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_PAGE_POOL_H_ 3 | #define MICA_TRANSACTION_PAGE_POOL_H_ 4 | 5 | #include 6 | #include "mica/util/lcore.h" 7 | 8 | namespace mica { 9 | namespace transaction { 10 | template 11 | class PagePool { 12 | public: 13 | typedef typename StaticConfig::Alloc Alloc; 14 | 15 | static constexpr uint64_t kPageSize = 2 * 1048576; 16 | 17 | PagePool(Alloc* alloc, uint64_t size, uint8_t numa_id) 18 | : alloc_(alloc), numa_id_(numa_id) { 19 | uint64_t page_count = (size + kPageSize - 1) / kPageSize; 20 | size_ = page_count * kPageSize; 21 | 22 | lock_ = 0; 23 | total_count_ = page_count; 24 | free_count_ = page_count; 25 | 26 | pages_ = 27 | reinterpret_cast(alloc_->malloc_contiguous(size_, numa_id_)); 28 | if (!pages_) { 29 | printf("failed to initialize PagePool\n"); 30 | return; 31 | } 32 | for (uint64_t i = 0; i < page_count; i++) 33 | *reinterpret_cast(pages_ + i * kPageSize) = 34 | pages_ + (i + 1) * kPageSize; 35 | 36 | *reinterpret_cast(pages_ + (page_count - 1) * kPageSize) = nullptr; 37 | next_ = pages_; 38 | 39 | printf("initialized PagePool on numa node %" PRIu8 " with %.3lf GB\n", 40 | numa_id_, static_cast(size) / 1000000000.); 41 | } 42 | 43 | ~PagePool() { alloc_->free_striped(pages_); } 44 | 45 | char* allocate() { 46 | while (__sync_lock_test_and_set(&lock_, 1) == 1) ::mica::util::pause(); 47 | 48 | auto p = next_; 49 | if (next_) { 50 | next_ = *reinterpret_cast(next_); 51 | free_count_--; 52 | } 53 | 54 | __sync_lock_release(&lock_); 55 | 56 | return p; 57 | } 58 | 59 | void free(char* p) { 60 | while (__sync_lock_test_and_set(&lock_, 1) == 1) ::mica::util::pause(); 61 | 62 | *reinterpret_cast(p) = next_; 63 | next_ = p; 64 | free_count_++; 65 | 66 | __sync_lock_release(&lock_); 67 | } 68 | 69 | uint8_t numa_id() const { return numa_id_; } 70 | 71 | uint64_t total_count() const { return total_count_; } 72 | uint64_t free_count() const { return free_count_; } 73 | 74 | void print_status() const { 75 | printf("PagePool on numa node %" PRIu8 "\n", numa_id_); 76 | printf(" in use: %7.3lf GB\n", 77 | static_cast((total_count_ - free_count_) * kPageSize) / 78 | 1000000000.); 79 | printf(" free: %7.3lf GB\n", 80 | static_cast(free_count_ * kPageSize) / 1000000000.); 81 | printf(" total: %7.3lf GB\n", 82 | static_cast(total_count_ * kPageSize) / 1000000000.); 83 | } 84 | 85 | private: 86 | Alloc* alloc_; 87 | uint64_t size_; 88 | uint8_t numa_id_; 89 | 90 | uint64_t total_count_; 91 | char* pages_; 92 | 93 | volatile uint32_t lock_; 94 | uint64_t free_count_; 95 | char* next_; 96 | } __attribute__((aligned(64))); 97 | } 98 | } 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /src/mica/transaction/row.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_ROW_H_ 3 | #define MICA_TRANSACTION_ROW_H_ 4 | 5 | #include "mica/common.h" 6 | 7 | namespace mica { 8 | namespace transaction { 9 | enum class RowVersionStatus : uint8_t { 10 | kInvalid = 0, 11 | kPending, 12 | kAborted, 13 | kCommitted, // Commited as a valid version. 14 | kDeleted, // Commited as a deleted row. 15 | }; 16 | 17 | template 18 | struct RowVersion; 19 | 20 | template 21 | struct RowCommon { 22 | RowVersion* volatile older_rv; 23 | }; 24 | 25 | template 26 | struct RowVersion : public RowCommon { 27 | typename StaticConfig::Timestamp wts; 28 | typename StaticConfig::ConcurrentTimestamp rts; 29 | 30 | volatile RowVersionStatus status; 31 | uint8_t numa_id; // NUMA node ID (set by Table or SharedRowVersionPool). 32 | uint16_t size_cls; // Size class (set by Table or SharedRowVersionPool). 33 | uint32_t data_size; // Data size (set by Context). 34 | 35 | static constexpr uint8_t kInlinedRowVersionNUMAID = static_cast(-1); 36 | bool is_inlined() const { return numa_id == kInlinedRowVersionNUMAID; } 37 | 38 | char data[0] __attribute__((aligned(8))); 39 | }; // Alignment of Rows is handled by the row pool manually. 40 | 41 | template 42 | struct RowHead : public RowCommon { 43 | RowVersion inlined_rv[0] __attribute__((aligned(8))); 44 | }; // Alignment of Rows is handled by the table manually. 45 | 46 | template 47 | struct RowGCInfo { 48 | typename StaticConfig::ConcurrentTimestamp gc_ts; 49 | volatile uint32_t gc_lock; 50 | } __attribute__((aligned(8))); // __attribute__((aligned(64))); 51 | } 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/mica/transaction/stats.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_STATS_H_ 3 | #define MICA_TRANSACTION_STATS_H_ 4 | 5 | #include 6 | #include "mica/util/stopwatch.h" 7 | #include "mica/util/memcpy.h" 8 | 9 | namespace mica { 10 | namespace transaction { 11 | struct Stats { 12 | // kCollectCommitStats 13 | uint64_t tx_count; 14 | uint64_t committed_count; 15 | uint64_t aborted_by_get_row_count; 16 | uint64_t aborted_by_pre_validation_count; 17 | uint64_t aborted_by_deferred_row_version_insert_count; 18 | uint64_t aborted_by_main_validation_count; 19 | uint64_t aborted_by_logging_count; 20 | uint64_t aborted_by_application_count; 21 | 22 | // kCollectCommitStats 23 | uint64_t tx_time; 24 | uint64_t committed_time; 25 | uint64_t aborted_by_get_row_time; 26 | uint64_t aborted_by_pre_validation_time; 27 | uint64_t aborted_by_deferred_row_version_insert_time; 28 | uint64_t aborted_by_main_validation_time; 29 | uint64_t aborted_by_logging_time; 30 | uint64_t aborted_by_application_time; 31 | 32 | // ActiveTiming 33 | uint64_t worker; 34 | uint64_t timestamping; 35 | uint64_t alloc; 36 | uint64_t dealloc; 37 | uint64_t execution_read; 38 | uint64_t execution_write; 39 | uint64_t index_read; 40 | uint64_t index_write; 41 | uint64_t row_copy; 42 | uint64_t wait_for_pending; 43 | uint64_t sort_wset; 44 | uint64_t pre_validation; 45 | uint64_t deferred_row_insert; 46 | uint64_t rts_update; 47 | uint64_t main_validation; 48 | uint64_t logging; 49 | uint64_t write; 50 | uint64_t rollback; 51 | uint64_t gc; 52 | uint64_t backoff; 53 | 54 | // kCollectProcessingStats 55 | uint64_t insert_row_count; 56 | uint64_t delete_row_count; 57 | uint64_t refill_rows_count; 58 | uint64_t return_rows_count; 59 | uint64_t gc_inc_count; 60 | uint64_t gc_forced_count; 61 | 62 | // kCollectProcessingStats 63 | uint64_t max_read_chain_len; 64 | uint64_t max_write_chain_len; 65 | uint64_t max_write_trials; 66 | uint64_t max_deferred_write_chain_len; 67 | uint64_t max_deferred_write_trials; 68 | uint64_t max_hash_index_chain_len; 69 | uint64_t max_gc_dealloc_chain_len; 70 | 71 | Stats() { reset(); } 72 | 73 | void reset() { ::mica::util::memset(this, 0, sizeof(Stats)); } 74 | 75 | Stats& operator+=(const Stats& o) { 76 | tx_count += o.tx_count; 77 | committed_count += o.committed_count; 78 | aborted_by_get_row_count += o.aborted_by_get_row_count; 79 | aborted_by_pre_validation_count += o.aborted_by_pre_validation_count; 80 | aborted_by_deferred_row_version_insert_count += 81 | o.aborted_by_deferred_row_version_insert_count; 82 | aborted_by_main_validation_count += o.aborted_by_main_validation_count; 83 | aborted_by_logging_count += o.aborted_by_logging_count; 84 | aborted_by_application_count += o.aborted_by_application_count; 85 | 86 | tx_time += o.tx_time; 87 | committed_time += o.committed_time; 88 | aborted_by_get_row_time += o.aborted_by_get_row_time; 89 | aborted_by_pre_validation_time += o.aborted_by_pre_validation_time; 90 | aborted_by_deferred_row_version_insert_time += 91 | o.aborted_by_deferred_row_version_insert_time; 92 | aborted_by_main_validation_time += o.aborted_by_main_validation_time; 93 | aborted_by_logging_time += o.aborted_by_logging_time; 94 | aborted_by_application_time += o.aborted_by_application_time; 95 | 96 | worker += o.worker; 97 | timestamping += o.timestamping; 98 | alloc += o.alloc; 99 | dealloc += o.dealloc; 100 | execution_read += o.execution_read; 101 | execution_write += o.execution_write; 102 | index_read += o.index_read; 103 | index_write += o.index_write; 104 | row_copy += o.row_copy; 105 | wait_for_pending += o.wait_for_pending; 106 | sort_wset += o.sort_wset; 107 | pre_validation += o.pre_validation; 108 | deferred_row_insert += o.deferred_row_insert; 109 | rts_update += o.rts_update; 110 | main_validation += o.main_validation; 111 | logging += o.logging; 112 | write += o.write; 113 | rollback += o.rollback; 114 | gc += o.gc; 115 | backoff += o.backoff; 116 | 117 | insert_row_count += o.insert_row_count; 118 | delete_row_count += o.delete_row_count; 119 | refill_rows_count += o.refill_rows_count; 120 | return_rows_count += o.return_rows_count; 121 | gc_inc_count += o.gc_inc_count; 122 | gc_forced_count += o.gc_forced_count; 123 | 124 | max_read_chain_len = std::max(max_read_chain_len, o.max_read_chain_len); 125 | max_write_chain_len = std::max(max_write_chain_len, o.max_write_chain_len); 126 | max_write_trials = std::max(max_write_trials, o.max_write_trials); 127 | max_deferred_write_chain_len = 128 | std::max(max_deferred_write_chain_len, o.max_deferred_write_chain_len); 129 | max_deferred_write_trials = 130 | std::max(max_deferred_write_trials, o.max_deferred_write_trials); 131 | max_hash_index_chain_len = 132 | std::max(max_hash_index_chain_len, o.max_hash_index_chain_len); 133 | max_gc_dealloc_chain_len = 134 | std::max(max_gc_dealloc_chain_len, o.max_gc_dealloc_chain_len); 135 | return *this; 136 | } 137 | } __attribute__((aligned(64))); 138 | 139 | class TimingStack { 140 | public: 141 | typedef ::mica::util::Stopwatch Stopwatch; 142 | 143 | static constexpr uint16_t kMaxDepth = 16; 144 | 145 | TimingStack(Stats* stats, const Stopwatch* sw) 146 | : stats_(stats), sw_(sw), depth_(0) { 147 | start_ = sw_->now(); 148 | } 149 | 150 | private: 151 | friend class ActiveTiming; 152 | 153 | Stats* stats_; 154 | const Stopwatch* sw_; 155 | 156 | uint64_t start_; 157 | uint64_t* targets_[kMaxDepth]; 158 | uint16_t depth_; 159 | }; 160 | 161 | class ActiveTiming { 162 | public: 163 | ActiveTiming(TimingStack* ts, uint64_t Stats::*target) : ts_(ts) { 164 | update(); 165 | 166 | assert(ts_->depth_ < TimingStack::kMaxDepth); 167 | ts_->targets_[ts_->depth_++] = &(ts_->stats_->*target); 168 | } 169 | 170 | ~ActiveTiming() { 171 | update(); 172 | ts_->depth_--; 173 | } 174 | 175 | void switch_to(uint64_t Stats::*target) { 176 | assert(ts_->depth_ != 0); 177 | update(); 178 | ts_->targets_[ts_->depth_ - 1] = &(ts_->stats_->*target); 179 | } 180 | 181 | private: 182 | TimingStack* ts_; 183 | 184 | void update() { 185 | uint64_t now = ts_->sw_->now(); 186 | if (ts_->depth_ != 0) *ts_->targets_[ts_->depth_ - 1] += now - ts_->start_; 187 | ts_->start_ = now; 188 | } 189 | }; 190 | 191 | class DummyTiming { 192 | public: 193 | DummyTiming(TimingStack*, uint64_t Stats::*) {} 194 | void switch_to(uint64_t Stats::*) {} 195 | }; 196 | } 197 | } 198 | 199 | #endif 200 | -------------------------------------------------------------------------------- /src/mica/transaction/table.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_TABLE_H_ 3 | #define MICA_TRANSACTION_TABLE_H_ 4 | 5 | #include 6 | #include "mica/common.h" 7 | #include "mica/transaction/db.h" 8 | #include "mica/transaction/row.h" 9 | #include "mica/transaction/context.h" 10 | #include "mica/transaction/transaction.h" 11 | #include "mica/util/memcpy.h" 12 | 13 | namespace mica { 14 | namespace transaction { 15 | template 16 | class DB; 17 | 18 | template 19 | class Table { 20 | public: 21 | typedef typename StaticConfig::Timestamp Timestamp; 22 | 23 | Table(DB* db, uint16_t cf_count, 24 | const uint64_t* data_size_hints); 25 | ~Table(); 26 | 27 | DB* db() { return db_; } 28 | const DB* db() const { return db_; } 29 | 30 | uint16_t cf_count() const { return cf_count_; } 31 | 32 | uint64_t data_size_hint(uint16_t cf_id) const { 33 | return cf_[cf_id].data_size_hint; 34 | } 35 | 36 | uint64_t row_count() const { return row_count_; } 37 | 38 | uint8_t inlining(uint16_t cf_id) const { return cf_[cf_id].inlining; } 39 | 40 | uint16_t inlined_rv_size_cls(uint16_t cf_id) const { 41 | return cf_[cf_id].inlined_rv_size_cls; 42 | } 43 | 44 | bool is_valid(uint16_t cf_id, uint64_t row_id) const; 45 | 46 | RowHead* head(uint16_t cf_id, uint64_t row_id); 47 | 48 | const RowHead* head(uint16_t cf_id, uint64_t row_id) const; 49 | 50 | RowHead* alt_head(uint16_t cf_id, uint64_t row_id); 51 | 52 | RowGCInfo* gc_info(uint16_t cf_id, uint64_t row_id); 53 | 54 | const RowVersion* latest_rv(uint16_t cf_id, 55 | uint64_t row_id) const; 56 | 57 | bool allocate_rows(Context* ctx, 58 | std::vector& row_ids); 59 | 60 | bool renew_rows(Context* ctx, uint16_t cf_id, 61 | uint64_t& row_id_begin, uint64_t row_id_end, 62 | bool expiring_only); 63 | 64 | template 65 | bool scan(Transaction* tx, uint16_t cf_id, uint64_t off, 66 | uint64_t len, const Func& f); 67 | 68 | void print_table_status() const; 69 | 70 | private: 71 | DB* db_; 72 | uint16_t cf_count_; 73 | 74 | struct ColumnFamilyInfo { 75 | uint64_t data_size_hint; 76 | 77 | uint64_t rh_offset; 78 | 79 | uint64_t rh_size; 80 | uint8_t inlining; 81 | uint16_t inlined_rv_size_cls; 82 | }; 83 | 84 | // We use only the half the first level because of shuffling. 85 | static constexpr uint64_t kFirstLevelWidth = 86 | PagePool::kPageSize / sizeof(char*) / 2; 87 | 88 | uint64_t total_rh_size_; 89 | uint64_t second_level_width_; 90 | uint64_t row_id_shift_; // log_2(second_level_width) 91 | uint64_t row_id_mask_; // (1 << row_id_shift) - 1 92 | 93 | ColumnFamilyInfo cf_[StaticConfig::kMaxColumnFamilyCount]; 94 | 95 | char* base_root_; 96 | char** root_; 97 | uint8_t* page_numa_ids_; 98 | 99 | volatile uint32_t lock_ __attribute__((aligned(64))); 100 | uint64_t row_count_; 101 | } __attribute__((aligned(64))); 102 | } 103 | } 104 | 105 | #include "table_impl.h" 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /src/mica/transaction/timestamp.cc: -------------------------------------------------------------------------------- 1 | #include "timestamp.h" 2 | 3 | namespace mica { 4 | namespace transaction { 5 | 6 | volatile uint64_t CentralizedTimestamp::next_t2 = 0; 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/mica/transaction/transaction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_TRANSACTION_H_ 3 | #define MICA_TRANSACTION_TRANSACTION_H_ 4 | 5 | #include "mica/common.h" 6 | #include "mica/transaction/context.h" 7 | #include "mica/transaction/table.h" 8 | #include "mica/transaction/row.h" 9 | #include "mica/transaction/row_access.h" 10 | #include "mica/transaction/timestamp.h" 11 | #include "mica/transaction/stats.h" 12 | #include "mica/util/memcpy.h" 13 | 14 | namespace mica { 15 | namespace transaction { 16 | enum class Result { 17 | kCommitted = 0, 18 | kAbortedByGetRow, // Not returned by Transaction::commit() but indicated by 19 | // a nullptr return value from get_row_for_write(). 20 | kAbortedByPreValidation, 21 | kAbortedByDeferredRowVersionInsert, 22 | kAbortedByMainValidation, 23 | kAbortedByLogging, 24 | kInvalid, 25 | }; 26 | 27 | template 28 | class Transaction { 29 | public: 30 | typedef typename StaticConfig::Timing Timing; 31 | typedef typename StaticConfig::Timestamp Timestamp; 32 | typedef RowAccessHandle RAH; 33 | typedef RowAccessHandlePeekOnly RAHPO; 34 | 35 | static constexpr uint64_t kNewRowID = static_cast(-1); 36 | static constexpr uint64_t kDefaultWriteDataSize = static_cast(-1); 37 | 38 | // transaction_impl/init.h 39 | Transaction(Context* ctx); 40 | ~Transaction(); 41 | 42 | // transaction_impl/commit.h 43 | bool begin(bool peek_only = false, 44 | const Timestamp* causally_after_ts = nullptr); 45 | 46 | // transaction_impl/operation.h 47 | struct NoopDataCopier { 48 | bool operator()(uint16_t cf_id, RowVersion* dest, 49 | const RowVersion* src) const { 50 | (void)cf_id; 51 | (void)dest; 52 | (void)src; 53 | return true; 54 | }; 55 | }; 56 | struct TrivialDataCopier { 57 | bool operator()(uint16_t cf_id, RowVersion* dest, 58 | const RowVersion* src) const { 59 | (void)cf_id; 60 | if (src != nullptr && dest->data_size != 0) { 61 | assert(dest->data_size >= src->data_size); 62 | ::mica::util::memcpy(dest->data, src->data, src->data_size); 63 | } 64 | return true; 65 | }; 66 | }; 67 | 68 | template 69 | bool new_row(RAH& rah, Table* tbl, uint16_t cf_id, 70 | uint64_t row_id, bool check_dup_access, 71 | uint64_t data_size, const DataCopier& data_copier); 72 | void prefetch_row(Table* tbl, uint16_t cf_id, uint64_t row_id, 73 | uint64_t off, uint64_t len); 74 | bool peek_row(RAH& rah, Table* tbl, uint16_t cf_id, 75 | uint64_t row_id, bool check_dup_access, bool read_hint, 76 | bool write_hint); 77 | bool peek_row(RAHPO& rah, Table* tbl, uint16_t cf_id, 78 | uint64_t row_id, bool check_dup_access); 79 | template 80 | bool read_row(RAH& rah, const DataCopier& data_copier); 81 | template 82 | bool write_row(RAH& rah, uint64_t data_size, const DataCopier& data_copier); 83 | bool delete_row(RAH& rah); 84 | 85 | // transaction_impl/commit.h 86 | struct NoopWriteFunc { 87 | bool operator()() const { return true; } 88 | }; 89 | template 90 | bool commit(Result* detail = nullptr, 91 | const WriteFunc& write_func = WriteFunc()); 92 | bool abort(bool skip_backoff = false); 93 | 94 | bool has_began() const { return began_; } 95 | bool is_peek_only() const { return peek_only_; } 96 | 97 | Context* context() { return ctx_; } 98 | const Context* context() const { return ctx_; } 99 | 100 | const Timestamp& ts() const { return ts_; } 101 | 102 | // For logging an verification. 103 | uint16_t access_size() const { return access_size_; } 104 | uint16_t iset_size() const { return iset_size_; } 105 | uint16_t rset_size() const { return rset_size_; } 106 | uint16_t wset_size() const { return wset_size_; } 107 | const uint16_t* iset_idx() const { return iset_idx_; } 108 | const uint16_t* rset_idx() const { return rset_idx_; } 109 | const uint16_t* wset_idx() const { return wset_idx_; } 110 | const RowAccessItem* accesses() const { return accesses_; } 111 | 112 | // For debugging. 113 | void print_version_chain(const Table* tbl, uint16_t cf_id, 114 | uint64_t row_id) const; 115 | 116 | protected: 117 | // transaction_impl/operation.h 118 | template 119 | void locate(RowCommon*& newer_rv, 120 | RowVersion*& rv); 121 | bool insert_version_deferred(); 122 | RowVersionStatus wait_for_pending(RowVersion* rv); 123 | void insert_row_deferred(); 124 | 125 | void reserve(Table* tbl, uint16_t cf_id, uint64_t row_id, 126 | bool read_hint, bool write_hint); 127 | 128 | // transaction_impl/commit.h 129 | Timestamp generate_timestamp(); 130 | void sort_wset(); 131 | bool check_version(); 132 | void update_rts(); 133 | void write(); 134 | 135 | void maintenance(); 136 | void backoff(); 137 | 138 | private: 139 | // transaction_impl/commit.h 140 | Context* ctx_; 141 | 142 | bool began_; 143 | Timestamp ts_; 144 | 145 | uint16_t access_size_; 146 | uint16_t iset_size_; 147 | uint16_t rset_size_; 148 | uint16_t wset_size_; 149 | 150 | uint8_t consecutive_commits_; 151 | 152 | uint8_t peek_only_; 153 | 154 | uint64_t begin_time_; 155 | uint64_t* abort_reason_target_count_; 156 | uint64_t* abort_reason_target_time_; 157 | 158 | uint64_t last_commit_time_; 159 | 160 | uint16_t access_bucket_count_; 161 | 162 | RowAccessItem accesses_[StaticConfig::kMaxAccessSize]; 163 | uint16_t iset_idx_[StaticConfig::kMaxAccessSize]; 164 | uint16_t rset_idx_[StaticConfig::kMaxAccessSize]; 165 | uint16_t wset_idx_[StaticConfig::kMaxAccessSize]; 166 | 167 | struct AccessBucket { 168 | static constexpr uint16_t kEmptyBucketID = static_cast(-1); 169 | uint16_t count; 170 | uint16_t next; 171 | uint16_t idx[StaticConfig::kAccessBucketSize]; 172 | } __attribute__((aligned(64))); 173 | std::vector access_buckets_; 174 | 175 | struct ReserveItem { 176 | ReserveItem(Table* tbl, uint16_t cf_id, uint64_t row_id, 177 | bool read_hint, bool write_hint) 178 | : tbl(tbl), 179 | cf_id(cf_id), 180 | row_id(row_id), 181 | read_hint(read_hint), 182 | write_hint(write_hint) {} 183 | Table* tbl; 184 | uint16_t cf_id; 185 | uint64_t row_id; 186 | bool read_hint; 187 | bool write_hint; 188 | }; 189 | std::vector to_reserve_; 190 | }; 191 | } 192 | } 193 | 194 | #include "transaction_impl/commit.h" 195 | #include "transaction_impl/init.h" 196 | #include "transaction_impl/operation.h" 197 | 198 | #endif 199 | -------------------------------------------------------------------------------- /src/mica/transaction/transaction_impl/init.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_TRANSACTION_TRANSACTION_IMPL_INIT_H_ 3 | #define MICA_TRANSACTION_TRANSACTION_IMPL_INIT_H_ 4 | 5 | namespace mica { 6 | namespace transaction { 7 | template 8 | Transaction::Transaction(Context* ctx) 9 | : ctx_(ctx), began_(false) { 10 | last_commit_time_ = 0; 11 | 12 | access_buckets_.resize(StaticConfig::kAccessBucketRootCount); 13 | 14 | consecutive_commits_ = 0; 15 | } 16 | 17 | template 18 | Transaction::~Transaction() { 19 | if (began_) abort(); 20 | } 21 | } 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /src/mica/util/barrier.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_BARRIER_H_ 3 | #define MICA_UTIL_BARRIER_H_ 4 | 5 | #include "mica/common.h" 6 | 7 | namespace mica { 8 | namespace util { 9 | static void memory_barrier() { asm volatile("" ::: "memory"); } 10 | 11 | static void lfence() { asm volatile("lfence" ::: "memory"); } 12 | 13 | static void sfence() { asm volatile("sfence" ::: "memory"); } 14 | 15 | static void mfence() { asm volatile("mfence" ::: "memory"); } 16 | 17 | static void pause() { asm volatile("pause"); } 18 | 19 | static void clflush(volatile void* p) { asm volatile("clflush (%0)" ::"r"(p)); } 20 | 21 | static void cpuid(unsigned int* eax, unsigned int* ebx, unsigned int* ecx, 22 | unsigned int* edx) { 23 | asm volatile("cpuid" 24 | : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) 25 | : "0"(*eax), "2"(*ecx)); 26 | } 27 | } 28 | } 29 | 30 | #endif -------------------------------------------------------------------------------- /src/mica/util/cityhash/city.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 Google, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | // 21 | // CityHash, by Geoff Pike and Jyrki Alakuijala 22 | // 23 | // http://code.google.com/p/cityhash/ 24 | // 25 | // This file provides a few functions for hashing strings. All of them are 26 | // high-quality functions in the sense that they pass standard tests such 27 | // as Austin Appleby's SMHasher. They are also fast. 28 | // 29 | // For 64-bit x86 code, on short strings, we don't know of anything faster than 30 | // CityHash64 that is of comparable quality. We believe our nearest competitor 31 | // is Murmur3. For 64-bit x86 code, CityHash64 is an excellent choice for hash 32 | // tables and most other hashing (excluding cryptography). 33 | // 34 | // For 64-bit x86 code, on long strings, the picture is more complicated. 35 | // On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc., 36 | // CityHashCrc128 appears to be faster than all competitors of comparable 37 | // quality. CityHash128 is also good but not quite as fast. We believe our 38 | // nearest competitor is Bob Jenkins' Spooky. We don't have great data for 39 | // other 64-bit CPUs, but for long strings we know that Spooky is slightly 40 | // faster than CityHash on some relatively recent AMD x86-64 CPUs, for example. 41 | // Note that CityHashCrc128 is declared in citycrc.h. 42 | // 43 | // For 32-bit x86 code, we don't know of anything faster than CityHash32 that 44 | // is of comparable quality. We believe our nearest competitor is Murmur3A. 45 | // (On 64-bit CPUs, it is typically faster to use the other CityHash variants.) 46 | // 47 | // Functions in the CityHash family are not suitable for cryptography. 48 | // 49 | // Please see CityHash's README file for more details on our performance 50 | // measurements and so on. 51 | // 52 | // WARNING: This code has been only lightly tested on big-endian platforms! 53 | // It is known to work well on little-endian platforms that have a small penalty 54 | // for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs. 55 | // It should work on all 32-bit and 64-bit platforms that allow unaligned reads; 56 | // bug reports are welcome. 57 | // 58 | // By the way, for some hash functions, given strings a and b, the hash 59 | // of a+b is easily derived from the hashes of a and b. This property 60 | // doesn't hold for any hash functions in this file. 61 | 62 | #ifndef CITY_HASH_H_ 63 | #define CITY_HASH_H_ 64 | 65 | #include // for size_t. 66 | #include 67 | #include 68 | 69 | typedef uint8_t uint8; 70 | typedef uint32_t uint32; 71 | typedef uint64_t uint64; 72 | typedef std::pair uint128; 73 | 74 | inline uint64 Uint128Low64(const uint128& x) { return x.first; } 75 | inline uint64 Uint128High64(const uint128& x) { return x.second; } 76 | 77 | // Hash function for a byte array. 78 | uint64 CityHash64(const char *buf, size_t len); 79 | 80 | // Hash function for a byte array. For convenience, a 64-bit seed is also 81 | // hashed into the result. 82 | uint64 CityHash64WithSeed(const char *buf, size_t len, uint64 seed); 83 | 84 | // Hash function for a byte array. For convenience, two seeds are also 85 | // hashed into the result. 86 | uint64 CityHash64WithSeeds(const char *buf, size_t len, 87 | uint64 seed0, uint64 seed1); 88 | 89 | // Hash function for a byte array. 90 | uint128 CityHash128(const char *s, size_t len); 91 | 92 | // Hash function for a byte array. For convenience, a 128-bit seed is also 93 | // hashed into the result. 94 | uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed); 95 | 96 | // Hash function for a byte array. Most useful in 32-bit binaries. 97 | uint32 CityHash32(const char *buf, size_t len); 98 | 99 | // Hash 128 input bits down to 64 bits of output. 100 | // This is intended to be a reasonably good hash function. 101 | inline uint64 Hash128to64(const uint128& x) { 102 | // Murmur-inspired hashing. 103 | const uint64 kMul = 0x9ddfea08eb382d69ULL; 104 | uint64 a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul; 105 | a ^= (a >> 47); 106 | uint64 b = (Uint128High64(x) ^ a) * kMul; 107 | b ^= (b >> 47); 108 | b *= kMul; 109 | return b; 110 | } 111 | 112 | #endif // CITY_HASH_H_ 113 | -------------------------------------------------------------------------------- /src/mica/util/cityhash/citycrc.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 Google, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | // 21 | // CityHash, by Geoff Pike and Jyrki Alakuijala 22 | // 23 | // This file declares the subset of the CityHash functions that require 24 | // _mm_crc32_u64(). See the CityHash README for details. 25 | // 26 | // Functions in the CityHash family are not suitable for cryptography. 27 | 28 | #ifndef CITY_HASH_CRC_H_ 29 | #define CITY_HASH_CRC_H_ 30 | 31 | #include 32 | 33 | // Hash function for a byte array. 34 | uint128 CityHashCrc128(const char *s, size_t len); 35 | 36 | // Hash function for a byte array. For convenience, a 128-bit seed is also 37 | // hashed into the result. 38 | uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed); 39 | 40 | // Hash function for a byte array. Sets result[0] ... result[3]. 41 | void CityHashCrc256(const char *s, size_t len, uint64 *result); 42 | 43 | #endif // CITY_HASH_CRC_H_ 44 | -------------------------------------------------------------------------------- /src/mica/util/cityhash/citycrc_mod.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 Google, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | // 21 | // CityHash, by Geoff Pike and Jyrki Alakuijala 22 | // 23 | // This file declares the subset of the CityHash functions that require 24 | // _mm_crc32_u64(). See the CityHash README for details. 25 | // 26 | // Functions in the CityHash family are not suitable for cryptography. 27 | 28 | #ifndef CITY_HASH_CRC_H_ 29 | #define CITY_HASH_CRC_H_ 30 | 31 | #include "city.h" 32 | 33 | // Hash function for a byte array. 34 | uint128 CityHashCrc128(const char *s, size_t len); 35 | 36 | // Hash function for a byte array. For convenience, a 128-bit seed is also 37 | // hashed into the result. 38 | uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed); 39 | 40 | // Hash function for a byte array. Sets result[0] ... result[3]. 41 | void CityHashCrc256(const char *s, size_t len, uint64 *result); 42 | 43 | #endif // CITY_HASH_CRC_H_ 44 | -------------------------------------------------------------------------------- /src/mica/util/config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_CONFIG_H_ 3 | #define MICA_UTIL_CONFIG_H_ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "mica/common.h" 10 | #pragma GCC diagnostic push 11 | #pragma GCC diagnostic ignored "-Wconversion" 12 | #pragma GCC diagnostic ignored "-Wsign-conversion" 13 | #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" 14 | #include "mica/util/rapidjson/document.h" 15 | #pragma GCC diagnostic pop 16 | 17 | namespace mica { 18 | namespace util { 19 | class Config { 20 | public: 21 | Config(); 22 | Config(const Config& config); 23 | ~Config() {} 24 | 25 | // This constructor is public to support emplace_back(), emplace(). 26 | Config(const std::shared_ptr& root, 27 | rapidjson::Value* current, std::string path); 28 | 29 | Config& operator=(const Config& config) = delete; 30 | 31 | static Config empty_array(std::string path); 32 | static Config empty_dict(std::string path); 33 | 34 | static Config load_file(std::string path); 35 | void dump_file(std::string path) const; 36 | 37 | static Config load(std::string json_text, std::string path); 38 | std::string dump() const; 39 | 40 | std::string get_path() const; 41 | 42 | bool exists() const; 43 | bool is_bool() const; 44 | bool is_int64() const; 45 | bool is_uint64() const; 46 | bool is_double() const; 47 | bool is_str() const; 48 | bool is_array() const; 49 | bool is_dict() const; 50 | 51 | bool get_bool() const; 52 | int64_t get_int64() const; 53 | uint64_t get_uint64() const; 54 | double get_double() const; 55 | std::string get_str() const; 56 | 57 | bool get_bool(bool default_v) const; 58 | int64_t get_int64(int64_t default_v) const; 59 | uint64_t get_uint64(uint64_t default_v) const; 60 | double get_double(double default_v) const; 61 | std::string get_str(const std::string& default_v) const; 62 | 63 | size_t size() const; 64 | const Config get(size_t index) const; 65 | Config get(size_t index); 66 | 67 | std::vector keys() const; 68 | const Config get(std::string key) const; 69 | Config get(std::string key); 70 | 71 | Config& push_back_bool(bool v); 72 | Config& push_back_int64(int64_t v); 73 | Config& push_back_uint64(uint64_t v); 74 | Config& push_back_double(double v); 75 | Config& push_back_string(const std::string& v); 76 | Config& push_back_array(const Config& v); 77 | Config& push_back_dict(const Config& v); 78 | 79 | Config& insert_bool(std::string key, bool v); 80 | Config& insert_int64(std::string key, int64_t v); 81 | Config& insert_uint64(std::string key, uint64_t v); 82 | Config& insert_double(std::string key, double v); 83 | Config& insert_string(std::string key, std::string v); 84 | Config& insert_array(std::string key, const Config& v); 85 | Config& insert_dict(std::string key, const Config& v); 86 | 87 | private: 88 | std::shared_ptr root_; 89 | rapidjson::Value* current_; 90 | std::string path_; 91 | }; 92 | } 93 | } 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /src/mica/util/hash.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_HASH_H_ 3 | #define MICA_UTIL_HASH_H_ 4 | 5 | #include "mica/common.h" 6 | #include "mica/util/cityhash/citycrc_mod.h" 7 | 8 | int siphash(uint8_t* out, const uint8_t* in, uint64_t inlen, const uint8_t* k); 9 | static const uint8_t siphash_key[16] = { 10 | 0, 11 | }; 12 | 13 | namespace mica { 14 | namespace util { 15 | template 16 | static uint64_t hash_cityhash(const T* key, size_t len) { 17 | return CityHash64(reinterpret_cast(key), len); 18 | } 19 | 20 | template 21 | static uint64_t hash_siphash(const T* key, size_t len) { 22 | uint64_t v; 23 | siphash(reinterpret_cast(&v), reinterpret_cast(key), 24 | len, siphash_key); 25 | return v; 26 | } 27 | 28 | template 29 | static uint64_t hash(const T* key, size_t len) { 30 | return hash_cityhash(key, len); 31 | } 32 | } 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/mica/util/latency.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_LATENCY_H_ 3 | #define MICA_UTIL_LATENCY_H_ 4 | 5 | #include 6 | #include 7 | #include "mica/common.h" 8 | #include "mica/util/memcpy.h" 9 | 10 | namespace mica { 11 | namespace util { 12 | class Latency { 13 | public: 14 | Latency() { reset(); } 15 | 16 | void reset() { ::mica::util::memset(this, 0, sizeof(Latency)); } 17 | 18 | void update(uint64_t us) { 19 | if (us < 128) 20 | bin0_[us]++; 21 | else if (us < 384) 22 | bin1_[(us - 128) / 2]++; 23 | else if (us < 896) 24 | bin2_[(us - 384) / 4]++; 25 | else if (us < 1920) 26 | bin3_[(us - 896) / 8]++; 27 | else if (us < 3968) 28 | bin4_[(us - 1920) / 16]++; 29 | else 30 | bin5_++; 31 | } 32 | 33 | Latency& operator+=(const Latency& o) { 34 | uint64_t i; 35 | for (i = 0; i < 128; i++) bin0_[i] += o.bin0_[i]; 36 | for (i = 0; i < 128; i++) bin1_[i] += o.bin1_[i]; 37 | for (i = 0; i < 128; i++) bin2_[i] += o.bin2_[i]; 38 | for (i = 0; i < 128; i++) bin3_[i] += o.bin3_[i]; 39 | for (i = 0; i < 128; i++) bin4_[i] += o.bin4_[i]; 40 | bin5_ += o.bin5_; 41 | return *this; 42 | } 43 | 44 | uint64_t count() const { 45 | uint64_t count = 0; 46 | uint64_t i; 47 | for (i = 0; i < 128; i++) count += bin0_[i]; 48 | for (i = 0; i < 128; i++) count += bin1_[i]; 49 | for (i = 0; i < 128; i++) count += bin2_[i]; 50 | for (i = 0; i < 128; i++) count += bin3_[i]; 51 | for (i = 0; i < 128; i++) count += bin4_[i]; 52 | count += bin5_; 53 | return count; 54 | } 55 | 56 | uint64_t sum() const { 57 | uint64_t sum = 0; 58 | uint64_t i; 59 | for (i = 0; i < 128; i++) sum += bin0_[i] * (0 + i * 1); 60 | for (i = 0; i < 128; i++) sum += bin1_[i] * (128 + i * 2); 61 | for (i = 0; i < 128; i++) sum += bin2_[i] * (384 + i * 4); 62 | for (i = 0; i < 128; i++) sum += bin3_[i] * (896 + i * 8); 63 | for (i = 0; i < 128; i++) sum += bin4_[i] * (1920 + i * 16); 64 | sum += bin5_ * 3968; 65 | return sum; 66 | } 67 | 68 | uint64_t avg() const { return sum() / std::max(uint64_t(1), count()); } 69 | 70 | double avg_f() const { 71 | return static_cast(sum()) / 72 | static_cast(std::max(uint64_t(1), count())); 73 | } 74 | 75 | uint64_t min() const { 76 | uint64_t i; 77 | for (i = 0; i < 128; i++) 78 | if (bin0_[i] != 0) return 0 + i * 1; 79 | for (i = 0; i < 128; i++) 80 | if (bin1_[i] != 0) return 128 + i * 2; 81 | for (i = 0; i < 128; i++) 82 | if (bin2_[i] != 0) return 384 + i * 4; 83 | for (i = 0; i < 128; i++) 84 | if (bin3_[i] != 0) return 896 + i * 8; 85 | for (i = 0; i < 128; i++) 86 | if (bin4_[i] != 0) return 1920 + i * 16; 87 | // if (bin5_ != 0) return 3968; 88 | return 3968; 89 | } 90 | 91 | uint64_t max() const { 92 | int64_t i; 93 | if (bin5_ != 0) return 3968; 94 | for (i = 127; i >= 0; i--) 95 | if (bin4_[i] != 0) return 1920 + static_cast(i) * 16; 96 | for (i = 127; i >= 0; i--) 97 | if (bin3_[i] != 0) return 896 + static_cast(i) * 8; 98 | for (i = 127; i >= 0; i--) 99 | if (bin2_[i] != 0) return 384 + static_cast(i) * 4; 100 | for (i = 127; i >= 0; i--) 101 | if (bin1_[i] != 0) return 128 + static_cast(i) * 2; 102 | for (i = 127; i >= 0; i--) 103 | if (bin0_[i] != 0) return 0 + static_cast(i) * 1; 104 | return 0; 105 | } 106 | 107 | uint64_t perc(double p) const { 108 | uint64_t i; 109 | int64_t thres = static_cast(p * static_cast(count())); 110 | for (i = 0; i < 128; i++) 111 | if ((thres -= static_cast(bin0_[i])) < 0) return 0 + i * 1; 112 | for (i = 0; i < 128; i++) 113 | if ((thres -= static_cast(bin1_[i])) < 0) return 128 + i * 2; 114 | for (i = 0; i < 128; i++) 115 | if ((thres -= static_cast(bin2_[i])) < 0) return 384 + i * 4; 116 | for (i = 0; i < 128; i++) 117 | if ((thres -= static_cast(bin3_[i])) < 0) return 896 + i * 8; 118 | for (i = 0; i < 128; i++) 119 | if ((thres -= static_cast(bin4_[i])) < 0) return 1920 + i * 16; 120 | return 3968; 121 | } 122 | 123 | void print(FILE* fp) const { 124 | uint64_t i; 125 | for (i = 0; i < 128; i++) 126 | if (bin0_[i] != 0) 127 | fprintf(fp, "%4" PRIu64 " %6" PRIu64 "\n", 0 + i * 1, bin0_[i]); 128 | for (i = 0; i < 128; i++) 129 | if (bin1_[i] != 0) 130 | fprintf(fp, "%4" PRIu64 " %6" PRIu64 "\n", 128 + i * 2, bin1_[i]); 131 | for (i = 0; i < 128; i++) 132 | if (bin2_[i] != 0) 133 | fprintf(fp, "%4" PRIu64 " %6" PRIu64 "\n", 384 + i * 4, bin2_[i]); 134 | for (i = 0; i < 128; i++) 135 | if (bin3_[i] != 0) 136 | fprintf(fp, "%4" PRIu64 " %6" PRIu64 "\n", 896 + i * 8, bin3_[i]); 137 | for (i = 0; i < 128; i++) 138 | if (bin4_[i] != 0) 139 | fprintf(fp, "%4" PRIu64 " %6" PRIu64 "\n", 1920 + i * 16, bin4_[i]); 140 | if (bin5_ != 0) fprintf(fp, "%4d %6" PRIu64 "\n", 3968, bin5_); 141 | } 142 | 143 | private: 144 | // [0, 128) us 145 | uint64_t bin0_[128]; 146 | // [128, 384) us 147 | uint64_t bin1_[128]; 148 | // [384, 896) us 149 | uint64_t bin2_[128]; 150 | // [896, 1920) us 151 | uint64_t bin3_[128]; 152 | // [1920, 3968) us 153 | uint64_t bin4_[128]; 154 | // [3968, inf) us 155 | uint64_t bin5_; 156 | }; 157 | } 158 | } 159 | 160 | #endif -------------------------------------------------------------------------------- /src/mica/util/lcore.cc: -------------------------------------------------------------------------------- 1 | // #pragma once 2 | #ifndef MICA_UTIL_LCORE_CC_ 3 | #define MICA_UTIL_LCORE_CC_ 4 | 5 | #include "mica/common.h" 6 | #include 7 | #include 8 | #include 9 | #ifdef USE_DPDK 10 | #include 11 | #include 12 | #endif 13 | #include "mica/util/lcore.h" 14 | 15 | namespace mica { 16 | namespace util { 17 | thread_local size_t LCore::this_lcore_id_ = LCore::kUnknown; 18 | 19 | LCore::LCore() { 20 | numa_count_ = static_cast(numa_num_configured_nodes()); 21 | 22 | for (auto i = 0; i < numa_num_configured_cpus(); i++) { 23 | lcore_to_numa_id_.push_back(static_cast(numa_node_of_cpu(i))); 24 | #ifndef NDEBUG 25 | // printf("LCore %d -> NUMA %zu\n", i, lcore_to_numa_id_[i]); 26 | #endif 27 | } 28 | } 29 | 30 | void LCore::pin_thread(size_t lcore_id) const { 31 | // #ifndef USE_DPDK 32 | cpu_set_t cpuset; 33 | 34 | CPU_ZERO(&cpuset); 35 | CPU_SET(lcore_id, &cpuset); 36 | 37 | auto s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); 38 | if (s != 0) { 39 | fprintf(stderr, "error: could not set affinity\n"); 40 | assert(false); 41 | return; 42 | } 43 | // #else 44 | // if (rte_lcore_id() != lcore_id) { 45 | // fprintf( 46 | // stderr, 47 | // "error: cannot pin the thread to a different lcore while using 48 | // DPDK\n"); 49 | // assert(false); 50 | // return; 51 | // } 52 | // if (lcore_to_numa_id_[lcore_id] != 53 | // rte_lcore_to_socket_id(static_cast(lcore_id))) { 54 | // fprintf(stderr, 55 | // "error: numactl and DPDK have inconsistent lcore-to-socket " 56 | // "mappings\n"); 57 | // } 58 | // #endif 59 | 60 | this_lcore_id_ = lcore_id; 61 | } 62 | 63 | const LCore lcore; 64 | } 65 | } 66 | 67 | #endif -------------------------------------------------------------------------------- /src/mica/util/lcore.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_LCORE_H_ 3 | #define MICA_UTIL_LCORE_H_ 4 | 5 | #include 6 | #include 7 | #include 8 | #include "mica/common.h" 9 | 10 | namespace mica { 11 | namespace util { 12 | class LCore { 13 | public: 14 | LCore(); 15 | 16 | static constexpr size_t kUnknown = std::numeric_limits::max(); 17 | 18 | size_t numa_count() const { return numa_count_; } 19 | size_t lcore_count() const { return lcore_to_numa_id_.size(); } 20 | 21 | size_t numa_id(size_t lcore_id) const { 22 | assert(lcore_id < lcore_count()); 23 | return lcore_to_numa_id_[lcore_id]; 24 | } 25 | 26 | size_t numa_id() const { return numa_id(lcore_id()); } 27 | 28 | size_t lcore_id() const { return this_lcore_id_; } 29 | 30 | void pin_thread(size_t lcore_id) const; 31 | 32 | private: 33 | std::vector lcore_to_numa_id_; 34 | size_t numa_count_; 35 | static thread_local size_t this_lcore_id_; 36 | }; 37 | 38 | extern const LCore lcore; 39 | } 40 | } 41 | 42 | #endif -------------------------------------------------------------------------------- /src/mica/util/memcpy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_MEMCPY_H_ 3 | #define MICA_UTIL_MEMCPY_H_ 4 | 5 | #include 6 | #include 7 | #include "mica/common.h" 8 | #include "mica/util/rte_memcpy/rte_memcpy_mod.h" 9 | #include "mica/util/roundup.h" 10 | 11 | namespace mica { 12 | namespace util { 13 | static void memset(void* dest, int c, size_t n) { ::memset(dest, c, n); } 14 | 15 | static void memcpy(void* dest, const void* src, size_t n) { 16 | ::mica::util::rte_memcpy_func(dest, src, n); 17 | } 18 | 19 | static void memmove(void* dest, const void* src, size_t n) { ::memmove(dest, src, n); } 20 | 21 | static int memcmp(const void* a, const void* b, size_t n) { return ::memcmp(a, b, n); } 22 | 23 | static bool memcmp_equal(const void* a, const void* b, size_t n) { 24 | return ::memcmp(a, b, n) == 0; 25 | } 26 | 27 | // Wrappers for any pointer. 28 | template 29 | void memset(T* dest, int c, size_t n) { 30 | ::mica::util::memset(reinterpret_cast(dest), c, n); 31 | } 32 | 33 | template 34 | void memcpy(T1* dest, const T2* src, size_t n) { 35 | ::mica::util::memcpy(reinterpret_cast(dest), 36 | reinterpret_cast(src), n); 37 | } 38 | 39 | template 40 | void memmove(T1* dest, const T2* src, size_t n) { 41 | ::mica::util::memmove(reinterpret_cast(dest), 42 | reinterpret_cast(src), n); 43 | } 44 | 45 | template 46 | int memcmp(const T1* a, const T2* b, size_t n) { 47 | return ::mica::util::memcmp(reinterpret_cast(a), 48 | reinterpret_cast(b), n); 49 | } 50 | 51 | template 52 | bool memcmp_equal(const T1* a, const T2* b, size_t n) { 53 | return ::mica::util::memcmp_equal(reinterpret_cast(a), 54 | reinterpret_cast(b), n); 55 | } 56 | 57 | template 58 | void memset(T* dest, int c, size_t n) { 59 | assert(n == ::mica::util::roundup(n)); 60 | assert(reinterpret_cast(dest) % Alignment == 0); 61 | ::mica::util::memset(dest, c, n); 62 | } 63 | 64 | template 65 | void memcpy(T1* dest, const T2* src, size_t n) { 66 | assert(n == ::mica::util::roundup(n)); 67 | assert(reinterpret_cast(dest) % Alignment == 0); 68 | assert(reinterpret_cast(src) % Alignment == 0); 69 | if (Alignment == 8) { 70 | switch (n >> 3) { 71 | case 4: 72 | *(uint64_t*)(reinterpret_cast(dest) + 24) = 73 | *(const uint64_t*)(reinterpret_cast(src) + 24); 74 | // fall-through 75 | case 3: 76 | *(uint64_t*)(reinterpret_cast(dest) + 16) = 77 | *(const uint64_t*)(reinterpret_cast(src) + 16); 78 | // fall-through 79 | case 2: 80 | *(uint64_t*)(reinterpret_cast(dest) + 8) = 81 | *(const uint64_t*)(reinterpret_cast(src) + 8); 82 | // fall-through 83 | case 1: 84 | *(uint64_t*)(reinterpret_cast(dest) + 0) = 85 | *(const uint64_t*)(reinterpret_cast(src) + 0); 86 | // fall-through 87 | case 0: 88 | break; 89 | default: 90 | ::mica::util::memcpy(dest, src, n); 91 | break; 92 | } 93 | } else 94 | ::mica::util::memcpy(dest, src, n); 95 | } 96 | 97 | template 98 | void memmove(T1* dest, const T2* src, size_t n) { 99 | assert(n == ::mica::util::roundup(n)); 100 | assert(reinterpret_cast(dest) % Alignment == 0); 101 | assert(reinterpret_cast(src) % Alignment == 0); 102 | ::mica::util::memmove(dest, src, n); 103 | } 104 | 105 | template 106 | int memcmp(const T1* a, const T2* b, size_t n) { 107 | assert(n == ::mica::util::roundup(n)); 108 | assert(reinterpret_cast(a) % Alignment == 0); 109 | assert(reinterpret_cast(b) % Alignment == 0); 110 | return ::mica::util::memcmp(a, b, n); 111 | } 112 | 113 | template 114 | bool memcmp_equal(const T1* a, const T2* b, size_t n) { 115 | assert(n == ::mica::util::roundup(n)); 116 | assert(reinterpret_cast(a) % Alignment == 0); 117 | assert(reinterpret_cast(b) % Alignment == 0); 118 | // printf("%p %p %zu\n", a, b, n); 119 | if (Alignment == 8) { 120 | switch (n >> 3) { 121 | case 4: 122 | if (*reinterpret_cast( 123 | reinterpret_cast(a) + 24) != 124 | *reinterpret_cast( 125 | reinterpret_cast(b) + 24)) 126 | return false; 127 | // fall-through 128 | case 3: 129 | if (*reinterpret_cast( 130 | reinterpret_cast(a) + 16) != 131 | *reinterpret_cast( 132 | reinterpret_cast(b) + 16)) 133 | return false; 134 | // fall-through 135 | case 2: 136 | if (*reinterpret_cast( 137 | reinterpret_cast(a) + 8) != 138 | *reinterpret_cast( 139 | reinterpret_cast(b) + 8)) 140 | return false; 141 | // fall-through 142 | case 1: 143 | if (*reinterpret_cast( 144 | reinterpret_cast(a) + 0) != 145 | *reinterpret_cast( 146 | reinterpret_cast(b) + 0)) 147 | return false; 148 | // fall-through 149 | case 0: 150 | return true; 151 | default: 152 | return ::mica::util::memcmp_equal(a, b, n); 153 | } 154 | } else 155 | return ::mica::util::memcmp_equal(a, b, n); 156 | } 157 | } 158 | } 159 | 160 | #endif -------------------------------------------------------------------------------- /src/mica/util/philox/philox_random.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2015 Google Inc. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | ==============================================================================*/ 15 | 16 | // Implement the Philox algorithm to generate random numbers in parallel. 17 | // Salmon et al. SC 2011. Parallel random numbers: as easy as 1, 2, 3. 18 | // http://www.thesalmons.org/john/random123/papers/random123sc11.pdf 19 | 20 | #ifndef TENSORFLOW_LIB_RANDOM_PHILOX_RANDOM_H_ 21 | #define TENSORFLOW_LIB_RANDOM_PHILOX_RANDOM_H_ 22 | 23 | #include 24 | 25 | //#include "tensorflow/core/platform/types.h" 26 | #include "mica/common.h" 27 | 28 | // Function qualifiers that need to work on both CPU and GPU. 29 | #if defined(__CUDACC__) 30 | // For nvcc. 31 | #define PHILOX_DEVICE_FUNC __host__ __device__ 32 | #define PHILOX_INLINE __inline__ 33 | #else 34 | // For non-nvcc. 35 | #define PHILOX_DEVICE_FUNC 36 | #define PHILOX_INLINE inline 37 | #endif 38 | #define PHILOX_DEVICE_INLINE PHILOX_DEVICE_FUNC PHILOX_INLINE 39 | 40 | #include 41 | 42 | namespace tensorflow { 43 | namespace random { 44 | 45 | typedef uint32_t uint32; 46 | typedef uint64_t uint64; 47 | 48 | // A class that represents an inline array. It can be used on both CPU and GPU, 49 | // and also trivially copyable between CPU and GPU. 50 | // Arguments: 51 | // T: the array element type; 52 | // ElementCount: the fixed size of the array; 53 | template 54 | class Array { 55 | public: 56 | PHILOX_DEVICE_INLINE Array() { 57 | for (int i = 0; i < ElementCount; ++i) { 58 | data_[i] = T(); 59 | } 60 | } 61 | 62 | PHILOX_DEVICE_INLINE const T& operator[](int index) const { 63 | return data_[index]; 64 | } 65 | 66 | PHILOX_DEVICE_INLINE T& operator[](int index) { return data_[index]; } 67 | 68 | size_t size() const { return ElementCount; } 69 | 70 | private: 71 | T data_[ElementCount]; 72 | }; 73 | 74 | // A class that encapsulates all the states for a random number generator using 75 | // the philox_4x32_10 algorithm. Each invocation returns a 128-bit random bits 76 | // in the form of four uint32. 77 | // There are multiple variants of this algorithm, we picked the 4x32_10 version 78 | // that is most suited for our applications. 79 | // Since this class is meant to be copied between CPU to GPU, it maintains a 80 | // value semantics. 81 | // 82 | // For example: To use this class and populate an array of 1024 randoms on CPU 83 | // with two threads, 84 | // 85 | // void Fill(PhiloxRandom rnd, uint32* output, int start, int limit) { 86 | // assert(start % 4 == 0); 87 | // assert(limit % 4 == 0); 88 | // rnd.Skip(start / 4); 89 | // for (int i = start; i < limit; i += 4) { 90 | // auto sample = rnd(); 91 | // ... copy sample[0..3] to output[i..i+3] 92 | // } 93 | // } 94 | // 95 | // PhiloxRandom rng(seed); 96 | // PhiloxRandom rng_copy = rng; 97 | // rng.Skip(1000/4); 98 | // 99 | // ... schedule Fill(rng_copy, output, 0, 512) in thread 1; 100 | // ... schedule Fill(rng_copy, output, 512, 1024) in thread 2; 101 | // ... wait for thread 1 & 2 to finish executing Fill(). 102 | // 103 | // NOTE: 104 | // 1. PhiloxRandom is trivially copyable. 105 | // 2. PhiloxRandom is compilable by gcc and nvcc. 106 | class PhiloxRandom { 107 | public: 108 | typedef Array ResultType; 109 | typedef uint32 ResultElementType; 110 | // The number of elements that will be returned. 111 | static const int kResultElementCount = 4; 112 | // Cost of generation of a single element (in cycles). 113 | static const int kElementCost = 10; 114 | 115 | PHILOX_DEVICE_INLINE 116 | PhiloxRandom() {} 117 | 118 | PHILOX_DEVICE_INLINE 119 | explicit PhiloxRandom(uint64 seed) { 120 | key_[0] = static_cast(seed); 121 | key_[1] = static_cast(seed >> 32); 122 | } 123 | 124 | PHILOX_DEVICE_INLINE 125 | explicit PhiloxRandom(uint64 seed_lo, uint64 seed_hi) { 126 | key_[0] = static_cast(seed_lo); 127 | key_[1] = static_cast(seed_lo >> 32); 128 | counter_[2] = static_cast(seed_hi); 129 | counter_[3] = static_cast(seed_hi >> 32); 130 | } 131 | 132 | // Skip the specified number of samples of 128-bits in the current stream. 133 | PHILOX_DEVICE_INLINE 134 | void Skip(uint64 count) { 135 | const uint32 count_lo = static_cast(count); 136 | uint32 count_hi = static_cast(count >> 32); 137 | 138 | counter_[0] += count_lo; 139 | if (counter_[0] < count_lo) { 140 | ++count_hi; 141 | } 142 | 143 | counter_[1] += count_hi; 144 | if (counter_[1] < count_hi) { 145 | if (++counter_[2] == 0) { 146 | ++counter_[3]; 147 | } 148 | } 149 | } 150 | 151 | // Returns a group of four random numbers using the underlying Philox 152 | // algorithm. 153 | PHILOX_DEVICE_INLINE ResultType operator()() { 154 | ResultType counter = counter_; 155 | Key key = key_; 156 | 157 | // Run the single rounds for ten times. Manually unrolling the loop 158 | // for better performance. 159 | counter = ComputeSingleRound(counter, key); 160 | RaiseKey(&key); 161 | counter = ComputeSingleRound(counter, key); 162 | RaiseKey(&key); 163 | counter = ComputeSingleRound(counter, key); 164 | RaiseKey(&key); 165 | counter = ComputeSingleRound(counter, key); 166 | RaiseKey(&key); 167 | counter = ComputeSingleRound(counter, key); 168 | RaiseKey(&key); 169 | counter = ComputeSingleRound(counter, key); 170 | RaiseKey(&key); 171 | counter = ComputeSingleRound(counter, key); 172 | RaiseKey(&key); 173 | counter = ComputeSingleRound(counter, key); 174 | RaiseKey(&key); 175 | counter = ComputeSingleRound(counter, key); 176 | RaiseKey(&key); 177 | counter = ComputeSingleRound(counter, key); 178 | 179 | SkipOne(); 180 | 181 | return counter; 182 | } 183 | 184 | private: 185 | // The type for the 64-bit key stored in the form of two 32-bit uint 186 | // that are used in the diffusion process. 187 | typedef Array Key; 188 | 189 | // We use the same constants as recommended by the original paper. 190 | static const uint32 kPhiloxW32A = 0x9E3779B9; 191 | static const uint32 kPhiloxW32B = 0xBB67AE85; 192 | static const uint32 kPhiloxM4x32A = 0xD2511F53; 193 | static const uint32 kPhiloxM4x32B = 0xCD9E8D57; 194 | 195 | // Helper function to skip the next sample of 128-bits in the current stream. 196 | PHILOX_DEVICE_INLINE void SkipOne() { 197 | if (++counter_[0] == 0) { 198 | if (++counter_[1] == 0) { 199 | if (++counter_[2] == 0) { 200 | ++counter_[3]; 201 | } 202 | } 203 | } 204 | } 205 | 206 | // Helper function to return the lower and higher 32-bits from two 32-bit 207 | // integer multiplications. 208 | PHILOX_DEVICE_INLINE 209 | static void MultiplyHighLow(uint32 a, uint32 b, uint32* result_low, 210 | uint32* result_high) { 211 | #ifndef __GCUDACC__ 212 | const uint64 product = static_cast(a) * b; 213 | *result_low = static_cast(product); 214 | *result_high = static_cast(product >> 32); 215 | #else 216 | *result_low = a * b; 217 | *result_high = __umulhi(a, b); 218 | #endif 219 | } 220 | 221 | // Helper function for a single round of the underlying Philox algorithm. 222 | PHILOX_DEVICE_INLINE static ResultType ComputeSingleRound( 223 | const ResultType& counter, const Key& key) { 224 | uint32 lo0; 225 | uint32 hi0; 226 | MultiplyHighLow(kPhiloxM4x32A, counter[0], &lo0, &hi0); 227 | 228 | uint32 lo1; 229 | uint32 hi1; 230 | MultiplyHighLow(kPhiloxM4x32B, counter[2], &lo1, &hi1); 231 | 232 | ResultType result; 233 | result[0] = hi1 ^ counter[1] ^ key[0]; 234 | result[1] = lo1; 235 | result[2] = hi0 ^ counter[3] ^ key[1]; 236 | result[3] = lo0; 237 | return result; 238 | } 239 | 240 | PHILOX_DEVICE_INLINE void RaiseKey(Key* key) { 241 | (*key)[0] += kPhiloxW32A; 242 | (*key)[1] += kPhiloxW32B; 243 | } 244 | 245 | private: 246 | ResultType counter_; 247 | Key key_; 248 | }; 249 | 250 | } // namespace random 251 | } // namespace tensorflow 252 | 253 | #endif // TENSORFLOW_LIB_RANDOM_PHILOX_RANDOM_H_ 254 | -------------------------------------------------------------------------------- /src/mica/util/queue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_QUEUE_H_ 3 | #define MICA_UTIL_QUEUE_H_ 4 | 5 | #include "mica/common.h" 6 | #include 7 | #include "mica/util/barrier.h" 8 | 9 | namespace mica { 10 | namespace util { 11 | template 13 | class Queue { 14 | public: 15 | Queue() : head_lock_(0), head_(0), tail_lock_(0), tail_(0) {} 16 | 17 | bool approximate_empty() const { 18 | ::mica::util::memory_barrier(); 19 | return head_ == tail_; 20 | } 21 | 22 | size_t approximate_size() const { 23 | ::mica::util::memory_barrier(); 24 | size_t head = head_; 25 | size_t tail = tail_; 26 | size_t size = tail - head; 27 | if (size > Capacity) size += Capacity; 28 | return size; 29 | } 30 | 31 | bool enqueue(const T& v) { 32 | if (MultipleProducer) 33 | while (!__sync_bool_compare_and_swap(&tail_lock_, 0, 1)) 34 | ::mica::util::pause(); 35 | 36 | size_t tail = tail_; 37 | size_t tail_next = tail + 1; 38 | if (tail_next == Capacity) tail_next = 0; 39 | 40 | // Full? 41 | if (tail_next == head_) { 42 | if (MultipleProducer) { 43 | tail_lock_ = 0; 44 | ::mica::util::memory_barrier(); 45 | } 46 | return false; 47 | } 48 | 49 | items_[tail] = v; 50 | tail_ = tail_next; 51 | 52 | if (MultipleProducer) { 53 | tail_lock_ = 0; 54 | ::mica::util::memory_barrier(); 55 | } 56 | return true; 57 | } 58 | 59 | bool dequeue(T* out_v) { 60 | if (MultipleConsumer) 61 | while (!__sync_bool_compare_and_swap(&head_lock_, 0, 1)) 62 | ::mica::util::pause(); 63 | 64 | size_t head = head_; 65 | size_t head_next = head + 1; 66 | if (head_next == Capacity) head_next = 0; 67 | 68 | // Empty? 69 | if (head == tail_) { 70 | if (MultipleConsumer) { 71 | head_lock_ = 0; 72 | ::mica::util::memory_barrier(); 73 | } 74 | return false; 75 | } 76 | 77 | *out_v = items_[head]; 78 | head_ = head_next; 79 | 80 | if (MultipleConsumer) { 81 | head_lock_ = 0; 82 | ::mica::util::memory_barrier(); 83 | } 84 | return true; 85 | } 86 | 87 | private: 88 | volatile uint8_t head_lock_ __attribute__((aligned(128))); 89 | size_t head_; 90 | 91 | volatile uint8_t tail_lock_ __attribute__((aligned(128))); 92 | size_t tail_; 93 | 94 | std::array items_ __attribute__((aligned(128))); 95 | } __attribute__((aligned(128))); 96 | 97 | template 98 | class SingleThreadedQueue { 99 | public: 100 | SingleThreadedQueue() : head_(0), tail_(0) {} 101 | 102 | bool empty() const { return head_ == tail_; } 103 | 104 | bool full() const { 105 | size_t tail_next = tail_ + 1; 106 | if (tail_next == Capacity) tail_next = 0; 107 | return tail_next == head_; 108 | } 109 | 110 | size_t size() const { 111 | size_t size = tail_ - head_; 112 | if (size > Capacity) size += Capacity; 113 | return size; 114 | } 115 | 116 | const T& head() const { return items_[head_]; } 117 | 118 | // The user must check empty() and read or copy head() before calling 119 | // pop_head(). 120 | void pop_head() { 121 | if (++head_ == Capacity) head_ = 0; 122 | } 123 | 124 | T& tail() { return items_[tail_]; } 125 | 126 | // The user must check full() and write to tail() before calling push_tail(). 127 | void push_tail() { 128 | if (++tail_ == Capacity) tail_ = 0; 129 | } 130 | 131 | private: 132 | size_t head_; 133 | size_t tail_; 134 | std::array items_; 135 | }; 136 | } 137 | } 138 | 139 | #endif 140 | -------------------------------------------------------------------------------- /src/mica/util/rand.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_RAND_H_ 3 | #define MICA_UTIL_RAND_H_ 4 | 5 | #include 6 | #include "mica/common.h" 7 | 8 | namespace mica { 9 | namespace util { 10 | class Rand { 11 | public: 12 | explicit Rand() : state_(0) {} 13 | explicit Rand(uint64_t seed) : state_(seed) { assert(seed < (1UL << 48)); } 14 | Rand(const Rand& o) : state_(o.state_) {} 15 | Rand& operator=(const Rand& o) { 16 | state_ = o.state_; 17 | return *this; 18 | } 19 | 20 | uint32_t next_u32() { 21 | // same as Java's 22 | state_ = (state_ * 0x5deece66dUL + 0xbUL) & ((1UL << 48) - 1); 23 | return (uint32_t)(state_ >> (48 - 32)); 24 | } 25 | 26 | double next_f64() { 27 | // caution: this is maybe too non-random 28 | state_ = (state_ * 0x5deece66dUL + 0xbUL) & ((1UL << 48) - 1); 29 | return (double)state_ / (double)((1UL << 48) - 1); 30 | } 31 | 32 | private: 33 | uint64_t state_; 34 | }; 35 | } 36 | } 37 | 38 | #endif -------------------------------------------------------------------------------- /src/mica/util/rand_pcg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_RAND_PCG_H_ 3 | #define MICA_UTIL_RAND_PCG_H_ 4 | 5 | #include 6 | #include "mica/common.h" 7 | #pragma GCC diagnostic push 8 | #pragma GCC diagnostic ignored "-Wunused-but-set-parameter" 9 | #include "mica/util/pcg/pcg_random.hpp" 10 | #pragma GCC diagnostic pop 11 | 12 | namespace mica { 13 | namespace util { 14 | class RandPCG { 15 | public: 16 | explicit RandPCG() : state_(0) {} 17 | explicit RandPCG(uint64_t seed) : state_(seed) { assert(seed < (1UL << 63)); } 18 | RandPCG(const RandPCG& o) : state_(o.state_) {} 19 | RandPCG& operator=(const RandPCG& o) { 20 | state_ = o.state_; 21 | return *this; 22 | } 23 | 24 | uint32_t next_u32() { return state_(); } 25 | 26 | double next_f64() { return next_u32() / (double)((1UL << 32) - 1); } 27 | 28 | private: 29 | // pcg32 state_; 30 | pcg32_oneseq state_; 31 | // pcg32_fast state_; 32 | }; 33 | } 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /src/mica/util/rand_philox.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_RAND_PHILOX_H_ 3 | #define MICA_UTIL_RAND_PHILOX_H_ 4 | 5 | #include "mica/common.h" 6 | #include "mica/util/philox/philox_random.h" 7 | 8 | namespace mica { 9 | namespace util { 10 | class RandPhilox { 11 | public: 12 | explicit RandPhilox() : state_(0), result_(), i_(0) {} 13 | explicit RandPhilox(uint64_t seed) : state_(seed), result_(), i_(0) {} 14 | RandPhilox(const RandPhilox& o) 15 | : state_(o.state_), result_(o.result_), i_(o.i_) {} 16 | RandPhilox& operator=(const RandPhilox& o) { 17 | state_ = o.state_; 18 | result_ = o.result_; 19 | i_ = o.i_; 20 | return *this; 21 | } 22 | 23 | uint32_t next_u32() { 24 | if (!i_) { 25 | result_ = state_(); 26 | i_ = 4; 27 | } 28 | return result_[--i_]; 29 | } 30 | 31 | double next_f64() { return next_u32() / (double)((1UL << 32) - 1); } 32 | 33 | private: 34 | ::tensorflow::random::PhiloxRandom state_; 35 | ::tensorflow::random::PhiloxRandom::ResultType result_; 36 | int i_; 37 | }; 38 | } 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/error/en.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ERROR_EN_H__ 16 | #define RAPIDJSON_ERROR_EN_H__ 17 | 18 | #include "error.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | 22 | //! Maps error code of parsing into error message. 23 | /*! 24 | \ingroup RAPIDJSON_ERRORS 25 | \param parseErrorCode Error code obtained in parsing. 26 | \return the error message. 27 | \note User can make a copy of this function for localization. 28 | Using switch-case is safer for future modification of error codes. 29 | */ 30 | inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { 31 | switch (parseErrorCode) { 32 | case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); 33 | 34 | case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); 35 | case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values."); 36 | 37 | case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); 38 | 39 | case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); 40 | case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); 41 | case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); 42 | 43 | case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); 44 | 45 | case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); 46 | case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); 47 | case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); 48 | case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); 49 | case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); 50 | 51 | case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); 52 | case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); 53 | case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); 54 | 55 | case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); 56 | case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); 57 | 58 | default: 59 | return RAPIDJSON_ERROR_STRING("Unknown error."); 60 | } 61 | } 62 | 63 | RAPIDJSON_NAMESPACE_END 64 | 65 | #endif // RAPIDJSON_ERROR_EN_H__ 66 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/error/error.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ERROR_ERROR_H__ 16 | #define RAPIDJSON_ERROR_ERROR_H__ 17 | 18 | #include "../rapidjson.h" 19 | 20 | /*! \file error.h */ 21 | 22 | /*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ 23 | 24 | /////////////////////////////////////////////////////////////////////////////// 25 | // RAPIDJSON_ERROR_CHARTYPE 26 | 27 | //! Character type of error messages. 28 | /*! \ingroup RAPIDJSON_ERRORS 29 | The default character type is \c char. 30 | On Windows, user can define this macro as \c TCHAR for supporting both 31 | unicode/non-unicode settings. 32 | */ 33 | #ifndef RAPIDJSON_ERROR_CHARTYPE 34 | #define RAPIDJSON_ERROR_CHARTYPE char 35 | #endif 36 | 37 | /////////////////////////////////////////////////////////////////////////////// 38 | // RAPIDJSON_ERROR_STRING 39 | 40 | //! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. 41 | /*! \ingroup RAPIDJSON_ERRORS 42 | By default this conversion macro does nothing. 43 | On Windows, user can define this macro as \c _T(x) for supporting both 44 | unicode/non-unicode settings. 45 | */ 46 | #ifndef RAPIDJSON_ERROR_STRING 47 | #define RAPIDJSON_ERROR_STRING(x) x 48 | #endif 49 | 50 | RAPIDJSON_NAMESPACE_BEGIN 51 | 52 | /////////////////////////////////////////////////////////////////////////////// 53 | // ParseErrorCode 54 | 55 | //! Error code of parsing. 56 | /*! \ingroup RAPIDJSON_ERRORS 57 | \see GenericReader::Parse, GenericReader::GetParseErrorCode 58 | */ 59 | enum ParseErrorCode { 60 | kParseErrorNone = 0, //!< No error. 61 | 62 | kParseErrorDocumentEmpty, //!< The document is empty. 63 | kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. 64 | 65 | kParseErrorValueInvalid, //!< Invalid value. 66 | 67 | kParseErrorObjectMissName, //!< Missing a name for object member. 68 | kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. 69 | kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. 70 | 71 | kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. 72 | 73 | kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. 74 | kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. 75 | kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. 76 | kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. 77 | kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. 78 | 79 | kParseErrorNumberTooBig, //!< Number too big to be stored in double. 80 | kParseErrorNumberMissFraction, //!< Miss fraction part in number. 81 | kParseErrorNumberMissExponent, //!< Miss exponent in number. 82 | 83 | kParseErrorTermination, //!< Parsing was terminated. 84 | kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. 85 | }; 86 | 87 | //! Result of parsing (wraps ParseErrorCode) 88 | /*! 89 | \ingroup RAPIDJSON_ERRORS 90 | \code 91 | Document doc; 92 | ParseResult ok = doc.Parse("[42]"); 93 | if (!ok) { 94 | fprintf(stderr, "JSON parse error: %s (%u)", 95 | GetParseError_En(ok.Code()), ok.Offset()); 96 | exit(EXIT_FAILURE); 97 | } 98 | \endcode 99 | \see GenericReader::Parse, GenericDocument::Parse 100 | */ 101 | struct ParseResult { 102 | 103 | //! Default constructor, no error. 104 | ParseResult() : code_(kParseErrorNone), offset_(0) {} 105 | //! Constructor to set an error. 106 | ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} 107 | 108 | //! Get the error code. 109 | ParseErrorCode Code() const { return code_; } 110 | //! Get the error offset, if \ref IsError(), 0 otherwise. 111 | size_t Offset() const { return offset_; } 112 | 113 | //! Conversion to \c bool, returns \c true, iff !\ref IsError(). 114 | operator bool() const { return !IsError(); } 115 | //! Whether the result is an error. 116 | bool IsError() const { return code_ != kParseErrorNone; } 117 | 118 | bool operator==(const ParseResult& that) const { return code_ == that.code_; } 119 | bool operator==(ParseErrorCode code) const { return code_ == code; } 120 | friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } 121 | 122 | //! Reset error code. 123 | void Clear() { Set(kParseErrorNone); } 124 | //! Update error code and offset. 125 | void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } 126 | 127 | private: 128 | ParseErrorCode code_; 129 | size_t offset_; 130 | }; 131 | 132 | //! Function pointer type of GetParseError(). 133 | /*! \ingroup RAPIDJSON_ERRORS 134 | 135 | This is the prototype for \c GetParseError_X(), where \c X is a locale. 136 | User can dynamically change locale in runtime, e.g.: 137 | \code 138 | GetParseErrorFunc GetParseError = GetParseError_En; // or whatever 139 | const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); 140 | \endcode 141 | */ 142 | typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); 143 | 144 | RAPIDJSON_NAMESPACE_END 145 | 146 | #endif // RAPIDJSON_ERROR_ERROR_H__ 147 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/filereadstream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEREADSTREAM_H_ 16 | #define RAPIDJSON_FILEREADSTREAM_H_ 17 | 18 | #include "rapidjson.h" 19 | #include 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | 23 | //! File byte stream for input using fread(). 24 | /*! 25 | \note implements Stream concept 26 | */ 27 | class FileReadStream { 28 | public: 29 | typedef char Ch; //!< Character type (byte). 30 | 31 | //! Constructor. 32 | /*! 33 | \param fp File pointer opened for read. 34 | \param buffer user-supplied buffer. 35 | \param bufferSize size of buffer in bytes. Must >=4 bytes. 36 | */ 37 | FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 38 | RAPIDJSON_ASSERT(fp_ != 0); 39 | RAPIDJSON_ASSERT(bufferSize >= 4); 40 | Read(); 41 | } 42 | 43 | Ch Peek() const { return *current_; } 44 | Ch Take() { Ch c = *current_; Read(); return c; } 45 | size_t Tell() const { return count_ + static_cast(current_ - buffer_); } 46 | 47 | // Not implemented 48 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 49 | void Flush() { RAPIDJSON_ASSERT(false); } 50 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 51 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 52 | 53 | // For encoding detection only. 54 | const Ch* Peek4() const { 55 | return (current_ + 4 <= bufferLast_) ? current_ : 0; 56 | } 57 | 58 | private: 59 | void Read() { 60 | if (current_ < bufferLast_) 61 | ++current_; 62 | else if (!eof_) { 63 | count_ += readCount_; 64 | readCount_ = fread(buffer_, 1, bufferSize_, fp_); 65 | bufferLast_ = buffer_ + readCount_ - 1; 66 | current_ = buffer_; 67 | 68 | if (readCount_ < bufferSize_) { 69 | buffer_[readCount_] = '\0'; 70 | ++bufferLast_; 71 | eof_ = true; 72 | } 73 | } 74 | } 75 | 76 | std::FILE* fp_; 77 | Ch *buffer_; 78 | size_t bufferSize_; 79 | Ch *bufferLast_; 80 | Ch *current_; 81 | size_t readCount_; 82 | size_t count_; //!< Number of characters read 83 | bool eof_; 84 | }; 85 | 86 | RAPIDJSON_NAMESPACE_END 87 | 88 | #endif // RAPIDJSON_FILESTREAM_H_ 89 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/filewritestream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEWRITESTREAM_H_ 16 | #define RAPIDJSON_FILEWRITESTREAM_H_ 17 | 18 | #include "rapidjson.h" 19 | #include 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | 23 | //! Wrapper of C file stream for input using fread(). 24 | /*! 25 | \note implements Stream concept 26 | */ 27 | class FileWriteStream { 28 | public: 29 | typedef char Ch; //!< Character type. Only support char. 30 | 31 | FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { 32 | RAPIDJSON_ASSERT(fp_ != 0); 33 | } 34 | 35 | void Put(char c) { 36 | if (current_ >= bufferEnd_) 37 | Flush(); 38 | 39 | *current_++ = c; 40 | } 41 | 42 | void PutN(char c, size_t n) { 43 | size_t avail = static_cast(bufferEnd_ - current_); 44 | while (n > avail) { 45 | std::memset(current_, c, avail); 46 | current_ += avail; 47 | Flush(); 48 | n -= avail; 49 | avail = static_cast(bufferEnd_ - current_); 50 | } 51 | 52 | if (n > 0) { 53 | std::memset(current_, c, n); 54 | current_ += n; 55 | } 56 | } 57 | 58 | void Flush() { 59 | if (current_ != buffer_) { 60 | size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); 61 | if (result < static_cast(current_ - buffer_)) { 62 | // failure deliberately ignored at this time 63 | // added to avoid warn_unused_result build errors 64 | } 65 | current_ = buffer_; 66 | } 67 | } 68 | 69 | // Not implemented 70 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 71 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 72 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 73 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 74 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 75 | 76 | private: 77 | // Prohibit copy constructor & assignment operator. 78 | FileWriteStream(const FileWriteStream&); 79 | FileWriteStream& operator=(const FileWriteStream&); 80 | 81 | std::FILE* fp_; 82 | char *buffer_; 83 | char *bufferEnd_; 84 | char *current_; 85 | }; 86 | 87 | //! Implement specialized version of PutN() with memset() for better performance. 88 | template<> 89 | inline void PutN(FileWriteStream& stream, char c, size_t n) { 90 | stream.PutN(c, n); 91 | } 92 | 93 | RAPIDJSON_NAMESPACE_END 94 | 95 | #endif // RAPIDJSON_FILESTREAM_H_ 96 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/internal/dtoa.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | // This is a C++ header-only implementation of Grisu2 algorithm from the publication: 16 | // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with 17 | // integers." ACM Sigplan Notices 45.6 (2010): 233-243. 18 | 19 | #ifndef RAPIDJSON_DTOA_ 20 | #define RAPIDJSON_DTOA_ 21 | 22 | #include "itoa.h" // GetDigitsLut() 23 | #include "diyfp.h" 24 | #include "ieee754.h" 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | namespace internal { 28 | 29 | #ifdef __GNUC__ 30 | RAPIDJSON_DIAG_PUSH 31 | RAPIDJSON_DIAG_OFF(effc++) 32 | #endif 33 | 34 | inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { 35 | while (rest < wp_w && delta - rest >= ten_kappa && 36 | (rest + ten_kappa < wp_w || /// closer 37 | wp_w - rest > rest + ten_kappa - wp_w)) { 38 | buffer[len - 1]--; 39 | rest += ten_kappa; 40 | } 41 | } 42 | 43 | inline unsigned CountDecimalDigit32(uint32_t n) { 44 | // Simple pure C++ implementation was faster than __builtin_clz version in this situation. 45 | if (n < 10) return 1; 46 | if (n < 100) return 2; 47 | if (n < 1000) return 3; 48 | if (n < 10000) return 4; 49 | if (n < 100000) return 5; 50 | if (n < 1000000) return 6; 51 | if (n < 10000000) return 7; 52 | if (n < 100000000) return 8; 53 | // Will not reach 10 digits in DigitGen() 54 | //if (n < 1000000000) return 9; 55 | //return 10; 56 | return 9; 57 | } 58 | 59 | inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { 60 | static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; 61 | const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); 62 | const DiyFp wp_w = Mp - W; 63 | uint32_t p1 = static_cast(Mp.f >> -one.e); 64 | uint64_t p2 = Mp.f & (one.f - 1); 65 | unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] 66 | *len = 0; 67 | 68 | while (kappa > 0) { 69 | uint32_t d = 0; 70 | switch (kappa) { 71 | case 9: d = p1 / 100000000; p1 %= 100000000; break; 72 | case 8: d = p1 / 10000000; p1 %= 10000000; break; 73 | case 7: d = p1 / 1000000; p1 %= 1000000; break; 74 | case 6: d = p1 / 100000; p1 %= 100000; break; 75 | case 5: d = p1 / 10000; p1 %= 10000; break; 76 | case 4: d = p1 / 1000; p1 %= 1000; break; 77 | case 3: d = p1 / 100; p1 %= 100; break; 78 | case 2: d = p1 / 10; p1 %= 10; break; 79 | case 1: d = p1; p1 = 0; break; 80 | default:; 81 | } 82 | if (d || *len) 83 | buffer[(*len)++] = static_cast('0' + static_cast(d)); 84 | kappa--; 85 | uint64_t tmp = (static_cast(p1) << -one.e) + p2; 86 | if (tmp <= delta) { 87 | *K += kappa; 88 | GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); 89 | return; 90 | } 91 | } 92 | 93 | // kappa = 0 94 | for (;;) { 95 | p2 *= 10; 96 | delta *= 10; 97 | char d = static_cast(p2 >> -one.e); 98 | if (d || *len) 99 | buffer[(*len)++] = static_cast('0' + d); 100 | p2 &= one.f - 1; 101 | kappa--; 102 | if (p2 < delta) { 103 | *K += kappa; 104 | GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-static_cast(kappa)]); 105 | return; 106 | } 107 | } 108 | } 109 | 110 | inline void Grisu2(double value, char* buffer, int* length, int* K) { 111 | const DiyFp v(value); 112 | DiyFp w_m, w_p; 113 | v.NormalizedBoundaries(&w_m, &w_p); 114 | 115 | const DiyFp c_mk = GetCachedPower(w_p.e, K); 116 | const DiyFp W = v.Normalize() * c_mk; 117 | DiyFp Wp = w_p * c_mk; 118 | DiyFp Wm = w_m * c_mk; 119 | Wm.f++; 120 | Wp.f--; 121 | DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); 122 | } 123 | 124 | inline char* WriteExponent(int K, char* buffer) { 125 | if (K < 0) { 126 | *buffer++ = '-'; 127 | K = -K; 128 | } 129 | 130 | if (K >= 100) { 131 | *buffer++ = static_cast('0' + static_cast(K / 100)); 132 | K %= 100; 133 | const char* d = GetDigitsLut() + K * 2; 134 | *buffer++ = d[0]; 135 | *buffer++ = d[1]; 136 | } 137 | else if (K >= 10) { 138 | const char* d = GetDigitsLut() + K * 2; 139 | *buffer++ = d[0]; 140 | *buffer++ = d[1]; 141 | } 142 | else 143 | *buffer++ = static_cast('0' + static_cast(K)); 144 | 145 | return buffer; 146 | } 147 | 148 | inline char* Prettify(char* buffer, int length, int k) { 149 | const int kk = length + k; // 10^(kk-1) <= v < 10^kk 150 | 151 | if (length <= kk && kk <= 21) { 152 | // 1234e7 -> 12340000000 153 | for (int i = length; i < kk; i++) 154 | buffer[i] = '0'; 155 | buffer[kk] = '.'; 156 | buffer[kk + 1] = '0'; 157 | return &buffer[kk + 2]; 158 | } 159 | else if (0 < kk && kk <= 21) { 160 | // 1234e-2 -> 12.34 161 | std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); 162 | buffer[kk] = '.'; 163 | return &buffer[length + 1]; 164 | } 165 | else if (-6 < kk && kk <= 0) { 166 | // 1234e-6 -> 0.001234 167 | const int offset = 2 - kk; 168 | std::memmove(&buffer[offset], &buffer[0], static_cast(length)); 169 | buffer[0] = '0'; 170 | buffer[1] = '.'; 171 | for (int i = 2; i < offset; i++) 172 | buffer[i] = '0'; 173 | return &buffer[length + offset]; 174 | } 175 | else if (length == 1) { 176 | // 1e30 177 | buffer[1] = 'e'; 178 | return WriteExponent(kk - 1, &buffer[2]); 179 | } 180 | else { 181 | // 1234e30 -> 1.234e33 182 | std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); 183 | buffer[1] = '.'; 184 | buffer[length + 1] = 'e'; 185 | return WriteExponent(kk - 1, &buffer[0 + length + 2]); 186 | } 187 | } 188 | 189 | inline char* dtoa(double value, char* buffer) { 190 | Double d(value); 191 | if (d.IsZero()) { 192 | if (d.Sign()) 193 | *buffer++ = '-'; // -0.0, Issue #289 194 | buffer[0] = '0'; 195 | buffer[1] = '.'; 196 | buffer[2] = '0'; 197 | return &buffer[3]; 198 | } 199 | else { 200 | if (value < 0) { 201 | *buffer++ = '-'; 202 | value = -value; 203 | } 204 | int length, K; 205 | Grisu2(value, buffer, &length, &K); 206 | return Prettify(buffer, length, K); 207 | } 208 | } 209 | 210 | #ifdef __GNUC__ 211 | RAPIDJSON_DIAG_POP 212 | #endif 213 | 214 | } // namespace internal 215 | RAPIDJSON_NAMESPACE_END 216 | 217 | #endif // RAPIDJSON_DTOA_ 218 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/internal/ieee754.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_IEEE754_ 16 | #define RAPIDJSON_IEEE754_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | class Double { 24 | public: 25 | Double() {} 26 | Double(double d) : d_(d) {} 27 | Double(uint64_t u) : u_(u) {} 28 | 29 | double Value() const { return d_; } 30 | uint64_t Uint64Value() const { return u_; } 31 | 32 | double NextPositiveDouble() const { 33 | RAPIDJSON_ASSERT(!Sign()); 34 | return Double(u_ + 1).Value(); 35 | } 36 | 37 | bool Sign() const { return (u_ & kSignMask) != 0; } 38 | uint64_t Significand() const { return u_ & kSignificandMask; } 39 | int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } 40 | 41 | bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } 42 | bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } 43 | bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } 44 | bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } 45 | 46 | uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } 47 | int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } 48 | uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } 49 | 50 | static unsigned EffectiveSignificandSize(int order) { 51 | if (order >= -1021) 52 | return 53; 53 | else if (order <= -1074) 54 | return 0; 55 | else 56 | return (unsigned)order + 1074; 57 | } 58 | 59 | private: 60 | static const int kSignificandSize = 52; 61 | static const int kExponentBias = 0x3FF; 62 | static const int kDenormalExponent = 1 - kExponentBias; 63 | static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); 64 | static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); 65 | static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); 66 | static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); 67 | 68 | union { 69 | double d_; 70 | uint64_t u_; 71 | }; 72 | }; 73 | 74 | } // namespace internal 75 | RAPIDJSON_NAMESPACE_END 76 | 77 | #endif // RAPIDJSON_IEEE754_ 78 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/internal/meta.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_META_H_ 16 | #define RAPIDJSON_INTERNAL_META_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #ifdef __GNUC__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(effc++) 23 | #endif 24 | #if defined(_MSC_VER) 25 | RAPIDJSON_DIAG_PUSH 26 | RAPIDJSON_DIAG_OFF(6334) 27 | #endif 28 | 29 | #if RAPIDJSON_HAS_CXX11_TYPETRAITS 30 | #include 31 | #endif 32 | 33 | //@cond RAPIDJSON_INTERNAL 34 | RAPIDJSON_NAMESPACE_BEGIN 35 | namespace internal { 36 | 37 | // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching 38 | template struct Void { typedef void Type; }; 39 | 40 | /////////////////////////////////////////////////////////////////////////////// 41 | // BoolType, TrueType, FalseType 42 | // 43 | template struct BoolType { 44 | static const bool Value = Cond; 45 | typedef BoolType Type; 46 | }; 47 | typedef BoolType TrueType; 48 | typedef BoolType FalseType; 49 | 50 | 51 | /////////////////////////////////////////////////////////////////////////////// 52 | // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr 53 | // 54 | 55 | template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; 56 | template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; 57 | template struct SelectIfCond : SelectIfImpl::template Apply {}; 58 | template struct SelectIf : SelectIfCond {}; 59 | 60 | template struct AndExprCond : FalseType {}; 61 | template <> struct AndExprCond : TrueType {}; 62 | template struct OrExprCond : TrueType {}; 63 | template <> struct OrExprCond : FalseType {}; 64 | 65 | template struct BoolExpr : SelectIf::Type {}; 66 | template struct NotExpr : SelectIf::Type {}; 67 | template struct AndExpr : AndExprCond::Type {}; 68 | template struct OrExpr : OrExprCond::Type {}; 69 | 70 | 71 | /////////////////////////////////////////////////////////////////////////////// 72 | // AddConst, MaybeAddConst, RemoveConst 73 | template struct AddConst { typedef const T Type; }; 74 | template struct MaybeAddConst : SelectIfCond {}; 75 | template struct RemoveConst { typedef T Type; }; 76 | template struct RemoveConst { typedef T Type; }; 77 | 78 | 79 | /////////////////////////////////////////////////////////////////////////////// 80 | // IsSame, IsConst, IsMoreConst, IsPointer 81 | // 82 | template struct IsSame : FalseType {}; 83 | template struct IsSame : TrueType {}; 84 | 85 | template struct IsConst : FalseType {}; 86 | template struct IsConst : TrueType {}; 87 | 88 | template 89 | struct IsMoreConst 90 | : AndExpr::Type, typename RemoveConst::Type>, 91 | BoolType::Value >= IsConst::Value> >::Type {}; 92 | 93 | template struct IsPointer : FalseType {}; 94 | template struct IsPointer : TrueType {}; 95 | 96 | /////////////////////////////////////////////////////////////////////////////// 97 | // IsBaseOf 98 | // 99 | #if RAPIDJSON_HAS_CXX11_TYPETRAITS 100 | 101 | template struct IsBaseOf 102 | : BoolType< ::std::is_base_of::value> {}; 103 | 104 | #else // simplified version adopted from Boost 105 | 106 | template struct IsBaseOfImpl { 107 | RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); 108 | RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); 109 | 110 | typedef char (&Yes)[1]; 111 | typedef char (&No) [2]; 112 | 113 | template 114 | static Yes Check(const D*, T); 115 | static No Check(const B*, int); 116 | 117 | struct Host { 118 | operator const B*() const; 119 | operator const D*(); 120 | }; 121 | 122 | enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; 123 | }; 124 | 125 | template struct IsBaseOf 126 | : OrExpr, BoolExpr > >::Type {}; 127 | 128 | #endif // RAPIDJSON_HAS_CXX11_TYPETRAITS 129 | 130 | 131 | ////////////////////////////////////////////////////////////////////////// 132 | // EnableIf / DisableIf 133 | // 134 | template struct EnableIfCond { typedef T Type; }; 135 | template struct EnableIfCond { /* empty */ }; 136 | 137 | template struct DisableIfCond { typedef T Type; }; 138 | template struct DisableIfCond { /* empty */ }; 139 | 140 | template 141 | struct EnableIf : EnableIfCond {}; 142 | 143 | template 144 | struct DisableIf : DisableIfCond {}; 145 | 146 | // SFINAE helpers 147 | struct SfinaeTag {}; 148 | template struct RemoveSfinaeTag; 149 | template struct RemoveSfinaeTag { typedef T Type; }; 150 | 151 | #define RAPIDJSON_REMOVEFPTR_(type) \ 152 | typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ 153 | < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type 154 | 155 | #define RAPIDJSON_ENABLEIF(cond) \ 156 | typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ 157 | ::Type * = NULL 158 | 159 | #define RAPIDJSON_DISABLEIF(cond) \ 160 | typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ 161 | ::Type * = NULL 162 | 163 | #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ 164 | typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ 165 | ::Type 167 | 168 | #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ 169 | typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ 170 | ::Type 172 | 173 | } // namespace internal 174 | RAPIDJSON_NAMESPACE_END 175 | //@endcond 176 | 177 | #if defined(__GNUC__) || defined(_MSC_VER) 178 | RAPIDJSON_DIAG_POP 179 | #endif 180 | 181 | #endif // RAPIDJSON_INTERNAL_META_H_ 182 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/internal/pow10.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_POW10_ 16 | #define RAPIDJSON_POW10_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | //! Computes integer powers of 10 in double (10.0^n). 24 | /*! This function uses lookup table for fast and accurate results. 25 | \param n non-negative exponent. Must <= 308. 26 | \return 10.0^n 27 | */ 28 | inline double Pow10(int n) { 29 | static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes 30 | 1e+0, 31 | 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 32 | 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 33 | 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 34 | 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 35 | 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 36 | 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 37 | 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 38 | 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 39 | 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 40 | 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 41 | 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 42 | 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 43 | 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 44 | 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 45 | 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 46 | 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 47 | }; 48 | RAPIDJSON_ASSERT(n >= 0 && n <= 308); 49 | return e[n]; 50 | } 51 | 52 | } // namespace internal 53 | RAPIDJSON_NAMESPACE_END 54 | 55 | #endif // RAPIDJSON_POW10_ 56 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/internal/stack.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_STACK_H_ 16 | #define RAPIDJSON_INTERNAL_STACK_H_ 17 | 18 | #include "../rapidjson.h" 19 | #include "swap.h" 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | namespace internal { 23 | 24 | /////////////////////////////////////////////////////////////////////////////// 25 | // Stack 26 | 27 | //! A type-unsafe stack for storing different types of data. 28 | /*! \tparam Allocator Allocator for allocating stack memory. 29 | */ 30 | template 31 | class Stack { 32 | public: 33 | // Optimization note: Do not allocate memory for stack_ in constructor. 34 | // Do it lazily when first Push() -> Expand() -> Resize(). 35 | Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { 36 | RAPIDJSON_ASSERT(stackCapacity > 0); 37 | } 38 | 39 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 40 | Stack(Stack&& rhs) 41 | : allocator_(rhs.allocator_), 42 | ownAllocator_(rhs.ownAllocator_), 43 | stack_(rhs.stack_), 44 | stackTop_(rhs.stackTop_), 45 | stackEnd_(rhs.stackEnd_), 46 | initialCapacity_(rhs.initialCapacity_) 47 | { 48 | rhs.allocator_ = 0; 49 | rhs.ownAllocator_ = 0; 50 | rhs.stack_ = 0; 51 | rhs.stackTop_ = 0; 52 | rhs.stackEnd_ = 0; 53 | rhs.initialCapacity_ = 0; 54 | } 55 | #endif 56 | 57 | ~Stack() { 58 | Destroy(); 59 | } 60 | 61 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 62 | Stack& operator=(Stack&& rhs) { 63 | if (&rhs != this) 64 | { 65 | Destroy(); 66 | 67 | allocator_ = rhs.allocator_; 68 | ownAllocator_ = rhs.ownAllocator_; 69 | stack_ = rhs.stack_; 70 | stackTop_ = rhs.stackTop_; 71 | stackEnd_ = rhs.stackEnd_; 72 | initialCapacity_ = rhs.initialCapacity_; 73 | 74 | rhs.allocator_ = 0; 75 | rhs.ownAllocator_ = 0; 76 | rhs.stack_ = 0; 77 | rhs.stackTop_ = 0; 78 | rhs.stackEnd_ = 0; 79 | rhs.initialCapacity_ = 0; 80 | } 81 | return *this; 82 | } 83 | #endif 84 | 85 | void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { 86 | internal::Swap(allocator_, rhs.allocator_); 87 | internal::Swap(ownAllocator_, rhs.ownAllocator_); 88 | internal::Swap(stack_, rhs.stack_); 89 | internal::Swap(stackTop_, rhs.stackTop_); 90 | internal::Swap(stackEnd_, rhs.stackEnd_); 91 | internal::Swap(initialCapacity_, rhs.initialCapacity_); 92 | } 93 | 94 | void Clear() { stackTop_ = stack_; } 95 | 96 | void ShrinkToFit() { 97 | if (Empty()) { 98 | // If the stack is empty, completely deallocate the memory. 99 | Allocator::Free(stack_); 100 | stack_ = 0; 101 | stackTop_ = 0; 102 | stackEnd_ = 0; 103 | } 104 | else 105 | Resize(GetSize()); 106 | } 107 | 108 | // Optimization note: try to minimize the size of this function for force inline. 109 | // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. 110 | template 111 | RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { 112 | // Expand the stack if needed 113 | if (stackTop_ + sizeof(T) * count >= stackEnd_) 114 | Expand(count); 115 | 116 | T* ret = reinterpret_cast(stackTop_); 117 | stackTop_ += sizeof(T) * count; 118 | return ret; 119 | } 120 | 121 | template 122 | T* Pop(size_t count) { 123 | RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); 124 | stackTop_ -= count * sizeof(T); 125 | return reinterpret_cast(stackTop_); 126 | } 127 | 128 | template 129 | T* Top() { 130 | RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); 131 | return reinterpret_cast(stackTop_ - sizeof(T)); 132 | } 133 | 134 | template 135 | T* Bottom() { return (T*)stack_; } 136 | 137 | bool HasAllocator() const { 138 | return allocator_ != 0; 139 | } 140 | 141 | Allocator& GetAllocator() { 142 | RAPIDJSON_ASSERT(allocator_); 143 | return *allocator_; 144 | } 145 | bool Empty() const { return stackTop_ == stack_; } 146 | size_t GetSize() const { return static_cast(stackTop_ - stack_); } 147 | size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } 148 | 149 | private: 150 | template 151 | void Expand(size_t count) { 152 | // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. 153 | size_t newCapacity; 154 | if (stack_ == 0) { 155 | if (!allocator_) 156 | ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); 157 | newCapacity = initialCapacity_; 158 | } else { 159 | newCapacity = GetCapacity(); 160 | newCapacity += (newCapacity + 1) / 2; 161 | } 162 | size_t newSize = GetSize() + sizeof(T) * count; 163 | if (newCapacity < newSize) 164 | newCapacity = newSize; 165 | 166 | Resize(newCapacity); 167 | } 168 | 169 | void Resize(size_t newCapacity) { 170 | const size_t size = GetSize(); // Backup the current size 171 | stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity); 172 | stackTop_ = stack_ + size; 173 | stackEnd_ = stack_ + newCapacity; 174 | } 175 | 176 | void Destroy() { 177 | Allocator::Free(stack_); 178 | RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack 179 | } 180 | 181 | // Prohibit copy constructor & assignment operator. 182 | Stack(const Stack&); 183 | Stack& operator=(const Stack&); 184 | 185 | Allocator* allocator_; 186 | Allocator* ownAllocator_; 187 | char *stack_; 188 | char *stackTop_; 189 | char *stackEnd_; 190 | size_t initialCapacity_; 191 | }; 192 | 193 | } // namespace internal 194 | RAPIDJSON_NAMESPACE_END 195 | 196 | #endif // RAPIDJSON_STACK_H_ 197 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/internal/strfunc.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ 16 | #define RAPIDJSON_INTERNAL_STRFUNC_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | //! Custom strlen() which works on different character types. 24 | /*! \tparam Ch Character type (e.g. char, wchar_t, short) 25 | \param s Null-terminated input string. 26 | \return Number of characters in the string. 27 | \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. 28 | */ 29 | template 30 | inline SizeType StrLen(const Ch* s) { 31 | const Ch* p = s; 32 | while (*p) ++p; 33 | return SizeType(p - s); 34 | } 35 | 36 | } // namespace internal 37 | RAPIDJSON_NAMESPACE_END 38 | 39 | #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ 40 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/internal/swap.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_SWAP_H_ 16 | #define RAPIDJSON_INTERNAL_SWAP_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | //! Custom swap() to avoid dependency on C++ header 24 | /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. 25 | \note This has the same semantics as std::swap(). 26 | */ 27 | template 28 | inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { 29 | T tmp = a; 30 | a = b; 31 | b = tmp; 32 | } 33 | 34 | } // namespace internal 35 | RAPIDJSON_NAMESPACE_END 36 | 37 | #endif // RAPIDJSON_INTERNAL_SWAP_H_ 38 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/memorybuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYBUFFER_H_ 16 | #define RAPIDJSON_MEMORYBUFFER_H_ 17 | 18 | #include "rapidjson.h" 19 | #include "internal/stack.h" 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | 23 | //! Represents an in-memory output byte stream. 24 | /*! 25 | This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. 26 | 27 | It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. 28 | 29 | Differences between MemoryBuffer and StringBuffer: 30 | 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 31 | 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. 32 | 33 | \tparam Allocator type for allocating memory buffer. 34 | \note implements Stream concept 35 | */ 36 | template 37 | struct GenericMemoryBuffer { 38 | typedef char Ch; // byte 39 | 40 | GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 41 | 42 | void Put(Ch c) { *stack_.template Push() = c; } 43 | void Flush() {} 44 | 45 | void Clear() { stack_.Clear(); } 46 | void ShrinkToFit() { stack_.ShrinkToFit(); } 47 | Ch* Push(size_t count) { return stack_.template Push(count); } 48 | void Pop(size_t count) { stack_.template Pop(count); } 49 | 50 | const Ch* GetBuffer() const { 51 | return stack_.template Bottom(); 52 | } 53 | 54 | size_t GetSize() const { return stack_.GetSize(); } 55 | 56 | static const size_t kDefaultCapacity = 256; 57 | mutable internal::Stack stack_; 58 | }; 59 | 60 | typedef GenericMemoryBuffer<> MemoryBuffer; 61 | 62 | //! Implement specialized version of PutN() with memset() for better performance. 63 | template<> 64 | inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { 65 | std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 71 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/memorystream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYSTREAM_H_ 16 | #define RAPIDJSON_MEMORYSTREAM_H_ 17 | 18 | #include "rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | 22 | //! Represents an in-memory input byte stream. 23 | /*! 24 | This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. 25 | 26 | It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. 27 | 28 | Differences between MemoryStream and StringStream: 29 | 1. StringStream has encoding but MemoryStream is a byte stream. 30 | 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. 31 | 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). 32 | \note implements Stream concept 33 | */ 34 | struct MemoryStream { 35 | typedef char Ch; // byte 36 | 37 | MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} 38 | 39 | Ch Peek() const { return (src_ == end_) ? '\0' : *src_; } 40 | Ch Take() { return (src_ == end_) ? '\0' : *src_++; } 41 | size_t Tell() const { return static_cast(src_ - begin_); } 42 | 43 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 44 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 45 | void Flush() { RAPIDJSON_ASSERT(false); } 46 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 47 | 48 | // For encoding detection only. 49 | const Ch* Peek4() const { 50 | return Tell() + 4 <= size_ ? src_ : 0; 51 | } 52 | 53 | const Ch* src_; //!< Current read position. 54 | const Ch* begin_; //!< Original head of the string. 55 | const Ch* end_; //!< End of stream. 56 | size_t size_; //!< Size of the stream. 57 | }; 58 | 59 | RAPIDJSON_NAMESPACE_END 60 | 61 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 62 | -------------------------------------------------------------------------------- /src/mica/util/rapidjson/stringbuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_STRINGBUFFER_H_ 16 | #define RAPIDJSON_STRINGBUFFER_H_ 17 | 18 | #include "rapidjson.h" 19 | 20 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 21 | #include // std::move 22 | #endif 23 | 24 | #include "internal/stack.h" 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Represents an in-memory output stream. 29 | /*! 30 | \tparam Encoding Encoding of the stream. 31 | \tparam Allocator type for allocating memory buffer. 32 | \note implements Stream concept 33 | */ 34 | template 35 | class GenericStringBuffer { 36 | public: 37 | typedef typename Encoding::Ch Ch; 38 | 39 | GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 40 | 41 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 42 | GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} 43 | GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { 44 | if (&rhs != this) 45 | stack_ = std::move(rhs.stack_); 46 | return *this; 47 | } 48 | #endif 49 | 50 | void Put(Ch c) { *stack_.template Push() = c; } 51 | void Flush() {} 52 | 53 | void Clear() { stack_.Clear(); } 54 | void ShrinkToFit() { 55 | // Push and pop a null terminator. This is safe. 56 | *stack_.template Push() = '\0'; 57 | stack_.ShrinkToFit(); 58 | stack_.template Pop(1); 59 | } 60 | Ch* Push(size_t count) { return stack_.template Push(count); } 61 | void Pop(size_t count) { stack_.template Pop(count); } 62 | 63 | const Ch* GetString() const { 64 | // Push and pop a null terminator. This is safe. 65 | *stack_.template Push() = '\0'; 66 | stack_.template Pop(1); 67 | 68 | return stack_.template Bottom(); 69 | } 70 | 71 | size_t GetSize() const { return stack_.GetSize(); } 72 | 73 | static const size_t kDefaultCapacity = 256; 74 | mutable internal::Stack stack_; 75 | 76 | private: 77 | // Prohibit copy constructor & assignment operator. 78 | GenericStringBuffer(const GenericStringBuffer&); 79 | GenericStringBuffer& operator=(const GenericStringBuffer&); 80 | }; 81 | 82 | //! String buffer with UTF8 encoding 83 | typedef GenericStringBuffer > StringBuffer; 84 | 85 | //! Implement specialized version of PutN() with memset() for better performance. 86 | template<> 87 | inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { 88 | std::memset(stream.stack_.Push(n), c, n * sizeof(c)); 89 | } 90 | 91 | RAPIDJSON_NAMESPACE_END 92 | 93 | #endif // RAPIDJSON_STRINGBUFFER_H_ 94 | -------------------------------------------------------------------------------- /src/mica/util/rate_limiter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_RATE_LIMITER_H_ 3 | #define MICA_UTIL_RATE_LIMITER_H_ 4 | 5 | #include "mica/common.h" 6 | #include 7 | #include 8 | #include "mica/util/rand.h" 9 | 10 | namespace mica { 11 | namespace util { 12 | class RateLimiter { 13 | public: 14 | void remove_tokens(double v); 15 | bool try_remove_tokens(double v); 16 | void remove_tokens_nowait(double v); 17 | void add_tokens(double v); 18 | }; 19 | 20 | class RegularRateLimiter : public RateLimiter { 21 | public: 22 | RegularRateLimiter(const Stopwatch& sw, double initial_tokens, 23 | double max_tokens, double new_tokens_per_cycle) 24 | : sw_(sw), 25 | tokens_(initial_tokens), 26 | max_tokens_(max_tokens), 27 | new_tokens_per_cycle_(new_tokens_per_cycle) { 28 | // printf("tokens=%lf\n", tokens_); 29 | // printf("max_tokens=%lf\n", max_tokens_); 30 | // printf("new_tokens_per_cycle=%lf\n", new_tokens_per_cycle); 31 | 32 | last_time_ = sw_.now(); 33 | } 34 | 35 | void remove_tokens(double v) { 36 | while (true) { 37 | update_tokens(); 38 | 39 | if (tokens_ < v) { 40 | ::mica::util::pause(); 41 | continue; 42 | } 43 | 44 | tokens_ -= v; 45 | } 46 | } 47 | 48 | bool try_remove_tokens(double v) { 49 | update_tokens(); 50 | 51 | if (tokens_ < v) return false; 52 | 53 | tokens_ -= v; 54 | return true; 55 | } 56 | 57 | void remove_tokens_nowait(double v) { tokens_ -= v; } 58 | 59 | void add_tokens(double v) { tokens_ += v; } 60 | 61 | private: 62 | void update_tokens() { 63 | uint64_t current_time = sw_.now(); 64 | 65 | double new_cycles = static_cast(current_time - last_time_); 66 | 67 | last_time_ = current_time; 68 | 69 | tokens_ = 70 | std::min(max_tokens_, tokens_ + new_cycles * new_tokens_per_cycle_); 71 | } 72 | 73 | private: 74 | const Stopwatch& sw_; 75 | 76 | double tokens_; 77 | double max_tokens_; 78 | double new_tokens_per_cycle_; 79 | 80 | uint64_t last_time_; 81 | }; 82 | 83 | class ExponentialRateLimiter : public RateLimiter { 84 | public: 85 | ExponentialRateLimiter(const Stopwatch& sw, double initial_tokens, 86 | double max_tokens, double new_tokens_per_cycle, 87 | uint64_t seed) 88 | : sw_(sw), 89 | tokens_(initial_tokens), 90 | max_tokens_(max_tokens), 91 | new_tokens_per_cycle_(new_tokens_per_cycle), 92 | cycles_per_new_token_(1. / new_tokens_per_cycle), 93 | rand_(seed) { 94 | // printf("tokens=%lf\n", tokens_); 95 | // printf("max_tokens=%lf\n", max_tokens_); 96 | // printf("new_tokens_per_cycle=%lf\n", new_tokens_per_cycle); 97 | 98 | last_time_ = sw_.now(); 99 | update_cycles_for_next_token(); 100 | } 101 | 102 | void remove_tokens(double v) { 103 | while (true) { 104 | update_tokens(); 105 | 106 | if (tokens_ < v) { 107 | ::mica::util::pause(); 108 | continue; 109 | } 110 | 111 | tokens_ -= v; 112 | } 113 | } 114 | 115 | bool try_remove_tokens(double v) { 116 | update_tokens(); 117 | 118 | if (tokens_ < v) return false; 119 | 120 | tokens_ -= v; 121 | return true; 122 | } 123 | 124 | void remove_tokens_nowait(double v) { tokens_ -= v; } 125 | 126 | void add_tokens(double v) { tokens_ += v; } 127 | 128 | private: 129 | void update_tokens() { 130 | uint64_t current_time = sw_.now(); 131 | 132 | uint64_t new_cycles = current_time - last_time_; 133 | while (new_cycles >= cycles_for_next_token_) { 134 | tokens_ += 1.; 135 | new_cycles -= cycles_for_next_token_; 136 | last_time_ += cycles_for_next_token_; 137 | 138 | update_cycles_for_next_token(); 139 | 140 | if (tokens_ >= max_tokens_) { 141 | tokens_ = max_tokens_; 142 | last_time_ = current_time; 143 | break; 144 | } 145 | } 146 | } 147 | 148 | void update_cycles_for_next_token() { 149 | double z; 150 | do { 151 | z = rand_.next_f64(); 152 | } while (z >= 1.); 153 | 154 | cycles_for_next_token_ = 155 | static_cast(-cycles_per_new_token_ * log(1. - z)); 156 | } 157 | 158 | private: 159 | const Stopwatch& sw_; 160 | 161 | double tokens_; 162 | double max_tokens_; 163 | double new_tokens_per_cycle_; 164 | 165 | double cycles_per_new_token_; 166 | Rand rand_; 167 | 168 | uint64_t last_time_; 169 | uint64_t cycles_for_next_token_; 170 | }; 171 | } 172 | } 173 | 174 | #endif -------------------------------------------------------------------------------- /src/mica/util/roundup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_ROUNDUP_H_ 3 | #define MICA_UTIL_ROUNDUP_H_ 4 | 5 | #include "mica/common.h" 6 | 7 | namespace mica { 8 | namespace util { 9 | template 10 | static constexpr bool is_power_of_two(T x) { 11 | return x && ((x & T(x - 1)) == 0); 12 | } 13 | 14 | template 15 | static constexpr T roundup(T x) { 16 | static_assert(is_power_of_two(PowerOfTwoNumber), 17 | "PowerOfTwoNumber must be a power of 2"); 18 | return ((x) + T(PowerOfTwoNumber - 1)) & (~T(PowerOfTwoNumber - 1)); 19 | } 20 | 21 | #pragma GCC diagnostic push 22 | #pragma GCC diagnostic ignored "-Winline" 23 | 24 | template 25 | static constexpr T next_power_of_two_recursive(T x, T s) { 26 | return ((T(1) << s) < x) ? next_power_of_two_recursive(x, s + 1) 27 | : (T(1) << s); 28 | } 29 | 30 | template 31 | static constexpr T next_power_of_two(T x) { 32 | // T s(0); 33 | // while ((T(1) << s) < x) s++; 34 | // return T(1) << s; 35 | return next_power_of_two_recursive(x, T(0)); 36 | } 37 | 38 | #pragma GCC diagnostic pop 39 | } 40 | } 41 | 42 | #endif -------------------------------------------------------------------------------- /src/mica/util/safe_cast.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_SAFE_CAST_H_ 3 | #define MICA_UTIL_SAFE_CAST_H_ 4 | 5 | #include 6 | #include 7 | #include 8 | #include "mica/common.h" 9 | #define NEEDS_NULLPTR_DEFINED 0 10 | #include "mica/util/SafeInt/SafeInt3_mod.hpp" 11 | #undef NEEDS_NULLPTR_DEFINED 12 | 13 | namespace mica { 14 | namespace util { 15 | template 16 | static To safe_cast(From x) noexcept { 17 | try { 18 | return static_cast(SafeInt(x)); 19 | } catch (...) { 20 | fprintf(stderr, 21 | "error: unable to cast safely due to an out-of-range error\n"); 22 | assert(false); 23 | return To(0); 24 | } 25 | // return static_cast(x); 26 | } 27 | } 28 | } 29 | 30 | #endif -------------------------------------------------------------------------------- /src/mica/util/siphash/siphash24.c: -------------------------------------------------------------------------------- 1 | /* 2 | SipHash reference C implementation 3 | 4 | Copyright (c) 2012-2014 Jean-Philippe Aumasson 5 | 6 | Copyright (c) 2012-2014 Daniel J. Bernstein 7 | 8 | To the extent possible under law, the author(s) have dedicated all copyright 9 | and related and neighboring rights to this software to the public domain 10 | worldwide. This software is distributed without any warranty. 11 | 12 | You should have received a copy of the CC0 Public Domain Dedication along 13 | with 14 | this software. If not, see 15 | . 16 | */ 17 | #include 18 | #include 19 | #include 20 | 21 | /* default: SipHash-2-4 */ 22 | #define cROUNDS 2 23 | #define dROUNDS 4 24 | 25 | #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) 26 | 27 | #define U32TO8_LE(p, v) \ 28 | (p)[0] = (uint8_t)((v)); \ 29 | (p)[1] = (uint8_t)((v) >> 8); \ 30 | (p)[2] = (uint8_t)((v) >> 16); \ 31 | (p)[3] = (uint8_t)((v) >> 24); 32 | 33 | #define U64TO8_LE(p, v) \ 34 | U32TO8_LE((p), (uint32_t)((v))); \ 35 | U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); 36 | 37 | #define U8TO64_LE(p) \ 38 | (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ 39 | ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ 40 | ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ 41 | ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) 42 | 43 | #define SIPROUND \ 44 | do { \ 45 | v0 += v1; \ 46 | v1 = ROTL(v1, 13); \ 47 | v1 ^= v0; \ 48 | v0 = ROTL(v0, 32); \ 49 | v2 += v3; \ 50 | v3 = ROTL(v3, 16); \ 51 | v3 ^= v2; \ 52 | v0 += v3; \ 53 | v3 = ROTL(v3, 21); \ 54 | v3 ^= v0; \ 55 | v2 += v1; \ 56 | v1 = ROTL(v1, 17); \ 57 | v1 ^= v2; \ 58 | v2 = ROTL(v2, 32); \ 59 | } while (0) 60 | 61 | #ifdef DEBUG 62 | #define TRACE \ 63 | do { \ 64 | printf("(%3d) v0 %08x %08x\n", (int)inlen, (uint32_t)(v0 >> 32), \ 65 | (uint32_t)v0); \ 66 | printf("(%3d) v1 %08x %08x\n", (int)inlen, (uint32_t)(v1 >> 32), \ 67 | (uint32_t)v1); \ 68 | printf("(%3d) v2 %08x %08x\n", (int)inlen, (uint32_t)(v2 >> 32), \ 69 | (uint32_t)v2); \ 70 | printf("(%3d) v3 %08x %08x\n", (int)inlen, (uint32_t)(v3 >> 32), \ 71 | (uint32_t)v3); \ 72 | } while (0) 73 | #else 74 | #define TRACE 75 | #endif 76 | 77 | int siphash(uint8_t *out, const uint8_t *in, uint64_t inlen, const uint8_t *k) { 78 | /* "somepseudorandomlygeneratedbytes" */ 79 | uint64_t v0 = 0x736f6d6570736575ULL; 80 | uint64_t v1 = 0x646f72616e646f6dULL; 81 | uint64_t v2 = 0x6c7967656e657261ULL; 82 | uint64_t v3 = 0x7465646279746573ULL; 83 | uint64_t b; 84 | uint64_t k0 = U8TO64_LE(k); 85 | uint64_t k1 = U8TO64_LE(k + 8); 86 | uint64_t m; 87 | int i; 88 | const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); 89 | const int left = inlen & 7; 90 | b = ((uint64_t)inlen) << 56; 91 | v3 ^= k1; 92 | v2 ^= k0; 93 | v1 ^= k1; 94 | v0 ^= k0; 95 | 96 | #ifdef DOUBLE 97 | v1 ^= 0xee; 98 | #endif 99 | 100 | for (; in != end; in += 8) { 101 | m = U8TO64_LE(in); 102 | v3 ^= m; 103 | 104 | TRACE; 105 | for (i = 0; i < cROUNDS; ++i) 106 | SIPROUND; 107 | 108 | v0 ^= m; 109 | } 110 | 111 | switch (left) { 112 | case 7: 113 | b |= ((uint64_t)in[6]) << 48; 114 | case 6: 115 | b |= ((uint64_t)in[5]) << 40; 116 | case 5: 117 | b |= ((uint64_t)in[4]) << 32; 118 | case 4: 119 | b |= ((uint64_t)in[3]) << 24; 120 | case 3: 121 | b |= ((uint64_t)in[2]) << 16; 122 | case 2: 123 | b |= ((uint64_t)in[1]) << 8; 124 | case 1: 125 | b |= ((uint64_t)in[0]); 126 | break; 127 | case 0: 128 | break; 129 | } 130 | 131 | v3 ^= b; 132 | 133 | TRACE; 134 | for (i = 0; i < cROUNDS; ++i) 135 | SIPROUND; 136 | 137 | v0 ^= b; 138 | 139 | #ifndef DOUBLE 140 | v2 ^= 0xff; 141 | #else 142 | v2 ^= 0xee; 143 | #endif 144 | 145 | TRACE; 146 | for (i = 0; i < dROUNDS; ++i) 147 | SIPROUND; 148 | 149 | b = v0 ^ v1 ^ v2 ^ v3; 150 | U64TO8_LE(out, b); 151 | 152 | #ifdef DOUBLE 153 | v1 ^= 0xdd; 154 | 155 | TRACE; 156 | for (i = 0; i < dROUNDS; ++i) 157 | SIPROUND; 158 | 159 | b = v0 ^ v1 ^ v2 ^ v3; 160 | U64TO8_LE(out + 8, b); 161 | #endif 162 | 163 | return 0; 164 | } 165 | 166 | -------------------------------------------------------------------------------- /src/mica/util/stopwatch.cc: -------------------------------------------------------------------------------- 1 | // #pragma once 2 | #ifndef MICA_UTIL_STOPWATCH_CC_ 3 | #define MICA_UTIL_STOPWATCH_CC_ 4 | 5 | #include "mica/util/stopwatch.h" 6 | #include "mica/util/barrier.h" 7 | 8 | namespace mica { 9 | namespace util { 10 | void Stopwatch::init_start() { 11 | init_t_ = now(); 12 | gettimeofday(&init_tv_, nullptr); 13 | } 14 | 15 | void Stopwatch::init_end() { 16 | struct timeval tv; 17 | 18 | const uint64_t min_time = 100000UL; // 100,000 us = 0.1 sec 19 | 20 | while (true) { 21 | gettimeofday(&tv, nullptr); 22 | 23 | uint64_t diff = 24 | static_cast(tv.tv_sec - init_tv_.tv_sec) * 1000000UL + 25 | static_cast(tv.tv_usec - init_tv_.tv_usec); 26 | 27 | if (diff >= min_time) { 28 | uint64_t t = now(); 29 | c_1_sec_ = (t - init_t_) * min_time * 10 / diff; 30 | c_1_msec_ = c_1_sec_ / 1000; 31 | c_1_usec_ = c_1_msec_ / 1000; 32 | c_1_nsec_ = c_1_usec_ / 1000; 33 | break; 34 | } 35 | 36 | pause(); 37 | } 38 | } 39 | } 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/mica/util/stopwatch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_STOPWATCH_H_ 3 | #define MICA_UTIL_STOPWATCH_H_ 4 | 5 | #include 6 | #include "mica/common.h" 7 | #include "mica/util/tsc.h" 8 | 9 | namespace mica { 10 | namespace util { 11 | class Stopwatch { 12 | public: 13 | void init_start(); 14 | void init_end(); 15 | 16 | uint64_t now() const { return rdtsc(); } 17 | 18 | uint64_t c_1_sec() const { return c_1_sec_; } 19 | uint64_t c_1_msec() const { return c_1_msec_; } 20 | uint64_t c_1_usec() const { return c_1_usec_; } 21 | uint64_t c_1_nsec() const { return c_1_nsec_; } // Usually not very accurate. 22 | 23 | uint64_t diff_in_cycles(uint64_t new_t, uint64_t old_t) const { 24 | return new_t - old_t; 25 | } 26 | 27 | uint64_t diff_in_ms(uint64_t new_t, uint64_t old_t) const { 28 | return (new_t - old_t) * 1000UL / c_1_sec_; 29 | } 30 | 31 | uint64_t diff_in_us(uint64_t new_t, uint64_t old_t) const { 32 | return (new_t - old_t) * 1000000UL / c_1_sec_; 33 | } 34 | 35 | uint64_t diff_in_ns(uint64_t new_t, uint64_t old_t) const { 36 | // XXX: This may overflow! 37 | return (new_t - old_t) * 1000000000UL / c_1_sec_; 38 | } 39 | 40 | double diff(uint64_t new_t, uint64_t old_t) const { 41 | return static_cast(diff_in_cycles(new_t, old_t)) / 42 | static_cast(c_1_sec_); 43 | } 44 | 45 | private: 46 | uint64_t c_1_sec_; 47 | uint64_t c_1_msec_; 48 | uint64_t c_1_usec_; 49 | uint64_t c_1_nsec_; 50 | 51 | struct timeval init_tv_; 52 | uint64_t init_t_; 53 | }; 54 | } 55 | } 56 | 57 | #endif -------------------------------------------------------------------------------- /src/mica/util/tsc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_TSC_H_ 3 | #define MICA_UTIL_TSC_H_ 4 | 5 | #include "mica/common.h" 6 | 7 | namespace mica { 8 | namespace util { 9 | static uint64_t rdtsc() { 10 | uint64_t rax; 11 | uint64_t rdx; 12 | asm volatile("rdtsc" : "=a"(rax), "=d"(rdx)); 13 | return (rdx << 32) | rax; 14 | } 15 | 16 | static uint64_t rdtscp() { 17 | uint64_t rax; 18 | uint64_t rdx; 19 | uint32_t aux; 20 | asm volatile("rdtscp" : "=a"(rax), "=d"(rdx), "=c"(aux) : :); 21 | return (rdx << 32) | rax; 22 | } 23 | } 24 | } 25 | 26 | #endif -------------------------------------------------------------------------------- /src/mica/util/type_traits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_TYPE_TRAITS_H_ 3 | #define MICA_UTIL_TYPE_TRAITS_H_ 4 | 5 | #include 6 | 7 | namespace std { 8 | // Fix compiliers that claim is_trivially_copyable>::value == false. 9 | template 10 | struct is_trivially_copyable> { 11 | static constexpr bool value = is_trivially_copyable::value; 12 | }; 13 | } 14 | 15 | #endif -------------------------------------------------------------------------------- /src/mica/util/zipf.cc: -------------------------------------------------------------------------------- 1 | // #pragma once 2 | #ifndef MICA_UTIL_ZIPF_CC_ 3 | #define MICA_UTIL_ZIPF_CC_ 4 | 5 | #include 6 | #include 7 | #include 8 | #include "mica/util/zipf.h" 9 | 10 | namespace mica { 11 | namespace util { 12 | double ZipfGen::pow_approx(double a, double b) { 13 | // from 14 | // http://martin.ankerl.com/2012/01/25/optimized-approximative-pow-in-c-and-cpp/ 15 | 16 | // calculate approximation with fraction of the exponent 17 | int e = (int)b; 18 | union { 19 | double d; 20 | int x[2]; 21 | } u = {a}; 22 | u.x[1] = (int)((b - (double)e) * (double)(u.x[1] - 1072632447) + 1072632447.); 23 | u.x[0] = 0; 24 | 25 | // exponentiation by squaring with the exponent's integer part 26 | // double r = u.d makes everything much slower, not sure why 27 | // TODO: use popcount? 28 | double r = 1.; 29 | while (e) { 30 | if (e & 1) r *= a; 31 | a *= a; 32 | e >>= 1; 33 | } 34 | 35 | return r * u.d; 36 | } 37 | 38 | ZipfGen::ZipfGen(uint64_t n, double theta, uint64_t rand_seed) { 39 | assert(n > 0); 40 | if (theta > 0.992 && theta < 1) 41 | fprintf(stderr, 42 | "warning: theta > 0.992 will be inaccurate due to approximation\n"); 43 | if (theta >= 1. && theta < 40.) { 44 | fprintf(stderr, "error: theta in [1., 40.) is not supported\n"); 45 | assert(false); 46 | theta_ = 0; // unused 47 | alpha_ = 0; // unused 48 | thres_ = 0; // unused 49 | return; 50 | } 51 | assert(theta == -1. || (theta >= 0. && theta < 1.) || theta >= 40.); 52 | n_ = n; 53 | theta_ = theta; 54 | if (theta == -1.) { 55 | seq_ = rand_seed % n; 56 | alpha_ = 0; // unused 57 | thres_ = 0; // unused 58 | } else if (theta > 0. && theta < 1.) { 59 | seq_ = 0; // unused 60 | alpha_ = 1. / (1. - theta); 61 | thres_ = 1. + pow_approx(0.5, theta); 62 | } else { 63 | seq_ = 0; // unused 64 | alpha_ = 0.; // unused 65 | thres_ = 0.; // unused 66 | } 67 | last_n_ = 0; 68 | zetan_ = 0.; 69 | eta_ = 0; 70 | // rand_state_[0] = (unsigned short)(rand_seed >> 0); 71 | // rand_state_[1] = (unsigned short)(rand_seed >> 16); 72 | // rand_state_[2] = (unsigned short)(rand_seed >> 32); 73 | rand_ = Rand(rand_seed); 74 | } 75 | 76 | ZipfGen::ZipfGen(const ZipfGen& src) { 77 | n_ = src.n_; 78 | theta_ = src.theta_; 79 | alpha_ = src.alpha_; 80 | thres_ = src.thres_; 81 | last_n_ = src.last_n_; 82 | dbl_n_ = src.dbl_n_; 83 | zetan_ = src.zetan_; 84 | eta_ = src.eta_; 85 | seq_ = src.seq_; 86 | rand_ = src.rand_; 87 | } 88 | 89 | ZipfGen::ZipfGen(const ZipfGen& src, uint64_t rand_seed) { 90 | n_ = src.n_; 91 | theta_ = src.theta_; 92 | alpha_ = src.alpha_; 93 | thres_ = src.thres_; 94 | last_n_ = src.last_n_; 95 | dbl_n_ = src.dbl_n_; 96 | zetan_ = src.zetan_; 97 | eta_ = src.eta_; 98 | seq_ = src.seq_; 99 | rand_ = Rand(rand_seed); 100 | } 101 | 102 | ZipfGen& ZipfGen::operator=(const ZipfGen& src) { 103 | n_ = src.n_; 104 | theta_ = src.theta_; 105 | alpha_ = src.alpha_; 106 | thres_ = src.thres_; 107 | last_n_ = src.last_n_; 108 | dbl_n_ = src.dbl_n_; 109 | zetan_ = src.zetan_; 110 | eta_ = src.eta_; 111 | seq_ = src.seq_; 112 | rand_ = src.rand_; 113 | return *this; 114 | } 115 | 116 | void ZipfGen::change_n(uint64_t n) { n_ = n; } 117 | 118 | double ZipfGen::zeta(uint64_t last_n, double last_sum, uint64_t n, 119 | double theta) { 120 | if (last_n > n) { 121 | last_n = 0; 122 | last_sum = 0.; 123 | } 124 | while (last_n < n) { 125 | last_sum += 1. / pow_approx((double)last_n + 1., theta); 126 | last_n++; 127 | } 128 | return last_sum; 129 | } 130 | 131 | uint64_t ZipfGen::next() { 132 | if (last_n_ != n_) { 133 | if (theta_ > 0. && theta_ < 1.) { 134 | zetan_ = zeta(last_n_, zetan_, n_, theta_); 135 | eta_ = (1. - pow_approx(2. / (double)n_, 1. - theta_)) / 136 | (1. - zeta(0, 0., 2, theta_) / zetan_); 137 | } 138 | last_n_ = n_; 139 | dbl_n_ = (double)n_; 140 | } 141 | 142 | if (theta_ == -1.) { 143 | uint64_t v = seq_; 144 | if (++seq_ >= n_) seq_ = 0; 145 | return v; 146 | } else if (theta_ == 0.) { 147 | double u = rand_.next_f64(); 148 | return (uint64_t)(dbl_n_ * u); 149 | } else if (theta_ >= 40.) { 150 | return 0UL; 151 | } else { 152 | // from J. Gray et al. Quickly generating billion-record synthetic 153 | // databases. In SIGMOD, 1994. 154 | 155 | // double u = erand48(rand_state_); 156 | double u = rand_.next_f64(); 157 | double uz = u * zetan_; 158 | if (uz < 1.) 159 | return 0UL; 160 | else if (uz < thres_) 161 | return 1UL; 162 | else { 163 | uint64_t v = 164 | (uint64_t)(dbl_n_ * pow_approx(eta_ * (u - 1.) + 1., alpha_)); 165 | if (v >= n_) v = n_ - 1; 166 | return v; 167 | } 168 | } 169 | } 170 | 171 | void ZipfGen::test(double theta) { 172 | double zetan = 0.; 173 | const uint64_t n = 1000000UL; 174 | uint64_t i; 175 | 176 | for (i = 0; i < n; i++) zetan += 1. / pow((double)i + 1., theta); 177 | 178 | if (theta < 1. || theta >= 40.) { 179 | ZipfGen zg(n, theta, 0); 180 | 181 | uint64_t num_key0 = 0; 182 | const uint64_t num_samples = 10000000UL; 183 | if (theta < 1. || theta >= 40.) { 184 | for (i = 0; i < num_samples; i++) 185 | if (zg.next() == 0) num_key0++; 186 | } 187 | 188 | printf("theta = %lf; using pow(): %.10lf", theta, 1. / zetan); 189 | if (theta < 1. || theta >= 40.) 190 | printf(", using approx-pow(): %.10lf", 191 | (double)num_key0 / (double)num_samples); 192 | printf("\n"); 193 | } 194 | } 195 | } 196 | } 197 | 198 | #endif -------------------------------------------------------------------------------- /src/mica/util/zipf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICA_UTIL_ZIPF_H_ 3 | #define MICA_UTIL_ZIPF_H_ 4 | 5 | #include "mica/common.h" 6 | #include "mica/util/rand.h" 7 | 8 | namespace mica { 9 | namespace util { 10 | class ZipfGen { 11 | public: 12 | ZipfGen(uint64_t n, double theta, uint64_t rand_seed); 13 | ZipfGen(const ZipfGen& src); 14 | ZipfGen(const ZipfGen& src, uint64_t rand_seed); 15 | ZipfGen& operator=(const ZipfGen& src); 16 | 17 | void change_n(uint64_t n); 18 | uint64_t next(); 19 | 20 | static void test(double theta); 21 | 22 | private: 23 | static double pow_approx(double a, double b); 24 | 25 | static double zeta(uint64_t last_n, double last_sum, uint64_t n, 26 | double theta); 27 | 28 | uint64_t n_; // number of items (input) 29 | double 30 | theta_; // skewness (input) in (0, 1); or, 0 = uniform, 1 = always zero 31 | double alpha_; // only depends on theta 32 | double thres_; // only depends on theta 33 | uint64_t last_n_; // last n used to calculate the following 34 | double dbl_n_; 35 | double zetan_; 36 | double eta_; 37 | // unsigned short rand_state[3]; // prng state 38 | uint64_t seq_; // for sequential number generation 39 | Rand rand_; 40 | } __attribute__((aligned(128))); // To prevent false sharing caused by 41 | // adjacent cacheline prefetching. 42 | } 43 | } 44 | 45 | #endif --------------------------------------------------------------------------------