Skip to content

Commit

Permalink
Merge branch 'unstable' into RELEASE_0_9
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnSully committed Mar 19, 2019
2 parents 8262170 + d380074 commit 8164c93
Show file tree
Hide file tree
Showing 34 changed files with 566 additions and 181 deletions.
67 changes: 0 additions & 67 deletions MANIFESTO

This file was deleted.

10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
What is KeyDB?
--------------

KeyDB is a high performance fork of Redis focussing on multithreading, memory efficiency, and high throughput. In addition to multithreading KeyDB also has features only available in Redis Enterprise such as 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 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.

KeyDB has full compatibility with the Redis protocol, modules, and scripts. This includes full support for transactions, and atomic execution of scripts. For more information see our architecture section below.

Try our docker container: https://hub.docker.com/r/eqalpha/keydb

Why fork Redis?
---------------

Expand Down Expand Up @@ -39,7 +41,7 @@ If you would like to use the FLASH backed storage this option configures the dir

db-s3-object /path/to/bucket

If you would like KeyDB to dump directly to AWS S3 this option specifies the bucket. Using this option with the traditional RDB options will result in KeyDB backing up twice to both locations. This requires the AWS CLI tools to be installed and configured which are used under the hood to transfer the data.
If you would like KeyDB to dump and load directly to AWS S3 this option specifies the bucket. Using this option with the traditional RDB options will result in KeyDB backing up twice to both locations. If both are specified KeyDB will first attempt to load from the local dump file and if that fails load from S3. This requires the AWS CLI tools to be installed and configured which are used under the hood to transfer the data.

All other configuration options behave as you'd expect. Your existing configuration files should continue to work unchanged.

Expand Down Expand Up @@ -179,6 +181,8 @@ for Ubuntu and Debian systems:
% cd utils
% ./install_server.sh

_Note_: `install_server.sh` will not work on Mac OSX; it is built for Linux only.

The script will ask you a few questions and will setup everything you need
to run KeyDB properly as a background daemon that will start again on
system reboots.
Expand All @@ -189,7 +193,7 @@ You'll be able to stop and start KeyDB using the script named
Multithreading Architecture
---------------------------

KeyDB works by running the normal Redis event loop on multiple threads. Network IO, and query parsing are done concurrently. Each connection is assigned a thread on accept(). Access to the core hash table is guarded by spinlock. Because the hashtable access is extremely fast this lock has low contention. Transactions hold the lock for the duration of the EXEC command. Modules work in concert with the GIL which is only acquired when all server threads are paused. This maintains the atomicity gurantees modules expect.
KeyDB works by running the normal Redis event loop on multiple threads. Network IO, and query parsing are done concurrently. Each connection is assigned a thread on accept(). Access to the core hash table is guarded by spinlock. Because the hashtable access is extremely fast this lock has low contention. Transactions hold the lock for the duration of the EXEC command. Modules work in concert with the GIL which is only acquired when all server threads are paused. This maintains the atomicity guarantees modules expect.

Unlike most databases the core data structure is the fastest part of the system. Most of the query time comes from parsing the REPL protocol and copying data to/from the network.

Expand Down
3 changes: 3 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,6 @@ install: all
$(REDIS_INSTALL) $(REDIS_CHECK_RDB_NAME) $(INSTALL_BIN)
$(REDIS_INSTALL) $(REDIS_CHECK_AOF_NAME) $(INSTALL_BIN)
@ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_SENTINEL_NAME)

uninstall:
rm -f $(INSTALL_BIN)/{$(REDIS_SERVER_NAME),$(REDIS_BENCHMARK_NAME),$(REDIS_CLI_NAME),$(REDIS_CHECK_RDB_NAME),$(REDIS_CHECK_AOF_NAME),$(REDIS_SENTINEL_NAME)}
7 changes: 7 additions & 0 deletions src/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,8 @@ void ACLLoadUsersAtStartup(void) {
* ACL SETUSER <username> ... acl rules ...
* ACL DELUSER <username> [...]
* ACL GETUSER <username>
* ACL GENPASS
* ACL WHOAMI
*/
void aclCommand(client *c) {
char *sub = ptrFromObj(c->argv[1]);
Expand Down Expand Up @@ -1571,6 +1573,10 @@ void aclCommand(client *c) {
}
dictReleaseIterator(di);
setDeferredArrayLen(c,dl,arraylen);
} else if (!strcasecmp(sub,"genpass") && c->argc == 2) {
char pass[32]; /* 128 bits of actual pseudo random data. */
getRandomHexChars(pass,sizeof(pass));
addReplyBulkCBuffer(c,pass,sizeof(pass));
} else if (!strcasecmp(sub,"help")) {
const char *help[] = {
"LOAD -- Reload users from the ACL file.",
Expand All @@ -1581,6 +1587,7 @@ void aclCommand(client *c) {
"DELUSER <username> [...] -- Delete a list of users.",
"CAT -- List available categories.",
"CAT <category> -- List commands inside category.",
"GENPASS -- Generate a secure user password.",
"WHOAMI -- Return the current connection username.",
NULL
};
Expand Down
3 changes: 3 additions & 0 deletions src/aof.c
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,9 @@ void aofRemoveTempFile(pid_t childpid) {

snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) childpid);
unlink(tmpfile);

snprintf(tmpfile,256,"temp-rewriteaof-%d.aof", (int) childpid);
unlink(tmpfile);
}

/* Update the server.aof_current_size field explicitly using stat(2)
Expand Down
15 changes: 11 additions & 4 deletions src/blocked.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,25 @@ int serveClientBlockedOnList(client *receiver, robj *key, robj *dstkey, redisDb
* is zero. */
int getTimeoutFromObjectOrReply(client *c, robj *object, mstime_t *timeout, int unit) {
long long tval;
long double ftval;

if (getLongLongFromObjectOrReply(c,object,&tval,
"timeout is not an integer or out of range") != C_OK)
return C_ERR;
if (unit == UNIT_SECONDS) {
if (getLongDoubleFromObjectOrReply(c,object,&ftval,
"timeout is not an float or out of range") != C_OK)
return C_ERR;
tval = (long long) (ftval * 1000.0);
} else {
if (getLongLongFromObjectOrReply(c,object,&tval,
"timeout is not an integer or out of range") != C_OK)
return C_ERR;
}

if (tval < 0) {
addReplyError(c,"timeout is negative");
return C_ERR;
}

if (tval > 0) {
if (unit == UNIT_SECONDS) tval *= 1000;
tval += mstime();
}
*timeout = tval;
Expand Down
1 change: 1 addition & 0 deletions src/cluster.c
Original file line number Diff line number Diff line change
Expand Up @@ -3031,6 +3031,7 @@ void clusterHandleSlaveFailover(void) {
if (server.cluster->mf_end) {
server.cluster->failover_auth_time = mstime();
server.cluster->failover_auth_rank = 0;
clusterDoBeforeSleep(CLUSTER_TODO_HANDLE_FAILOVER);
}
serverLog(LL_WARNING,
"Start of election delayed for %lld milliseconds "
Expand Down
4 changes: 2 additions & 2 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -1103,8 +1103,8 @@ void configSetCommand(client *c) {
int soft_seconds;

class = getClientTypeByName(v[j]);
hard = strtoll(v[j+1],NULL,10);
soft = strtoll(v[j+2],NULL,10);
hard = memtoll(v[j+1],NULL);
soft = memtoll(v[j+2],NULL);
soft_seconds = strtoll(v[j+3],NULL,10);

server.client_obuf_limits[class].hard_limit_bytes = hard;
Expand Down
2 changes: 1 addition & 1 deletion src/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ NULL
}
emptyDb(-1,EMPTYDB_NO_FLAGS,NULL);
protectClient(c);
int ret = rdbLoad(server.rdb_filename,NULL);
int ret = rdbLoad(NULL);
unprotectClient(c);
if (ret != C_OK) {
addReplyError(c,"Error trying to load the RDB dump");
Expand Down
2 changes: 1 addition & 1 deletion src/geo.c
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ void georadiusGeneric(client *c, int flags) {
zsetConvertToZiplistIfNeeded(zobj,maxelelen);
setKey(c->db,storekey,zobj);
decrRefCount(zobj);
notifyKeyspaceEvent(NOTIFY_LIST,"georadiusstore",storekey,
notifyKeyspaceEvent(NOTIFY_ZSET,"georadiusstore",storekey,
c->db->id);
server.dirty += returned_items;
} else if (dbDelete(c->db,storekey)) {
Expand Down
9 changes: 8 additions & 1 deletion src/hyperloglog.c
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,7 @@ int hllSparseToDense(robj *o) {
} else {
runlen = HLL_SPARSE_VAL_LEN(p);
regval = HLL_SPARSE_VAL_VALUE(p);
if ((runlen + idx) > HLL_REGISTERS) break; /* Overflow. */
while(runlen--) {
HLL_DENSE_SET_REGISTER(hdr->registers,idx,regval);
idx++;
Expand Down Expand Up @@ -1013,7 +1014,12 @@ uint64_t hllCount(struct hllhdr *hdr, int *invalid) {
double m = HLL_REGISTERS;
double E;
int j;
int reghisto[HLL_Q+2] = {0};
/* Note that reghisto size could be just HLL_Q+2, becuase HLL_Q+1 is
* the maximum frequency of the "000...1" sequence the hash function is
* able to return. However it is slow to check for sanity of the
* input: instead we history array at a safe size: overflows will
* just write data to wrong, but correctly allocated, places. */
int reghisto[64] = {0};

/* Compute register histogram */
if (hdr->encoding == HLL_DENSE) {
Expand Down Expand Up @@ -1088,6 +1094,7 @@ int hllMerge(uint8_t *max, size_t cmax, robj *hll) {
} else {
runlen = HLL_SPARSE_VAL_LEN(p);
regval = HLL_SPARSE_VAL_VALUE(p);
if ((runlen + i) > HLL_REGISTERS) break; /* Overflow. */
while(runlen--) {
if (i < 0 || (size_t)i >= cmax)
return C_ERR;
Expand Down
Loading

0 comments on commit 8164c93

Please sign in to comment.