Skip to content

Commit

Permalink
Final 0.9 release before v5
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnSully committed Jul 16, 2019
2 parents 7617a87 + a19d0f6 commit 0483047
Show file tree
Hide file tree
Showing 63 changed files with 1,081 additions and 467 deletions.
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,23 @@ matrix:
include:
- os: linux
script: make
env: COMPILER_NAME=gcc CXX=g++-5 CC=gcc-5
env: COMPILER_NAME=g++-6 CXX=g++-6 CC=gcc-6
addons:
apt:
packages:
- g++-5
- g++-6
- nasm
- uuid-dev
sources: &sources
- llvm-toolchain-precise-3.8
- ubuntu-toolchain-r-test
- os: linux
script: make MALLOC=libc
env: COMPILER_NAME=clang CXX=clang++-3.8 CC=clang-3.8 CXXFLAGS="-stdlib=libc++" LDFLAGS="-stdlib=libc++"
env: COMPILER_NAME=clang CXX=clang++-3.8 CC=clang-3.8 CXXFLAGS="-I/usr/include/libcxxabi/" LDFLAGS="-lc++"
addons:
apt:
packages:
- libc++abi-dev
- clang-3.8
- libc++-dev
- libc++abi-dev
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
![Current Release](https://img.shields.io/github/release/JohnSully/KeyDB.svg)
[![Build Status](https://travis-ci.org/JohnSully/KeyDB.svg?branch=unstable)](https://travis-ci.org/JohnSully/KeyDB) [![Join the chat at https://gitter.im/KeyDB/community](https://badges.gitter.im/KeyDB/community.svg)](https://gitter.im/KeyDB/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![StackShare](http://img.shields.io/badge/tech-stack-0690fa.svg?style=flat)](https://stackshare.io/eq-alpha-technology-inc/eq-alpha-technology-inc)

What is KeyDB?
--------------

KeyDB is a high performance fork of Redis focusing on multithreading, memory efficiency, and high throughput. In addition to multithreading KeyDB also has features only available in Redis Enterprise such as [Active Replication](https://github.com/JohnSully/KeyDB/wiki/KeyDB-(Redis-Fork):-Active-Replica-Support), [FLASH storage](https://github.com/JohnSully/KeyDB/wiki/FLASH-Storage) support, and some not available at all such as direct backup to AWS S3.
KeyDB is a high performance fork of Redis focusing on multithreading, memory efficiency, and high throughput. In addition to multithreading KeyDB also has features only available in Redis Enterprise such as [Active Replication](https://github.com/JohnSully/KeyDB/wiki/Active-Replication), [FLASH storage](https://github.com/JohnSully/KeyDB/wiki/FLASH-Storage) support, and some not available at all such as direct backup to AWS S3.

On the same hardware KeyDB can perform twice as many queries per second as Redis, with 60% lower latency.

Expand All @@ -14,12 +15,14 @@ Try our docker container: https://hub.docker.com/r/eqalpha/keydb

Talk on Gitter: https://gitter.im/KeyDB

[Subscribe to the KeyDB mailing list](https://eqalpha.us20.list-manage.com/subscribe/post?u=978f486c2f95589b24591a9cc&id=4ab9220500)

Management GUI: We recommend [FastoNoSQL](https://fastonosql.com/) which has official KeyDB support.

New: Active Replica Support
---------------------------

New! KeyDB now has support for Active Replicas. This feature greatly simplifies hot-spare failover and allows you to distribute writes over replicas instead of just a single master. For more information [see the wiki page](https://github.com/JohnSully/KeyDB/wiki/KeyDB-(Redis-Fork):-Active-Replica-Support).
New! KeyDB now has support for Active Replicas. This feature greatly simplifies hot-spare failover and allows you to distribute writes over replicas instead of just a single master. For more information [see the wiki page](https://github.com/JohnSully/KeyDB/wiki/Active-Replication).

Why fork Redis?
---------------
Expand Down Expand Up @@ -249,4 +252,3 @@ source distribution.
Please see the CONTRIBUTING file in this source distribution for more
information.


1 change: 1 addition & 0 deletions deps/hiredis/read.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#include "fmacros.h"
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#ifndef _MSC_VER
#include <unistd.h>
Expand Down
8 changes: 1 addition & 7 deletions redis.conf
Original file line number Diff line number Diff line change
Expand Up @@ -942,13 +942,7 @@ aof-use-rdb-preamble yes
lua-time-limit 5000

################################ REDIS CLUSTER ###############################
#
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# WARNING EXPERIMENTAL: Redis Cluster is considered to be stable code, however
# in order to mark it as "mature" we need to wait for a non trivial percentage
# of users to deploy it in production.
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#

# Normal Redis instances can't be part of a Redis Cluster; only nodes that are
# started as cluster nodes can. In order to start a Redis instance as a
# cluster node enable the cluster support uncommenting the following:
Expand Down
16 changes: 16 additions & 0 deletions runtest-moduleapi
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/sh
TCL_VERSIONS="8.5 8.6"
TCLSH=""

for VERSION in $TCL_VERSIONS; do
TCL=`which tclsh$VERSION 2>/dev/null` && TCLSH=$TCL
done

if [ -z $TCLSH ]
then
echo "You need tcl 8.5 or newer in order to run the Redis test"
exit 1
fi

make -C tests/modules && \
$TCLSH tests/test_helper.tcl --single unit/moduleapi/commandfilter "${@}"
11 changes: 6 additions & 5 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ DEPENDENCY_TARGETS=hiredis linenoise lua
NODEPS:=clean distclean

# Default settings
STD=-std=c99 -pedantic -DREDIS_STATIC=''
STD=-std=c11 -pedantic -DREDIS_STATIC=''
CXX_STD=-std=c++14 -pedantic -fno-rtti -D__STDC_FORMAT_MACROS
ifneq (,$(findstring clang,$(CC)))
ifneq (,$(findstring FreeBSD,$(uname_S)))
Expand Down Expand Up @@ -140,6 +140,7 @@ else
# All the other OSes (notably Linux)
FINAL_LDFLAGS+= -rdynamic
FINAL_LIBS+=-ldl -pthread -lrt -luuid
FINAL_CFLAGS += -DMOTD
endif
endif
endif
Expand Down Expand Up @@ -197,11 +198,11 @@ endif

REDIS_SERVER_NAME=keydb-server
REDIS_SENTINEL_NAME=keydb-sentinel
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o acl.o storage.o rdb-s3.o fastlock.o $(ASM_OBJ)
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o acl.o storage.o rdb-s3.o fastlock.o new.o $(ASM_OBJ)
REDIS_CLI_NAME=keydb-cli
REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o redis-cli-cpphelper.o zmalloc.o release.o anet.o ae.o crc64.o siphash.o crc16.o storage-lite.o fastlock.o $(ASM_OBJ)
REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o redis-cli-cpphelper.o zmalloc.o release.o anet.o ae.o crc64.o siphash.o crc16.o storage-lite.o fastlock.o new.o $(ASM_OBJ)
REDIS_BENCHMARK_NAME=keydb-benchmark
REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o dict.o zmalloc.o siphash.o redis-benchmark.o storage-lite.o fastlock.o $(ASM_OBJ)
REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o dict.o zmalloc.o siphash.o redis-benchmark.o storage-lite.o fastlock.o new.o $(ASM_OBJ)
REDIS_CHECK_RDB_NAME=keydb-check-rdb
REDIS_CHECK_AOF_NAME=keydb-check-aof

Expand Down Expand Up @@ -264,7 +265,7 @@ $(REDIS_CHECK_AOF_NAME): $(REDIS_SERVER_NAME)

# keydb-cli
$(REDIS_CLI_NAME): $(REDIS_CLI_OBJ)
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS)
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS) -lcurl

# keydb-benchmark
$(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ)
Expand Down
2 changes: 2 additions & 0 deletions src/acl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,8 @@ struct redisCommand *ACLLookupCommand(const char *name) {
* and command ID. */
void ACLResetSubcommandsForCommand(user *u, unsigned long id) {
if (u->allowed_subcommands && u->allowed_subcommands[id]) {
for (int i = 0; u->allowed_subcommands[id][i]; i++)
sdsfree(u->allowed_subcommands[id][i]);
zfree(u->allowed_subcommands[id]);
u->allowed_subcommands[id] = NULL;
}
Expand Down
4 changes: 2 additions & 2 deletions src/ae.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -803,9 +803,9 @@ void aeAcquireLock()
g_lock.lock();
}

int aeTryAcquireLock()
int aeTryAcquireLock(int fWeak)
{
return g_lock.try_lock();
return g_lock.try_lock(!!fWeak);
}

void aeReleaseLock()
Expand Down
2 changes: 1 addition & 1 deletion src/ae.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ int aeGetSetSize(aeEventLoop *eventLoop);
int aeResizeSetSize(aeEventLoop *eventLoop, int setsize);

void aeAcquireLock();
int aeTryAcquireLock();
int aeTryAcquireLock(int fWeak);
void aeReleaseLock();
int aeThreadOwnsLock();

Expand Down
69 changes: 69 additions & 0 deletions src/aelocker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#pragma once

class AeLocker
{
bool m_fArmed = false;

public:
AeLocker()
{
}

void arm(client *c) // if a client is passed, then the client is already locked
{
if (c != nullptr)
{
serverAssert(!m_fArmed);
serverAssert(c->lock.fOwnLock());

if (!aeTryAcquireLock(true /*fWeak*/)) // avoid locking the client if we can
{
bool fOwnClientLock = true;
int clientNesting = 1;
for (;;)
{
if (fOwnClientLock)
{
clientNesting = c->lock.unlock_recursive();
fOwnClientLock = false;
}
aeAcquireLock();
if (!c->lock.try_lock(false)) // ensure a strong try because aeAcquireLock is expensive
{
aeReleaseLock();
}
else
{
break;
}
}
c->lock.lock_recursive(clientNesting);
}

m_fArmed = true;
}
else if (!m_fArmed)
{
m_fArmed = true;
aeAcquireLock();
}
}

void disarm()
{
serverAssert(m_fArmed);
m_fArmed = false;
aeReleaseLock();
}

bool isArmed() const
{
return m_fArmed;
}

~AeLocker()
{
if (m_fArmed)
aeReleaseLock();
}
};
37 changes: 32 additions & 5 deletions src/aof.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ ssize_t aofRewriteBufferWrite(int fd) {
* AOF file implementation
* ------------------------------------------------------------------------- */

/* Return true if an AOf fsync is currently already in progress in a
* BIO thread. */
int aofFsyncInProgress(void) {
return bioPendingJobsOfType(BIO_AOF_FSYNC) != 0;
}

/* Starts a background task that performs fsync() against the specified
* file descriptor (the one of the AOF file) in another thread. */
void aof_background_fsync(int fd) {
Expand Down Expand Up @@ -337,10 +343,24 @@ void flushAppendOnlyFile(int force) {
int sync_in_progress = 0;
mstime_t latency;

if (sdslen(g_pserver->aof_buf) == 0) return;
if (sdslen(g_pserver->aof_buf) == 0) {
/* Check if we need to do fsync even the aof buffer is empty,
* because previously in AOF_FSYNC_EVERYSEC mode, fsync is
* called only when aof buffer is not empty, so if users
* stop write commands before fsync called in one second,
* the data in page cache cannot be flushed in time. */
if (g_pserver->aof_fsync == AOF_FSYNC_EVERYSEC &&
g_pserver->aof_fsync_offset != g_pserver->aof_current_size &&
g_pserver->unixtime > g_pserver->aof_last_fsync &&
!(sync_in_progress = aofFsyncInProgress())) {
goto try_fsync;
} else {
return;
}
}

if (g_pserver->aof_fsync == AOF_FSYNC_EVERYSEC)
sync_in_progress = bioPendingJobsOfType(BIO_AOF_FSYNC) != 0;
sync_in_progress = aofFsyncInProgress();

if (g_pserver->aof_fsync == AOF_FSYNC_EVERYSEC && !force) {
/* With this append fsync policy we do background fsyncing.
Expand Down Expand Up @@ -472,6 +492,7 @@ void flushAppendOnlyFile(int force) {
g_pserver->aof_buf = sdsempty();
}

try_fsync:
/* Don't fsync if no-appendfsync-on-rewrite is set to yes and there are
* children doing I/O in the background. */
if (g_pserver->aof_no_fsync_on_rewrite &&
Expand All @@ -486,10 +507,14 @@ void flushAppendOnlyFile(int force) {
redis_fsync(g_pserver->aof_fd); /* Let's try to get this data on the disk */
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("aof-fsync-always",latency);
g_pserver->aof_fsync_offset = g_pserver->aof_current_size;
g_pserver->aof_last_fsync = g_pserver->unixtime;
} else if ((g_pserver->aof_fsync == AOF_FSYNC_EVERYSEC &&
g_pserver->unixtime > g_pserver->aof_last_fsync)) {
if (!sync_in_progress) aof_background_fsync(g_pserver->aof_fd);
if (!sync_in_progress) {
aof_background_fsync(g_pserver->aof_fd);
g_pserver->aof_fsync_offset = g_pserver->aof_current_size;
}
g_pserver->aof_last_fsync = g_pserver->unixtime;
}
}
Expand Down Expand Up @@ -703,6 +728,7 @@ int loadAppendOnlyFile(char *filename) {
* operation is received. */
if (fp && redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0) {
g_pserver->aof_current_size = 0;
g_pserver->aof_fsync_offset = g_pserver->aof_current_size;
fclose(fp);
return C_ERR;
}
Expand All @@ -726,7 +752,7 @@ int loadAppendOnlyFile(char *filename) {

serverLog(LL_NOTICE,"Reading RDB preamble from AOF file...");
if (fseek(fp,0,SEEK_SET) == -1) goto readerr;
rioInitWithFile(&rdb,fileno(fp));
rioInitWithFile(&rdb,fp);
rdbSaveInfo rsi = RDB_SAVE_INFO_INIT;
if (rdbLoadRio(&rdb,&rsi,1) != C_OK) {
serverLog(LL_WARNING,"Error reading the RDB preamble of the AOF file, AOF loading aborted");
Expand Down Expand Up @@ -842,6 +868,7 @@ int loadAppendOnlyFile(char *filename) {
stopLoading();
aofUpdateCurrentSize();
g_pserver->aof_rewrite_base_size = g_pserver->aof_current_size;
g_pserver->aof_fsync_offset = g_pserver->aof_current_size;
return C_OK;

readerr: /* Read error. If feof(fp) is true, fall through to unexpected EOF. */
Expand Down Expand Up @@ -1373,7 +1400,7 @@ int rewriteAppendOnlyFile(char *filename) {
}

g_pserver->aof_child_diff = sdsempty();
rioInitWithFile(&aof,fileno(fp));
rioInitWithFile(&aof,fp);

if (g_pserver->aof_rewrite_incremental_fsync)
rioSetAutoSync(&aof,REDIS_AUTOSYNC_BYTES);
Expand Down
10 changes: 8 additions & 2 deletions src/bitops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -995,12 +995,18 @@ void bitfieldCommand(client *c) {
/* Lookup for read is ok if key doesn't exit, but errors
* if it's not a string. */
o = lookupKeyRead(c->db,c->argv[1]);
if (o != nullptr && checkType(c,o,OBJ_STRING)) return;
if (o != nullptr && checkType(c,o,OBJ_STRING)) {
zfree(ops);
return;
}
} else {
/* Lookup by making room up to the farest bit reached by
* this operation. */
if ((o = lookupStringForBitCommand(c,
highest_write_offset)) == nullptr) return;
highest_write_offset)) == nullptr) {
zfree(ops);
return;
}
}

addReplyArrayLen(c,numops);
Expand Down
3 changes: 3 additions & 0 deletions src/blocked.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
*/

#include "server.h"
#include <mutex>

int serveClientBlockedOnList(client *receiver, robj *key, robj *dstkey, redisDb *db, robj *value, int where);

Expand Down Expand Up @@ -180,6 +181,7 @@ void queueClientForReprocessing(client *c) {
* of operation the client is blocking for. */
void unblockClient(client *c) {
serverAssert(GlobalLocksAcquired());
serverAssert(c->lock.fOwnLock());
if (c->btype == BLOCKED_LIST ||
c->btype == BLOCKED_ZSET ||
c->btype == BLOCKED_STREAM) {
Expand Down Expand Up @@ -301,6 +303,7 @@ void handleClientsBlockedOnKeys(void) {
while(numclients--) {
listNode *clientnode = listFirst(clients);
client *receiver = (client*)clientnode->value;
std::unique_lock<decltype(client::lock)> lock(receiver->lock);

if (receiver->btype != BLOCKED_LIST) {
/* Put at the tail, so that at the next call
Expand Down
2 changes: 2 additions & 0 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,8 @@ void loadServerConfigFromString(char *config) {
} else if (!strcasecmp(argv[0], "version-override") && argc == 2) {
KEYDB_SET_VERSION = zstrdup(argv[1]);
serverLog(LL_WARNING, "Warning version is overriden to: %s\n", KEYDB_SET_VERSION);
} else if (!strcasecmp(argv[0],"testmode") && argc == 2){
g_fTestMode = yesnotoi(argv[1]);
} else {
err = "Bad directive or wrong number of arguments"; goto loaderr;
}
Expand Down
Loading

0 comments on commit 0483047

Please sign in to comment.