Skip to content

Commit 035a8b4

Browse files
BenGoldbergerLukeMathWalkerDarthBlerman25alonre24
authored
Yield to redis while indexing - [MOD-9220] (#6103)
* add op-counter + config * Run all Rust benchmarks in the workspace (#6030) * Run all Rust benchmarks in the workspace * Allow forcing the run for micro-benchmarks * Fix bench run * Update .github/workflows/flow-micro-benchmarks.yml Co-authored-by: Tim Janus <tim@janus.rs> --------- Co-authored-by: Tim Janus <tim@janus.rs> * Fix Rust build after switching off readies (#6086) Fix Rust linking * [MOD-9560] Change default config value for _BG_INDEX_MEM_PCT_THR (#6053) * change default value * change default value in config pytest * change index oom tests to lower value then new default * change debug commands tests to lower value then default value * change default value of set tight memory functions * 100testv1 * test default value * Build unit tests without readies [MOD-9099] (#6082) * purge readeis from cmake. Use new build script instead of makefile * call script in CI * libuv * restore build folder * libuv * unit tests * pretty build.sh * pytest * fixed extension build error * Add profile flags + try pass linker flag properly (wip) * fix build and linkage + pytest + adjust json * small cleanup * Add pytz dep * bump googletest version, use same variant name as before * remove ld libs * Fix executable linker flags - build unit test properly. run unit tests with old "make unit-tests" way (until this is fixed via ./build.sh) * fix rust build via build.sh * fix san build * Set coverage flags and use the same bin dir for sanitizer (build it for debug) * update benchmark image for regression test * remove leftover * Build hiredis static * fix json env flag in CI * CR changes * Restore deleted files until unit tests are done as well, use boolean params * restore vecsim version * fix profile and fix build error * fix for profile * try fix mac build * fix unit tests for arm * Define boost dir * remove the policies * try fix the binroot for unit-tests * change dir name for arm * remove policy from hash as well * use clang in mac * try to set hardcoded clang * try to mimic readies in macos includes * try set CMAKE_OSX_DEPLOYMENT_TARGET * whitespace formatting * Set CC to clang in apple * try to export llvm * try set compiler in build script * use bin in path * try EXPORT properly with homebrew * remove setting bad path to clang * set clang path * update to llvm@18 * update c++ path * set compiler with LLVM env var * fix? * set proper link flags for mac * remove bsymbolic from hiredis * revert hiredis in non macos to how it was * clean stuff * cleanups * Fix the extract debug symbols command so it will work as before (required for packing properly) * update deps * fix for alpine * Refactor unit-tests script to not using readies WIP * revert vecsim accidental change * Fix script so it will work for sanitizer as well, address CR --------- Co-authored-by: DvirDukhan <dvir@redis.com> Co-authored-by: GuyAv46 <guy.avimor@gmail.com> * Wrongly included the text of GPLv3 instead of AGPLv3 (#6089) * README.md - added no standalone released note (#6074) * Update README.md * Update README.md * Update README.md * small change to opcounter * debug command for yield counter + test * add config test * Update SECURITY.md (#6070) * Update SECURITY.md * Update SECURITY.md * Enforce license headers for Rust files (#6090) * A small binary to enforce license headers in all Rust files * Enforce license headers in CI * MOD-6151: Build without readies - simplify packing (#5908) * fix * change ramp version * fix macos * GHA3 * fix macos * fix maxos * fix * fix * fix * new * purge readies * double * typo * remove debug * shapshot * gp * go conflict * darwin to macos * Account for get-platform change, remove redundant mkdir, remove not used/used once variables * remove unused DEP_NAMES * remove unused function * remove un condition * improve pack_ramp * remove unused DEPS * macos * remove xtx * replace eprint * remove runn * replace realapth * Revert "remove xtx" This reverts commit 6efb895. * try remove xtx * remove NOP * remove NUMVER * without tmp * delete * remove eval * remove release * Assume SNAPSHOT=1 * remove SEMVER * fin * remove sbin/getver * Don't add unnecessary \n after the license header (#6095) Otherwise, `cargo fmt` fails on them. * [MOD-9547] Core trie iterators (#6016) * Basic iterators * Typo * Clean up API * Add tests for iterators * More comments * Fix warning for miri * Verify that all prefixed iterators agree with each other and match expectations * Test both lending and non-lending traversals * Clarify comment * Test the empty key case * Fix where bounds on traversal_filter * Add missing license headers * SSPLv1.txt - removed irrelevant text (#6097) * MOD-9612: Fix flaky test and change early timeout error message (#6100) * Fix flaky test AND change early timeout error message * Fix TimeLimit initialization * Add comment * remove deps changes * remove deps changes * fix a possibly new flaky test * temp fix for config * changes to use the config_cmd func * try to fix issue test * use cluster conn in test * handle num of yield with cluster * dont test with cluster * pr changes * move whitespace * add tag and geoshape idx * pr changes * changes to yield only while server is loading * and check if module function exist * remove white space * add wait_for_index in test * pr change rename config * change help text * add isLoading argument * check globally if loading with g_isLoading * pr change --------- Co-authored-by: Luca Palmieri <20745048+LukeMathWalker@users.noreply.github.com> Co-authored-by: Tim Janus <tim@janus.rs> Co-authored-by: lerman25 <58445352+lerman25@users.noreply.github.com> Co-authored-by: alonre24 <alon.reshef@redis.com> Co-authored-by: DvirDukhan <dvir@redis.com> Co-authored-by: GuyAv46 <guy.avimor@gmail.com> Co-authored-by: Lior Kogan <koganlior1@gmail.com> Co-authored-by: Zeeshan Ali Khan <zeenix@gmail.com> Co-authored-by: Raz Monsonego <74051729+raz-mon@users.noreply.github.com>
1 parent 80a973e commit 035a8b4

10 files changed

Lines changed: 262 additions & 2 deletions

File tree

src/config.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ configPair_t __configPairs[] = {
8686
{"ENABLE_UNSTABLE_FEATURES", "search-enable-unstable-features"},
8787
{"BM25STD_TANH_FACTOR", "search-bm25std-tanh-factor"},
8888
{"_BG_INDEX_OOM_PAUSE_TIME", "search-_bg-index-oom-pause-time"},
89+
{"INDEXER_YIELD_EVERY_OPS", "search-indexer-yield-every-ops"},
8990
};
9091

9192
static const char* FTConfigNameToConfigName(const char *name) {
@@ -956,6 +957,19 @@ CONFIG_GETTER(getIndexCursorLimit) {
956957
CONFIG_BOOLEAN_SETTER(set_EnableUnstableFeatures, enableUnstableFeatures)
957958
CONFIG_BOOLEAN_GETTER(get_EnableUnstableFeatures, enableUnstableFeatures, 0)
958959

960+
// INDEXER_YIELD_EVERY_OPS
961+
CONFIG_SETTER(setIndexerYieldEveryOps) {
962+
unsigned int yieldEveryOps;
963+
int acrc = AC_GetUnsigned(ac, &yieldEveryOps, AC_F_GE1);
964+
config->indexerYieldEveryOpsWhileLoading = yieldEveryOps;
965+
RETURN_STATUS(acrc);
966+
}
967+
968+
CONFIG_GETTER(getIndexerYieldEveryOps) {
969+
sds ss = sdsempty();
970+
return sdscatprintf(ss, "%u", config->indexerYieldEveryOpsWhileLoading);
971+
}
972+
959973
RSConfig RSGlobalConfig = RS_DEFAULT_CONFIG;
960974

961975
static RSConfigVar *findConfigVar(const RSConfigOptions *config, const char *name) {
@@ -1280,6 +1294,10 @@ RSConfigOptions RSGlobalConfigOptions = {
12801294
"The default value is 5 seconds in Redis Enterprise, 0 in Redis OS.",
12811295
.setValue = setBgOOMpauseTimeForRetry,
12821296
.getValue = getBgOOMpauseTimeForRetry},
1297+
{.name = "INDEXER_YIELD_EVERY_OPS",
1298+
.helpText = "The number of operations to perform before yielding to Redis during indexing while loading",
1299+
.setValue = setIndexerYieldEveryOps,
1300+
.getValue = getIndexerYieldEveryOps},
12831301
{.name = NULL}}};
12841302

12851303
void RSConfigOptions_AddConfigs(RSConfigOptions *src, RSConfigOptions *dst) {
@@ -1763,6 +1781,15 @@ int RegisterModuleConfig(RedisModuleCtx *ctx) {
17631781
)
17641782
)
17651783

1784+
RM_TRY(
1785+
RedisModule_RegisterNumericConfig(
1786+
ctx, "search-indexer-yield-every-ops", DEFAULT_INDEXER_YIELD_EVERY_OPS,
1787+
REDISMODULE_CONFIG_UNPREFIXED, 1,
1788+
UINT32_MAX, get_uint_numeric_config, set_uint_numeric_config, NULL,
1789+
(void *)&(RSGlobalConfig.indexerYieldEveryOpsWhileLoading)
1790+
)
1791+
)
1792+
17661793
// String parameters
17671794
RM_TRY(
17681795
RedisModule_RegisterStringConfig(

src/config.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ typedef struct {
153153
// If set, we use an optimization that sorts the children of an intersection iterator in a way
154154
// where union iterators are being factorize by the number of their own children.
155155
int prioritizeIntersectUnionChildren;
156+
// The number of indexing operations per field to perform before yielding to Redis during indexing while loading (so redis can be responsive)
157+
unsigned int indexerYieldEveryOpsWhileLoading;
156158
// Limit the number of cursors that can be created for a single index
157159
long long indexCursorLimit;
158160
// The maximum ratio between current memory and max memory for which background indexing is allowed
@@ -277,6 +279,7 @@ char *getRedisConfigValue(RedisModuleCtx *ctx, const char* confName);
277279
#define BM25STD_TANH_FACTOR_MAX 10000
278280
#define BM25STD_TANH_FACTOR_MIN 1
279281
#define DEFAULT_BG_OOM_PAUSE_TIME_BEFOR_RETRY 5
282+
#define DEFAULT_INDEXER_YIELD_EVERY_OPS 1000
280283

281284
// default configuration
282285
#define RS_DEFAULT_CONFIG { \
@@ -324,6 +327,7 @@ char *getRedisConfigValue(RedisModuleCtx *ctx, const char* confName);
324327
.indexingMemoryLimit = DEFAULT_INDEXING_MEMORY_LIMIT, \
325328
.requestConfigParams.BM25STD_TanhFactor = DEFAULT_BM25STD_TANH_FACTOR, \
326329
.bgIndexingOomPauseTimeBeforeRetry = DEFAULT_BG_OOM_PAUSE_TIME_BEFOR_RETRY, \
330+
.indexerYieldEveryOpsWhileLoading = DEFAULT_INDEXER_YIELD_EVERY_OPS, \
327331
}
328332

329333
#define REDIS_ARRAY_LIMIT 7

src/debug_commands.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,48 @@ DEBUG_COMMAND(getHideUserDataFromLogs) {
17891789
return RedisModule_ReplyWithLongLong(ctx, value);
17901790
}
17911791

1792+
// Global counter for tracking yield calls during loading
1793+
static size_t g_yieldCallCounter = 0;
1794+
1795+
// Function to increment the yield counter (to be called from IndexerBulkAdd)
1796+
void IncrementYieldCounter(void) {
1797+
g_yieldCallCounter++;
1798+
}
1799+
1800+
// Reset the yield counter
1801+
void ResetYieldCounter(void) {
1802+
g_yieldCallCounter = 0;
1803+
}
1804+
1805+
/**
1806+
* FT.DEBUG YIELDS_ON_LOAD_COUNTER [RESET]
1807+
* Get or reset the counter for yields during loading operations
1808+
*/
1809+
DEBUG_COMMAND(YieldCounter) {
1810+
if (!debugCommandsEnabled(ctx)) {
1811+
return RedisModule_ReplyWithError(ctx, NODEBUG_ERR);
1812+
}
1813+
1814+
if (argc > 3) {
1815+
return RedisModule_WrongArity(ctx);
1816+
}
1817+
1818+
// Check if we need to reset the counter
1819+
if (argc == 3) {
1820+
size_t len;
1821+
const char *subCmd = RedisModule_StringPtrLen(argv[2], &len);
1822+
if (STR_EQCASE(subCmd, len, "RESET")) {
1823+
ResetYieldCounter();
1824+
return RedisModule_ReplyWithSimpleString(ctx, "OK");
1825+
} else {
1826+
return RedisModule_ReplyWithError(ctx, "Unknown subcommand");
1827+
}
1828+
}
1829+
1830+
// Return the current counter value
1831+
return RedisModule_ReplyWithLongLong(ctx, g_yieldCallCounter);
1832+
}
1833+
17921834
DebugCommandType commands[] = {{"DUMP_INVIDX", DumpInvertedIndex}, // Print all the inverted index entries.
17931835
{"DUMP_NUMIDX", DumpNumericIndex}, // Print all the headers (optional) + entries of the numeric tree.
17941836
{"DUMP_NUMIDXTREE", DumpNumericIndexTree}, // Print tree general info, all leaves + nodes + stats
@@ -1824,6 +1866,7 @@ DebugCommandType commands[] = {{"DUMP_INVIDX", DumpInvertedIndex}, // Print all
18241866
{"INDEXES", ListIndexesSwitch},
18251867
{"INFO", IndexObfuscatedInfo},
18261868
{"GET_HIDE_USER_DATA_FROM_LOGS", getHideUserDataFromLogs},
1869+
{"YIELDS_ON_LOAD_COUNTER", YieldCounter},
18271870
/**
18281871
* The following commands are for debugging distributed search/aggregation.
18291872
*/

src/indexer.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,17 @@
1515
#include "index.h"
1616
#include "redis_index.h"
1717
#include "suffix.h"
18+
#include "config.h"
1819
#include "rmutil/rm_assert.h"
1920
#include "phonetic_manager.h"
2021
#include "obfuscation/obfuscation_api.h"
22+
#include "redismodule.h"
23+
#include "debug_commands.h"
2124

2225
extern RedisModuleCtx *RSDummyContext;
2326

27+
extern void IncrementYieldCounter(void);
28+
2429
#include <unistd.h>
2530

2631
static void writeIndexEntry(IndexSpec *spec, InvertedIndex *idx, IndexEncoder encoder,
@@ -104,6 +109,7 @@ static void writeCurEntries(RSAddDocumentCtx *aCtx, RedisSearchCtx *ctx) {
104109
if (invidx) {
105110
entry->docId = aCtx->doc->docId;
106111
RS_LOG_ASSERT(entry->docId, "docId should not be 0");
112+
IndexerYieldWhileLoading(ctx->redisCtx);
107113
writeIndexEntry(spec, invidx, encoder, entry);
108114
if (Index_StoreFieldMask(spec)) {
109115
invidx->fieldMask |= entry->fieldMask;
@@ -227,6 +233,7 @@ static void indexBulkFields(RSAddDocumentCtx *aCtx, RedisSearchCtx *sctx) {
227233
continue;
228234
}
229235

236+
IndexerYieldWhileLoading(sctx->redisCtx);
230237
if (IndexerBulkAdd(cur, sctx, doc->fields + ii, fs, fdata, &cur->status) != 0) {
231238
IndexError_AddQueryError(&cur->spec->stats.indexError, &cur->status, doc->docKey);
232239
FieldSpec_AddQueryError(&cur->spec->fields[fs->index], &cur->status, doc->docKey);
@@ -385,3 +392,21 @@ int IndexDocument(RSAddDocumentCtx *aCtx) {
385392
AddDocumentCtx_Finish(aCtx);
386393
return 0;
387394
}
395+
396+
bool g_isLoading = false;
397+
398+
/**
399+
* Yield to Redis after a certain number of operations during indexing.
400+
* This helps keep Redis responsive during long indexing operations.
401+
* @param ctx The Redis context
402+
*/
403+
static void IndexerYieldWhileLoading(RedisModuleCtx *ctx) {
404+
static size_t opCounter = 0;
405+
406+
// If server is loading, Yield to Redis every RSGlobalConfig.indexerYieldEveryOps operations
407+
if (g_isLoading && ++opCounter >= RSGlobalConfig.indexerYieldEveryOpsWhileLoading) {
408+
opCounter = 0;
409+
IncrementYieldCounter(); // Track that we called yield
410+
RedisModule_Yield(ctx, REDISMODULE_YIELD_FLAG_CLIENTS, NULL);
411+
}
412+
}

src/indexer.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#include "concurrent_ctx.h"
1414
#include "util/arr.h"
1515
#include "geometry_index.h"
16+
17+
extern bool g_isLoading;
18+
1619
// Preprocessors can store field data to this location
1720
typedef struct FieldIndexerData {
1821
int isMulti;
@@ -75,4 +78,11 @@ int IndexerBulkAdd(RSAddDocumentCtx *cur, RedisSearchCtx *sctx,
7578
const DocumentField *field, const FieldSpec *fs, FieldIndexerData *fdata,
7679
QueryError *status);
7780

81+
/**
82+
* Yield to Redis after a certain number of operations during indexing while loading.
83+
* This helps keep Redis responsive during long indexing operations.
84+
* @param ctx The Redis context
85+
*/
86+
static void IndexerYieldWhileLoading(RedisModuleCtx *ctx);
87+
7888
#endif

src/spec.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3039,6 +3039,7 @@ int CompareVersions(Version v1, Version v2) {
30393039

30403040
return 0;
30413041
}
3042+
30423043
// This function is called in case the server is started or
30433044
// when the replica is loading the RDB file from the master.
30443045
static void Indexes_LoadingEvent(RedisModuleCtx *ctx, RedisModuleEvent eid, uint64_t subevent,
@@ -3053,6 +3054,7 @@ static void Indexes_LoadingEvent(RedisModuleCtx *ctx, RedisModuleEvent eid, uint
30533054
legacySpecDict = dictCreate(&dictTypeHeapHiddenStrings, NULL);
30543055
}
30553056
RedisModule_Log(RSDummyContext, "notice", "Loading event starts");
3057+
g_isLoading = true;
30563058
workersThreadPool_OnEventStart();
30573059
} else if (subevent == REDISMODULE_SUBEVENT_LOADING_ENDED) {
30583060
int hasLegacyIndexes = dictSize(legacySpecDict);
@@ -3068,10 +3070,12 @@ static void Indexes_LoadingEvent(RedisModuleCtx *ctx, RedisModuleEvent eid, uint
30683070
Indexes_ScanAndReindex();
30693071
}
30703072
workersThreadPool_OnEventEnd(true);
3073+
g_isLoading = false;
30713074
RedisModule_Log(RSDummyContext, "notice", "Loading event ends");
30723075
} else if (subevent == REDISMODULE_SUBEVENT_LOADING_FAILED) {
30733076
// Clear pending jobs from job queue in case of short read.
30743077
workersThreadPool_OnEventEnd(true);
3078+
g_isLoading = false;
30753079
}
30763080
}
30773081

tests/cpptests/redismock/redismock.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,15 @@ static int RMCK_SubscribeToServerEvent(RedisModuleCtx *ctx, RedisModuleEvent eve
977977
return REDISMODULE_OK;
978978
}
979979

980+
void RMCK_Yield(RedisModuleCtx *ctx, int flags, const char *busy_reply) {
981+
return;
982+
}
983+
984+
int RMCK_GetContextFlags(RedisModuleCtx *ctx) {
985+
return 0;
986+
}
987+
988+
980989
/** Fork */
981990
static int RMCK_Fork(RedisModuleForkDoneHandler cb, void *user_data) {
982991
return fork();
@@ -1208,6 +1217,8 @@ static void registerApis() {
12081217
REGISTER_API(Fork);
12091218
REGISTER_API(AddACLCategory);
12101219
REGISTER_API(SetCommandACLCategories);
1220+
REGISTER_API(Yield);
1221+
REGISTER_API(GetContextFlags);
12111222
}
12121223

12131224
static int RMCK_GetApi(const char *s, void *pp) {

tests/pytests/test_config.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ def check_config(conf):
9393
check_config('_BG_INDEX_MEM_PCT_THR')
9494
check_config('BM25STD_TANH_FACTOR')
9595
check_config('_BG_INDEX_OOM_PAUSE_TIME')
96+
check_config('INDEXER_YIELD_EVERY_OPS')
9697

9798
@skip(cluster=True)
9899
def testSetConfigOptions(env):
@@ -122,6 +123,7 @@ def testSetConfigOptions(env):
122123
env.expect(config_cmd(), 'set', 'BM25STD_TANH_FACTOR', 1).equal('OK')
123124
env.expect(config_cmd(), 'set', '_BG_INDEX_OOM_PAUSE_TIME', 1).equal('OK')
124125

126+
env.expect(config_cmd(), 'set', 'INDEXER_YIELD_EVERY_OPS', 1).equal('OK')
125127

126128
@skip(cluster=True)
127129
def testSetConfigOptionsErrors(env):
@@ -138,7 +140,9 @@ def testSetConfigOptionsErrors(env):
138140
env.expect(config_cmd(), 'set', 'BM25STD_TANH_FACTOR', -1).contains('Value is outside acceptable bounds')
139141
env.expect(config_cmd(), 'set', 'BM25STD_TANH_FACTOR', 10001).contains('BM25STD_TANH_FACTOR must be between 1 and 10000')
140142
env.expect(config_cmd(), 'set', '_BG_INDEX_OOM_PAUSE_TIME', -1).contains('Value is outside acceptable bounds')
141-
env.expect(config_cmd(), 'set', '_BG_INDEX_OOM_PAUSE_TIME', UINT32_MAX+1).contains('Value is outside acceptable bounds')
143+
env.expect(config_cmd(), 'set', '_BG_INDEX_OOM_PAUSE_TIME', UINT32_MAX+1).contains('Value is outside acceptable bounds')
144+
env.expect(config_cmd(), 'set', 'INDEXER_YIELD_EVERY_OPS', -1).contains('Value is outside acceptable bounds')
145+
142146
@skip(cluster=True)
143147
def testAllConfig(env):
144148
## on existing env the pre tests might change the config
@@ -187,6 +191,7 @@ def testAllConfig(env):
187191
env.assertEqual(res_dict['BM25STD_TANH_FACTOR'][0], '4')
188192
env.assertEqual(res_dict['_BG_INDEX_OOM_PAUSE_TIME'][0], '0')
189193

194+
env.assertEqual(res_dict['INDEXER_YIELD_EVERY_OPS'][0], '1000')
190195

191196
@skip(cluster=True)
192197
def testInitConfig():
@@ -493,6 +498,7 @@ def _getRDBFilePath(env: Env):
493498
('search-_bg-index-mem-pct-thr', '_BG_INDEX_MEM_PCT_THR', 100, 0, 100, False, False),
494499
('search-bm25std-tanh-factor', 'BM25STD_TANH_FACTOR', 4, 1, 10000, False, False),
495500
('search-_bg-index-oom-pause-time','_BG_INDEX_OOM_PAUSE_TIME', 0, 0, UINT32_MAX, False, False),
501+
('search-indexer-yield-every-ops', 'INDEXER_YIELD_EVERY_OPS', 1000, 1, UINT32_MAX, False, False),
496502
# Cluster parameters
497503
('search-threads', 'SEARCH_THREADS', 20, 1, LLONG_MAX, True, True),
498504
('search-topology-validation-timeout', 'TOPOLOGY_VALIDATION_TIMEOUT', 30_000, 0, LLONG_MAX, False, True),

tests/pytests/test_debug_commands.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def testDebugHelp(self):
5757
"INDEXES",
5858
"INFO",
5959
'GET_HIDE_USER_DATA_FROM_LOGS',
60+
'YIELDS_ON_LOAD_COUNTER',
6061
'FT.AGGREGATE',
6162
'_FT.AGGREGATE',
6263
'FT.SEARCH',
@@ -68,7 +69,7 @@ def testDebugHelp(self):
6869
self.env.expect(debug_cmd(), 'help').equal(help_list)
6970

7071
arity_2_cmds = ['GIT_SHA', 'DUMP_PREFIX_TRIE', 'GC_WAIT_FOR_JOBS', 'DELETE_LOCAL_CURSORS', 'SHARD_CONNECTION_STATES',
71-
'PAUSE_TOPOLOGY_UPDATER', 'RESUME_TOPOLOGY_UPDATER', 'CLEAR_PENDING_TOPOLOGY', 'INFO', 'INDEXES', 'GET_HIDE_USER_DATA_FROM_LOGS']
72+
'PAUSE_TOPOLOGY_UPDATER', 'RESUME_TOPOLOGY_UPDATER', 'CLEAR_PENDING_TOPOLOGY', 'INFO', 'INDEXES', 'GET_HIDE_USER_DATA_FROM_LOGS', 'YIELDS_ON_LOAD_COUNTER']
7273
for cmd in [c for c in help_list if c not in arity_2_cmds]:
7374
self.env.expect(debug_cmd(), cmd).error().contains(err_msg)
7475

@@ -1024,3 +1025,12 @@ def test_update_debug_scanner_config(env):
10241025
# Test error handling
10251026
# Giving non existing index name
10261027
checkDebugScannerUpdateError(env, 'non_existing', 'Unknown index name')
1028+
1029+
@skip(cluster=True)
1030+
def test_yield_counter(env):
1031+
# Giving wrong arity
1032+
env.expect(debug_cmd(), 'YIELDS_ON_LOAD_COUNTER','ExtraARG1','ExtraARG2').error()\
1033+
.contains('wrong number of arguments')
1034+
# Giving wrong subcommand
1035+
env.expect(debug_cmd(), 'YIELDS_ON_LOAD_COUNTER', 'NOT_A_COMMAND').error()\
1036+
.contains('Unknown subcommand')

0 commit comments

Comments
 (0)