Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply all pending changes in preparation for 8.0.1 release. #1099

Merged
merged 9 commits into from
Oct 1, 2024
17 changes: 17 additions & 0 deletions 00-RELEASENOTES
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP.
SECURITY: There are security fixes in the release.
--------------------------------------------------------------------------------

================================================================================
Valkey 8.0.1 - Released Tue 1 Oct 2024
================================================================================

Upgrade urgency SECURITY: This release includes security fixes we recommend you
apply as soon as possible.

Bug fixes
=========
* Fix a build issue with RDMA when using additional make parameters. (#1074)
* Fix an issue where `CLUSTER SLOTS` might return the wrong tcp or tls port when called
from inside a script or from a module. (#1072)
* Fix a crash when `CLUSTER SLOTS` or `CLUSTER SHARDS` is called from inside
a script or from a module. (#1063)
* Fix a build issue on systems where `<threads.h>` is unavailable. (#1053)
* Fix an issue with the default `sentinel.conf` being invalid. (#1040)

================================================================================
Valkey 8.0.0 GA - Released Sun 15 Sep 2024
================================================================================
Expand Down
2 changes: 1 addition & 1 deletion sentinel.conf
Original file line number Diff line number Diff line change
Expand Up @@ -355,4 +355,4 @@ SENTINEL announce-hostnames no
# accept a -LOADING response after a primary has been rebooted, before failing
# over.

SENTINEL primary-reboot-down-after-period myprimary 0
SENTINEL primary-reboot-down-after-period mymaster 0
2 changes: 1 addition & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ $(TLS_MODULE_NAME): $(SERVER_NAME)
$(QUIET_CC)$(CC) -o $@ tls.c -shared -fPIC $(TLS_MODULE_CFLAGS) $(TLS_CLIENT_LIBS)

# valkey-rdma.so
$(RDMA_MODULE_NAME): $(REDIS_SERVER_NAME)
$(RDMA_MODULE_NAME): $(SERVER_NAME)
$(QUIET_CC)$(CC) -o $@ rdma.c -shared -fPIC $(RDMA_MODULE_CFLAGS)

# valkey-cli
Expand Down
1 change: 1 addition & 0 deletions src/aof.c
Original file line number Diff line number Diff line change
Expand Up @@ -1371,6 +1371,7 @@ struct client *createAOFClient(void) {
*/
c->raw_flag = 0;
c->flag.deny_blocking = 1;
c->flag.fake = 1;

/* We set the fake client as a replica waiting for the synchronization
* so that the server will not try to send replies to this client. */
Expand Down
2 changes: 1 addition & 1 deletion src/cluster.c
Original file line number Diff line number Diff line change
Expand Up @@ -1428,7 +1428,7 @@ void clusterCommandSlots(client *c) {
* ... continued until done
*/
int conn_type = 0;
if (connIsTLS(c->conn)) conn_type |= CACHE_CONN_TYPE_TLS;
if (shouldReturnTlsInfo()) conn_type |= CACHE_CONN_TYPE_TLS;
if (isClientConnIpV6(c)) conn_type |= CACHE_CONN_TYPE_IPv6;
if (c->resp == 3) conn_type |= CACHE_CONN_TYPE_RESP3;

Expand Down
15 changes: 13 additions & 2 deletions src/cluster_legacy.c
Original file line number Diff line number Diff line change
Expand Up @@ -2670,7 +2670,7 @@ void clusterUpdateSlotsConfigWith(clusterNode *sender, uint64_t senderConfigEpoc
* If the sender and myself are in the same shard, try psync. */
clusterSetPrimary(sender, !are_in_same_shard, !are_in_same_shard);
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG | CLUSTER_TODO_UPDATE_STATE | CLUSTER_TODO_FSYNC_CONFIG);
} else if ((sender_slots >= migrated_our_slots) && !are_in_same_shard) {
} else if (nodeIsPrimary(myself) && (sender_slots >= migrated_our_slots) && !are_in_same_shard) {
/* When all our slots are lost to the sender and the sender belongs to
* a different shard, this is likely due to a client triggered slot
* migration. Don't reconfigure this node to migrate to the new shard
Expand Down Expand Up @@ -6419,11 +6419,12 @@ void clusterCommandSetSlot(client *c) {
int slot_was_mine = server.cluster->slots[slot] == my_primary;
clusterDelSlot(slot);
clusterAddSlot(n, slot);
int shard_is_empty = my_primary->numslots == 0;

/* If replica migration is allowed, check if the primary of this shard
* loses its last slot and the shard becomes empty. In this case, we
* should turn into a replica of the new primary. */
if (server.cluster_allow_replica_migration && slot_was_mine && my_primary->numslots == 0) {
if (server.cluster_allow_replica_migration && slot_was_mine && shard_is_empty) {
serverAssert(n != my_primary);
serverLog(LL_NOTICE,
"Lost my last slot during slot migration. Reconfiguring myself "
Expand All @@ -6439,6 +6440,16 @@ void clusterCommandSetSlot(client *c) {
clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG | CLUSTER_TODO_UPDATE_STATE | CLUSTER_TODO_FSYNC_CONFIG);
}

/* If replica migration is not allowed, check if the primary of this shard
* loses its last slot and the shard becomes empty. In this case, we will
* print the exact same log as during the gossip process. */
if (!server.cluster_allow_replica_migration && nodeIsPrimary(myself) && slot_was_mine && shard_is_empty) {
serverAssert(n != my_primary);
serverLog(LL_NOTICE,
"My last slot was migrated to node %.40s (%s) in shard %.40s. I am now an empty primary.",
n->name, n->human_nodename, n->shard_id);
}

/* If this node or this node's primary was importing this slot,
* assigning the slot to itself also clears the importing status. */
if ((n == myself || n == myself->replicaof) && server.cluster->importing_slots_from[slot]) {
Expand Down
1 change: 1 addition & 0 deletions src/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ void scriptingInit(int setup) {
if (lctx.lua_client == NULL) {
lctx.lua_client = createClient(NULL);
lctx.lua_client->flag.script = 1;
lctx.lua_client->flag.fake = 1;

/* We do not want to allow blocking commands inside Lua */
lctx.lua_client->flag.deny_blocking = 1;
Expand Down
1 change: 1 addition & 0 deletions src/functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ int functionsRegisterEngine(const char *engine_name, engine *engine) {
client *c = createClient(NULL);
c->flag.deny_blocking = 1;
c->flag.script = 1;
c->flag.fake = 1;
engineInfo *ei = zmalloc(sizeof(*ei));
*ei = (engineInfo){
.name = engine_name_sds,
Expand Down
5 changes: 4 additions & 1 deletion src/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ client *moduleAllocTempClient(void) {
} else {
c = createClient(NULL);
c->flag.module = 1;
c->flag.fake = 1;
c->user = NULL; /* Root user */
}
return c;
Expand Down Expand Up @@ -894,8 +895,10 @@ void moduleCreateContext(ValkeyModuleCtx *out_ctx, ValkeyModule *module, int ctx
out_ctx->flags = ctx_flags;
if (ctx_flags & VALKEYMODULE_CTX_TEMP_CLIENT)
out_ctx->client = moduleAllocTempClient();
else if (ctx_flags & VALKEYMODULE_CTX_NEW_CLIENT)
else if (ctx_flags & VALKEYMODULE_CTX_NEW_CLIENT) {
out_ctx->client = createClient(NULL);
out_ctx->client->flag.fake = 1;
}

/* Calculate the initial yield time for long blocked contexts.
* in loading we depend on the server hz, but in other cases we also wait
Expand Down
7 changes: 5 additions & 2 deletions src/networking.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ client *createCachedResponseClient(int resp) {
/* Allocating the `conn` allows to prepare the caching client before adding
* data to the clients output buffer by `prepareClientToWrite`. */
recording_client->conn = zcalloc(sizeof(connection));
recording_client->flag.fake = 1;
return recording_client;
}

Expand Down Expand Up @@ -3246,8 +3247,10 @@ char *getClientSockname(client *c) {
int isClientConnIpV6(client *c) {
/* The cached client peer id is on the form "[IPv6]:port" for IPv6
* addresses, so we just check for '[' here. */
if (c->conn->type == NULL && server.current_client) {
/* Fake client? Use current client instead. */
if (c->flag.fake && server.current_client) {
/* Fake client? Use current client instead.
* Noted that in here we are assuming server.current_client is set
* and real (aof has already violated this in loadSingleAppendOnlyFil). */
c = server.current_client;
}
return getClientPeerId(c)[0] == '[';
Expand Down
2 changes: 1 addition & 1 deletion src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -2636,7 +2636,7 @@ void initServer(void) {
serverLog(LL_WARNING, "Failed creating the event loop. Error message: '%s'", strerror(errno));
exit(1);
}
server.db = zmalloc(sizeof(server) * server.dbnum);
server.db = zmalloc(sizeof(serverDb) * server.dbnum);

/* Create the databases, and initialize other internal state. */
int slot_count_bits = 0;
Expand Down
3 changes: 2 additions & 1 deletion src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,8 @@ typedef struct ClientFlags {
uint64_t dont_cache_primary : 1; /* In some cases we don't want to cache the primary. For example, the replica
* knows that it does not need the cache and required a full sync. With this
* flag, we won't cache the primary in freeClient. */
uint64_t reserved : 6; /* Reserved for future use */
uint64_t fake : 1; /* This is a fake client without a real connection. */
uint64_t reserved : 5; /* Reserved for future use */
} ClientFlags;

typedef struct client {
Expand Down
4 changes: 2 additions & 2 deletions src/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* similar. */
#define SERVER_NAME "valkey"
#define SERVER_TITLE "Valkey"
#define VALKEY_VERSION "8.0.0"
#define VALKEY_VERSION_NUM 0x00080000
#define VALKEY_VERSION "8.0.1"
#define VALKEY_VERSION_NUM 0x00080001

/* Redis OSS compatibility version, should never
* exceed 7.2.x. */
Expand Down
6 changes: 1 addition & 5 deletions src/zmalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,7 @@ void zlibc_free(void *ptr) {
#define dallocx(ptr, flags) je_dallocx(ptr, flags)
#endif

#if __STDC_NO_THREADS__
#define thread_local __thread
#else
#include <threads.h>
#endif
#define thread_local _Thread_local

#define MAX_THREADS_NUM (IO_THREADS_MAX_NUM + 3 + 1)
/* A thread-local storage which keep the current thread's index in the used_memory_thread array. */
Expand Down
23 changes: 23 additions & 0 deletions tests/integration/aof.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -673,3 +673,26 @@ tags {"aof external:skip"} {
}
}
}

# make sure the test infra won't use SELECT
set old_singledb $::singledb
set ::singledb 1

tags {"aof cluster external:skip"} {
test {Test cluster slots / cluster shards in aof won't crash} {
create_aof $aof_dirpath $aof_file {
append_to_aof [formatCommand cluster slots]
append_to_aof [formatCommand cluster shards]
}

create_aof_manifest $aof_dirpath $aof_manifest_file {
append_to_manifest "file appendonly.aof.1.incr.aof seq 1 type i\n"
}

start_server_aof [list dir $server_path cluster-enabled yes] {
assert_equal [r ping] {PONG}
}
}
}

set ::singledb $old_singledb
3 changes: 2 additions & 1 deletion tests/modules/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ TEST_MODULES = \
postnotifications.so \
moduleauthtwo.so \
rdbloadsave.so \
crash.so
crash.so \
cluster.so

.PHONY: all

Expand Down
51 changes: 51 additions & 0 deletions tests/modules/cluster.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "valkeymodule.h"

#define UNUSED(x) (void)(x)

int test_cluster_slots(ValkeyModuleCtx *ctx, ValkeyModuleString **argv, int argc) {
UNUSED(argv);

if (argc != 1) return ValkeyModule_WrongArity(ctx);

ValkeyModuleCallReply *rep = ValkeyModule_Call(ctx, "CLUSTER", "c", "SLOTS");
if (!rep) {
ValkeyModule_ReplyWithError(ctx, "ERR NULL reply returned");
} else {
ValkeyModule_ReplyWithCallReply(ctx, rep);
ValkeyModule_FreeCallReply(rep);
}

return VALKEYMODULE_OK;
}

int test_cluster_shards(ValkeyModuleCtx *ctx, ValkeyModuleString **argv, int argc) {
UNUSED(argv);

if (argc != 1) return ValkeyModule_WrongArity(ctx);

ValkeyModuleCallReply *rep = ValkeyModule_Call(ctx, "CLUSTER", "c", "SHARDS");
if (!rep) {
ValkeyModule_ReplyWithError(ctx, "ERR NULL reply returned");
} else {
ValkeyModule_ReplyWithCallReply(ctx, rep);
ValkeyModule_FreeCallReply(rep);
}

return VALKEYMODULE_OK;
}

int ValkeyModule_OnLoad(ValkeyModuleCtx *ctx, ValkeyModuleString **argv, int argc) {
VALKEYMODULE_NOT_USED(argv);
VALKEYMODULE_NOT_USED(argc);

if (ValkeyModule_Init(ctx, "cluster", 1, VALKEYMODULE_APIVER_1)== VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;

if (ValkeyModule_CreateCommand(ctx, "test.cluster_slots", test_cluster_slots, "", 0, 0, 0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;

if (ValkeyModule_CreateCommand(ctx, "test.cluster_shards", test_cluster_shards, "", 0, 0, 0) == VALKEYMODULE_ERR)
return VALKEYMODULE_ERR;

return VALKEYMODULE_OK;
}
9 changes: 9 additions & 0 deletions tests/unit/cluster/cluster-response-tls.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ proc get_port_from_node_info {line} {

proc cluster_response_tls {tls_cluster} {

test "CLUSTER SLOTS cached using EVAL over TLS -- tls-cluster $tls_cluster" {
set client_tcp [valkey 127.0.0.1 [srv 0 pport] 0 0]
set client_tls [valkey 127.0.0.1 [srv 0 port] 0 1]
set slots1 [$client_tls EVAL {return server.call('CLUSTER', 'SLOTS')} 0]
set slots2 [$client_tcp CLUSTER SLOTS]
# Compare the ports in the first row
assert_no_match [lindex $slots1 0 2 1] [lindex $slots2 0 2 1]
}

test "CLUSTER SLOTS with different connection type -- tls-cluster $tls_cluster" {
set slots1 [R 0 cluster slots]
set pport [srv 0 pport]
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/cluster/replica-migration.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ proc test_cluster_setslot {type} {
fail "valkey-cli --cluster rebalance returns non-zero exit code, output below:\n$result"
}

# Wait for R 3 to report that it is an empty replica (cluster-allow-replica-migration no)
# Wait for R 3 to report that it is an empty primary (cluster-allow-replica-migration no)
wait_for_log_messages -3 {"*I am now an empty primary*"} 0 1000 50

if {$type == "setslot"} {
Expand Down
8 changes: 8 additions & 0 deletions tests/unit/cluster/scripting.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,12 @@ start_cluster 1 0 {tags {external:skip cluster}} {

assert_match {*Can not run script on cluster, 'no-cluster' flag is set*} $e
}

test "Calling cluster slots in scripts is OK" {
assert_equal [lsort [r 0 cluster slots]] [lsort [r 0 eval "return redis.call('cluster', 'slots')" 0]]
}

test "Calling cluster shards in scripts is OK" {
assert_equal [lsort [r 0 cluster shards]] [lsort [r 0 eval "return redis.call('cluster', 'shards')" 0]]
}
}
Loading
Loading