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

Add support to notify modules of keys loaded by flash on startup #536

Merged
merged 30 commits into from
Feb 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
bb34d86
add option to notify modules of all keys loaded from flash
msotheeswaran-sc Jan 6, 2023
3d7117a
add test module
msotheeswaran-sc Jan 7, 2023
8a12ebb
add log for each loaded key
msotheeswaran-sc Jan 7, 2023
391df0a
wrong function type
msotheeswaran-sc Jan 7, 2023
cfb77ce
wrong function type
msotheeswaran-sc Jan 7, 2023
8695915
more log
msotheeswaran-sc Jan 7, 2023
3d43e6b
h -> h
msotheeswaran-sc Jan 7, 2023
5911a5d
missing *
msotheeswaran-sc Jan 7, 2023
505abe8
move to loadDataFromDisk
msotheeswaran-sc Jan 7, 2023
630591c
fix logs
msotheeswaran-sc Jan 7, 2023
47c7d75
missed the name part
msotheeswaran-sc Jan 7, 2023
4757fc8
fix warnings
msotheeswaran-sc Jan 7, 2023
1329436
move test module to test folder
msotheeswaran-sc Jan 7, 2023
064c701
add simple module test
msotheeswaran-sc Jan 7, 2023
2c9ef56
forgot to update script
msotheeswaran-sc Jan 7, 2023
33b2de4
make test work
msotheeswaran-sc Jan 7, 2023
d383f42
remove unnecessary includes
msotheeswaran-sc Jan 7, 2023
b952a45
idk
msotheeswaran-sc Jan 7, 2023
801d858
I don't know tcl
msotheeswaran-sc Jan 7, 2023
2838edc
just work
msotheeswaran-sc Jan 7, 2023
cc2aa19
help
msotheeswaran-sc Jan 7, 2023
e166ba1
gsdgd
msotheeswaran-sc Jan 7, 2023
47a5d1c
sfsf
msotheeswaran-sc Jan 7, 2023
24a665c
remove helloload ref
msotheeswaran-sc Jan 7, 2023
9570ca3
asdasd
msotheeswaran-sc Jan 7, 2023
a3f3b3f
try to add module call back into initial load
msotheeswaran-sc Jan 9, 2023
0651e24
remove config
msotheeswaran-sc Jan 9, 2023
737adfa
add flash load case to hooks.c
msotheeswaran-sc Jan 10, 2023
40c4887
fix test
msotheeswaran-sc Jan 10, 2023
32832f3
fix test
msotheeswaran-sc Jan 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions runtest-moduleapi
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ $TCLSH tests/test_helper.tcl \
--single unit/moduleapi/hash \
--single unit/moduleapi/zset \
--single unit/moduleapi/stream \
--single unit/moduleapi/load \
--config server-threads 3 \
"${@}"
12 changes: 10 additions & 2 deletions src/db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2607,6 +2607,14 @@ void clusterStorageLoadCallback(const char *rgchkey, size_t cch, void *)
slotToKeyUpdateKeyCore(rgchkey, cch, true /*add*/);
}

void moduleLoadCallback(const char * rgchKey, size_t cchKey, void *data) {
if (g_pserver->cluster_enabled) {
clusterStorageLoadCallback(rgchKey, cchKey, data);
}
robj *keyobj = createEmbeddedStringObject(rgchKey, cchKey);
moduleNotifyKeyspaceEvent(NOTIFY_LOADED, "loaded", keyobj, *(int *)data);
}

void redisDb::initialize(int id)
{
redisDbPersistentData::initialize();
Expand All @@ -2625,8 +2633,8 @@ void redisDb::storageProviderInitialize()
{
if (g_pserver->m_pstorageFactory != nullptr)
{
IStorageFactory::key_load_iterator itr = (g_pserver->cluster_enabled) ? clusterStorageLoadCallback : nullptr;
this->setStorageProvider(StorageCache::create(g_pserver->m_pstorageFactory, id, itr, nullptr));
IStorageFactory::key_load_iterator itr = moduleLoadCallback;
this->setStorageProvider(StorageCache::create(g_pserver->m_pstorageFactory, id, itr, &id));
}
}

Expand Down
1 change: 1 addition & 0 deletions src/redismodule.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ static const RedisModuleEvent
#define REDISMODULE_SUBEVENT_LOADING_ENDED 3
#define REDISMODULE_SUBEVENT_LOADING_FAILED 4
#define _REDISMODULE_SUBEVENT_LOADING_NEXT 5
#define REDISMODULE_SUBEVENT_LOADING_FLASH_START 6

#define REDISMODULE_SUBEVENT_CLIENT_CHANGE_CONNECTED 0
#define REDISMODULE_SUBEVENT_CLIENT_CHANGE_DISCONNECTED 1
Expand Down
15 changes: 9 additions & 6 deletions src/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4067,12 +4067,6 @@ void initServer(void) {
}
}

/* We have to initialize storage providers after the cluster has been initialized */
for (int idb = 0; idb < cserver.dbnum; ++idb)
{
g_pserver->db[idb]->storageProviderInitialize();
}

saveMasterStatusToStorage(false); // eliminate the repl-offset field

/* Initialize ACL default password if it exists */
Expand All @@ -4085,6 +4079,15 @@ void initServer(void) {
* Thread Local Storage initialization collides with dlopen call.
* see: https://sourceware.org/bugzilla/show_bug.cgi?id=19329 */
void InitServerLast() {

/* We have to initialize storage providers after the cluster has been initialized */
moduleFireServerEvent(REDISMODULE_EVENT_LOADING, REDISMODULE_SUBEVENT_LOADING_FLASH_START, NULL);
for (int idb = 0; idb < cserver.dbnum; ++idb)
{
g_pserver->db[idb]->storageProviderInitialize();
}
moduleFireServerEvent(REDISMODULE_EVENT_LOADING, REDISMODULE_SUBEVENT_LOADING_ENDED, NULL);

bioInit();
set_jemalloc_bg_thread(cserver.jemalloc_bg_thread);
g_pserver->initial_memory_usage = zmalloc_used_memory();
Expand Down
3 changes: 2 additions & 1 deletion tests/modules/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ TEST_MODULES = \
defragtest.so \
hash.so \
zset.so \
stream.so
stream.so \
load.so


.PHONY: all
Expand Down
1 change: 1 addition & 0 deletions tests/modules/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ void loadingCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void
case REDISMODULE_SUBEVENT_LOADING_RDB_START: keyname = "loading-rdb-start"; break;
case REDISMODULE_SUBEVENT_LOADING_AOF_START: keyname = "loading-aof-start"; break;
case REDISMODULE_SUBEVENT_LOADING_REPL_START: keyname = "loading-repl-start"; break;
case REDISMODULE_SUBEVENT_LOADING_FLASH_START: keyname = "loading-flash-start"; break;
case REDISMODULE_SUBEVENT_LOADING_ENDED: keyname = "loading-end"; break;
case REDISMODULE_SUBEVENT_LOADING_FAILED: keyname = "loading-failed"; break;
}
Expand Down
94 changes: 94 additions & 0 deletions tests/modules/load.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/* Server hooks API example
*
* -----------------------------------------------------------------------------
*
* Copyright (c) 2019, 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.
*/

#define REDISMODULE_EXPERIMENTAL_API
#include "redismodule.h"

size_t count, finalCount;

/* Client state change callback. */
void loadCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) {
REDISMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(e);
REDISMODULE_NOT_USED(data);

if (sub == REDISMODULE_SUBEVENT_LOADING_FLASH_START || sub == REDISMODULE_SUBEVENT_LOADING_RDB_START || sub == REDISMODULE_SUBEVENT_LOADING_AOF_START || sub == REDISMODULE_SUBEVENT_LOADING_REPL_START) {
count = 0;
finalCount = 0;
} else if (sub == REDISMODULE_SUBEVENT_LOADING_ENDED) {
finalCount = count;
}
}

int loadKeyCallback(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) {
REDISMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(type);
REDISMODULE_NOT_USED(event);

const char *keyname = RedisModule_StringPtrLen(key, NULL);

RedisModule_Log(ctx, REDISMODULE_LOGLEVEL_NOTICE, "Loaded key: %s", keyname);

count++;
return 0;
}

int LoadCount_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
RedisModule_AutoMemory(ctx); /* Use automatic memory management. */

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

RedisModule_ReplyWithLongLong(ctx, finalCount);

return REDISMODULE_OK;
}

/* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);

if (RedisModule_Init(ctx,"load",1,REDISMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR;

RedisModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_Loading, loadCallback);
RedisModule_SubscribeToKeyspaceEvents(ctx,
REDISMODULE_NOTIFY_LOADED, loadKeyCallback);

if (RedisModule_CreateCommand(ctx, "load.count",
LoadCount_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
return REDISMODULE_OK;
}
15 changes: 15 additions & 0 deletions tests/unit/moduleapi/load.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
set testmodule [file normalize tests/modules/load.so]

if {$::flash_enabled} {
start_server [list tags [list "modules"] overrides [list storage-provider {flash ./rocks.db.master} databases 256 loadmodule $testmodule]] {
test "Module is notified of keys loaded from flash" {
r flushall
r set foo bar
r set bar foo
r set foobar barfoo
assert_equal [r load.count] 0
r debug reload
assert_equal [r load.count] 3
}
}
}