Add bunch of redis files
Files are taken from redis commit e84ccc3f566f78344b098c3eef6e371653bc311b We need low-level redis datastructures for encoding values that are not strings, i.e. lists, sets, zsets etc.
This commit is contained in:
parent
55ee0563b0
commit
b1b0213cd2
|
@ -25,4 +25,5 @@ include_directories(helio)
|
|||
|
||||
add_subdirectory(helio)
|
||||
add_subdirectory(core)
|
||||
add_subdirectory(redis)
|
||||
add_subdirectory(server)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
add_library(redis_lib endianconv.c intset.c listpack.c object.c
|
||||
lzf_c.c lzf_d.c sds.c sha256.c
|
||||
quicklist.c util.c zmalloc.c)
|
||||
|
||||
cxx_link(redis_lib)
|
|
@ -0,0 +1,10 @@
|
|||
Copyright (c) 2006-2020, Salvatore Sanfilippo
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Redis nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,158 @@
|
|||
/* This file implements atomic counters using c11 _Atomic, __atomic or __sync
|
||||
* macros if available, otherwise we will throw an error when compile.
|
||||
*
|
||||
* The exported interface is composed of three macros:
|
||||
*
|
||||
* atomicIncr(var,count) -- Increment the atomic counter
|
||||
* atomicGetIncr(var,oldvalue_var,count) -- Get and increment the atomic counter
|
||||
* atomicDecr(var,count) -- Decrement the atomic counter
|
||||
* atomicGet(var,dstvar) -- Fetch the atomic counter value
|
||||
* atomicSet(var,value) -- Set the atomic counter value
|
||||
* atomicGetWithSync(var,value) -- 'atomicGet' with inter-thread synchronization
|
||||
* atomicSetWithSync(var,value) -- 'atomicSet' with inter-thread synchronization
|
||||
*
|
||||
* Never use return value from the macros, instead use the AtomicGetIncr()
|
||||
* if you need to get the current value and increment it atomically, like
|
||||
* in the following example:
|
||||
*
|
||||
* long oldvalue;
|
||||
* atomicGetIncr(myvar,oldvalue,1);
|
||||
* doSomethingWith(oldvalue);
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include "config.h"
|
||||
|
||||
#ifndef __ATOMIC_VAR_H
|
||||
#define __ATOMIC_VAR_H
|
||||
|
||||
/* Define redisAtomic for atomic variable. */
|
||||
#define redisAtomic
|
||||
|
||||
/* To test Redis with Helgrind (a Valgrind tool) it is useful to define
|
||||
* the following macro, so that __sync macros are used: those can be detected
|
||||
* by Helgrind (even if they are less efficient) so that no false positive
|
||||
* is reported. */
|
||||
// #define __ATOMIC_VAR_FORCE_SYNC_MACROS
|
||||
|
||||
/* There will be many false positives if we test Redis with Helgrind, since
|
||||
* Helgrind can't understand we have imposed ordering on the program, so
|
||||
* we use macros in helgrind.h to tell Helgrind inter-thread happens-before
|
||||
* relationship explicitly for avoiding false positives.
|
||||
*
|
||||
* For more details, please see: valgrind/helgrind.h and
|
||||
* https://www.valgrind.org/docs/manual/hg-manual.html#hg-manual.effective-use
|
||||
*
|
||||
* These macros take effect only when 'make helgrind', and you must first
|
||||
* install Valgrind in the default path configuration. */
|
||||
#ifdef __ATOMIC_VAR_FORCE_SYNC_MACROS
|
||||
#include <valgrind/helgrind.h>
|
||||
#else
|
||||
#define ANNOTATE_HAPPENS_BEFORE(v) ((void) v)
|
||||
#define ANNOTATE_HAPPENS_AFTER(v) ((void) v)
|
||||
#endif
|
||||
|
||||
#if !defined(__ATOMIC_VAR_FORCE_SYNC_MACROS) && defined(__STDC_VERSION__) && \
|
||||
(__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__)
|
||||
/* Use '_Atomic' keyword if the compiler supports. */
|
||||
#undef redisAtomic
|
||||
#define redisAtomic _Atomic
|
||||
/* Implementation using _Atomic in C11. */
|
||||
|
||||
#include <stdatomic.h>
|
||||
#define atomicIncr(var,count) atomic_fetch_add_explicit(&var,(count),memory_order_relaxed)
|
||||
#define atomicGetIncr(var,oldvalue_var,count) do { \
|
||||
oldvalue_var = atomic_fetch_add_explicit(&var,(count),memory_order_relaxed); \
|
||||
} while(0)
|
||||
#define atomicDecr(var,count) atomic_fetch_sub_explicit(&var,(count),memory_order_relaxed)
|
||||
#define atomicGet(var,dstvar) do { \
|
||||
dstvar = atomic_load_explicit(&var,memory_order_relaxed); \
|
||||
} while(0)
|
||||
#define atomicSet(var,value) atomic_store_explicit(&var,value,memory_order_relaxed)
|
||||
#define atomicGetWithSync(var,dstvar) do { \
|
||||
dstvar = atomic_load_explicit(&var,memory_order_seq_cst); \
|
||||
} while(0)
|
||||
#define atomicSetWithSync(var,value) \
|
||||
atomic_store_explicit(&var,value,memory_order_seq_cst)
|
||||
#define REDIS_ATOMIC_API "c11-builtin"
|
||||
|
||||
#elif !defined(__ATOMIC_VAR_FORCE_SYNC_MACROS) && \
|
||||
(!defined(__clang__) || !defined(__APPLE__) || __apple_build_version__ > 4210057) && \
|
||||
defined(__ATOMIC_RELAXED) && defined(__ATOMIC_SEQ_CST)
|
||||
/* Implementation using __atomic macros. */
|
||||
|
||||
#define atomicIncr(var,count) __atomic_add_fetch(&var,(count),__ATOMIC_RELAXED)
|
||||
#define atomicGetIncr(var,oldvalue_var,count) do { \
|
||||
oldvalue_var = __atomic_fetch_add(&var,(count),__ATOMIC_RELAXED); \
|
||||
} while(0)
|
||||
#define atomicDecr(var,count) __atomic_sub_fetch(&var,(count),__ATOMIC_RELAXED)
|
||||
#define atomicGet(var,dstvar) do { \
|
||||
dstvar = __atomic_load_n(&var,__ATOMIC_RELAXED); \
|
||||
} while(0)
|
||||
#define atomicSet(var,value) __atomic_store_n(&var,value,__ATOMIC_RELAXED)
|
||||
#define atomicGetWithSync(var,dstvar) do { \
|
||||
dstvar = __atomic_load_n(&var,__ATOMIC_SEQ_CST); \
|
||||
} while(0)
|
||||
#define atomicSetWithSync(var,value) \
|
||||
__atomic_store_n(&var,value,__ATOMIC_SEQ_CST)
|
||||
#define REDIS_ATOMIC_API "atomic-builtin"
|
||||
|
||||
#elif defined(HAVE_ATOMIC)
|
||||
/* Implementation using __sync macros. */
|
||||
|
||||
#define atomicIncr(var,count) __sync_add_and_fetch(&var,(count))
|
||||
#define atomicGetIncr(var,oldvalue_var,count) do { \
|
||||
oldvalue_var = __sync_fetch_and_add(&var,(count)); \
|
||||
} while(0)
|
||||
#define atomicDecr(var,count) __sync_sub_and_fetch(&var,(count))
|
||||
#define atomicGet(var,dstvar) do { \
|
||||
dstvar = __sync_sub_and_fetch(&var,0); \
|
||||
} while(0)
|
||||
#define atomicSet(var,value) do { \
|
||||
while(!__sync_bool_compare_and_swap(&var,var,value)); \
|
||||
} while(0)
|
||||
/* Actually the builtin issues a full memory barrier by default. */
|
||||
#define atomicGetWithSync(var,dstvar) { \
|
||||
dstvar = __sync_sub_and_fetch(&var,0,__sync_synchronize); \
|
||||
ANNOTATE_HAPPENS_AFTER(&var); \
|
||||
} while(0)
|
||||
#define atomicSetWithSync(var,value) do { \
|
||||
ANNOTATE_HAPPENS_BEFORE(&var); \
|
||||
while(!__sync_bool_compare_and_swap(&var,var,value,__sync_synchronize)); \
|
||||
} while(0)
|
||||
#define REDIS_ATOMIC_API "sync-builtin"
|
||||
|
||||
#else
|
||||
#error "Unable to determine atomic operations for your platform"
|
||||
|
||||
#endif
|
||||
#endif /* __ATOMIC_VAR_H */
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_H
|
||||
#define __CONFIG_H
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <AvailabilityMacros.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <features.h>
|
||||
#endif
|
||||
|
||||
/* Define redis_fstat to fstat or fstat64() */
|
||||
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
|
||||
#define redis_fstat fstat64
|
||||
#define redis_stat stat64
|
||||
#else
|
||||
#define redis_fstat fstat
|
||||
#define redis_stat stat
|
||||
#endif
|
||||
|
||||
/* Test for proc filesystem */
|
||||
#ifdef __linux__
|
||||
#define HAVE_PROC_STAT 1
|
||||
#define HAVE_PROC_MAPS 1
|
||||
#define HAVE_PROC_SMAPS 1
|
||||
#define HAVE_PROC_SOMAXCONN 1
|
||||
#define HAVE_PROC_OOM_SCORE_ADJ 1
|
||||
#endif
|
||||
|
||||
/* Test for task_info() */
|
||||
#if defined(__APPLE__)
|
||||
#define HAVE_TASKINFO 1
|
||||
#endif
|
||||
|
||||
/* Test for backtrace() */
|
||||
#if defined(__APPLE__) || (defined(__linux__) && defined(__GLIBC__)) || \
|
||||
defined(__FreeBSD__) || ((defined(__OpenBSD__) || defined(__NetBSD__)) && defined(USE_BACKTRACE))\
|
||||
|| defined(__DragonFly__) || (defined(__UCLIBC__) && defined(__UCLIBC_HAS_BACKTRACE__))
|
||||
#define HAVE_BACKTRACE 1
|
||||
#endif
|
||||
|
||||
/* MSG_NOSIGNAL. */
|
||||
#ifdef __linux__
|
||||
#define HAVE_MSG_NOSIGNAL 1
|
||||
#endif
|
||||
|
||||
/* Test for polling API */
|
||||
#ifdef __linux__
|
||||
#define HAVE_EPOLL 1
|
||||
#endif
|
||||
|
||||
#if (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__)
|
||||
#define HAVE_KQUEUE 1
|
||||
#endif
|
||||
|
||||
#ifdef __sun
|
||||
#include <sys/feature_tests.h>
|
||||
#ifdef _DTRACE_VERSION
|
||||
#define HAVE_EVPORT 1
|
||||
#define HAVE_PSINFO 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define redis_fsync to fdatasync() in Linux and fsync() for all the rest */
|
||||
#ifdef __linux__
|
||||
#define redis_fsync fdatasync
|
||||
#else
|
||||
#define redis_fsync fsync
|
||||
#endif
|
||||
|
||||
#if __GNUC__ >= 4
|
||||
#define redis_unreachable __builtin_unreachable
|
||||
#else
|
||||
#define redis_unreachable abort
|
||||
#endif
|
||||
#if __GNUC__ >= 3
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define likely(x) (x)
|
||||
#define unlikely(x) (x)
|
||||
#endif
|
||||
|
||||
/* Define rdb_fsync_range to sync_file_range() on Linux, otherwise we use
|
||||
* the plain fsync() call. */
|
||||
#if (defined(__linux__) && defined(SYNC_FILE_RANGE_WAIT_BEFORE))
|
||||
#define rdb_fsync_range(fd,off,size) sync_file_range(fd,off,size,SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE)
|
||||
#else
|
||||
#define rdb_fsync_range(fd,off,size) fsync(fd)
|
||||
#endif
|
||||
|
||||
/* Check if we can use setproctitle().
|
||||
* BSD systems have support for it, we provide an implementation for
|
||||
* Linux and osx. */
|
||||
#if (defined __NetBSD__ || defined __FreeBSD__ || defined __OpenBSD__)
|
||||
#define USE_SETPROCTITLE
|
||||
#endif
|
||||
|
||||
#if defined(__HAIKU__)
|
||||
#define ESOCKTNOSUPPORT 0
|
||||
#endif
|
||||
|
||||
#if (defined __linux || defined __APPLE__)
|
||||
#define USE_SETPROCTITLE
|
||||
#define INIT_SETPROCTITLE_REPLACEMENT
|
||||
void spt_init(int argc, char *argv[]);
|
||||
void setproctitle(const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
/* Byte ordering detection */
|
||||
#include <sys/types.h> /* This will likely define BYTE_ORDER */
|
||||
|
||||
#ifndef BYTE_ORDER
|
||||
#if (BSD >= 199103)
|
||||
# include <machine/endian.h>
|
||||
#else
|
||||
#if defined(linux) || defined(__linux__)
|
||||
# include <endian.h>
|
||||
#else
|
||||
#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */
|
||||
#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */
|
||||
#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp)*/
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__amd64__) || \
|
||||
defined(vax) || defined(ns32000) || defined(sun386) || \
|
||||
defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
|
||||
defined(__alpha__) || defined(__alpha)
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
|
||||
defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
|
||||
defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
|
||||
defined(apollo) || defined(__convex__) || defined(_CRAY) || \
|
||||
defined(__hppa) || defined(__hp9000) || \
|
||||
defined(__hp9000s300) || defined(__hp9000s700) || \
|
||||
defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc)
|
||||
#define BYTE_ORDER BIG_ENDIAN
|
||||
#endif
|
||||
#endif /* linux */
|
||||
#endif /* BSD */
|
||||
#endif /* BYTE_ORDER */
|
||||
|
||||
/* Sometimes after including an OS-specific header that defines the
|
||||
* endianness we end with __BYTE_ORDER but not with BYTE_ORDER that is what
|
||||
* the Redis code uses. In this case let's define everything without the
|
||||
* underscores. */
|
||||
#ifndef BYTE_ORDER
|
||||
#ifdef __BYTE_ORDER
|
||||
#if defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
|
||||
#ifndef LITTLE_ENDIAN
|
||||
#define LITTLE_ENDIAN __LITTLE_ENDIAN
|
||||
#endif
|
||||
#ifndef BIG_ENDIAN
|
||||
#define BIG_ENDIAN __BIG_ENDIAN
|
||||
#endif
|
||||
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
#else
|
||||
#define BYTE_ORDER BIG_ENDIAN
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(BYTE_ORDER) || \
|
||||
(BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN)
|
||||
/* you must determine what the correct bit order is for
|
||||
* your compiler - the next line is an intentional error
|
||||
* which will force your compiles to bomb until you fix
|
||||
* the above macros.
|
||||
*/
|
||||
#error "Undefined or invalid BYTE_ORDER"
|
||||
#endif
|
||||
|
||||
#if (__i386 || __amd64 || __powerpc__) && __GNUC__
|
||||
#define GNUC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||
#if defined(__clang__)
|
||||
#define HAVE_ATOMIC
|
||||
#endif
|
||||
#if (defined(__GLIBC__) && defined(__GLIBC_PREREQ))
|
||||
#if (GNUC_VERSION >= 40100 && __GLIBC_PREREQ(2, 6))
|
||||
#define HAVE_ATOMIC
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Make sure we can test for ARM just checking for __arm__, since sometimes
|
||||
* __arm is defined but __arm__ is not. */
|
||||
#if defined(__arm) && !defined(__arm__)
|
||||
#define __arm__
|
||||
#endif
|
||||
#if defined (__aarch64__) && !defined(__arm64__)
|
||||
#define __arm64__
|
||||
#endif
|
||||
|
||||
/* Make sure we can test for SPARC just checking for __sparc__. */
|
||||
#if defined(__sparc) && !defined(__sparc__)
|
||||
#define __sparc__
|
||||
#endif
|
||||
|
||||
#if defined(__sparc__) || defined(__arm__)
|
||||
#define USE_ALIGNED_ACCESS
|
||||
#endif
|
||||
|
||||
/* Define for redis_set_thread_title */
|
||||
#ifdef __linux__
|
||||
#define redis_set_thread_title(name) pthread_setname_np(pthread_self(), name)
|
||||
#else
|
||||
#if (defined __FreeBSD__ || defined __OpenBSD__)
|
||||
#include <pthread_np.h>
|
||||
#define redis_set_thread_title(name) pthread_set_name_np(pthread_self(), name)
|
||||
#elif defined __NetBSD__
|
||||
#include <pthread.h>
|
||||
#define redis_set_thread_title(name) pthread_setname_np(pthread_self(), "%s", name)
|
||||
#elif defined __HAIKU__
|
||||
#include <kernel/OS.h>
|
||||
#define redis_set_thread_title(name) rename_thread(find_thread(0), name)
|
||||
#else
|
||||
#if (defined __APPLE__ && defined(MAC_OS_X_VERSION_10_7))
|
||||
int pthread_setname_np(const char *name);
|
||||
#include <pthread.h>
|
||||
#define redis_set_thread_title(name) pthread_setname_np(name)
|
||||
#else
|
||||
#define redis_set_thread_title(name)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Check if we can use setcpuaffinity(). */
|
||||
#if (defined __linux || defined __NetBSD__ || defined __FreeBSD__ || defined __DragonFly__)
|
||||
#define USE_SETCPUAFFINITY
|
||||
void setcpuaffinity(const char *cpulist);
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,201 @@
|
|||
/* Hash Tables Implementation.
|
||||
*
|
||||
* This file implements in-memory hash tables with insert/del/replace/find/
|
||||
* get-random-element operations. Hash tables will auto-resize if needed
|
||||
* tables of power of two in size are used, collisions are handled by
|
||||
* chaining. See the source code for more information... :)
|
||||
*
|
||||
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __DICT_H
|
||||
#define __DICT_H
|
||||
|
||||
#include "mt19937-64.h"
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DICT_OK 0
|
||||
#define DICT_ERR 1
|
||||
|
||||
/* Unused arguments generate annoying warnings... */
|
||||
#define DICT_NOTUSED(V) ((void) V)
|
||||
|
||||
typedef struct dictEntry {
|
||||
void *key;
|
||||
union {
|
||||
void *val;
|
||||
uint64_t u64;
|
||||
int64_t s64;
|
||||
double d;
|
||||
} v;
|
||||
struct dictEntry *next; /* Next entry in the same hash bucket. */
|
||||
} dictEntry;
|
||||
|
||||
typedef struct dict dict;
|
||||
|
||||
typedef struct dictType {
|
||||
uint64_t (*hashFunction)(const void *key);
|
||||
void *(*keyDup)(dict *d, const void *key);
|
||||
void *(*valDup)(dict *d, const void *obj);
|
||||
int (*keyCompare)(dict *d, const void *key1, const void *key2);
|
||||
void (*keyDestructor)(dict *d, void *key);
|
||||
void (*valDestructor)(dict *d, void *obj);
|
||||
int (*expandAllowed)(size_t moreMem, double usedRatio);
|
||||
} dictType;
|
||||
|
||||
#define DICTHT_SIZE(exp) ((exp) == -1 ? 0 : (unsigned long)1<<(exp))
|
||||
#define DICTHT_SIZE_MASK(exp) ((exp) == -1 ? 0 : (DICTHT_SIZE(exp))-1)
|
||||
|
||||
struct dict {
|
||||
dictType *type;
|
||||
|
||||
dictEntry **ht_table[2];
|
||||
unsigned long ht_used[2];
|
||||
|
||||
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
|
||||
|
||||
/* Keep small vars at end for optimal (minimal) struct padding */
|
||||
int16_t pauserehash; /* If >0 rehashing is paused (<0 indicates coding error) */
|
||||
signed char ht_size_exp[2]; /* exponent of size. (size = 1<<exp) */
|
||||
};
|
||||
|
||||
/* If safe is set to 1 this is a safe iterator, that means, you can call
|
||||
* dictAdd, dictFind, and other functions against the dictionary even while
|
||||
* iterating. Otherwise it is a non safe iterator, and only dictNext()
|
||||
* should be called while iterating. */
|
||||
typedef struct dictIterator {
|
||||
dict *d;
|
||||
long index;
|
||||
int table, safe;
|
||||
dictEntry *entry, *nextEntry;
|
||||
/* unsafe iterator fingerprint for misuse detection. */
|
||||
unsigned long long fingerprint;
|
||||
} dictIterator;
|
||||
|
||||
typedef void (dictScanFunction)(void *privdata, const dictEntry *de);
|
||||
typedef void (dictScanBucketFunction)(dict *d, dictEntry **bucketref);
|
||||
|
||||
/* This is the initial size of every hash table */
|
||||
#define DICT_HT_INITIAL_EXP 2
|
||||
#define DICT_HT_INITIAL_SIZE (1<<(DICT_HT_INITIAL_EXP))
|
||||
|
||||
/* ------------------------------- Macros ------------------------------------*/
|
||||
#define dictFreeVal(d, entry) \
|
||||
if ((d)->type->valDestructor) \
|
||||
(d)->type->valDestructor((d), (entry)->v.val)
|
||||
|
||||
#define dictSetVal(d, entry, _val_) do { \
|
||||
if ((d)->type->valDup) \
|
||||
(entry)->v.val = (d)->type->valDup((d), _val_); \
|
||||
else \
|
||||
(entry)->v.val = (_val_); \
|
||||
} while(0)
|
||||
|
||||
#define dictSetSignedIntegerVal(entry, _val_) \
|
||||
do { (entry)->v.s64 = _val_; } while(0)
|
||||
|
||||
#define dictSetUnsignedIntegerVal(entry, _val_) \
|
||||
do { (entry)->v.u64 = _val_; } while(0)
|
||||
|
||||
#define dictSetDoubleVal(entry, _val_) \
|
||||
do { (entry)->v.d = _val_; } while(0)
|
||||
|
||||
#define dictFreeKey(d, entry) \
|
||||
if ((d)->type->keyDestructor) \
|
||||
(d)->type->keyDestructor((d), (entry)->key)
|
||||
|
||||
#define dictSetKey(d, entry, _key_) do { \
|
||||
if ((d)->type->keyDup) \
|
||||
(entry)->key = (d)->type->keyDup((d), _key_); \
|
||||
else \
|
||||
(entry)->key = (_key_); \
|
||||
} while(0)
|
||||
|
||||
#define dictCompareKeys(d, key1, key2) \
|
||||
(((d)->type->keyCompare) ? \
|
||||
(d)->type->keyCompare((d), key1, key2) : \
|
||||
(key1) == (key2))
|
||||
|
||||
#define dictHashKey(d, key) (d)->type->hashFunction(key)
|
||||
#define dictGetKey(he) ((he)->key)
|
||||
#define dictGetVal(he) ((he)->v.val)
|
||||
#define dictGetSignedIntegerVal(he) ((he)->v.s64)
|
||||
#define dictGetUnsignedIntegerVal(he) ((he)->v.u64)
|
||||
#define dictGetDoubleVal(he) ((he)->v.d)
|
||||
#define dictSlots(d) (DICTHT_SIZE((d)->ht_size_exp[0])+DICTHT_SIZE((d)->ht_size_exp[1]))
|
||||
#define dictSize(d) ((d)->ht_used[0]+(d)->ht_used[1])
|
||||
#define dictIsRehashing(d) ((d)->rehashidx != -1)
|
||||
#define dictPauseRehashing(d) (d)->pauserehash++
|
||||
#define dictResumeRehashing(d) (d)->pauserehash--
|
||||
|
||||
/* If our unsigned long type can store a 64 bit number, use a 64 bit PRNG. */
|
||||
#if ULONG_MAX >= 0xffffffffffffffff
|
||||
#define randomULong() ((unsigned long) genrand64_int64())
|
||||
#else
|
||||
#define randomULong() random()
|
||||
#endif
|
||||
|
||||
/* API */
|
||||
dict *dictCreate(dictType *type);
|
||||
int dictExpand(dict *d, unsigned long size);
|
||||
int dictTryExpand(dict *d, unsigned long size);
|
||||
int dictAdd(dict *d, void *key, void *val);
|
||||
dictEntry *dictAddRaw(dict *d, void *key, dictEntry **existing);
|
||||
dictEntry *dictAddOrFind(dict *d, void *key);
|
||||
int dictReplace(dict *d, void *key, void *val);
|
||||
int dictDelete(dict *d, const void *key);
|
||||
dictEntry *dictUnlink(dict *d, const void *key);
|
||||
void dictFreeUnlinkedEntry(dict *d, dictEntry *he);
|
||||
void dictRelease(dict *d);
|
||||
dictEntry * dictFind(dict *d, const void *key);
|
||||
void *dictFetchValue(dict *d, const void *key);
|
||||
int dictResize(dict *d);
|
||||
dictIterator *dictGetIterator(dict *d);
|
||||
dictIterator *dictGetSafeIterator(dict *d);
|
||||
dictEntry *dictNext(dictIterator *iter);
|
||||
void dictReleaseIterator(dictIterator *iter);
|
||||
dictEntry *dictGetRandomKey(dict *d);
|
||||
dictEntry *dictGetFairRandomKey(dict *d);
|
||||
unsigned int dictGetSomeKeys(dict *d, dictEntry **des, unsigned int count);
|
||||
void dictGetStats(char *buf, size_t bufsize, dict *d);
|
||||
uint64_t dictGenHashFunction(const void *key, size_t len);
|
||||
uint64_t dictGenCaseHashFunction(const unsigned char *buf, size_t len);
|
||||
void dictEmpty(dict *d, void(callback)(dict*));
|
||||
void dictEnableResize(void);
|
||||
void dictDisableResize(void);
|
||||
int dictRehash(dict *d, int n);
|
||||
int dictRehashMilliseconds(dict *d, int ms);
|
||||
void dictSetHashFunctionSeed(uint8_t *seed);
|
||||
uint8_t *dictGetHashFunctionSeed(void);
|
||||
unsigned long dictScan(dict *d, unsigned long v, dictScanFunction *fn, dictScanBucketFunction *bucketfn, void *privdata);
|
||||
uint64_t dictGetHash(dict *d, const void *key);
|
||||
dictEntry **dictFindEntryRefByPtrAndHash(dict *d, const void *oldptr, uint64_t hash);
|
||||
|
||||
#endif /* __DICT_H */
|
|
@ -0,0 +1,129 @@
|
|||
/* endinconv.c -- Endian conversions utilities.
|
||||
*
|
||||
* This functions are never called directly, but always using the macros
|
||||
* defined into endianconv.h, this way we define everything is a non-operation
|
||||
* if the arch is already little endian.
|
||||
*
|
||||
* Redis tries to encode everything as little endian (but a few things that need
|
||||
* to be backward compatible are still in big endian) because most of the
|
||||
* production environments are little endian, and we have a lot of conversions
|
||||
* in a few places because ziplists, intsets, zipmaps, need to be endian-neutral
|
||||
* even in memory, since they are serialized on RDB files directly with a single
|
||||
* write(2) without other additional steps.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2011-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Toggle the 16 bit unsigned integer pointed by *p from little endian to
|
||||
* big endian */
|
||||
void memrev16(void *p) {
|
||||
unsigned char *x = p, t;
|
||||
|
||||
t = x[0];
|
||||
x[0] = x[1];
|
||||
x[1] = t;
|
||||
}
|
||||
|
||||
/* Toggle the 32 bit unsigned integer pointed by *p from little endian to
|
||||
* big endian */
|
||||
void memrev32(void *p) {
|
||||
unsigned char *x = p, t;
|
||||
|
||||
t = x[0];
|
||||
x[0] = x[3];
|
||||
x[3] = t;
|
||||
t = x[1];
|
||||
x[1] = x[2];
|
||||
x[2] = t;
|
||||
}
|
||||
|
||||
/* Toggle the 64 bit unsigned integer pointed by *p from little endian to
|
||||
* big endian */
|
||||
void memrev64(void *p) {
|
||||
unsigned char *x = p, t;
|
||||
|
||||
t = x[0];
|
||||
x[0] = x[7];
|
||||
x[7] = t;
|
||||
t = x[1];
|
||||
x[1] = x[6];
|
||||
x[6] = t;
|
||||
t = x[2];
|
||||
x[2] = x[5];
|
||||
x[5] = t;
|
||||
t = x[3];
|
||||
x[3] = x[4];
|
||||
x[4] = t;
|
||||
}
|
||||
|
||||
uint16_t intrev16(uint16_t v) {
|
||||
memrev16(&v);
|
||||
return v;
|
||||
}
|
||||
|
||||
uint32_t intrev32(uint32_t v) {
|
||||
memrev32(&v);
|
||||
return v;
|
||||
}
|
||||
|
||||
uint64_t intrev64(uint64_t v) {
|
||||
memrev64(&v);
|
||||
return v;
|
||||
}
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
#include <stdio.h>
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
int endianconvTest(int argc, char *argv[], int flags) {
|
||||
char buf[32];
|
||||
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
UNUSED(flags);
|
||||
|
||||
sprintf(buf,"ciaoroma");
|
||||
memrev16(buf);
|
||||
printf("%s\n", buf);
|
||||
|
||||
sprintf(buf,"ciaoroma");
|
||||
memrev32(buf);
|
||||
printf("%s\n", buf);
|
||||
|
||||
sprintf(buf,"ciaoroma");
|
||||
memrev64(buf);
|
||||
printf("%s\n", buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,78 @@
|
|||
/* See endianconv.c top comments for more information
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2011-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __ENDIANCONV_H
|
||||
#define __ENDIANCONV_H
|
||||
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void memrev16(void *p);
|
||||
void memrev32(void *p);
|
||||
void memrev64(void *p);
|
||||
uint16_t intrev16(uint16_t v);
|
||||
uint32_t intrev32(uint32_t v);
|
||||
uint64_t intrev64(uint64_t v);
|
||||
|
||||
/* variants of the function doing the actual conversion only if the target
|
||||
* host is big endian */
|
||||
#if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
#define memrev16ifbe(p) ((void)(0))
|
||||
#define memrev32ifbe(p) ((void)(0))
|
||||
#define memrev64ifbe(p) ((void)(0))
|
||||
#define intrev16ifbe(v) (v)
|
||||
#define intrev32ifbe(v) (v)
|
||||
#define intrev64ifbe(v) (v)
|
||||
#else
|
||||
#define memrev16ifbe(p) memrev16(p)
|
||||
#define memrev32ifbe(p) memrev32(p)
|
||||
#define memrev64ifbe(p) memrev64(p)
|
||||
#define intrev16ifbe(v) intrev16(v)
|
||||
#define intrev32ifbe(v) intrev32(v)
|
||||
#define intrev64ifbe(v) intrev64(v)
|
||||
#endif
|
||||
|
||||
/* The functions htonu64() and ntohu64() convert the specified value to
|
||||
* network byte ordering and back. In big endian systems they are no-ops. */
|
||||
#if (BYTE_ORDER == BIG_ENDIAN)
|
||||
#define htonu64(v) (v)
|
||||
#define ntohu64(v) (v)
|
||||
#else
|
||||
#define htonu64(v) intrev64(v)
|
||||
#define ntohu64(v) intrev64(v)
|
||||
#endif
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
int endianconvTest(int argc, char *argv[], int flags);
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,547 @@
|
|||
/*
|
||||
* Copyright (c) 2009-2012, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "intset.h"
|
||||
#include "zmalloc.h"
|
||||
#include "endianconv.h"
|
||||
|
||||
/* Note that these encodings are ordered, so:
|
||||
* INTSET_ENC_INT16 < INTSET_ENC_INT32 < INTSET_ENC_INT64. */
|
||||
#define INTSET_ENC_INT16 (sizeof(int16_t))
|
||||
#define INTSET_ENC_INT32 (sizeof(int32_t))
|
||||
#define INTSET_ENC_INT64 (sizeof(int64_t))
|
||||
|
||||
/* Return the required encoding for the provided value. */
|
||||
static uint8_t _intsetValueEncoding(int64_t v) {
|
||||
if (v < INT32_MIN || v > INT32_MAX)
|
||||
return INTSET_ENC_INT64;
|
||||
else if (v < INT16_MIN || v > INT16_MAX)
|
||||
return INTSET_ENC_INT32;
|
||||
else
|
||||
return INTSET_ENC_INT16;
|
||||
}
|
||||
|
||||
/* Return the value at pos, given an encoding. */
|
||||
static int64_t _intsetGetEncoded(intset *is, int pos, uint8_t enc) {
|
||||
int64_t v64;
|
||||
int32_t v32;
|
||||
int16_t v16;
|
||||
|
||||
if (enc == INTSET_ENC_INT64) {
|
||||
memcpy(&v64,((int64_t*)is->contents)+pos,sizeof(v64));
|
||||
memrev64ifbe(&v64);
|
||||
return v64;
|
||||
} else if (enc == INTSET_ENC_INT32) {
|
||||
memcpy(&v32,((int32_t*)is->contents)+pos,sizeof(v32));
|
||||
memrev32ifbe(&v32);
|
||||
return v32;
|
||||
} else {
|
||||
memcpy(&v16,((int16_t*)is->contents)+pos,sizeof(v16));
|
||||
memrev16ifbe(&v16);
|
||||
return v16;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the value at pos, using the configured encoding. */
|
||||
static int64_t _intsetGet(intset *is, int pos) {
|
||||
return _intsetGetEncoded(is,pos,intrev32ifbe(is->encoding));
|
||||
}
|
||||
|
||||
/* Set the value at pos, using the configured encoding. */
|
||||
static void _intsetSet(intset *is, int pos, int64_t value) {
|
||||
uint32_t encoding = intrev32ifbe(is->encoding);
|
||||
|
||||
if (encoding == INTSET_ENC_INT64) {
|
||||
((int64_t*)is->contents)[pos] = value;
|
||||
memrev64ifbe(((int64_t*)is->contents)+pos);
|
||||
} else if (encoding == INTSET_ENC_INT32) {
|
||||
((int32_t*)is->contents)[pos] = value;
|
||||
memrev32ifbe(((int32_t*)is->contents)+pos);
|
||||
} else {
|
||||
((int16_t*)is->contents)[pos] = value;
|
||||
memrev16ifbe(((int16_t*)is->contents)+pos);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create an empty intset. */
|
||||
intset *intsetNew(void) {
|
||||
intset *is = zmalloc(sizeof(intset));
|
||||
is->encoding = intrev32ifbe(INTSET_ENC_INT16);
|
||||
is->length = 0;
|
||||
return is;
|
||||
}
|
||||
|
||||
/* Resize the intset */
|
||||
static intset *intsetResize(intset *is, uint32_t len) {
|
||||
uint64_t size = (uint64_t)len*intrev32ifbe(is->encoding);
|
||||
assert(size <= SIZE_MAX - sizeof(intset));
|
||||
is = zrealloc(is,sizeof(intset)+size);
|
||||
return is;
|
||||
}
|
||||
|
||||
/* Search for the position of "value". Return 1 when the value was found and
|
||||
* sets "pos" to the position of the value within the intset. Return 0 when
|
||||
* the value is not present in the intset and sets "pos" to the position
|
||||
* where "value" can be inserted. */
|
||||
static uint8_t intsetSearch(intset *is, int64_t value, uint32_t *pos) {
|
||||
int min = 0, max = intrev32ifbe(is->length)-1, mid = -1;
|
||||
int64_t cur = -1;
|
||||
|
||||
/* The value can never be found when the set is empty */
|
||||
if (intrev32ifbe(is->length) == 0) {
|
||||
if (pos) *pos = 0;
|
||||
return 0;
|
||||
} else {
|
||||
/* Check for the case where we know we cannot find the value,
|
||||
* but do know the insert position. */
|
||||
if (value > _intsetGet(is,max)) {
|
||||
if (pos) *pos = intrev32ifbe(is->length);
|
||||
return 0;
|
||||
} else if (value < _intsetGet(is,0)) {
|
||||
if (pos) *pos = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
while(max >= min) {
|
||||
mid = ((unsigned int)min + (unsigned int)max) >> 1;
|
||||
cur = _intsetGet(is,mid);
|
||||
if (value > cur) {
|
||||
min = mid+1;
|
||||
} else if (value < cur) {
|
||||
max = mid-1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (value == cur) {
|
||||
if (pos) *pos = mid;
|
||||
return 1;
|
||||
} else {
|
||||
if (pos) *pos = min;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Upgrades the intset to a larger encoding and inserts the given integer. */
|
||||
static intset *intsetUpgradeAndAdd(intset *is, int64_t value) {
|
||||
uint8_t curenc = intrev32ifbe(is->encoding);
|
||||
uint8_t newenc = _intsetValueEncoding(value);
|
||||
int length = intrev32ifbe(is->length);
|
||||
int prepend = value < 0 ? 1 : 0;
|
||||
|
||||
/* First set new encoding and resize */
|
||||
is->encoding = intrev32ifbe(newenc);
|
||||
is = intsetResize(is,intrev32ifbe(is->length)+1);
|
||||
|
||||
/* Upgrade back-to-front so we don't overwrite values.
|
||||
* Note that the "prepend" variable is used to make sure we have an empty
|
||||
* space at either the beginning or the end of the intset. */
|
||||
while(length--)
|
||||
_intsetSet(is,length+prepend,_intsetGetEncoded(is,length,curenc));
|
||||
|
||||
/* Set the value at the beginning or the end. */
|
||||
if (prepend)
|
||||
_intsetSet(is,0,value);
|
||||
else
|
||||
_intsetSet(is,intrev32ifbe(is->length),value);
|
||||
is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
|
||||
return is;
|
||||
}
|
||||
|
||||
static void intsetMoveTail(intset *is, uint32_t from, uint32_t to) {
|
||||
void *src, *dst;
|
||||
uint32_t bytes = intrev32ifbe(is->length)-from;
|
||||
uint32_t encoding = intrev32ifbe(is->encoding);
|
||||
|
||||
if (encoding == INTSET_ENC_INT64) {
|
||||
src = (int64_t*)is->contents+from;
|
||||
dst = (int64_t*)is->contents+to;
|
||||
bytes *= sizeof(int64_t);
|
||||
} else if (encoding == INTSET_ENC_INT32) {
|
||||
src = (int32_t*)is->contents+from;
|
||||
dst = (int32_t*)is->contents+to;
|
||||
bytes *= sizeof(int32_t);
|
||||
} else {
|
||||
src = (int16_t*)is->contents+from;
|
||||
dst = (int16_t*)is->contents+to;
|
||||
bytes *= sizeof(int16_t);
|
||||
}
|
||||
memmove(dst,src,bytes);
|
||||
}
|
||||
|
||||
/* Insert an integer in the intset */
|
||||
intset *intsetAdd(intset *is, int64_t value, uint8_t *success) {
|
||||
uint8_t valenc = _intsetValueEncoding(value);
|
||||
uint32_t pos;
|
||||
if (success) *success = 1;
|
||||
|
||||
/* Upgrade encoding if necessary. If we need to upgrade, we know that
|
||||
* this value should be either appended (if > 0) or prepended (if < 0),
|
||||
* because it lies outside the range of existing values. */
|
||||
if (valenc > intrev32ifbe(is->encoding)) {
|
||||
/* This always succeeds, so we don't need to curry *success. */
|
||||
return intsetUpgradeAndAdd(is,value);
|
||||
} else {
|
||||
/* Abort if the value is already present in the set.
|
||||
* This call will populate "pos" with the right position to insert
|
||||
* the value when it cannot be found. */
|
||||
if (intsetSearch(is,value,&pos)) {
|
||||
if (success) *success = 0;
|
||||
return is;
|
||||
}
|
||||
|
||||
is = intsetResize(is,intrev32ifbe(is->length)+1);
|
||||
if (pos < intrev32ifbe(is->length)) intsetMoveTail(is,pos,pos+1);
|
||||
}
|
||||
|
||||
_intsetSet(is,pos,value);
|
||||
is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
|
||||
return is;
|
||||
}
|
||||
|
||||
/* Delete integer from intset */
|
||||
intset *intsetRemove(intset *is, int64_t value, int *success) {
|
||||
uint8_t valenc = _intsetValueEncoding(value);
|
||||
uint32_t pos;
|
||||
if (success) *success = 0;
|
||||
|
||||
if (valenc <= intrev32ifbe(is->encoding) && intsetSearch(is,value,&pos)) {
|
||||
uint32_t len = intrev32ifbe(is->length);
|
||||
|
||||
/* We know we can delete */
|
||||
if (success) *success = 1;
|
||||
|
||||
/* Overwrite value with tail and update length */
|
||||
if (pos < (len-1)) intsetMoveTail(is,pos+1,pos);
|
||||
is = intsetResize(is,len-1);
|
||||
is->length = intrev32ifbe(len-1);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
/* Determine whether a value belongs to this set */
|
||||
uint8_t intsetFind(intset *is, int64_t value) {
|
||||
uint8_t valenc = _intsetValueEncoding(value);
|
||||
return valenc <= intrev32ifbe(is->encoding) && intsetSearch(is,value,NULL);
|
||||
}
|
||||
|
||||
/* Return random member */
|
||||
int64_t intsetRandom(intset *is) {
|
||||
uint32_t len = intrev32ifbe(is->length);
|
||||
assert(len); /* avoid division by zero on corrupt intset payload. */
|
||||
return _intsetGet(is,rand()%len);
|
||||
}
|
||||
|
||||
/* Get the value at the given position. When this position is
|
||||
* out of range the function returns 0, when in range it returns 1. */
|
||||
uint8_t intsetGet(intset *is, uint32_t pos, int64_t *value) {
|
||||
if (pos < intrev32ifbe(is->length)) {
|
||||
*value = _intsetGet(is,pos);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return intset length */
|
||||
uint32_t intsetLen(const intset *is) {
|
||||
return intrev32ifbe(is->length);
|
||||
}
|
||||
|
||||
/* Return intset blob size in bytes. */
|
||||
size_t intsetBlobLen(intset *is) {
|
||||
return sizeof(intset)+(size_t)intrev32ifbe(is->length)*intrev32ifbe(is->encoding);
|
||||
}
|
||||
|
||||
/* Validate the integrity of the data structure.
|
||||
* when `deep` is 0, only the integrity of the header is validated.
|
||||
* when `deep` is 1, we make sure there are no duplicate or out of order records. */
|
||||
int intsetValidateIntegrity(const unsigned char *p, size_t size, int deep) {
|
||||
intset *is = (intset *)p;
|
||||
/* check that we can actually read the header. */
|
||||
if (size < sizeof(*is))
|
||||
return 0;
|
||||
|
||||
uint32_t encoding = intrev32ifbe(is->encoding);
|
||||
|
||||
size_t record_size;
|
||||
if (encoding == INTSET_ENC_INT64) {
|
||||
record_size = INTSET_ENC_INT64;
|
||||
} else if (encoding == INTSET_ENC_INT32) {
|
||||
record_size = INTSET_ENC_INT32;
|
||||
} else if (encoding == INTSET_ENC_INT16){
|
||||
record_size = INTSET_ENC_INT16;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check that the size matches (all records are inside the buffer). */
|
||||
uint32_t count = intrev32ifbe(is->length);
|
||||
if (sizeof(*is) + count*record_size != size)
|
||||
return 0;
|
||||
|
||||
/* check that the set is not empty. */
|
||||
if (count==0)
|
||||
return 0;
|
||||
|
||||
if (!deep)
|
||||
return 1;
|
||||
|
||||
/* check that there are no dup or out of order records. */
|
||||
int64_t prev = _intsetGet(is,0);
|
||||
for (uint32_t i=1; i<count; i++) {
|
||||
int64_t cur = _intsetGet(is,i);
|
||||
if (cur <= prev)
|
||||
return 0;
|
||||
prev = cur;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#if 0
|
||||
static void intsetRepr(intset *is) {
|
||||
for (uint32_t i = 0; i < intrev32ifbe(is->length); i++) {
|
||||
printf("%lld\n", (uint64_t)_intsetGet(is,i));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void error(char *err) {
|
||||
printf("%s\n", err);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ok(void) {
|
||||
printf("OK\n");
|
||||
}
|
||||
|
||||
static long long usec(void) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
return (((long long)tv.tv_sec)*1000000)+tv.tv_usec;
|
||||
}
|
||||
|
||||
static intset *createSet(int bits, int size) {
|
||||
uint64_t mask = (1<<bits)-1;
|
||||
uint64_t value;
|
||||
intset *is = intsetNew();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (bits > 32) {
|
||||
value = (rand()*rand()) & mask;
|
||||
} else {
|
||||
value = rand() & mask;
|
||||
}
|
||||
is = intsetAdd(is,value,NULL);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
static void checkConsistency(intset *is) {
|
||||
for (uint32_t i = 0; i < (intrev32ifbe(is->length)-1); i++) {
|
||||
uint32_t encoding = intrev32ifbe(is->encoding);
|
||||
|
||||
if (encoding == INTSET_ENC_INT16) {
|
||||
int16_t *i16 = (int16_t*)is->contents;
|
||||
assert(i16[i] < i16[i+1]);
|
||||
} else if (encoding == INTSET_ENC_INT32) {
|
||||
int32_t *i32 = (int32_t*)is->contents;
|
||||
assert(i32[i] < i32[i+1]);
|
||||
} else {
|
||||
int64_t *i64 = (int64_t*)is->contents;
|
||||
assert(i64[i] < i64[i+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
int intsetTest(int argc, char **argv, int flags) {
|
||||
uint8_t success;
|
||||
int i;
|
||||
intset *is;
|
||||
srand(time(NULL));
|
||||
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
UNUSED(flags);
|
||||
|
||||
printf("Value encodings: "); {
|
||||
assert(_intsetValueEncoding(-32768) == INTSET_ENC_INT16);
|
||||
assert(_intsetValueEncoding(+32767) == INTSET_ENC_INT16);
|
||||
assert(_intsetValueEncoding(-32769) == INTSET_ENC_INT32);
|
||||
assert(_intsetValueEncoding(+32768) == INTSET_ENC_INT32);
|
||||
assert(_intsetValueEncoding(-2147483648) == INTSET_ENC_INT32);
|
||||
assert(_intsetValueEncoding(+2147483647) == INTSET_ENC_INT32);
|
||||
assert(_intsetValueEncoding(-2147483649) == INTSET_ENC_INT64);
|
||||
assert(_intsetValueEncoding(+2147483648) == INTSET_ENC_INT64);
|
||||
assert(_intsetValueEncoding(-9223372036854775808ull) ==
|
||||
INTSET_ENC_INT64);
|
||||
assert(_intsetValueEncoding(+9223372036854775807ull) ==
|
||||
INTSET_ENC_INT64);
|
||||
ok();
|
||||
}
|
||||
|
||||
printf("Basic adding: "); {
|
||||
is = intsetNew();
|
||||
is = intsetAdd(is,5,&success); assert(success);
|
||||
is = intsetAdd(is,6,&success); assert(success);
|
||||
is = intsetAdd(is,4,&success); assert(success);
|
||||
is = intsetAdd(is,4,&success); assert(!success);
|
||||
ok();
|
||||
zfree(is);
|
||||
}
|
||||
|
||||
printf("Large number of random adds: "); {
|
||||
uint32_t inserts = 0;
|
||||
is = intsetNew();
|
||||
for (i = 0; i < 1024; i++) {
|
||||
is = intsetAdd(is,rand()%0x800,&success);
|
||||
if (success) inserts++;
|
||||
}
|
||||
assert(intrev32ifbe(is->length) == inserts);
|
||||
checkConsistency(is);
|
||||
ok();
|
||||
zfree(is);
|
||||
}
|
||||
|
||||
printf("Upgrade from int16 to int32: "); {
|
||||
is = intsetNew();
|
||||
is = intsetAdd(is,32,NULL);
|
||||
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
|
||||
is = intsetAdd(is,65535,NULL);
|
||||
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
|
||||
assert(intsetFind(is,32));
|
||||
assert(intsetFind(is,65535));
|
||||
checkConsistency(is);
|
||||
zfree(is);
|
||||
|
||||
is = intsetNew();
|
||||
is = intsetAdd(is,32,NULL);
|
||||
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
|
||||
is = intsetAdd(is,-65535,NULL);
|
||||
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
|
||||
assert(intsetFind(is,32));
|
||||
assert(intsetFind(is,-65535));
|
||||
checkConsistency(is);
|
||||
ok();
|
||||
zfree(is);
|
||||
}
|
||||
|
||||
printf("Upgrade from int16 to int64: "); {
|
||||
is = intsetNew();
|
||||
is = intsetAdd(is,32,NULL);
|
||||
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
|
||||
is = intsetAdd(is,4294967295,NULL);
|
||||
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
|
||||
assert(intsetFind(is,32));
|
||||
assert(intsetFind(is,4294967295));
|
||||
checkConsistency(is);
|
||||
zfree(is);
|
||||
|
||||
is = intsetNew();
|
||||
is = intsetAdd(is,32,NULL);
|
||||
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
|
||||
is = intsetAdd(is,-4294967295,NULL);
|
||||
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
|
||||
assert(intsetFind(is,32));
|
||||
assert(intsetFind(is,-4294967295));
|
||||
checkConsistency(is);
|
||||
ok();
|
||||
zfree(is);
|
||||
}
|
||||
|
||||
printf("Upgrade from int32 to int64: "); {
|
||||
is = intsetNew();
|
||||
is = intsetAdd(is,65535,NULL);
|
||||
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
|
||||
is = intsetAdd(is,4294967295,NULL);
|
||||
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
|
||||
assert(intsetFind(is,65535));
|
||||
assert(intsetFind(is,4294967295));
|
||||
checkConsistency(is);
|
||||
zfree(is);
|
||||
|
||||
is = intsetNew();
|
||||
is = intsetAdd(is,65535,NULL);
|
||||
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
|
||||
is = intsetAdd(is,-4294967295,NULL);
|
||||
assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
|
||||
assert(intsetFind(is,65535));
|
||||
assert(intsetFind(is,-4294967295));
|
||||
checkConsistency(is);
|
||||
ok();
|
||||
zfree(is);
|
||||
}
|
||||
|
||||
printf("Stress lookups: "); {
|
||||
long num = 100000, size = 10000;
|
||||
int i, bits = 20;
|
||||
long long start;
|
||||
is = createSet(bits,size);
|
||||
checkConsistency(is);
|
||||
|
||||
start = usec();
|
||||
for (i = 0; i < num; i++) intsetSearch(is,rand() % ((1<<bits)-1),NULL);
|
||||
printf("%ld lookups, %ld element set, %lldusec\n",
|
||||
num,size,usec()-start);
|
||||
zfree(is);
|
||||
}
|
||||
|
||||
printf("Stress add+delete: "); {
|
||||
int i, v1, v2;
|
||||
is = intsetNew();
|
||||
for (i = 0; i < 0xffff; i++) {
|
||||
v1 = rand() % 0xfff;
|
||||
is = intsetAdd(is,v1,NULL);
|
||||
assert(intsetFind(is,v1));
|
||||
|
||||
v2 = rand() % 0xfff;
|
||||
is = intsetRemove(is,v2,NULL);
|
||||
assert(!intsetFind(is,v2));
|
||||
}
|
||||
checkConsistency(is);
|
||||
ok();
|
||||
zfree(is);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2009-2012, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __INTSET_H
|
||||
#define __INTSET_H
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct intset {
|
||||
uint32_t encoding;
|
||||
uint32_t length;
|
||||
int8_t contents[];
|
||||
} intset;
|
||||
|
||||
intset *intsetNew(void);
|
||||
intset *intsetAdd(intset *is, int64_t value, uint8_t *success);
|
||||
intset *intsetRemove(intset *is, int64_t value, int *success);
|
||||
uint8_t intsetFind(intset *is, int64_t value);
|
||||
int64_t intsetRandom(intset *is);
|
||||
uint8_t intsetGet(intset *is, uint32_t pos, int64_t *value);
|
||||
uint32_t intsetLen(const intset *is);
|
||||
size_t intsetBlobLen(intset *is);
|
||||
int intsetValidateIntegrity(const unsigned char *is, size_t size, int deep);
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
int intsetTest(int argc, char *argv[], int flags);
|
||||
#endif
|
||||
|
||||
#endif // __INTSET_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,98 @@
|
|||
/* Listpack -- A lists of strings serialization format
|
||||
*
|
||||
* This file implements the specification you can find at:
|
||||
*
|
||||
* https://github.com/antirez/listpack
|
||||
*
|
||||
* Copyright (c) 2017, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __LISTPACK_H
|
||||
#define __LISTPACK_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define LP_INTBUF_SIZE 21 /* 20 digits of -2^63 + 1 null term = 21. */
|
||||
|
||||
/* lpInsert() where argument possible values: */
|
||||
#define LP_BEFORE 0
|
||||
#define LP_AFTER 1
|
||||
#define LP_REPLACE 2
|
||||
|
||||
/* Each entry in the listpack is either a string or an integer. */
|
||||
typedef struct {
|
||||
/* When string is used, it is provided with the length (slen). */
|
||||
unsigned char *sval;
|
||||
uint32_t slen;
|
||||
/* When integer is used, 'sval' is NULL, and lval holds the value. */
|
||||
long long lval;
|
||||
} listpackEntry;
|
||||
|
||||
unsigned char *lpNew(size_t capacity);
|
||||
void lpFree(unsigned char *lp);
|
||||
unsigned char* lpShrinkToFit(unsigned char *lp);
|
||||
unsigned char *lpInsertString(unsigned char *lp, const unsigned char *s, uint32_t slen,
|
||||
unsigned char *p, int where, unsigned char **newp);
|
||||
unsigned char *lpPrepend(unsigned char *lp, const unsigned char *s, uint32_t slen);
|
||||
unsigned char *lpPrependInteger(unsigned char *lp, long long lval);
|
||||
unsigned char *lpAppend(unsigned char *lp, const unsigned char *s, uint32_t slen);
|
||||
unsigned char *lpAppendInteger(unsigned char *lp, long long lval);
|
||||
unsigned char *lpReplace(unsigned char *lp, unsigned char **p, const unsigned char *s, uint32_t slen);
|
||||
unsigned char *lpReplaceInteger(unsigned char *lp, unsigned char **p, long long lval);
|
||||
unsigned char *lpDelete(unsigned char *lp, unsigned char *p, unsigned char **newp);
|
||||
unsigned char *lpDeleteRangeWithEntry(unsigned char *lp, unsigned char **p, unsigned long num);
|
||||
unsigned char *lpDeleteRange(unsigned char *lp, long index, unsigned long num);
|
||||
unsigned char *lpMerge(unsigned char **first, unsigned char **second);
|
||||
unsigned long lpLength(unsigned char *lp);
|
||||
unsigned char *lpGet(unsigned char *p, int64_t *count, unsigned char *intbuf);
|
||||
unsigned char *lpGetValue(unsigned char *p, unsigned int *slen, long long *lval);
|
||||
unsigned char *lpFind(unsigned char *lp, unsigned char *p, unsigned char *s, uint32_t slen, unsigned int skip);
|
||||
unsigned char *lpFirst(unsigned char *lp);
|
||||
unsigned char *lpLast(unsigned char *lp);
|
||||
unsigned char *lpNext(unsigned char *lp, unsigned char *p);
|
||||
unsigned char *lpPrev(unsigned char *lp, unsigned char *p);
|
||||
size_t lpBytes(unsigned char *lp);
|
||||
unsigned char *lpSeek(unsigned char *lp, long index);
|
||||
typedef int (*listpackValidateEntryCB)(unsigned char *p, unsigned int head_count, void *userdata);
|
||||
int lpValidateIntegrity(unsigned char *lp, size_t size, int deep,
|
||||
listpackValidateEntryCB entry_cb, void *cb_userdata);
|
||||
unsigned char *lpValidateFirst(unsigned char *lp);
|
||||
int lpValidateNext(unsigned char *lp, unsigned char **pp, size_t lpbytes);
|
||||
unsigned int lpCompare(unsigned char *p, const unsigned char *s, uint32_t slen);
|
||||
void lpRandomPair(unsigned char *lp, unsigned long total_count, listpackEntry *key, listpackEntry *val);
|
||||
void lpRandomPairs(unsigned char *lp, unsigned int count, listpackEntry *keys, listpackEntry *vals);
|
||||
unsigned int lpRandomPairsUnique(unsigned char *lp, unsigned int count, listpackEntry *keys, listpackEntry *vals);
|
||||
int lpSafeToAdd(unsigned char* lp, size_t add);
|
||||
void lpRepr(unsigned char *lp);
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
int listpackTest(int argc, char *argv[], int flags);
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2008 Marc Alexander Lehmann <schmorp@schmorp.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef LZF_H
|
||||
#define LZF_H
|
||||
|
||||
/***********************************************************************
|
||||
**
|
||||
** lzf -- an extremely fast/free compression/decompression-method
|
||||
** http://liblzf.plan9.de/
|
||||
**
|
||||
** This algorithm is believed to be patent-free.
|
||||
**
|
||||
***********************************************************************/
|
||||
|
||||
#define LZF_VERSION 0x0105 /* 1.5, API version */
|
||||
|
||||
/*
|
||||
* Compress in_len bytes stored at the memory block starting at
|
||||
* in_data and write the result to out_data, up to a maximum length
|
||||
* of out_len bytes.
|
||||
*
|
||||
* If the output buffer is not large enough or any error occurs return 0,
|
||||
* otherwise return the number of bytes used, which might be considerably
|
||||
* more than in_len (but less than 104% of the original size), so it
|
||||
* makes sense to always use out_len == in_len - 1), to ensure _some_
|
||||
* compression, and store the data uncompressed otherwise (with a flag, of
|
||||
* course.
|
||||
*
|
||||
* lzf_compress might use different algorithms on different systems and
|
||||
* even different runs, thus might result in different compressed strings
|
||||
* depending on the phase of the moon or similar factors. However, all
|
||||
* these strings are architecture-independent and will result in the
|
||||
* original data when decompressed using lzf_decompress.
|
||||
*
|
||||
* The buffers must not be overlapping.
|
||||
*
|
||||
* If the option LZF_STATE_ARG is enabled, an extra argument must be
|
||||
* supplied which is not reflected in this header file. Refer to lzfP.h
|
||||
* and lzf_c.c.
|
||||
*
|
||||
*/
|
||||
size_t
|
||||
lzf_compress (const void *const in_data, size_t in_len,
|
||||
void *out_data, size_t out_len
|
||||
#if LZF_STATE_ARG
|
||||
, LZF_STATE htab
|
||||
#endif
|
||||
);
|
||||
|
||||
/*
|
||||
* Decompress data compressed with some version of the lzf_compress
|
||||
* function and stored at location in_data and length in_len. The result
|
||||
* will be stored at out_data up to a maximum of out_len characters.
|
||||
*
|
||||
* If the output buffer is not large enough to hold the decompressed
|
||||
* data, a 0 is returned and errno is set to E2BIG. Otherwise the number
|
||||
* of decompressed bytes (i.e. the original length of the data) is
|
||||
* returned.
|
||||
*
|
||||
* If an error in the compressed data is detected, a zero is returned and
|
||||
* errno is set to EINVAL.
|
||||
*
|
||||
* This function is very fast, about as fast as a copying loop.
|
||||
*/
|
||||
size_t
|
||||
lzf_decompress (const void *const in_data, size_t in_len,
|
||||
void *out_data, size_t out_len);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2007 Marc Alexander Lehmann <schmorp@schmorp.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef LZFP_h
|
||||
#define LZFP_h
|
||||
|
||||
// ROMAN: #define STANDALONE 1 /* at the moment, this is ok. */
|
||||
|
||||
/* ROMAN: Moved below since it depends on LZF_STATE
|
||||
#ifndef STANDALONE
|
||||
# include "lzf.h"
|
||||
#endif
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Size of hashtable is (1 << HLOG) * sizeof (char *)
|
||||
* decompression is independent of the hash table size
|
||||
* the difference between 15 and 14 is very small
|
||||
* for small blocks (and 14 is usually a bit faster).
|
||||
* For a low-memory/faster configuration, use HLOG == 13;
|
||||
* For best compression, use 15 or 16 (or more, up to 22).
|
||||
*/
|
||||
#ifndef HLOG
|
||||
# define HLOG 16
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Sacrifice very little compression quality in favour of compression speed.
|
||||
* This gives almost the same compression as the default code, and is
|
||||
* (very roughly) 15% faster. This is the preferred mode of operation.
|
||||
*/
|
||||
#ifndef VERY_FAST
|
||||
# define VERY_FAST 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Sacrifice some more compression quality in favour of compression speed.
|
||||
* (roughly 1-2% worse compression for large blocks and
|
||||
* 9-10% for small, redundant, blocks and >>20% better speed in both cases)
|
||||
* In short: when in need for speed, enable this for binary data,
|
||||
* possibly disable this for text data.
|
||||
*/
|
||||
#ifndef ULTRA_FAST
|
||||
# define ULTRA_FAST 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unconditionally aligning does not cost very much, so do it if unsure
|
||||
*/
|
||||
#ifndef STRICT_ALIGN
|
||||
# if !(defined(__i386) || defined (__amd64))
|
||||
# define STRICT_ALIGN 1
|
||||
# else
|
||||
# define STRICT_ALIGN 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* You may choose to pre-set the hash table (might be faster on some
|
||||
* modern cpus and large (>>64k) blocks, and also makes compression
|
||||
* deterministic/repeatable when the configuration otherwise is the same).
|
||||
*/
|
||||
#ifndef INIT_HTAB
|
||||
# define INIT_HTAB 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Avoid assigning values to errno variable? for some embedding purposes
|
||||
* (linux kernel for example), this is necessary. NOTE: this breaks
|
||||
* the documentation in lzf.h. Avoiding errno has no speed impact.
|
||||
*/
|
||||
#ifndef AVOID_ERRNO
|
||||
# define AVOID_ERRNO 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Whether to pass the LZF_STATE variable as argument, or allocate it
|
||||
* on the stack. For small-stack environments, define this to 1.
|
||||
* NOTE: this breaks the prototype in lzf.h.
|
||||
*/
|
||||
#ifndef LZF_STATE_ARG
|
||||
# define LZF_STATE_ARG 1 // ROMAN
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Whether to add extra checks for input validity in lzf_decompress
|
||||
* and return EINVAL if the input stream has been corrupted. This
|
||||
* only shields against overflowing the input buffer and will not
|
||||
* detect most corrupted streams.
|
||||
* This check is not normally noticeable on modern hardware
|
||||
* (<1% slowdown), but might slow down older cpus considerably.
|
||||
*/
|
||||
#ifndef CHECK_INPUT
|
||||
# define CHECK_INPUT 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Whether to store pointers or offsets inside the hash table. On
|
||||
* 64 bit architectures, pointers take up twice as much space,
|
||||
* and might also be slower. Default is to autodetect.
|
||||
* Notice: Don't set this value to 1, it will result in 'LZF_HSLOT'
|
||||
* not being able to store offset above UINT32_MAX in 64bit. */
|
||||
#define LZF_USE_OFFSETS 0
|
||||
|
||||
/*****************************************************************************/
|
||||
/* nothing should be changed below */
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include <cstring>
|
||||
# include <climits>
|
||||
using namespace std;
|
||||
#else
|
||||
# include <string.h>
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#ifndef LZF_USE_OFFSETS
|
||||
# if defined (WIN32)
|
||||
# define LZF_USE_OFFSETS defined(_M_X64)
|
||||
# else
|
||||
# if __cplusplus > 199711L
|
||||
# include <cstdint>
|
||||
# else
|
||||
# include <stdint.h>
|
||||
# endif
|
||||
# define LZF_USE_OFFSETS (UINTPTR_MAX > 0xffffffffU)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef unsigned char u8;
|
||||
|
||||
#if LZF_USE_OFFSETS
|
||||
# define LZF_HSLOT_BIAS ((const u8 *)in_data)
|
||||
typedef unsigned int LZF_HSLOT;
|
||||
#else
|
||||
# define LZF_HSLOT_BIAS 0
|
||||
typedef const u8 *LZF_HSLOT;
|
||||
#endif
|
||||
|
||||
typedef LZF_HSLOT LZF_STATE[1 << (HLOG)];
|
||||
|
||||
// ROMAN: moved here deliberately because we depend on LZF_STATE.
|
||||
#ifndef STANDALONE
|
||||
# include "lzf.h"
|
||||
#endif
|
||||
|
||||
#if !STRICT_ALIGN
|
||||
/* for unaligned accesses we need a 16 bit datatype. */
|
||||
# if USHRT_MAX == 65535
|
||||
typedef unsigned short u16;
|
||||
# elif UINT_MAX == 65535
|
||||
typedef unsigned int u16;
|
||||
# else
|
||||
# undef STRICT_ALIGN
|
||||
# define STRICT_ALIGN 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ULTRA_FAST
|
||||
# undef VERY_FAST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2010 Marc Alexander Lehmann <schmorp@schmorp.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
#include "lzfP.h"
|
||||
|
||||
#define HSIZE (1 << (HLOG))
|
||||
|
||||
/*
|
||||
* don't play with this unless you benchmark!
|
||||
* the data format is not dependent on the hash function.
|
||||
* the hash function might seem strange, just believe me,
|
||||
* it works ;)
|
||||
*/
|
||||
#ifndef FRST
|
||||
# define FRST(p) (((p[0]) << 8) | p[1])
|
||||
# define NEXT(v,p) (((v) << 8) | p[2])
|
||||
# if ULTRA_FAST
|
||||
# define IDX(h) ((( h >> (3*8 - HLOG)) - h ) & (HSIZE - 1))
|
||||
# elif VERY_FAST
|
||||
# define IDX(h) ((( h >> (3*8 - HLOG)) - h*5) & (HSIZE - 1))
|
||||
# else
|
||||
# define IDX(h) ((((h ^ (h << 5)) >> (3*8 - HLOG)) - h*5) & (HSIZE - 1))
|
||||
# endif
|
||||
#endif
|
||||
/*
|
||||
* IDX works because it is very similar to a multiplicative hash, e.g.
|
||||
* ((h * 57321 >> (3*8 - HLOG)) & (HSIZE - 1))
|
||||
* the latter is also quite fast on newer CPUs, and compresses similarly.
|
||||
*
|
||||
* the next one is also quite good, albeit slow ;)
|
||||
* (int)(cos(h & 0xffffff) * 1e6)
|
||||
*/
|
||||
|
||||
#if 0
|
||||
/* original lzv-like hash function, much worse and thus slower */
|
||||
# define FRST(p) (p[0] << 5) ^ p[1]
|
||||
# define NEXT(v,p) ((v) << 5) ^ p[2]
|
||||
# define IDX(h) ((h) & (HSIZE - 1))
|
||||
#endif
|
||||
|
||||
#define MAX_LIT (1 << 5)
|
||||
#define MAX_OFF (1 << 13)
|
||||
#define MAX_REF ((1 << 8) + (1 << 3))
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
# define expect(expr,value) __builtin_expect ((expr),(value))
|
||||
# define inline inline
|
||||
#else
|
||||
# define expect(expr,value) (expr)
|
||||
# define inline static
|
||||
#endif
|
||||
|
||||
#define expect_false(expr) expect ((expr) != 0, 0)
|
||||
#define expect_true(expr) expect ((expr) != 0, 1)
|
||||
|
||||
#if defined(__has_attribute)
|
||||
# if __has_attribute(no_sanitize)
|
||||
# define NO_SANITIZE(sanitizer) __attribute__((no_sanitize(sanitizer)))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(NO_SANITIZE)
|
||||
# define NO_SANITIZE(sanitizer)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* compressed format
|
||||
*
|
||||
* 000LLLLL <L+1> ; literal, L+1=1..33 octets
|
||||
* LLLooooo oooooooo ; backref L+1=1..7 octets, o+1=1..4096 offset
|
||||
* 111ooooo LLLLLLLL oooooooo ; backref L+8 octets, o+1=1..4096 offset
|
||||
*
|
||||
*/
|
||||
NO_SANITIZE("alignment")
|
||||
size_t
|
||||
lzf_compress (const void *const in_data, size_t in_len,
|
||||
void *out_data, size_t out_len
|
||||
#if LZF_STATE_ARG
|
||||
, LZF_STATE htab
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if !LZF_STATE_ARG
|
||||
LZF_STATE htab;
|
||||
#endif
|
||||
const u8 *ip = (const u8 *)in_data;
|
||||
u8 *op = (u8 *)out_data;
|
||||
const u8 *in_end = ip + in_len;
|
||||
u8 *out_end = op + out_len;
|
||||
const u8 *ref;
|
||||
|
||||
/* off requires a type wide enough to hold a general pointer difference.
|
||||
* ISO C doesn't have that (size_t might not be enough and ptrdiff_t only
|
||||
* works for differences within a single object). We also assume that no
|
||||
* no bit pattern traps. Since the only platform that is both non-POSIX
|
||||
* and fails to support both assumptions is windows 64 bit, we make a
|
||||
* special workaround for it.
|
||||
*/
|
||||
#if defined (WIN32) && defined (_M_X64)
|
||||
unsigned _int64 off; /* workaround for missing POSIX compliance */
|
||||
#else
|
||||
size_t off;
|
||||
#endif
|
||||
unsigned int hval;
|
||||
int lit;
|
||||
|
||||
if (!in_len || !out_len)
|
||||
return 0;
|
||||
|
||||
#if INIT_HTAB
|
||||
memset (htab, 0, sizeof (htab));
|
||||
#endif
|
||||
|
||||
lit = 0; op++; /* start run */
|
||||
|
||||
hval = FRST (ip);
|
||||
while (ip < in_end - 2)
|
||||
{
|
||||
LZF_HSLOT *hslot;
|
||||
|
||||
hval = NEXT (hval, ip);
|
||||
hslot = htab + IDX (hval);
|
||||
ref = *hslot ? (*hslot + LZF_HSLOT_BIAS) : NULL; /* avoid applying zero offset to null pointer */
|
||||
*hslot = ip - LZF_HSLOT_BIAS;
|
||||
|
||||
if (1
|
||||
#if INIT_HTAB
|
||||
&& ref < ip /* the next test will actually take care of this, but this is faster */
|
||||
#endif
|
||||
&& (off = ip - ref - 1) < MAX_OFF
|
||||
&& ref > (u8 *)in_data
|
||||
&& ref[2] == ip[2]
|
||||
#if STRICT_ALIGN
|
||||
&& ((ref[1] << 8) | ref[0]) == ((ip[1] << 8) | ip[0])
|
||||
#else
|
||||
&& *(u16 *)ref == *(u16 *)ip
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* match found at *ref++ */
|
||||
unsigned int len = 2;
|
||||
size_t maxlen = in_end - ip - len;
|
||||
maxlen = maxlen > MAX_REF ? MAX_REF : maxlen;
|
||||
|
||||
if (expect_false (op + 3 + 1 >= out_end)) /* first a faster conservative test */
|
||||
if (op - !lit + 3 + 1 >= out_end) /* second the exact but rare test */
|
||||
return 0;
|
||||
|
||||
op [- lit - 1] = lit - 1; /* stop run */
|
||||
op -= !lit; /* undo run if length is zero */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (expect_true (maxlen > 16))
|
||||
{
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
len++; if (ref [len] != ip [len]) break;
|
||||
}
|
||||
|
||||
do
|
||||
len++;
|
||||
while (len < maxlen && ref[len] == ip[len]);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
len -= 2; /* len is now #octets - 1 */
|
||||
ip++;
|
||||
|
||||
if (len < 7)
|
||||
{
|
||||
*op++ = (off >> 8) + (len << 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
*op++ = (off >> 8) + ( 7 << 5);
|
||||
*op++ = len - 7;
|
||||
}
|
||||
|
||||
*op++ = off;
|
||||
|
||||
lit = 0; op++; /* start run */
|
||||
|
||||
ip += len + 1;
|
||||
|
||||
if (expect_false (ip >= in_end - 2))
|
||||
break;
|
||||
|
||||
#if ULTRA_FAST || VERY_FAST
|
||||
--ip;
|
||||
# if VERY_FAST && !ULTRA_FAST
|
||||
--ip;
|
||||
# endif
|
||||
hval = FRST (ip);
|
||||
|
||||
hval = NEXT (hval, ip);
|
||||
htab[IDX (hval)] = ip - LZF_HSLOT_BIAS;
|
||||
ip++;
|
||||
|
||||
# if VERY_FAST && !ULTRA_FAST
|
||||
hval = NEXT (hval, ip);
|
||||
htab[IDX (hval)] = ip - LZF_HSLOT_BIAS;
|
||||
ip++;
|
||||
# endif
|
||||
#else
|
||||
ip -= len + 1;
|
||||
|
||||
do
|
||||
{
|
||||
hval = NEXT (hval, ip);
|
||||
htab[IDX (hval)] = ip - LZF_HSLOT_BIAS;
|
||||
ip++;
|
||||
}
|
||||
while (len--);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* one more literal byte we must copy */
|
||||
if (expect_false (op >= out_end))
|
||||
return 0;
|
||||
|
||||
lit++; *op++ = *ip++;
|
||||
|
||||
if (expect_false (lit == MAX_LIT))
|
||||
{
|
||||
op [- lit - 1] = lit - 1; /* stop run */
|
||||
lit = 0; op++; /* start run */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (op + 3 > out_end) /* at most 3 bytes can be missing here */
|
||||
return 0;
|
||||
|
||||
while (ip < in_end)
|
||||
{
|
||||
lit++; *op++ = *ip++;
|
||||
|
||||
if (expect_false (lit == MAX_LIT))
|
||||
{
|
||||
op [- lit - 1] = lit - 1; /* stop run */
|
||||
lit = 0; op++; /* start run */
|
||||
}
|
||||
}
|
||||
|
||||
op [- lit - 1] = lit - 1; /* end run */
|
||||
op -= !lit; /* undo run if length is zero */
|
||||
|
||||
return op - (u8 *)out_data;
|
||||
}
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2010 Marc Alexander Lehmann <schmorp@schmorp.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
#include "lzfP.h"
|
||||
|
||||
#if AVOID_ERRNO
|
||||
# define SET_ERRNO(n)
|
||||
#else
|
||||
# include <errno.h>
|
||||
# define SET_ERRNO(n) errno = (n)
|
||||
#endif
|
||||
|
||||
#if USE_REP_MOVSB /* small win on amd, big loss on intel */
|
||||
#if (__i386 || __amd64) && __GNUC__ >= 3
|
||||
# define lzf_movsb(dst, src, len) \
|
||||
asm ("rep movsb" \
|
||||
: "=D" (dst), "=S" (src), "=c" (len) \
|
||||
: "0" (dst), "1" (src), "2" (len));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 7
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#endif
|
||||
size_t
|
||||
lzf_decompress (const void *const in_data, size_t in_len,
|
||||
void *out_data, size_t out_len)
|
||||
{
|
||||
u8 const *ip = (const u8 *)in_data;
|
||||
u8 *op = (u8 *)out_data;
|
||||
u8 const *const in_end = ip + in_len;
|
||||
u8 *const out_end = op + out_len;
|
||||
|
||||
while (ip < in_end)
|
||||
{
|
||||
unsigned int ctrl;
|
||||
ctrl = *ip++;
|
||||
|
||||
if (ctrl < (1 << 5)) /* literal run */
|
||||
{
|
||||
ctrl++;
|
||||
|
||||
if (op + ctrl > out_end)
|
||||
{
|
||||
SET_ERRNO (E2BIG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CHECK_INPUT
|
||||
if (ip + ctrl > in_end)
|
||||
{
|
||||
SET_ERRNO (EINVAL);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef lzf_movsb
|
||||
lzf_movsb (op, ip, ctrl);
|
||||
#else
|
||||
switch (ctrl)
|
||||
{
|
||||
case 32: *op++ = *ip++; case 31: *op++ = *ip++; case 30: *op++ = *ip++; case 29: *op++ = *ip++;
|
||||
case 28: *op++ = *ip++; case 27: *op++ = *ip++; case 26: *op++ = *ip++; case 25: *op++ = *ip++;
|
||||
case 24: *op++ = *ip++; case 23: *op++ = *ip++; case 22: *op++ = *ip++; case 21: *op++ = *ip++;
|
||||
case 20: *op++ = *ip++; case 19: *op++ = *ip++; case 18: *op++ = *ip++; case 17: *op++ = *ip++;
|
||||
case 16: *op++ = *ip++; case 15: *op++ = *ip++; case 14: *op++ = *ip++; case 13: *op++ = *ip++;
|
||||
case 12: *op++ = *ip++; case 11: *op++ = *ip++; case 10: *op++ = *ip++; case 9: *op++ = *ip++;
|
||||
case 8: *op++ = *ip++; case 7: *op++ = *ip++; case 6: *op++ = *ip++; case 5: *op++ = *ip++;
|
||||
case 4: *op++ = *ip++; case 3: *op++ = *ip++; case 2: *op++ = *ip++; case 1: *op++ = *ip++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else /* back reference */
|
||||
{
|
||||
unsigned int len = ctrl >> 5;
|
||||
|
||||
u8 *ref = op - ((ctrl & 0x1f) << 8) - 1;
|
||||
|
||||
#if CHECK_INPUT
|
||||
if (ip >= in_end)
|
||||
{
|
||||
SET_ERRNO (EINVAL);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (len == 7)
|
||||
{
|
||||
len += *ip++;
|
||||
#if CHECK_INPUT
|
||||
if (ip >= in_end)
|
||||
{
|
||||
SET_ERRNO (EINVAL);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ref -= *ip++;
|
||||
|
||||
if (op + len + 2 > out_end)
|
||||
{
|
||||
SET_ERRNO (E2BIG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ref < (u8 *)out_data)
|
||||
{
|
||||
SET_ERRNO (EINVAL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef lzf_movsb
|
||||
len += 2;
|
||||
lzf_movsb (op, ref, len);
|
||||
#else
|
||||
switch (len)
|
||||
{
|
||||
default:
|
||||
len += 2;
|
||||
|
||||
if (op >= ref + len)
|
||||
{
|
||||
/* disjunct areas */
|
||||
memcpy (op, ref, len);
|
||||
op += len;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* overlapping, use octte by octte copying */
|
||||
do
|
||||
*op++ = *ref++;
|
||||
while (--len);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 9: *op++ = *ref++; /* fall-thru */
|
||||
case 8: *op++ = *ref++; /* fall-thru */
|
||||
case 7: *op++ = *ref++; /* fall-thru */
|
||||
case 6: *op++ = *ref++; /* fall-thru */
|
||||
case 5: *op++ = *ref++; /* fall-thru */
|
||||
case 4: *op++ = *ref++; /* fall-thru */
|
||||
case 3: *op++ = *ref++; /* fall-thru */
|
||||
case 2: *op++ = *ref++; /* fall-thru */
|
||||
case 1: *op++ = *ref++; /* fall-thru */
|
||||
case 0: *op++ = *ref++; /* two octets more */
|
||||
*op++ = *ref++; /* fall-thru */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return op - (u8 *)out_data;
|
||||
}
|
||||
#if defined(__GNUC__) && __GNUC__ >= 5
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
A C-program for MT19937-64 (2004/9/29 version).
|
||||
Coded by Takuji Nishimura and Makoto Matsumoto.
|
||||
|
||||
This is a 64-bit version of Mersenne Twister pseudorandom number
|
||||
generator.
|
||||
|
||||
Before using, initialize the state by using init_genrand64(seed)
|
||||
or init_by_array64(init_key, key_length).
|
||||
|
||||
Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura,
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of its contributors may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
References:
|
||||
T. Nishimura, ``Tables of 64-bit Mersenne Twisters''
|
||||
ACM Transactions on Modeling and
|
||||
Computer Simulation 10. (2000) 348--357.
|
||||
M. Matsumoto and T. Nishimura,
|
||||
``Mersenne Twister: a 623-dimensionally equidistributed
|
||||
uniform pseudorandom number generator''
|
||||
ACM Transactions on Modeling and
|
||||
Computer Simulation 8. (Jan. 1998) 3--30.
|
||||
|
||||
Any feedback is very welcome.
|
||||
http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html
|
||||
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces)
|
||||
*/
|
||||
|
||||
|
||||
#include "mt19937-64.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define NN 312
|
||||
#define MM 156
|
||||
#define MATRIX_A 0xB5026F5AA96619E9ULL
|
||||
#define UM 0xFFFFFFFF80000000ULL /* Most significant 33 bits */
|
||||
#define LM 0x7FFFFFFFULL /* Least significant 31 bits */
|
||||
|
||||
|
||||
/* The array for the state vector */
|
||||
static unsigned long long mt[NN];
|
||||
/* mti==NN+1 means mt[NN] is not initialized */
|
||||
static int mti=NN+1;
|
||||
|
||||
/* initializes mt[NN] with a seed */
|
||||
void init_genrand64(unsigned long long seed)
|
||||
{
|
||||
mt[0] = seed;
|
||||
for (mti=1; mti<NN; mti++)
|
||||
mt[mti] = (6364136223846793005ULL * (mt[mti-1] ^ (mt[mti-1] >> 62)) + mti);
|
||||
}
|
||||
|
||||
/* initialize by an array with array-length */
|
||||
/* init_key is the array for initializing keys */
|
||||
/* key_length is its length */
|
||||
void init_by_array64(unsigned long long init_key[],
|
||||
unsigned long long key_length)
|
||||
{
|
||||
unsigned long long i, j, k;
|
||||
init_genrand64(19650218ULL);
|
||||
i=1; j=0;
|
||||
k = (NN>key_length ? NN : key_length);
|
||||
for (; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 62)) * 3935559000370003845ULL))
|
||||
+ init_key[j] + j; /* non linear */
|
||||
i++; j++;
|
||||
if (i>=NN) { mt[0] = mt[NN-1]; i=1; }
|
||||
if (j>=key_length) j=0;
|
||||
}
|
||||
for (k=NN-1; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 62)) * 2862933555777941757ULL))
|
||||
- i; /* non linear */
|
||||
i++;
|
||||
if (i>=NN) { mt[0] = mt[NN-1]; i=1; }
|
||||
}
|
||||
|
||||
mt[0] = 1ULL << 63; /* MSB is 1; assuring non-zero initial array */
|
||||
}
|
||||
|
||||
/* generates a random number on [0, 2^64-1]-interval */
|
||||
unsigned long long genrand64_int64(void)
|
||||
{
|
||||
int i;
|
||||
unsigned long long x;
|
||||
static unsigned long long mag01[2]={0ULL, MATRIX_A};
|
||||
|
||||
if (mti >= NN) { /* generate NN words at one time */
|
||||
|
||||
/* if init_genrand64() has not been called, */
|
||||
/* a default initial seed is used */
|
||||
if (mti == NN+1)
|
||||
init_genrand64(5489ULL);
|
||||
|
||||
for (i=0;i<NN-MM;i++) {
|
||||
x = (mt[i]&UM)|(mt[i+1]&LM);
|
||||
mt[i] = mt[i+MM] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
|
||||
}
|
||||
for (;i<NN-1;i++) {
|
||||
x = (mt[i]&UM)|(mt[i+1]&LM);
|
||||
mt[i] = mt[i+(MM-NN)] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
|
||||
}
|
||||
x = (mt[NN-1]&UM)|(mt[0]&LM);
|
||||
mt[NN-1] = mt[MM-1] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
|
||||
|
||||
mti = 0;
|
||||
}
|
||||
|
||||
x = mt[mti++];
|
||||
|
||||
x ^= (x >> 29) & 0x5555555555555555ULL;
|
||||
x ^= (x << 17) & 0x71D67FFFEDA60000ULL;
|
||||
x ^= (x << 37) & 0xFFF7EEE000000000ULL;
|
||||
x ^= (x >> 43);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/* generates a random number on [0, 2^63-1]-interval */
|
||||
long long genrand64_int63(void)
|
||||
{
|
||||
return (long long)(genrand64_int64() >> 1);
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1]-real-interval */
|
||||
double genrand64_real1(void)
|
||||
{
|
||||
return (genrand64_int64() >> 11) * (1.0/9007199254740991.0);
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1)-real-interval */
|
||||
double genrand64_real2(void)
|
||||
{
|
||||
return (genrand64_int64() >> 11) * (1.0/9007199254740992.0);
|
||||
}
|
||||
|
||||
/* generates a random number on (0,1)-real-interval */
|
||||
double genrand64_real3(void)
|
||||
{
|
||||
return ((genrand64_int64() >> 12) + 0.5) * (1.0/4503599627370496.0);
|
||||
}
|
||||
|
||||
#ifdef MT19937_64_MAIN
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
unsigned long long init[4]={0x12345ULL, 0x23456ULL, 0x34567ULL, 0x45678ULL}, length=4;
|
||||
init_by_array64(init, length);
|
||||
printf("1000 outputs of genrand64_int64()\n");
|
||||
for (i=0; i<1000; i++) {
|
||||
printf("%20llu ", genrand64_int64());
|
||||
if (i%5==4) printf("\n");
|
||||
}
|
||||
printf("\n1000 outputs of genrand64_real2()\n");
|
||||
for (i=0; i<1000; i++) {
|
||||
printf("%10.8f ", genrand64_real2());
|
||||
if (i%5==4) printf("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
A C-program for MT19937-64 (2004/9/29 version).
|
||||
Coded by Takuji Nishimura and Makoto Matsumoto.
|
||||
|
||||
This is a 64-bit version of Mersenne Twister pseudorandom number
|
||||
generator.
|
||||
|
||||
Before using, initialize the state by using init_genrand64(seed)
|
||||
or init_by_array64(init_key, key_length).
|
||||
|
||||
Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura,
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of its contributors may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
References:
|
||||
T. Nishimura, ``Tables of 64-bit Mersenne Twisters''
|
||||
ACM Transactions on Modeling and
|
||||
Computer Simulation 10. (2000) 348--357.
|
||||
M. Matsumoto and T. Nishimura,
|
||||
``Mersenne Twister: a 623-dimensionally equidistributed
|
||||
uniform pseudorandom number generator''
|
||||
ACM Transactions on Modeling and
|
||||
Computer Simulation 8. (Jan. 1998) 3--30.
|
||||
|
||||
Any feedback is very welcome.
|
||||
http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html
|
||||
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces)
|
||||
*/
|
||||
|
||||
#ifndef __MT19937_64_H
|
||||
#define __MT19937_64_H
|
||||
|
||||
/* initializes mt[NN] with a seed */
|
||||
void init_genrand64(unsigned long long seed);
|
||||
|
||||
/* initialize by an array with array-length */
|
||||
/* init_key is the array for initializing keys */
|
||||
/* key_length is its length */
|
||||
void init_by_array64(unsigned long long init_key[],
|
||||
unsigned long long key_length);
|
||||
|
||||
/* generates a random number on [0, 2^64-1]-interval */
|
||||
unsigned long long genrand64_int64(void);
|
||||
|
||||
|
||||
/* generates a random number on [0, 2^63-1]-interval */
|
||||
long long genrand64_int63(void);
|
||||
|
||||
/* generates a random number on [0,1]-real-interval */
|
||||
double genrand64_real1(void);
|
||||
|
||||
/* generates a random number on [0,1)-real-interval */
|
||||
double genrand64_real2(void);
|
||||
|
||||
/* generates a random number on (0,1)-real-interval */
|
||||
double genrand64_real3(void);
|
||||
|
||||
/* generates a random number on (0,1]-real-interval */
|
||||
double genrand64_real4(void);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,203 @@
|
|||
#ifndef __REDIS_OBJECT_H
|
||||
#define __REDIS_OBJECT_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "dict.h"
|
||||
#include "sds.h"
|
||||
#include "quicklist.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
/* The actual Redis Object */
|
||||
#define OBJ_STRING 0U /* String object. */
|
||||
#define OBJ_LIST 1U /* List object. */
|
||||
#define OBJ_SET 2U /* Set object. */
|
||||
#define OBJ_ZSET 3U /* Sorted set object. */
|
||||
#define OBJ_HASH 4U /* Hash object. */
|
||||
#define OBJ_MODULE 5U /* Module object. */
|
||||
#define OBJ_STREAM 6U /* Stream object. */
|
||||
|
||||
/* Objects encoding. Some kind of objects like Strings and Hashes can be
|
||||
* internally represented in multiple ways. The 'encoding' field of the object
|
||||
* is set to one of this fields for this object. */
|
||||
#define OBJ_ENCODING_RAW 0U /* Raw representation */
|
||||
#define OBJ_ENCODING_INT 1U /* Encoded as integer */
|
||||
#define OBJ_ENCODING_HT 2U /* Encoded as hash table */
|
||||
#define OBJ_ENCODING_ZIPMAP 3U /* Encoded as zipmap */
|
||||
#define OBJ_ENCODING_LINKEDLIST 4U /* No longer used: old list encoding. */
|
||||
#define OBJ_ENCODING_ZIPLIST 5U /* Encoded as ziplist */
|
||||
#define OBJ_ENCODING_INTSET 6U /* Encoded as intset */
|
||||
#define OBJ_ENCODING_SKIPLIST 7U /* Encoded as skiplist */
|
||||
#define OBJ_ENCODING_EMBSTR 8U /* Embedded sds string encoding */
|
||||
#define OBJ_ENCODING_QUICKLIST 9U /* Encoded as linked list of ziplists */
|
||||
#define OBJ_ENCODING_STREAM 10U /* Encoded as a radix tree of listpacks */
|
||||
#define OBJ_ENCODING_LISTPACK 11 /* Encoded as a listpack */
|
||||
#define OBJ_ENCODING_COMPRESS_INTERNAL 15U /* Kept as lzf compressed, to pass compressed blob to another thread */
|
||||
|
||||
#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^64 elements */
|
||||
#define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
|
||||
|
||||
|
||||
#define OBJ_HASH_KEY 1
|
||||
#define OBJ_HASH_VALUE 2
|
||||
|
||||
|
||||
#define OBJ_SHARED_INTEGERS 10000
|
||||
#define OBJ_SHARED_REFCOUNT INT_MAX /* Global object never destroyed. */
|
||||
#define OBJ_STATIC_REFCOUNT (INT_MAX-1) /* Object allocated in the stack. */
|
||||
#define OBJ_FIRST_SPECIAL_REFCOUNT OBJ_STATIC_REFCOUNT
|
||||
|
||||
/* List related stuff */
|
||||
#define LIST_HEAD 0
|
||||
#define LIST_TAIL 1
|
||||
#define ZSET_MIN 0
|
||||
#define ZSET_MAX 1
|
||||
|
||||
/* Error codes */
|
||||
#define C_OK 0
|
||||
#define C_ERR -1
|
||||
|
||||
typedef struct redisObject {
|
||||
unsigned type:4;
|
||||
unsigned encoding:4;
|
||||
unsigned lru:24; /* LRU time (relative to global lru_clock) or
|
||||
* LFU data (least significant 8 bits frequency
|
||||
* and most significant 16 bits access time). */
|
||||
int refcount;
|
||||
void *ptr;
|
||||
} robj;
|
||||
|
||||
|
||||
/* Redis object implementation */
|
||||
void decrRefCount(robj *o);
|
||||
void decrRefCountVoid(void *o);
|
||||
int getLongLongFromObject(robj *o, long long *target);
|
||||
void incrRefCount(robj *o);
|
||||
robj *makeObjectShared(robj *o);
|
||||
robj *resetRefCount(robj *obj);
|
||||
void freeStringObject(robj *o);
|
||||
void freeListObject(robj *o);
|
||||
void freeSetObject(robj *o);
|
||||
void freeZsetObject(robj *o);
|
||||
void freeHashObject(robj *o);
|
||||
robj *createObject(int type, void *ptr);
|
||||
robj *createStringObject(const char *ptr, size_t len);
|
||||
robj *createRawStringObject(const char *ptr, size_t len);
|
||||
robj *createEmbeddedStringObject(const char *ptr, size_t len);
|
||||
robj *dupStringObject(const robj *o);
|
||||
int isSdsRepresentableAsLongLong(sds s, long long *llval);
|
||||
int isObjectRepresentableAsLongLong(robj *o, long long *llongval);
|
||||
robj *getDecodedObject(robj *o);
|
||||
size_t stringObjectLen(robj *o);
|
||||
robj *createStringObjectFromLongLong(long long value);
|
||||
robj *createStringObjectFromLongLongForValue(long long value);
|
||||
robj *createStringObjectFromLongDouble(long double value, int humanfriendly);
|
||||
robj *createQuicklistObject(void);
|
||||
robj *createSetObject(void);
|
||||
robj *createIntsetObject(void);
|
||||
robj *createHashObject(void);
|
||||
robj *createZsetObject(void);
|
||||
robj *createZsetListpackObject(void);
|
||||
unsigned long long estimateObjectIdleTime(const robj *o);
|
||||
uint8_t LFUDecrAndReturn(time_t epoch_sec, const robj *o);
|
||||
void listTypeConvert(robj *subject, int enc);
|
||||
void hashTypeConvert(robj *o, int enc);
|
||||
unsigned long hashTypeLength(const robj *o);
|
||||
int hashZiplistValidateIntegrity(unsigned char *zl, size_t size, int deep);
|
||||
int objectSetLRUOrLFU(robj *val, long long lfu_freq, long long lru_idle,
|
||||
long long lru_clock, int lru_multiplier);
|
||||
|
||||
|
||||
robj *setTypeCreate(sds value);
|
||||
int setTypeAdd(robj *subject, sds value);
|
||||
int setTypeRemove(robj *subject, sds value);
|
||||
int setTypeIsMember(const robj *subject, sds value);
|
||||
int setTypeRandomElement(robj *setobj, sds *sdsele, int64_t *llele);
|
||||
unsigned long setTypeRandomElements(robj *set, unsigned long count, robj *aux_set);
|
||||
unsigned long setTypeSize(const robj *subject);
|
||||
void setTypeConvert(robj *subject, int enc);
|
||||
|
||||
|
||||
static inline int sdsEncodedObject(const robj *o) {
|
||||
return o->encoding == OBJ_ENCODING_RAW || o->encoding == OBJ_ENCODING_EMBSTR;
|
||||
}
|
||||
|
||||
|
||||
/* Structure to hold set iteration abstraction. */
|
||||
typedef struct {
|
||||
robj *subject;
|
||||
int encoding;
|
||||
int ii; /* intset iterator */
|
||||
dictIterator *di;
|
||||
} setTypeIterator;
|
||||
|
||||
/* Structure to hold hash iteration abstraction. Note that iteration over
|
||||
* hashes involves both fields and values. Because it is possible that
|
||||
* not both are required, store pointers in the iterator to avoid
|
||||
* unnecessary memory allocation for fields/values. */
|
||||
typedef struct {
|
||||
robj *subject;
|
||||
int encoding;
|
||||
|
||||
unsigned char *fptr, *vptr;
|
||||
|
||||
dictIterator *di;
|
||||
dictEntry *de;
|
||||
} hashTypeIterator;
|
||||
|
||||
/* Structure to hold list iteration abstraction. */
|
||||
typedef struct {
|
||||
robj *subject;
|
||||
unsigned char encoding;
|
||||
unsigned char direction; /* Iteration direction */
|
||||
quicklistIter *iter;
|
||||
} listTypeIterator;
|
||||
|
||||
/* Structure for an entry while iterating over a list. */
|
||||
typedef struct {
|
||||
listTypeIterator *li;
|
||||
quicklistEntry entry; /* Entry in quicklist */
|
||||
} listTypeEntry;
|
||||
|
||||
setTypeIterator *setTypeInitIterator(robj *subject);
|
||||
void setTypeReleaseIterator(setTypeIterator *si);
|
||||
int setTypeNext(setTypeIterator *si, sds *sdsele, int64_t *llele);
|
||||
sds setTypeNextObject(setTypeIterator *si);
|
||||
|
||||
|
||||
/* Macro used to initialize a Redis object allocated on the stack.
|
||||
* Note that this macro is taken near the structure definition to make sure
|
||||
* we'll update it when the structure is changed, to avoid bugs like
|
||||
* bug #85 introduced exactly in this way. */
|
||||
#define initStaticStringObject(_var,_ptr) do { \
|
||||
_var.refcount = OBJ_STATIC_REFCOUNT; \
|
||||
_var.type = OBJ_STRING; \
|
||||
_var.encoding = OBJ_ENCODING_RAW; \
|
||||
_var.ptr = _ptr; \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define serverAssertWithInfo(x, y, z) serverAssert(z)
|
||||
|
||||
#define PROTO_SHARED_SELECT_CMDS 10
|
||||
#define OBJ_SHARED_BULKHDR_LEN 32
|
||||
|
||||
struct sharedObjectsStruct {
|
||||
robj *crlf, *ok, *err, *emptybulk, *czero, *cone, *pong, *space,
|
||||
*colon, *queued, *null[4], *nullarray[4], *emptymap[4], *emptyset[4],
|
||||
*emptyarray, *wrongtypeerr, *nokeyerr, *syntaxerr, *sameobjecterr,
|
||||
*outofrangeerr, *noscripterr, *loadingerr, *slowscripterr, *bgsaveerr,
|
||||
*masterdownerr, *roslaveerr, *execaborterr, *noautherr, *noreplicaserr,
|
||||
*busykeyerr, *oomerr, *plus, *messagebulk, *pmessagebulk, *subscribebulk,
|
||||
*unsubscribebulk, *psubscribebulk, *punsubscribebulk, *del, *unlink,
|
||||
*rpop, *lpop, *lpush, *rpoplpush, *lmove, *blmove, *zpopmin, *zpopmax,
|
||||
*emptyscan, *multi, *exec, *left, *right;
|
||||
sds minstring, maxstring;
|
||||
};
|
||||
|
||||
extern struct sharedObjectsStruct shared;
|
||||
|
||||
void initSharedStruct();
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,211 @@
|
|||
/* quicklist.h - A generic doubly linked quicklist implementation
|
||||
*
|
||||
* Copyright (c) 2014, Matt Stancliff <matt@genges.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this quicklist of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this quicklist of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdint.h> // for UINTPTR_MAX
|
||||
|
||||
#ifndef __QUICKLIST_H__
|
||||
#define __QUICKLIST_H__
|
||||
|
||||
/* Node, quicklist, and Iterator are the only data structures used currently. */
|
||||
|
||||
/* quicklistNode is a 32 byte struct describing a listpack for a quicklist.
|
||||
* We use bit fields keep the quicklistNode at 32 bytes.
|
||||
* count: 16 bits, max 65536 (max lp bytes is 65k, so max count actually < 32k).
|
||||
* encoding: 2 bits, RAW=1, LZF=2.
|
||||
* container: 2 bits, PLAIN=1, PACKED=2.
|
||||
* recompress: 1 bit, bool, true if node is temporary decompressed for usage.
|
||||
* attempted_compress: 1 bit, boolean, used for verifying during testing.
|
||||
* extra: 10 bits, free for future use; pads out the remainder of 32 bits */
|
||||
typedef struct quicklistNode {
|
||||
struct quicklistNode *prev;
|
||||
struct quicklistNode *next;
|
||||
unsigned char *entry;
|
||||
size_t sz; /* entry size in bytes */
|
||||
unsigned int count : 16; /* count of items in listpack */
|
||||
unsigned int encoding : 2; /* RAW==1 or LZF==2 */
|
||||
unsigned int container : 2; /* PLAIN==1 or PACKED==2 */
|
||||
unsigned int recompress : 1; /* was this node previous compressed? */
|
||||
unsigned int attempted_compress : 1; /* node can't compress; too small */
|
||||
unsigned int extra : 10; /* more bits to steal for future usage */
|
||||
} quicklistNode;
|
||||
|
||||
/* quicklistLZF is a 8+N byte struct holding 'sz' followed by 'compressed'.
|
||||
* 'sz' is byte length of 'compressed' field.
|
||||
* 'compressed' is LZF data with total (compressed) length 'sz'
|
||||
* NOTE: uncompressed length is stored in quicklistNode->sz.
|
||||
* When quicklistNode->entry is compressed, node->entry points to a quicklistLZF */
|
||||
typedef struct quicklistLZF {
|
||||
size_t sz; /* LZF size in bytes*/
|
||||
char compressed[];
|
||||
} quicklistLZF;
|
||||
|
||||
/* Bookmarks are padded with realloc at the end of of the quicklist struct.
|
||||
* They should only be used for very big lists if thousands of nodes were the
|
||||
* excess memory usage is negligible, and there's a real need to iterate on them
|
||||
* in portions.
|
||||
* When not used, they don't add any memory overhead, but when used and then
|
||||
* deleted, some overhead remains (to avoid resonance).
|
||||
* The number of bookmarks used should be kept to minimum since it also adds
|
||||
* overhead on node deletion (searching for a bookmark to update). */
|
||||
typedef struct quicklistBookmark {
|
||||
quicklistNode *node;
|
||||
char *name;
|
||||
} quicklistBookmark;
|
||||
|
||||
#if UINTPTR_MAX == 0xffffffff
|
||||
/* 32-bit */
|
||||
# define QL_FILL_BITS 14
|
||||
# define QL_COMP_BITS 14
|
||||
# define QL_BM_BITS 4
|
||||
#elif UINTPTR_MAX == 0xffffffffffffffff
|
||||
/* 64-bit */
|
||||
# define QL_FILL_BITS 16
|
||||
# define QL_COMP_BITS 16
|
||||
# define QL_BM_BITS 4 /* we can encode more, but we rather limit the user
|
||||
since they cause performance degradation. */
|
||||
#else
|
||||
# error unknown arch bits count
|
||||
#endif
|
||||
|
||||
/* quicklist is a 40 byte struct (on 64-bit systems) describing a quicklist.
|
||||
* 'count' is the number of total entries.
|
||||
* 'len' is the number of quicklist nodes.
|
||||
* 'compress' is: 0 if compression disabled, otherwise it's the number
|
||||
* of quicklistNodes to leave uncompressed at ends of quicklist.
|
||||
* 'fill' is the user-requested (or default) fill factor.
|
||||
* 'bookmarks are an optional feature that is used by realloc this struct,
|
||||
* so that they don't consume memory when not used. */
|
||||
typedef struct quicklist {
|
||||
quicklistNode *head;
|
||||
quicklistNode *tail;
|
||||
unsigned long count; /* total count of all entries in all listpacks */
|
||||
unsigned long len; /* number of quicklistNodes */
|
||||
signed int fill : QL_FILL_BITS; /* fill factor for individual nodes */
|
||||
unsigned int compress : QL_COMP_BITS; /* depth of end nodes not to compress;0=off */
|
||||
unsigned int bookmark_count: QL_BM_BITS;
|
||||
quicklistBookmark bookmarks[];
|
||||
} quicklist;
|
||||
|
||||
typedef struct quicklistIter {
|
||||
quicklist *quicklist;
|
||||
quicklistNode *current;
|
||||
unsigned char *zi;
|
||||
long offset; /* offset in current listpack */
|
||||
int direction;
|
||||
} quicklistIter;
|
||||
|
||||
typedef struct quicklistEntry {
|
||||
const quicklist *quicklist;
|
||||
quicklistNode *node;
|
||||
unsigned char *zi;
|
||||
unsigned char *value;
|
||||
long long longval;
|
||||
size_t sz;
|
||||
int offset;
|
||||
} quicklistEntry;
|
||||
|
||||
#define QUICKLIST_HEAD 0
|
||||
#define QUICKLIST_TAIL -1
|
||||
|
||||
/* quicklist node encodings */
|
||||
#define QUICKLIST_NODE_ENCODING_RAW 1
|
||||
#define QUICKLIST_NODE_ENCODING_LZF 2
|
||||
|
||||
/* quicklist compression disable */
|
||||
#define QUICKLIST_NOCOMPRESS 0
|
||||
|
||||
/* quicklist container formats */
|
||||
#define QUICKLIST_NODE_CONTAINER_PLAIN 1
|
||||
#define QUICKLIST_NODE_CONTAINER_PACKED 2
|
||||
|
||||
#define QL_NODE_IS_PLAIN(node) ((node)->container == QUICKLIST_NODE_CONTAINER_PLAIN)
|
||||
|
||||
#define quicklistNodeIsCompressed(node) \
|
||||
((node)->encoding == QUICKLIST_NODE_ENCODING_LZF)
|
||||
|
||||
/* Prototypes */
|
||||
quicklist *quicklistCreate(void);
|
||||
quicklist *quicklistNew(int fill, int compress);
|
||||
void quicklistSetCompressDepth(quicklist *quicklist, int depth);
|
||||
void quicklistSetFill(quicklist *quicklist, int fill);
|
||||
void quicklistSetOptions(quicklist *quicklist, int fill, int depth);
|
||||
void quicklistRelease(quicklist *quicklist);
|
||||
int quicklistPushHead(quicklist *quicklist, void *value, const size_t sz);
|
||||
int quicklistPushTail(quicklist *quicklist, void *value, const size_t sz);
|
||||
void quicklistPush(quicklist *quicklist, void *value, const size_t sz,
|
||||
int where);
|
||||
void quicklistAppendListpack(quicklist *quicklist, unsigned char *zl);
|
||||
void quicklistAppendPlainNode(quicklist *quicklist, unsigned char *data, size_t sz);
|
||||
void quicklistInsertAfter(quicklistIter *iter, quicklistEntry *entry,
|
||||
const void *value, const size_t sz);
|
||||
void quicklistInsertBefore(quicklistIter *iter, quicklistEntry *entry,
|
||||
void *value, const size_t sz);
|
||||
void quicklistDelEntry(quicklistIter *iter, quicklistEntry *entry);
|
||||
void quicklistReplaceEntry(quicklistIter *iter, quicklistEntry *entry,
|
||||
const void *data, size_t sz);
|
||||
int quicklistReplaceAtIndex(quicklist *quicklist, long index, const void *data,
|
||||
const size_t sz);
|
||||
int quicklistDelRange(quicklist *quicklist, const long start, const long stop);
|
||||
quicklistIter *quicklistGetIterator(quicklist *quicklist, int direction);
|
||||
quicklistIter *quicklistGetIteratorAtIdx(quicklist *quicklist,
|
||||
int direction, const long long idx);
|
||||
quicklistIter *quicklistGetIteratorEntryAtIdx(quicklist *quicklist, const long long index,
|
||||
quicklistEntry *entry);
|
||||
int quicklistNext(quicklistIter *iter, quicklistEntry *entry);
|
||||
void quicklistSetDirection(quicklistIter *iter, int direction);
|
||||
void quicklistReleaseIterator(quicklistIter *iter);
|
||||
quicklist *quicklistDup(quicklist *orig);
|
||||
void quicklistRotate(quicklist *quicklist);
|
||||
int quicklistPopCustom(quicklist *quicklist, int where, unsigned char **data,
|
||||
size_t *sz, long long *sval,
|
||||
void *(*saver)(unsigned char *data, size_t sz));
|
||||
int quicklistPop(quicklist *quicklist, int where, unsigned char **data,
|
||||
size_t *sz, long long *slong);
|
||||
unsigned long quicklistCount(const quicklist *ql);
|
||||
int quicklistCompare(const quicklistEntry *entry, const unsigned char *p2, const size_t p2_len);
|
||||
size_t quicklistGetLzf(const quicklistNode *node, void **data);
|
||||
void quicklistRepr(unsigned char *ql, int full);
|
||||
|
||||
/* bookmarks */
|
||||
int quicklistBookmarkCreate(quicklist **ql_ref, const char *name, quicklistNode *node);
|
||||
int quicklistBookmarkDelete(quicklist *ql, const char *name);
|
||||
quicklistNode *quicklistBookmarkFind(quicklist *ql, const char *name);
|
||||
void quicklistBookmarksClear(quicklist *ql);
|
||||
int quicklistisSetPackedThreshold(size_t sz);
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
int quicklistTest(int argc, char *argv[], int flags);
|
||||
#endif
|
||||
|
||||
/* Directions for iterators */
|
||||
#define AL_START_HEAD 0
|
||||
#define AL_START_TAIL 1
|
||||
|
||||
#endif /* __QUICKLIST_H__ */
|
|
@ -0,0 +1,150 @@
|
|||
#include "redis_aux.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "crc64.h"
|
||||
#include "object.h"
|
||||
#include "zmalloc.h"
|
||||
|
||||
Server server;
|
||||
|
||||
void InitRedisTables() {
|
||||
crc64_init();
|
||||
server.page_size = sysconf(_SC_PAGESIZE);
|
||||
server.zset_max_listpack_entries = 128;
|
||||
server.zset_max_listpack_value = 64;
|
||||
}
|
||||
|
||||
// These functions are moved here from server.c
|
||||
int htNeedsResize(dict* dict) {
|
||||
long long size, used;
|
||||
|
||||
size = dictSlots(dict);
|
||||
used = dictSize(dict);
|
||||
return (size > DICT_HT_INITIAL_SIZE && (used * 100 / size < HASHTABLE_MIN_FILL));
|
||||
}
|
||||
|
||||
uint64_t dictSdsHash(const void* key) {
|
||||
return dictGenHashFunction((unsigned char*)key, sdslen((char*)key));
|
||||
}
|
||||
|
||||
// MurmurHash64A for 8 bytes blob.
|
||||
uint64_t dictPtrHash(const void* key) {
|
||||
const uint64_t m = 0xc6a4a7935bd1e995ULL;
|
||||
const int r = 47;
|
||||
uint64_t h = 120577 ^ (8 * m);
|
||||
uint64_t data;
|
||||
memcpy(&data, key, 8);
|
||||
uint64_t k = data;
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
h ^= k;
|
||||
h *= m;
|
||||
|
||||
h ^= h >> r;
|
||||
h *= m;
|
||||
h ^= h >> r;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
int dictPtrKeyCompare(dict* privdata, const void* key1, const void* key2) {
|
||||
return key1 == key2;
|
||||
}
|
||||
|
||||
int dictSdsKeyCompare(dict *d, const void* key1, const void* key2) {
|
||||
int l1, l2;
|
||||
DICT_NOTUSED(d);
|
||||
|
||||
l1 = sdslen((sds)key1);
|
||||
l2 = sdslen((sds)key2);
|
||||
if (l1 != l2)
|
||||
return 0;
|
||||
return memcmp(key1, key2, l1) == 0;
|
||||
}
|
||||
|
||||
void dictSdsDestructor(dict *d, void* val) {
|
||||
DICT_NOTUSED(d);
|
||||
|
||||
sdsfree(val);
|
||||
}
|
||||
|
||||
/* Return the size consumed from the allocator, for the specified SDS string,
|
||||
* including internal fragmentation. This function is used in order to compute
|
||||
* the client output buffer size. */
|
||||
size_t sdsZmallocSize(sds s) {
|
||||
void* sh = sdsAllocPtr(s);
|
||||
return zmalloc_size(sh);
|
||||
}
|
||||
|
||||
/* Return 1 if currently we allow dict to expand. Dict may allocate huge
|
||||
* memory to contain hash buckets when dict expands, that may lead redis
|
||||
* rejects user's requests or evicts some keys, we can stop dict to expand
|
||||
* provisionally if used memory will be over maxmemory after dict expands,
|
||||
* but to guarantee the performance of redis, we still allow dict to expand
|
||||
* if dict load factor exceeds HASHTABLE_MAX_LOAD_FACTOR. */
|
||||
static int dictExpandAllowed(size_t moreMem, double usedRatio) {
|
||||
if (usedRatio <= HASHTABLE_MAX_LOAD_FACTOR) {
|
||||
return !overMaxmemoryAfterAlloc(moreMem);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set dictionary type. Keys are SDS strings, values are not used. */
|
||||
dictType setDictType = {
|
||||
dictSdsHash, /* hash function */
|
||||
NULL, /* key dup */
|
||||
NULL, /* val dup */
|
||||
dictSdsKeyCompare, /* key compare */
|
||||
dictSdsDestructor, /* key destructor */
|
||||
NULL, /* val destructor */
|
||||
NULL /* allow to expand */
|
||||
};
|
||||
|
||||
/* Sorted sets hash (note: a skiplist is used in addition to the hash table) */
|
||||
dictType zsetDictType = {
|
||||
dictSdsHash, /* hash function */
|
||||
NULL, /* key dup */
|
||||
NULL, /* val dup */
|
||||
dictSdsKeyCompare, /* key compare */
|
||||
NULL, /* Note: SDS string shared & freed by skiplist */
|
||||
NULL, /* val destructor */
|
||||
NULL /* allow to expand */
|
||||
};
|
||||
|
||||
static void dictObjectDestructor(dict* privdata, void* val) {
|
||||
DICT_NOTUSED(privdata);
|
||||
|
||||
if (val == NULL)
|
||||
return; /* Lazy freeing will set value to NULL. */
|
||||
decrRefCount(val);
|
||||
}
|
||||
|
||||
/* Db->dict, keys are sds strings, vals are Redis objects. */
|
||||
dictType dbDictType = {
|
||||
dictSdsHash, /* hash function */
|
||||
NULL, /* key dup */
|
||||
NULL, /* val dup */
|
||||
dictSdsKeyCompare, /* key compare */
|
||||
dictSdsDestructor, /* key destructor */
|
||||
dictObjectDestructor, /* val destructor */
|
||||
dictExpandAllowed /* allow to expand */
|
||||
};
|
||||
|
||||
/* Db->expires */
|
||||
/* Db->expires stores keys that are contained in redis_dict_.
|
||||
Which means that uniqueness of the strings is guaranteed through uniqueness of the pointers
|
||||
Therefore, it's enough to compare and hash keys by their addresses without reading the contents
|
||||
of the key
|
||||
*/
|
||||
dictType keyPtrDictType = {
|
||||
dictPtrHash, /* hash function */
|
||||
NULL, /* key dup */
|
||||
NULL, /* val dup */
|
||||
dictPtrKeyCompare, /* key compare */
|
||||
NULL, /* key destructor */
|
||||
NULL, /* val destructor */
|
||||
NULL /* allow to expand */
|
||||
};
|
|
@ -0,0 +1,114 @@
|
|||
#ifndef __REDIS_AUX_H
|
||||
#define __REDIS_AUX_H
|
||||
|
||||
#include "dict.h"
|
||||
#include "sds.h"
|
||||
|
||||
#define HASHTABLE_MIN_FILL 10 /* Minimal hash table fill 10% */
|
||||
#define HASHTABLE_MAX_LOAD_FACTOR 1.618 /* Maximum hash table load factor. */
|
||||
|
||||
/* Redis maxmemory strategies. Instead of using just incremental number
|
||||
* for this defines, we use a set of flags so that testing for certain
|
||||
* properties common to multiple policies is faster. */
|
||||
#define MAXMEMORY_FLAG_LRU (1<<0)
|
||||
#define MAXMEMORY_FLAG_LFU (1<<1)
|
||||
#define MAXMEMORY_FLAG_ALLKEYS (1<<2)
|
||||
#define MAXMEMORY_FLAG_NO_SHARED_INTEGERS (MAXMEMORY_FLAG_LRU|MAXMEMORY_FLAG_LFU)
|
||||
|
||||
#define LFU_INIT_VAL 5
|
||||
|
||||
#define MAXMEMORY_VOLATILE_LRU ((0<<8)|MAXMEMORY_FLAG_LRU)
|
||||
#define MAXMEMORY_VOLATILE_LFU ((1<<8)|MAXMEMORY_FLAG_LFU)
|
||||
#define MAXMEMORY_VOLATILE_TTL (2<<8)
|
||||
#define MAXMEMORY_VOLATILE_RANDOM (3<<8)
|
||||
#define MAXMEMORY_ALLKEYS_LRU ((4<<8)|MAXMEMORY_FLAG_LRU|MAXMEMORY_FLAG_ALLKEYS)
|
||||
#define MAXMEMORY_ALLKEYS_LFU ((5<<8)|MAXMEMORY_FLAG_LFU|MAXMEMORY_FLAG_ALLKEYS)
|
||||
#define MAXMEMORY_ALLKEYS_RANDOM ((6<<8)|MAXMEMORY_FLAG_ALLKEYS)
|
||||
#define MAXMEMORY_NO_EVICTION (7<<8)
|
||||
|
||||
|
||||
#define CONFIG_RUN_ID_SIZE 40
|
||||
|
||||
#define EVPOOL_CACHED_SDS_SIZE 255
|
||||
#define EVPOOL_SIZE 16
|
||||
|
||||
int htNeedsResize(dict *dict); // moved from server.cc
|
||||
|
||||
/* Hash table types */
|
||||
extern dictType dbDictType;
|
||||
extern dictType zsetDictType;
|
||||
extern dictType setDictType;
|
||||
extern dictType keyPtrDictType;
|
||||
extern dictType hashDictType;
|
||||
|
||||
/* To improve the quality of the LRU approximation we take a set of keys
|
||||
* that are good candidate for eviction across performEvictions() calls.
|
||||
*
|
||||
* Entries inside the eviction pool are taken ordered by idle time, putting
|
||||
* greater idle times to the right (ascending order).
|
||||
*
|
||||
* When an LFU policy is used instead, a reverse frequency indication is used
|
||||
* instead of the idle time, so that we still evict by larger value (larger
|
||||
* inverse frequency means to evict keys with the least frequent accesses).
|
||||
*
|
||||
* Empty entries have the key pointer set to NULL. */
|
||||
|
||||
struct evictionPoolEntry {
|
||||
unsigned long long idle; /* Object idle time (inverse frequency for LFU) */
|
||||
sds key; /* Key name. */
|
||||
sds cached; /* Cached SDS object for key name. */
|
||||
int dbid; /* Key DB number. */
|
||||
};
|
||||
|
||||
uint64_t dictSdsHash(const void *key);
|
||||
int dictSdsKeyCompare(dict *privdata, const void *key1, const void *key2);
|
||||
void dictSdsDestructor(dict *privdata, void *val);
|
||||
int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level);
|
||||
|
||||
void evictionPoolPopulate(int dbid, dict *sampledict, dict *keydict, struct evictionPoolEntry *pool);
|
||||
int overMaxmemoryAfterAlloc(size_t moremem);
|
||||
size_t sdsZmallocSize(sds s) ;
|
||||
|
||||
typedef struct ServerStub {
|
||||
// char replid[CONFIG_RUN_ID_SIZE+1]; /* Master replication ID (if master). */
|
||||
size_t loading_loaded_bytes;
|
||||
size_t page_size;
|
||||
long long dirty, master_repl_offset;
|
||||
time_t lastsave;
|
||||
char* masterhost;
|
||||
|
||||
int rdb_compression;
|
||||
int loading;
|
||||
int key_load_delay;
|
||||
int repl_state;
|
||||
int loading_start_time;
|
||||
int loading_total_bytes;
|
||||
int lastbgsave_status;
|
||||
|
||||
int lfu_decay_time; /* LFU counter decay factor. */
|
||||
/* should not be used. Use FLAGS_list_max_ziplist_size and FLAGS_list_compress_depth instead. */
|
||||
int list_compress_depth;
|
||||
int list_max_ziplist_size;
|
||||
|
||||
unsigned long long maxmemory; /* Max number of memory bytes to use */
|
||||
int maxmemory_policy; /* Policy for key eviction */
|
||||
|
||||
int rdb_save_incremental_fsync;
|
||||
size_t stat_peak_memory;
|
||||
size_t set_max_intset_entries, hash_max_ziplist_entries,
|
||||
hash_max_ziplist_value;
|
||||
size_t zset_max_listpack_entries;
|
||||
size_t zset_max_listpack_value;
|
||||
int sanitize_dump_payload; /* Enables deep sanitization for ziplist and listpack in RDB and RESTORE. */
|
||||
long long stat_dump_payload_sanitizations; /* Number deep dump payloads integrity validations. */
|
||||
off_t loading_rdb_used_mem;
|
||||
} Server;
|
||||
|
||||
|
||||
extern Server server;
|
||||
|
||||
void InitRedisTables();
|
||||
|
||||
typedef struct redisObject robj;
|
||||
|
||||
#endif /* __REDIS_AUX_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,286 @@
|
|||
/* SDSLib 2.0 -- A C dynamic strings library
|
||||
*
|
||||
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2015, Oran Agra
|
||||
* Copyright (c) 2015, Redis Labs, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __SDS_H
|
||||
#define __SDS_H
|
||||
|
||||
#define SDS_MAX_PREALLOC (1024*1024)
|
||||
extern const char *SDS_NOINIT;
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef char *sds;
|
||||
|
||||
/* Note: sdshdr5 is never used, we just access the flags byte directly.
|
||||
* However is here to document the layout of type 5 SDS strings. */
|
||||
struct __attribute__ ((__packed__)) sdshdr5 {
|
||||
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr8 {
|
||||
uint8_t len; /* used */
|
||||
uint8_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr16 {
|
||||
uint16_t len; /* used */
|
||||
uint16_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr32 {
|
||||
uint32_t len; /* used */
|
||||
uint32_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr64 {
|
||||
uint64_t len; /* used */
|
||||
uint64_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
|
||||
#define SDS_TYPE_5 0
|
||||
#define SDS_TYPE_8 1
|
||||
#define SDS_TYPE_16 2
|
||||
#define SDS_TYPE_32 3
|
||||
#define SDS_TYPE_64 4
|
||||
#define SDS_TYPE_MASK 7
|
||||
#define SDS_TYPE_BITS 3
|
||||
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
|
||||
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = SDS_HDR(T,s);
|
||||
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
|
||||
|
||||
static inline size_t sdslen(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
return SDS_TYPE_5_LEN(flags);
|
||||
case SDS_TYPE_8:
|
||||
return SDS_HDR(8,s)->len;
|
||||
case SDS_TYPE_16:
|
||||
return SDS_HDR(16,s)->len;
|
||||
case SDS_TYPE_32:
|
||||
return SDS_HDR(32,s)->len;
|
||||
case SDS_TYPE_64:
|
||||
return SDS_HDR(64,s)->len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t sdsavail(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5: {
|
||||
return 0;
|
||||
}
|
||||
case SDS_TYPE_8: {
|
||||
SDS_HDR_VAR(8,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_16: {
|
||||
SDS_HDR_VAR(16,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_32: {
|
||||
SDS_HDR_VAR(32,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_64: {
|
||||
SDS_HDR_VAR(64,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sdssetlen(sds s, size_t newlen) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
{
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
||||
}
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->len = newlen;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->len = newlen;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->len = newlen;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len = newlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sdsinclen(sds s, size_t inc) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
{
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc;
|
||||
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
||||
}
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->len += inc;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->len += inc;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->len += inc;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len += inc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* sdsalloc() = sdsavail() + sdslen() */
|
||||
static inline size_t sdsalloc(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
return SDS_TYPE_5_LEN(flags);
|
||||
case SDS_TYPE_8:
|
||||
return SDS_HDR(8,s)->alloc;
|
||||
case SDS_TYPE_16:
|
||||
return SDS_HDR(16,s)->alloc;
|
||||
case SDS_TYPE_32:
|
||||
return SDS_HDR(32,s)->alloc;
|
||||
case SDS_TYPE_64:
|
||||
return SDS_HDR(64,s)->alloc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sdssetalloc(sds s, size_t newlen) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
/* Nothing to do, this type has no total allocation info. */
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->alloc = newlen;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->alloc = newlen;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->alloc = newlen;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->alloc = newlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sds sdsnewlen(const void *init, size_t initlen);
|
||||
sds sdstrynewlen(const void *init, size_t initlen);
|
||||
sds sdsnew(const char *init);
|
||||
sds sdsempty(void);
|
||||
sds sdsdup(const sds s);
|
||||
void sdsfree(sds s);
|
||||
sds sdsgrowzero(sds s, size_t len);
|
||||
sds sdscatlen(sds s, const void *t, size_t len);
|
||||
sds sdscat(sds s, const char *t);
|
||||
sds sdscatsds(sds s, const sds t);
|
||||
sds sdscpylen(sds s, const char *t, size_t len);
|
||||
sds sdscpy(sds s, const char *t);
|
||||
|
||||
sds sdscatvprintf(sds s, const char *fmt, va_list ap);
|
||||
#ifdef __GNUC__
|
||||
sds sdscatprintf(sds s, const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
#else
|
||||
sds sdscatprintf(sds s, const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
sds sdscatfmt(sds s, char const *fmt, ...);
|
||||
sds sdstrim(sds s, const char *cset);
|
||||
void sdssubstr(sds s, size_t start, size_t len);
|
||||
void sdsrange(sds s, ssize_t start, ssize_t end);
|
||||
void sdsupdatelen(sds s);
|
||||
void sdsclear(sds s);
|
||||
int sdscmp(const sds s1, const sds s2);
|
||||
sds *sdssplitlen(const char *s, ssize_t len, const char *sep, int seplen, int *count);
|
||||
void sdsfreesplitres(sds *tokens, int count);
|
||||
void sdstolower(sds s);
|
||||
void sdstoupper(sds s);
|
||||
sds sdsfromlonglong(long long value);
|
||||
sds sdscatrepr(sds s, const char *p, size_t len);
|
||||
sds *sdssplitargs(const char *line, int *argc);
|
||||
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
|
||||
sds sdsjoin(char **argv, int argc, char *sep);
|
||||
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
|
||||
|
||||
/* Callback for sdstemplate. The function gets called by sdstemplate
|
||||
* every time a variable needs to be expanded. The variable name is
|
||||
* provided as variable, and the callback is expected to return a
|
||||
* substitution value. Returning a NULL indicates an error.
|
||||
*/
|
||||
typedef sds (*sdstemplate_callback_t)(const sds variable, void *arg);
|
||||
sds sdstemplate(const char *templ, sdstemplate_callback_t cb_func, void *cb_arg);
|
||||
|
||||
/* Low level functions exposed to the user API */
|
||||
sds sdsMakeRoomFor(sds s, size_t addlen);
|
||||
sds sdsMakeRoomForNonGreedy(sds s, size_t addlen);
|
||||
void sdsIncrLen(sds s, ssize_t incr);
|
||||
sds sdsRemoveFreeSpace(sds s);
|
||||
sds sdsResize(sds s, size_t size);
|
||||
size_t sdsAllocSize(sds s);
|
||||
void *sdsAllocPtr(sds s);
|
||||
|
||||
/* Export the allocator used by SDS to the program using SDS.
|
||||
* Sometimes the program SDS is linked to, may use a different set of
|
||||
* allocators, but may want to allocate or free things that SDS will
|
||||
* respectively free or allocate. */
|
||||
void *sds_malloc(size_t size);
|
||||
void *sds_realloc(void *ptr, size_t size);
|
||||
void sds_free(void *ptr);
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
int sdsTest(int argc, char *argv[], int flags);
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,54 @@
|
|||
/* SDSLib 2.0 -- A C dynamic strings library
|
||||
*
|
||||
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2015, Redis Labs, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* SDS allocator selection.
|
||||
*
|
||||
* This file is used in order to change the SDS allocator at compile time.
|
||||
* Just define the following defines to what you want to use. Also add
|
||||
* the include of your alternate allocator if needed (not needed in order
|
||||
* to use the default libc allocator). */
|
||||
|
||||
#ifndef __SDS_ALLOC_H__
|
||||
#define __SDS_ALLOC_H__
|
||||
|
||||
#include "zmalloc.h"
|
||||
#define s_malloc zmalloc
|
||||
#define s_realloc zrealloc
|
||||
#define s_trymalloc ztrymalloc
|
||||
#define s_tryrealloc ztryrealloc
|
||||
#define s_free zfree
|
||||
#define s_malloc_usable zmalloc_usable
|
||||
#define s_realloc_usable zrealloc_usable
|
||||
#define s_trymalloc_usable ztrymalloc_usable
|
||||
#define s_tryrealloc_usable ztryrealloc_usable
|
||||
#define s_free_usable zfree_usable
|
||||
|
||||
#endif
|
|
@ -0,0 +1,163 @@
|
|||
/*********************************************************************
|
||||
* Filename: sha256.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Implementation of the SHA-256 hashing algorithm.
|
||||
SHA-256 is one of the three algorithms in the SHA2
|
||||
specification. The others, SHA-384 and SHA-512, are not
|
||||
offered in this implementation.
|
||||
Algorithm specification can be found here:
|
||||
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
|
||||
This implementation uses little endian byte order.
|
||||
*********************************************************************/
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sha256.h"
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
|
||||
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
|
||||
|
||||
#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
|
||||
#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
|
||||
#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
|
||||
#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
|
||||
|
||||
/**************************** VARIABLES *****************************/
|
||||
static const WORD k[64] = {
|
||||
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
|
||||
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
|
||||
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
|
||||
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
|
||||
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
|
||||
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
|
||||
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
|
||||
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
};
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
|
||||
{
|
||||
WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
|
||||
|
||||
for (i = 0, j = 0; i < 16; ++i, j += 4) {
|
||||
m[i] = ((WORD) data[j + 0] << 24) |
|
||||
((WORD) data[j + 1] << 16) |
|
||||
((WORD) data[j + 2] << 8) |
|
||||
((WORD) data[j + 3]);
|
||||
}
|
||||
|
||||
for ( ; i < 64; ++i)
|
||||
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
|
||||
|
||||
a = ctx->state[0];
|
||||
b = ctx->state[1];
|
||||
c = ctx->state[2];
|
||||
d = ctx->state[3];
|
||||
e = ctx->state[4];
|
||||
f = ctx->state[5];
|
||||
g = ctx->state[6];
|
||||
h = ctx->state[7];
|
||||
|
||||
for (i = 0; i < 64; ++i) {
|
||||
t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
|
||||
t2 = EP0(a) + MAJ(a,b,c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
|
||||
ctx->state[0] += a;
|
||||
ctx->state[1] += b;
|
||||
ctx->state[2] += c;
|
||||
ctx->state[3] += d;
|
||||
ctx->state[4] += e;
|
||||
ctx->state[5] += f;
|
||||
ctx->state[6] += g;
|
||||
ctx->state[7] += h;
|
||||
}
|
||||
|
||||
void sha256_init(SHA256_CTX *ctx)
|
||||
{
|
||||
ctx->datalen = 0;
|
||||
ctx->bitlen = 0;
|
||||
ctx->state[0] = 0x6a09e667;
|
||||
ctx->state[1] = 0xbb67ae85;
|
||||
ctx->state[2] = 0x3c6ef372;
|
||||
ctx->state[3] = 0xa54ff53a;
|
||||
ctx->state[4] = 0x510e527f;
|
||||
ctx->state[5] = 0x9b05688c;
|
||||
ctx->state[6] = 0x1f83d9ab;
|
||||
ctx->state[7] = 0x5be0cd19;
|
||||
}
|
||||
|
||||
void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
|
||||
{
|
||||
WORD i;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
ctx->data[ctx->datalen] = data[i];
|
||||
ctx->datalen++;
|
||||
if (ctx->datalen == 64) {
|
||||
sha256_transform(ctx, ctx->data);
|
||||
ctx->bitlen += 512;
|
||||
ctx->datalen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sha256_final(SHA256_CTX *ctx, BYTE hash[])
|
||||
{
|
||||
WORD i;
|
||||
|
||||
i = ctx->datalen;
|
||||
|
||||
// Pad whatever data is left in the buffer.
|
||||
if (ctx->datalen < 56) {
|
||||
ctx->data[i++] = 0x80;
|
||||
while (i < 56)
|
||||
ctx->data[i++] = 0x00;
|
||||
}
|
||||
else {
|
||||
ctx->data[i++] = 0x80;
|
||||
while (i < 64)
|
||||
ctx->data[i++] = 0x00;
|
||||
sha256_transform(ctx, ctx->data);
|
||||
memset(ctx->data, 0, 56);
|
||||
}
|
||||
|
||||
// Append to the padding the total message's length in bits and transform.
|
||||
ctx->bitlen += ctx->datalen * 8;
|
||||
ctx->data[63] = ctx->bitlen;
|
||||
ctx->data[62] = ctx->bitlen >> 8;
|
||||
ctx->data[61] = ctx->bitlen >> 16;
|
||||
ctx->data[60] = ctx->bitlen >> 24;
|
||||
ctx->data[59] = ctx->bitlen >> 32;
|
||||
ctx->data[58] = ctx->bitlen >> 40;
|
||||
ctx->data[57] = ctx->bitlen >> 48;
|
||||
ctx->data[56] = ctx->bitlen >> 56;
|
||||
sha256_transform(ctx, ctx->data);
|
||||
|
||||
// Since this implementation uses little endian byte ordering and SHA uses big endian,
|
||||
// reverse all the bytes when copying the final state to the output hash.
|
||||
for (i = 0; i < 4; ++i) {
|
||||
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*********************************************************************
|
||||
* Filename: sha256.h
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Defines the API for the corresponding SHA256 implementation.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef SHA256_H
|
||||
#define SHA256_H
|
||||
|
||||
/*************************** HEADER FILES ***************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
|
||||
|
||||
/**************************** DATA TYPES ****************************/
|
||||
typedef uint8_t BYTE; // 8-bit byte
|
||||
typedef uint32_t WORD; // 32-bit word
|
||||
|
||||
typedef struct {
|
||||
BYTE data[64];
|
||||
WORD datalen;
|
||||
unsigned long long bitlen;
|
||||
WORD state[8];
|
||||
} SHA256_CTX;
|
||||
|
||||
/*********************** FUNCTION DECLARATIONS **********************/
|
||||
void sha256_init(SHA256_CTX *ctx);
|
||||
void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
|
||||
void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
|
||||
|
||||
#endif // SHA256_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __REDIS_UTIL_H
|
||||
#define __REDIS_UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
/* The maximum number of characters needed to represent a long double
|
||||
* as a string (long double has a huge range).
|
||||
* This should be the size of the buffer given to ld2string */
|
||||
#define MAX_LONG_DOUBLE_CHARS 5*1024
|
||||
|
||||
/* long double to string convertion options */
|
||||
typedef enum {
|
||||
LD_STR_AUTO, /* %.17Lg */
|
||||
LD_STR_HUMAN, /* %.17Lf + Trimming of trailing zeros */
|
||||
LD_STR_HEX /* %La */
|
||||
} ld2string_mode;
|
||||
|
||||
int stringmatchlen(const char *p, int plen, const char *s, int slen, int nocase);
|
||||
int stringmatch(const char *p, const char *s, int nocase);
|
||||
int stringmatchlen_fuzz_test(void);
|
||||
long long memtoll(const char *p, int *err);
|
||||
const char *mempbrk(const char *s, size_t len, const char *chars, size_t charslen);
|
||||
char *memmapchars(char *s, size_t len, const char *from, const char *to, size_t setlen);
|
||||
uint32_t digits10(uint64_t v);
|
||||
uint32_t sdigits10(int64_t v);
|
||||
int ll2string(char *s, size_t len, long long value);
|
||||
int string2ll(const char *s, size_t slen, long long *value);
|
||||
int string2ull(const char *s, unsigned long long *value);
|
||||
int string2l(const char *s, size_t slen, long *value);
|
||||
int string2ld(const char *s, size_t slen, long double *dp);
|
||||
int string2d(const char *s, size_t slen, double *dp);
|
||||
int d2string(char *buf, size_t len, double value);
|
||||
int ld2string(char *buf, size_t len, long double value, ld2string_mode mode);
|
||||
|
||||
long getTimeZone(void);
|
||||
int pathIsBaseName(char *path);
|
||||
|
||||
#define LOG_MAX_LEN 1024 /* Default maximum length of syslog messages.*/
|
||||
|
||||
/* Log levels */
|
||||
#define LL_DEBUG 0
|
||||
#define LL_VERBOSE 1
|
||||
#define LL_NOTICE 2
|
||||
#define LL_WARNING 3
|
||||
#define LL_RAW (1<<10) /* Modifier to log without timestamp */
|
||||
|
||||
|
||||
#define LRU_BITS 24
|
||||
#define LRU_CLOCK_MAX ((1<<LRU_BITS)-1) /* Max value of obj->lru */
|
||||
#define LRU_CLOCK_RESOLUTION 1000 /* LRU clock resolution in ms */
|
||||
|
||||
void serverLog(int level, const char *fmt, ...);
|
||||
void _serverPanic(const char *file, int line, const char *msg, ...);
|
||||
void _serverAssert(const char *estr, const char *file, int line);
|
||||
void serverLogHexDump(int level, char *descr, void *value, size_t len);
|
||||
|
||||
#define serverPanic(...) _serverPanic(__FILE__,__LINE__,__VA_ARGS__),_exit(1)
|
||||
#define serverAssert(_e) ((_e)?(void)0 : (_serverAssert(#_e,__FILE__,__LINE__),_exit(1)))
|
||||
|
||||
extern int verbosity;
|
||||
|
||||
typedef long long mstime_t; /* millisecond time type. */
|
||||
unsigned int LRU_CLOCK(void);
|
||||
void debugDelay(int usec);
|
||||
long long ustime(void);
|
||||
|
||||
/* Return the current time in minutes, just taking the least significant
|
||||
* 16 bits. The returned time is suitable to be stored as LDT (last decrement
|
||||
* time) for the LFU implementation. */
|
||||
static inline unsigned long LFUGetTimeInMinutesT(size_t sec) {
|
||||
return (sec / 60) & 65535;
|
||||
}
|
||||
|
||||
static inline unsigned long LFUGetTimeInMinutes() {
|
||||
return LFUGetTimeInMinutesT(time(NULL));
|
||||
}
|
||||
|
||||
/* Given an object last access time, compute the minimum number of minutes
|
||||
* that elapsed since the last access. Handle overflow (ldt greater than
|
||||
* the current 16 bits minutes time) considering the time as wrapping
|
||||
* exactly once. */
|
||||
static inline unsigned long LFUTimeElapsed(time_t sec, unsigned long ldt) {
|
||||
unsigned long now = LFUGetTimeInMinutesT(sec);
|
||||
if (now >= ldt) return now-ldt;
|
||||
return 65535-ldt+now;
|
||||
}
|
||||
|
||||
|
||||
/* Return the UNIX time in milliseconds */
|
||||
static inline mstime_t mstime(void) {
|
||||
return ustime()/1000;
|
||||
}
|
||||
|
||||
/* Return the LRU clock, based on the clock resolution. This is a time
|
||||
* in a reduced-bits format that can be used to set and check the
|
||||
* object->lru field of redisObject structures. */
|
||||
static inline unsigned int getLRUClock(void) {
|
||||
int64_t t = time(NULL);
|
||||
return t & LRU_CLOCK_MAX;
|
||||
}
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
int utilTest(int argc, char **argv, int accurate);
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,721 @@
|
|||
/* zmalloc - total amount of allocated memory aware version of malloc()
|
||||
*
|
||||
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* This function provide us access to the original libc free(). This is useful
|
||||
* for instance to free results obtained by backtrace_symbols(). We need
|
||||
* to define this function before including zmalloc.h that may shadow the
|
||||
* free implementation if we use jemalloc or another non standard allocator. */
|
||||
void zlibc_free(void *ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "config.h"
|
||||
#include "zmalloc.h"
|
||||
#include "atomicvar.h"
|
||||
|
||||
#ifdef HAVE_MALLOC_SIZE
|
||||
#define PREFIX_SIZE (0)
|
||||
#define ASSERT_NO_SIZE_OVERFLOW(sz)
|
||||
#else
|
||||
#if defined(__sun) || defined(__sparc) || defined(__sparc__)
|
||||
#define PREFIX_SIZE (sizeof(long long))
|
||||
#else
|
||||
#define PREFIX_SIZE (sizeof(size_t))
|
||||
#endif
|
||||
#define ASSERT_NO_SIZE_OVERFLOW(sz) assert((sz) + PREFIX_SIZE > (sz))
|
||||
#endif
|
||||
|
||||
/* When using the libc allocator, use a minimum allocation size to match the
|
||||
* jemalloc behavior that doesn't return NULL in this case.
|
||||
*/
|
||||
#define MALLOC_MIN_SIZE(x) ((x) > 0 ? (x) : sizeof(long))
|
||||
/* Explicitly override malloc/free etc when using tcmalloc. */
|
||||
#if defined(USE_TCMALLOC)
|
||||
#define malloc(size) tc_malloc(size)
|
||||
#define calloc(count,size) tc_calloc(count,size)
|
||||
#define realloc(ptr,size) tc_realloc(ptr,size)
|
||||
#define free(ptr) tc_free(ptr)
|
||||
#elif defined(USE_JEMALLOC)
|
||||
#define malloc(size) je_malloc(size)
|
||||
#define calloc(count,size) je_calloc(count,size)
|
||||
#define realloc(ptr,size) je_realloc(ptr,size)
|
||||
#define free(ptr) je_free(ptr)
|
||||
#define mallocx(size,flags) je_mallocx(size,flags)
|
||||
#define dallocx(ptr,flags) je_dallocx(ptr,flags)
|
||||
#endif
|
||||
|
||||
#define update_zmalloc_stat_alloc(__n) used_memory_tl += (__n)
|
||||
#define update_zmalloc_stat_free(__n) used_memory_tl -= (__n)
|
||||
|
||||
static redisAtomic size_t used_memory_cached = 0;
|
||||
__thread ssize_t used_memory_tl = 0;
|
||||
|
||||
void set_used_memory_cached(size_t val) {
|
||||
atomicSet(used_memory_cached, val);
|
||||
}
|
||||
|
||||
|
||||
static void zmalloc_default_oom(size_t size) {
|
||||
fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
|
||||
size);
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
|
||||
|
||||
/* Try allocating memory, and return NULL if failed.
|
||||
* '*usable' is set to the usable size if non NULL. */
|
||||
void *ztrymalloc_usable(size_t size, size_t *usable) {
|
||||
ASSERT_NO_SIZE_OVERFLOW(size);
|
||||
void *ptr = malloc(MALLOC_MIN_SIZE(size)+PREFIX_SIZE);
|
||||
|
||||
if (!ptr) return NULL;
|
||||
#ifdef HAVE_MALLOC_SIZE
|
||||
size = zmalloc_size(ptr);
|
||||
update_zmalloc_stat_alloc(size);
|
||||
if (usable) *usable = size;
|
||||
return ptr;
|
||||
#else
|
||||
*((size_t*)ptr) = size;
|
||||
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
|
||||
if (usable) *usable = size;
|
||||
return (char*)ptr+PREFIX_SIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Allocate memory or panic */
|
||||
void *zmalloc(size_t size) {
|
||||
void *ptr = ztrymalloc_usable(size, NULL);
|
||||
if (!ptr) zmalloc_oom_handler(size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Try allocating memory, and return NULL if failed. */
|
||||
void *ztrymalloc(size_t size) {
|
||||
void *ptr = ztrymalloc_usable(size, NULL);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Allocate memory or panic.
|
||||
* '*usable' is set to the usable size if non NULL. */
|
||||
void *zmalloc_usable(size_t size, size_t *usable) {
|
||||
void *ptr = ztrymalloc_usable(size, usable);
|
||||
if (!ptr) zmalloc_oom_handler(size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
size_t znallocx(size_t size) {
|
||||
#if defined(USE_JEMALLOC)
|
||||
return je_ncallocx(size, 0);
|
||||
#else
|
||||
return size;
|
||||
#endif
|
||||
}
|
||||
|
||||
void zfree_size(void* ptr, size_t size) {
|
||||
#if defined(USE_JEMALLOC)
|
||||
je_sdallocx(ptr, size, 0);
|
||||
#else
|
||||
free(ptr);
|
||||
(void)size;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* Allocation and free functions that bypass the thread cache
|
||||
* and go straight to the allocator arena bins.
|
||||
* Currently implemented only for jemalloc. Used for online defragmentation. */
|
||||
#ifdef HAVE_DEFRAG
|
||||
void *zmalloc_no_tcache(size_t size) {
|
||||
ASSERT_NO_SIZE_OVERFLOW(size);
|
||||
void *ptr = mallocx(size+PREFIX_SIZE, MALLOCX_TCACHE_NONE);
|
||||
if (!ptr) zmalloc_oom_handler(size);
|
||||
update_zmalloc_stat_alloc(zmalloc_size(ptr));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void zfree_no_tcache(void *ptr) {
|
||||
if (ptr == NULL) return;
|
||||
update_zmalloc_stat_free(zmalloc_size(ptr));
|
||||
dallocx(ptr, MALLOCX_TCACHE_NONE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Try allocating memory and zero it, and return NULL if failed.
|
||||
* '*usable' is set to the usable size if non NULL. */
|
||||
void *ztrycalloc_usable(size_t size, size_t *usable) {
|
||||
ASSERT_NO_SIZE_OVERFLOW(size);
|
||||
void *ptr = calloc(1, MALLOC_MIN_SIZE(size)+PREFIX_SIZE);
|
||||
if (ptr == NULL) return NULL;
|
||||
|
||||
#ifdef HAVE_MALLOC_SIZE
|
||||
size = zmalloc_size(ptr);
|
||||
update_zmalloc_stat_alloc(size);
|
||||
if (usable) *usable = size;
|
||||
return ptr;
|
||||
#else
|
||||
*((size_t*)ptr) = size;
|
||||
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
|
||||
if (usable) *usable = size;
|
||||
return (char*)ptr+PREFIX_SIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Allocate memory and zero it or panic */
|
||||
void *zcalloc(size_t size) {
|
||||
void *ptr = ztrycalloc_usable(size, NULL);
|
||||
|
||||
if (!ptr) zmalloc_oom_handler(size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Try allocating memory, and return NULL if failed. */
|
||||
void *ztrycalloc(size_t size) {
|
||||
void *ptr = ztrycalloc_usable(size, NULL);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Allocate memory or panic.
|
||||
* '*usable' is set to the usable size if non NULL. */
|
||||
void *zcalloc_usable(size_t size, size_t *usable) {
|
||||
void *ptr = ztrycalloc_usable(size, usable);
|
||||
if (!ptr) zmalloc_oom_handler(size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Try reallocating memory, and return NULL if failed.
|
||||
* '*usable' is set to the usable size if non NULL. */
|
||||
void *ztryrealloc_usable(void *ptr, size_t size, size_t *usable) {
|
||||
ASSERT_NO_SIZE_OVERFLOW(size);
|
||||
#ifndef HAVE_MALLOC_SIZE
|
||||
void *realptr;
|
||||
#endif
|
||||
size_t oldsize;
|
||||
void *newptr;
|
||||
|
||||
/* not allocating anything, just redirect to free. */
|
||||
if (size == 0 && ptr != NULL) {
|
||||
zfree(ptr);
|
||||
if (usable) *usable = 0;
|
||||
return NULL;
|
||||
}
|
||||
/* Not freeing anything, just redirect to malloc. */
|
||||
if (ptr == NULL)
|
||||
return ztrymalloc_usable(size, usable);
|
||||
#ifdef HAVE_MALLOC_SIZE
|
||||
oldsize = zmalloc_size(ptr);
|
||||
newptr = realloc(ptr,size);
|
||||
if (newptr == NULL) {
|
||||
if (usable) *usable = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
update_zmalloc_stat_free(oldsize);
|
||||
size = zmalloc_size(newptr);
|
||||
update_zmalloc_stat_alloc(size);
|
||||
if (usable) *usable = size;
|
||||
return newptr;
|
||||
#else
|
||||
realptr = (char*)ptr-PREFIX_SIZE;
|
||||
oldsize = *((size_t*)realptr);
|
||||
newptr = realloc(realptr,size+PREFIX_SIZE);
|
||||
if (newptr == NULL) {
|
||||
if (usable) *usable = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*((size_t*)newptr) = size;
|
||||
update_zmalloc_stat_free(oldsize);
|
||||
update_zmalloc_stat_alloc(size);
|
||||
if (usable) *usable = size;
|
||||
return (char*)newptr+PREFIX_SIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Reallocate memory and zero it or panic */
|
||||
void *zrealloc(void *ptr, size_t size) {
|
||||
ptr = ztryrealloc_usable(ptr, size, NULL);
|
||||
if (!ptr && size != 0) zmalloc_oom_handler(size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Try Reallocating memory, and return NULL if failed. */
|
||||
void *ztryrealloc(void *ptr, size_t size) {
|
||||
ptr = ztryrealloc_usable(ptr, size, NULL);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Reallocate memory or panic.
|
||||
* '*usable' is set to the usable size if non NULL. */
|
||||
void *zrealloc_usable(void *ptr, size_t size, size_t *usable) {
|
||||
ptr = ztryrealloc_usable(ptr, size, usable);
|
||||
if (!ptr && size != 0) zmalloc_oom_handler(size);
|
||||
return ptr;
|
||||
}
|
||||
/* Provide zmalloc_size() for systems where this function is not provided by
|
||||
* malloc itself, given that in that case we store a header with this
|
||||
* information as the first bytes of every allocation. */
|
||||
#ifndef HAVE_MALLOC_SIZE
|
||||
size_t zmalloc_size(void *ptr) {
|
||||
void *realptr = (char*)ptr-PREFIX_SIZE;
|
||||
size_t size = *((size_t*)realptr);
|
||||
return size+PREFIX_SIZE;
|
||||
}
|
||||
size_t zmalloc_usable_size(void *ptr) {
|
||||
return zmalloc_size(ptr)-PREFIX_SIZE;
|
||||
}
|
||||
#endif
|
||||
|
||||
void zfree(void *ptr) {
|
||||
#ifndef HAVE_MALLOC_SIZE
|
||||
void *realptr;
|
||||
size_t oldsize;
|
||||
#endif
|
||||
|
||||
if (ptr == NULL) return;
|
||||
#ifdef HAVE_MALLOC_SIZE
|
||||
update_zmalloc_stat_free(zmalloc_size(ptr));
|
||||
free(ptr);
|
||||
#else
|
||||
realptr = (char*)ptr-PREFIX_SIZE;
|
||||
oldsize = *((size_t*)realptr);
|
||||
update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
|
||||
free(realptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Similar to zfree, '*usable' is set to the usable size being freed. */
|
||||
void zfree_usable(void *ptr, size_t *usable) {
|
||||
#ifndef HAVE_MALLOC_SIZE
|
||||
void *realptr;
|
||||
size_t oldsize;
|
||||
#endif
|
||||
|
||||
if (ptr == NULL) return;
|
||||
#ifdef HAVE_MALLOC_SIZE
|
||||
update_zmalloc_stat_free(*usable = zmalloc_size(ptr));
|
||||
free(ptr);
|
||||
#else
|
||||
realptr = (char*)ptr-PREFIX_SIZE;
|
||||
*usable = oldsize = *((size_t*)realptr);
|
||||
update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
|
||||
free(realptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
char *zstrdup(const char *s) {
|
||||
size_t l = strlen(s)+1;
|
||||
char *p = zmalloc(l);
|
||||
|
||||
memcpy(p,s,l);
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t zmalloc_used_memory(void) {
|
||||
size_t um;
|
||||
atomicGet(used_memory_cached,um);
|
||||
return um;
|
||||
}
|
||||
|
||||
void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) {
|
||||
zmalloc_oom_handler = oom_handler;
|
||||
}
|
||||
|
||||
/* Get the RSS information in an OS-specific way.
|
||||
*
|
||||
* WARNING: the function zmalloc_get_rss() is not designed to be fast
|
||||
* and may not be called in the busy loops where Redis tries to release
|
||||
* memory expiring or swapping out objects.
|
||||
*
|
||||
* For this kind of "fast RSS reporting" usages use instead the
|
||||
* function RedisEstimateRSS() that is a much faster (and less precise)
|
||||
* version of the function. */
|
||||
|
||||
#if defined(HAVE_PROC_STAT)
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
size_t zmalloc_get_rss(void) {
|
||||
int page = sysconf(_SC_PAGESIZE);
|
||||
size_t rss;
|
||||
char buf[4096];
|
||||
char filename[256];
|
||||
int fd, count;
|
||||
char *p, *x;
|
||||
|
||||
snprintf(filename,256,"/proc/%ld/stat",(long) getpid());
|
||||
if ((fd = open(filename,O_RDONLY)) == -1) return 0;
|
||||
if (read(fd,buf,4096) <= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
p = buf;
|
||||
count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
|
||||
while(p && count--) {
|
||||
p = strchr(p,' ');
|
||||
if (p) p++;
|
||||
}
|
||||
if (!p) return 0;
|
||||
x = strchr(p,' ');
|
||||
if (!x) return 0;
|
||||
*x = '\0';
|
||||
|
||||
rss = strtoll(p,NULL,10);
|
||||
rss *= page;
|
||||
return rss;
|
||||
}
|
||||
#elif defined(HAVE_TASKINFO)
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <mach/task.h>
|
||||
#include <mach/mach_init.h>
|
||||
|
||||
size_t zmalloc_get_rss(void) {
|
||||
task_t task = MACH_PORT_NULL;
|
||||
struct task_basic_info t_info;
|
||||
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
|
||||
|
||||
if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS)
|
||||
return 0;
|
||||
task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
|
||||
|
||||
return t_info.resident_size;
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
size_t zmalloc_get_rss(void) {
|
||||
struct kinfo_proc info;
|
||||
size_t infolen = sizeof(info);
|
||||
int mib[4];
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = getpid();
|
||||
|
||||
if (sysctl(mib, 4, &info, &infolen, NULL, 0) == 0)
|
||||
#if defined(__FreeBSD__)
|
||||
return (size_t)info.ki_rssize * getpagesize();
|
||||
#else
|
||||
return (size_t)info.kp_vm_rssize * getpagesize();
|
||||
#endif
|
||||
|
||||
return 0L;
|
||||
}
|
||||
#elif defined(__NetBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
size_t zmalloc_get_rss(void) {
|
||||
struct kinfo_proc2 info;
|
||||
size_t infolen = sizeof(info);
|
||||
int mib[6];
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = getpid();
|
||||
mib[4] = sizeof(info);
|
||||
mib[5] = 1;
|
||||
if (sysctl(mib, 4, &info, &infolen, NULL, 0) == 0)
|
||||
return (size_t)info.p_vm_rssize * getpagesize();
|
||||
|
||||
return 0L;
|
||||
}
|
||||
#elif defined(HAVE_PSINFO)
|
||||
#include <unistd.h>
|
||||
#include <sys/procfs.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
size_t zmalloc_get_rss(void) {
|
||||
struct prpsinfo info;
|
||||
char filename[256];
|
||||
int fd;
|
||||
|
||||
snprintf(filename,256,"/proc/%ld/psinfo",(long) getpid());
|
||||
|
||||
if ((fd = open(filename,O_RDONLY)) == -1) return 0;
|
||||
if (ioctl(fd, PIOCPSINFO, &info) == -1) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return info.pr_rssize;
|
||||
}
|
||||
#else
|
||||
size_t zmalloc_get_rss(void) {
|
||||
/* If we can't get the RSS in an OS-specific way for this system just
|
||||
* return the memory usage we estimated in zmalloc()..
|
||||
*
|
||||
* Fragmentation will appear to be always 1 (no fragmentation)
|
||||
* of course... */
|
||||
return zmalloc_used_memory();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_JEMALLOC)
|
||||
|
||||
int zmalloc_get_allocator_info(size_t *allocated,
|
||||
size_t *active,
|
||||
size_t *resident) {
|
||||
uint64_t epoch = 1;
|
||||
size_t sz;
|
||||
*allocated = *resident = *active = 0;
|
||||
/* Update the statistics cached by mallctl. */
|
||||
sz = sizeof(epoch);
|
||||
je_mallctl("epoch", &epoch, &sz, &epoch, sz);
|
||||
sz = sizeof(size_t);
|
||||
/* Unlike RSS, this does not include RSS from shared libraries and other non
|
||||
* heap mappings. */
|
||||
je_mallctl("stats.resident", resident, &sz, NULL, 0);
|
||||
/* Unlike resident, this doesn't not include the pages jemalloc reserves
|
||||
* for re-use (purge will clean that). */
|
||||
je_mallctl("stats.active", active, &sz, NULL, 0);
|
||||
/* Unlike zmalloc_used_memory, this matches the stats.resident by taking
|
||||
* into account all allocations done by this process (not only zmalloc). */
|
||||
je_mallctl("stats.allocated", allocated, &sz, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void set_jemalloc_bg_thread(int enable) {
|
||||
/* let jemalloc do purging asynchronously, required when there's no traffic
|
||||
* after flushdb */
|
||||
char val = !!enable;
|
||||
je_mallctl("background_thread", NULL, 0, &val, 1);
|
||||
}
|
||||
|
||||
int jemalloc_purge() {
|
||||
/* return all unused (reserved) pages to the OS */
|
||||
char tmp[32];
|
||||
unsigned narenas = 0;
|
||||
size_t sz = sizeof(unsigned);
|
||||
if (!je_mallctl("arenas.narenas", &narenas, &sz, NULL, 0)) {
|
||||
sprintf(tmp, "arena.%d.purge", narenas);
|
||||
if (!je_mallctl(tmp, NULL, 0, NULL, 0))
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int zmalloc_get_allocator_info(size_t *allocated,
|
||||
size_t *active,
|
||||
size_t *resident) {
|
||||
*allocated = *resident = *active = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void set_jemalloc_bg_thread(int enable) {
|
||||
((void)(enable));
|
||||
}
|
||||
|
||||
int jemalloc_purge() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* For proc_pidinfo() used later in zmalloc_get_smap_bytes_by_field().
|
||||
* Note that this file cannot be included in zmalloc.h because it includes
|
||||
* a Darwin queue.h file where there is a "LIST_HEAD" macro (!) defined
|
||||
* conficting with Redis user code. */
|
||||
#include <libproc.h>
|
||||
#endif
|
||||
|
||||
/* Get the sum of the specified field (converted form kb to bytes) in
|
||||
* /proc/self/smaps. The field must be specified with trailing ":" as it
|
||||
* apperas in the smaps output.
|
||||
*
|
||||
* If a pid is specified, the information is extracted for such a pid,
|
||||
* otherwise if pid is -1 the information is reported is about the
|
||||
* current process.
|
||||
*
|
||||
* Example: zmalloc_get_smap_bytes_by_field("Rss:",-1);
|
||||
*/
|
||||
#if defined(HAVE_PROC_SMAPS)
|
||||
size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
|
||||
char line[1024];
|
||||
size_t bytes = 0;
|
||||
int flen = strlen(field);
|
||||
FILE *fp;
|
||||
|
||||
if (pid == -1) {
|
||||
fp = fopen("/proc/self/smaps","r");
|
||||
} else {
|
||||
char filename[128];
|
||||
snprintf(filename,sizeof(filename),"/proc/%ld/smaps",pid);
|
||||
fp = fopen(filename,"r");
|
||||
}
|
||||
|
||||
if (!fp) return 0;
|
||||
while(fgets(line,sizeof(line),fp) != NULL) {
|
||||
if (strncmp(line,field,flen) == 0) {
|
||||
char *p = strchr(line,'k');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
bytes += strtol(line+flen,NULL,10) * 1024;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return bytes;
|
||||
}
|
||||
#else
|
||||
/* Get sum of the specified field from libproc api call.
|
||||
* As there are per page value basis we need to convert
|
||||
* them accordingly.
|
||||
*
|
||||
* Note that AnonHugePages is a no-op as THP feature
|
||||
* is not supported in this platform
|
||||
*/
|
||||
size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
|
||||
#if defined(__APPLE__)
|
||||
struct proc_regioninfo pri;
|
||||
if (pid == -1) pid = getpid();
|
||||
if (proc_pidinfo(pid, PROC_PIDREGIONINFO, 0, &pri,
|
||||
PROC_PIDREGIONINFO_SIZE) == PROC_PIDREGIONINFO_SIZE)
|
||||
{
|
||||
int pagesize = getpagesize();
|
||||
if (!strcmp(field, "Private_Dirty:")) {
|
||||
return (size_t)pri.pri_pages_dirtied * pagesize;
|
||||
} else if (!strcmp(field, "Rss:")) {
|
||||
return (size_t)pri.pri_pages_resident * pagesize;
|
||||
} else if (!strcmp(field, "AnonHugePages:")) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
((void) field);
|
||||
((void) pid);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return the total number bytes in pages marked as Private Dirty.
|
||||
*
|
||||
* Note: depending on the platform and memory footprint of the process, this
|
||||
* call can be slow, exceeding 1000ms!
|
||||
*/
|
||||
size_t zmalloc_get_private_dirty(long pid) {
|
||||
return zmalloc_get_smap_bytes_by_field("Private_Dirty:",pid);
|
||||
}
|
||||
|
||||
/* Returns the size of physical memory (RAM) in bytes.
|
||||
* It looks ugly, but this is the cleanest way to achieve cross platform results.
|
||||
* Cleaned up from:
|
||||
*
|
||||
* http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
|
||||
*
|
||||
* Note that this function:
|
||||
* 1) Was released under the following CC attribution license:
|
||||
* http://creativecommons.org/licenses/by/3.0/deed.en_US.
|
||||
* 2) Was originally implemented by David Robert Nadeau.
|
||||
* 3) Was modified for Redis by Matt Stancliff.
|
||||
* 4) This note exists in order to comply with the original license.
|
||||
*/
|
||||
size_t zmalloc_get_memory_size(void) {
|
||||
#if defined(__unix__) || defined(__unix) || defined(unix) || \
|
||||
(defined(__APPLE__) && defined(__MACH__))
|
||||
#if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
|
||||
int mib[2];
|
||||
mib[0] = CTL_HW;
|
||||
#if defined(HW_MEMSIZE)
|
||||
mib[1] = HW_MEMSIZE; /* OSX. --------------------- */
|
||||
#elif defined(HW_PHYSMEM64)
|
||||
mib[1] = HW_PHYSMEM64; /* NetBSD, OpenBSD. --------- */
|
||||
#endif
|
||||
int64_t size = 0; /* 64-bit */
|
||||
size_t len = sizeof(size);
|
||||
if (sysctl( mib, 2, &size, &len, NULL, 0) == 0)
|
||||
return (size_t)size;
|
||||
return 0L; /* Failed? */
|
||||
|
||||
#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
|
||||
/* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */
|
||||
return (size_t)sysconf(_SC_PHYS_PAGES) * (size_t)sysconf(_SC_PAGESIZE);
|
||||
|
||||
#elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM))
|
||||
/* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */
|
||||
int mib[2];
|
||||
mib[0] = CTL_HW;
|
||||
#if defined(HW_REALMEM)
|
||||
mib[1] = HW_REALMEM; /* FreeBSD. ----------------- */
|
||||
#elif defined(HW_PHYSMEM)
|
||||
mib[1] = HW_PHYSMEM; /* Others. ------------------ */
|
||||
#endif
|
||||
unsigned int size = 0; /* 32-bit */
|
||||
size_t len = sizeof(size);
|
||||
if (sysctl(mib, 2, &size, &len, NULL, 0) == 0)
|
||||
return (size_t)size;
|
||||
return 0L; /* Failed? */
|
||||
#else
|
||||
return 0L; /* Unknown method to get the data. */
|
||||
#endif
|
||||
#else
|
||||
return 0L; /* Unknown OS. */
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
#define UNUSED(x) ((void)(x))
|
||||
int zmalloc_test(int argc, char **argv, int accurate) {
|
||||
void *ptr;
|
||||
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
UNUSED(accurate);
|
||||
printf("Malloc prefix size: %d\n", (int) PREFIX_SIZE);
|
||||
printf("Initial used memory: %zu\n", zmalloc_used_memory());
|
||||
ptr = zmalloc(123);
|
||||
printf("Allocated 123 bytes; used: %zu\n", zmalloc_used_memory());
|
||||
ptr = zrealloc(ptr, 456);
|
||||
printf("Reallocated to 456 bytes; used: %zu\n", zmalloc_used_memory());
|
||||
zfree(ptr);
|
||||
printf("Freed pointer; used: %zu\n", zmalloc_used_memory());
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,157 @@
|
|||
/* zmalloc - total amount of allocated memory aware version of malloc()
|
||||
*
|
||||
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __ZMALLOC_H
|
||||
#define __ZMALLOC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Double expansion needed for stringification of macro values. */
|
||||
#define __xstr(s) __zm_str(s)
|
||||
#define __zm_str(s) #s
|
||||
|
||||
#if defined(USE_TCMALLOC)
|
||||
#define ZMALLOC_LIB ("tcmalloc-" __xstr(TC_VERSION_MAJOR) "." __xstr(TC_VERSION_MINOR))
|
||||
#include <google/tcmalloc.h>
|
||||
#if (TC_VERSION_MAJOR == 1 && TC_VERSION_MINOR >= 6) || (TC_VERSION_MAJOR > 1)
|
||||
#define HAVE_MALLOC_SIZE 1
|
||||
#define zmalloc_size(p) tc_malloc_size(p)
|
||||
#else
|
||||
#error "Newer version of tcmalloc required"
|
||||
#endif
|
||||
|
||||
#elif defined(USE_JEMALLOC)
|
||||
#define ZMALLOC_LIB ("jemalloc-" __xstr(JEMALLOC_VERSION_MAJOR) "." __xstr(JEMALLOC_VERSION_MINOR) "." __xstr(JEMALLOC_VERSION_BUGFIX))
|
||||
#include <jemalloc/jemalloc.h>
|
||||
#if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || (JEMALLOC_VERSION_MAJOR > 2)
|
||||
#define HAVE_MALLOC_SIZE 1
|
||||
#define zmalloc_size(p) je_malloc_usable_size(p)
|
||||
#else
|
||||
#error "Newer version of jemalloc required"
|
||||
#endif
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#include <malloc/malloc.h>
|
||||
#define HAVE_MALLOC_SIZE 1
|
||||
#define zmalloc_size(p) malloc_size(p)
|
||||
#endif
|
||||
|
||||
/* On native libc implementations, we should still do our best to provide a
|
||||
* HAVE_MALLOC_SIZE capability. This can be set explicitly as well:
|
||||
*
|
||||
* NO_MALLOC_USABLE_SIZE disables it on all platforms, even if they are
|
||||
* known to support it.
|
||||
* USE_MALLOC_USABLE_SIZE forces use of malloc_usable_size() regardless
|
||||
* of platform.
|
||||
*/
|
||||
#ifndef ZMALLOC_LIB
|
||||
#define ZMALLOC_LIB "libc"
|
||||
#if !defined(NO_MALLOC_USABLE_SIZE) && \
|
||||
(defined(__GLIBC__) || defined(__FreeBSD__) || \
|
||||
defined(USE_MALLOC_USABLE_SIZE))
|
||||
|
||||
/* Includes for malloc_usable_size() */
|
||||
#ifdef __FreeBSD__
|
||||
#include <malloc_np.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#define HAVE_MALLOC_SIZE 1
|
||||
#ifdef USE_ZMALLOC_MI
|
||||
#define zmalloc_size(p) zmalloc_usable_size(p)
|
||||
#else
|
||||
#define zmalloc_size(p) malloc_usable_size(p)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* We can enable the Redis defrag capabilities only if we are using Jemalloc
|
||||
* and the version used is our special version modified for Redis having
|
||||
* the ability to return per-allocation fragmentation hints. */
|
||||
#if defined(USE_JEMALLOC) && defined(JEMALLOC_FRAG_HINT)
|
||||
#define HAVE_DEFRAG
|
||||
#endif
|
||||
|
||||
void *zmalloc(size_t size);
|
||||
void *zcalloc(size_t size);
|
||||
void *zrealloc(void *ptr, size_t size);
|
||||
void *ztrymalloc(size_t size);
|
||||
void *ztrycalloc(size_t size);
|
||||
void *ztryrealloc(void *ptr, size_t size);
|
||||
void zfree(void *ptr);
|
||||
|
||||
size_t znallocx(size_t size); // Equivalent to nallocx for jemalloc or mi_good_size for mimalloc.
|
||||
void zfree_size(void* ptr, size_t size); // equivalent to sdallocx or mi_free_size
|
||||
|
||||
void *zmalloc_usable(size_t size, size_t *usable);
|
||||
void *zcalloc_usable(size_t size, size_t *usable);
|
||||
void *zrealloc_usable(void *ptr, size_t size, size_t *usable);
|
||||
void *ztrymalloc_usable(size_t size, size_t *usable);
|
||||
void *ztrycalloc_usable(size_t size, size_t *usable);
|
||||
void *ztryrealloc_usable(void *ptr, size_t size, size_t *usable);
|
||||
void zfree_usable(void *ptr, size_t *usable);
|
||||
char *zstrdup(const char *s);
|
||||
size_t zmalloc_used_memory(void);
|
||||
void zmalloc_set_oom_handler(void (*oom_handler)(size_t));
|
||||
size_t zmalloc_get_rss(void);
|
||||
int zmalloc_get_allocator_info(size_t *allocated, size_t *active, size_t *resident);
|
||||
void set_jemalloc_bg_thread(int enable);
|
||||
int jemalloc_purge();
|
||||
size_t zmalloc_get_private_dirty(long pid);
|
||||
size_t zmalloc_get_smap_bytes_by_field(char *field, long pid);
|
||||
size_t zmalloc_get_memory_size(void);
|
||||
size_t zmalloc_usable_size(const void* p);
|
||||
|
||||
void zlibc_free(void *ptr);
|
||||
|
||||
#ifdef HAVE_DEFRAG
|
||||
void zfree_no_tcache(void *ptr);
|
||||
void *zmalloc_no_tcache(size_t size);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_MALLOC_SIZE
|
||||
size_t zmalloc_size(void *ptr);
|
||||
size_t zmalloc_usable_size(void *ptr);
|
||||
#else
|
||||
// #define zmalloc_usable_size(p) zmalloc_size(p)
|
||||
#endif
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
int zmalloc_test(int argc, char **argv, int accurate);
|
||||
#endif
|
||||
|
||||
extern __thread ssize_t used_memory_tl;
|
||||
void set_used_memory_cached(size_t val);
|
||||
|
||||
#undef __zm_str
|
||||
#undef __xstr
|
||||
|
||||
#endif /* __ZMALLOC_H */
|
|
@ -0,0 +1,103 @@
|
|||
#ifndef __REDIS_ZSET_H
|
||||
#define __REDIS_ZSET_H
|
||||
|
||||
#include "redis/sds.h"
|
||||
|
||||
/* Sorted sets data type */
|
||||
|
||||
/* Sorted sets data type */
|
||||
|
||||
/* Input flags. */
|
||||
#define ZADD_IN_NONE 0
|
||||
#define ZADD_IN_INCR (1 << 0) /* Increment the score instead of setting it. */
|
||||
#define ZADD_IN_NX (1 << 1) /* Don't touch elements not already existing. */
|
||||
#define ZADD_IN_XX (1 << 2) /* Only touch elements already existing. */
|
||||
#define ZADD_IN_GT (1 << 3) /* Only update existing when new scores are higher. */
|
||||
#define ZADD_IN_LT (1 << 4) /* Only update existing when new scores are lower. */
|
||||
|
||||
/* Output flags. */
|
||||
#define ZADD_OUT_NOP (1 << 0) /* Operation not performed because of conditionals.*/
|
||||
#define ZADD_OUT_NAN (1 << 1) /* Only touch elements already existing. */
|
||||
#define ZADD_OUT_ADDED (1 << 2) /* The element was new and was added. */
|
||||
#define ZADD_OUT_UPDATED (1 << 3) /* The element already existed, score updated. */
|
||||
|
||||
/* ZSETs use a specialized version of Skiplists */
|
||||
typedef struct zskiplistNode {
|
||||
sds ele;
|
||||
double score;
|
||||
struct zskiplistNode* backward;
|
||||
struct zskiplistLevel {
|
||||
struct zskiplistNode* forward;
|
||||
unsigned long span;
|
||||
} level[];
|
||||
} zskiplistNode;
|
||||
|
||||
typedef struct zskiplist {
|
||||
struct zskiplistNode *header, *tail;
|
||||
unsigned long length;
|
||||
int level;
|
||||
} zskiplist;
|
||||
|
||||
struct dict;
|
||||
|
||||
typedef struct zset {
|
||||
struct dict* dict;
|
||||
zskiplist* zsl;
|
||||
} zset;
|
||||
|
||||
/* Struct to hold an inclusive/exclusive range spec by score comparison. */
|
||||
typedef struct {
|
||||
double min, max;
|
||||
int minex, maxex; /* are min or max exclusive? */
|
||||
} zrangespec;
|
||||
|
||||
/* Struct to hold an inclusive/exclusive range spec by lexicographic comparison. */
|
||||
typedef struct {
|
||||
sds min, max; /* May be set to shared.(minstring|maxstring) */
|
||||
int minex, maxex; /* are min or max exclusive? */
|
||||
} zlexrangespec;
|
||||
|
||||
typedef struct redisObject robj;
|
||||
|
||||
zskiplist* zslCreate(void);
|
||||
void zslFree(zskiplist* zsl);
|
||||
zskiplistNode* zslInsert(zskiplist* zsl, double score, sds ele);
|
||||
unsigned char* zzlInsert(unsigned char* zl, sds ele, double score);
|
||||
// int zslDelete(zskiplist *zsl, double score, sds ele, zskiplistNode **node);
|
||||
zskiplistNode* zslFirstInRange(zskiplist* zsl, const zrangespec* range);
|
||||
zskiplistNode* zslLastInRange(zskiplist* zsl, const zrangespec* range);
|
||||
// double zzlGetScore(unsigned char *sptr);
|
||||
// void zzlNext(unsigned char *zl, unsigned char **eptr, unsigned char **sptr);
|
||||
// void zzlPrev(unsigned char *zl, unsigned char **eptr, unsigned char **sptr);
|
||||
unsigned char* zzlFirstInRange(unsigned char* zl, const zrangespec* range);
|
||||
unsigned char* zzlLastInRange(unsigned char* zl, const zrangespec* range);
|
||||
unsigned long zsetLength(const robj* zobj);
|
||||
void zsetConvert(robj* zobj, int encoding);
|
||||
void zsetConvertToZiplistIfNeeded(robj* zobj, size_t maxelelen);
|
||||
int zsetScore(robj* zobj, sds member, double* score);
|
||||
// unsigned long zslGetRank(zskiplist *zsl, double score, sds o);
|
||||
int zsetAdd(robj* zobj, double score, sds ele, int in_flags, int* out_flags, double* newscore);
|
||||
long zsetRank(robj* zobj, sds ele, int reverse);
|
||||
int zsetDel(robj* zobj, sds ele);
|
||||
|
||||
void zzlPrev(unsigned char* zl, unsigned char** eptr, unsigned char** sptr);
|
||||
void zzlNext(unsigned char* zl, unsigned char** eptr, unsigned char** sptr);
|
||||
double zzlGetScore(unsigned char* sptr);
|
||||
int zslValueGteMin(double value, const zrangespec* spec);
|
||||
int zslValueLteMax(double value, const zrangespec* spec);
|
||||
void zslFreeLexRange(zlexrangespec* spec);
|
||||
int zslParseLexRange(robj* min, robj* max, zlexrangespec* spec);
|
||||
unsigned char* zzlFirstInLexRange(unsigned char* zl, zlexrangespec* range);
|
||||
unsigned char* zzlLastInLexRange(unsigned char* zl, zlexrangespec* range);
|
||||
zskiplistNode* zslFirstInLexRange(zskiplist* zsl, zlexrangespec* range);
|
||||
zskiplistNode* zslLastInLexRange(zskiplist* zsl, zlexrangespec* range);
|
||||
int zzlLexValueGteMin(unsigned char* p, const zlexrangespec* spec);
|
||||
int zzlLexValueLteMax(unsigned char* p, const zlexrangespec* spec);
|
||||
int zslLexValueGteMin(sds value, const zlexrangespec* spec);
|
||||
int zslLexValueLteMax(sds value, const zlexrangespec* spec);
|
||||
int zsetZiplistValidateIntegrity(unsigned char* zl, size_t size, int deep);
|
||||
|
||||
extern size_t zset_max_ziplist_entries;
|
||||
extern size_t zset_max_ziplist_value;
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue