redis: refactor knot.zone.list

This commit is contained in:
Daniel Salzman 2025-11-05 14:38:14 +01:00
parent 356e9c4987
commit 88860fe2c9
2 changed files with 46 additions and 43 deletions

View file

@ -1305,35 +1305,24 @@ static void zone_list_cb(RedisModuleKey *key, RedisModuleString *zone_name,
RedisModuleString *mask, void *privdata) RedisModuleString *mask, void *privdata)
{ {
scan_ctx_t *sctx = privdata; scan_ctx_t *sctx = privdata;
if (sctx->txt) { if (sctx->txt) {
char buf[KNOT_DNAME_TXT_MAXLEN + INSTANCE_MAX * 3];
size_t len; size_t len;
const char *dname = RedisModule_StringPtrLen(zone_name, &len); const char *dname = RedisModule_StringPtrLen(zone_name, &len);
char buf[KNOT_DNAME_TXT_MAXLEN + TXN_MAX * 3]; RedisModule_Assert(knot_dname_to_str(buf, (knot_dname_t *)dname, sizeof(buf)) != NULL);
if (knot_dname_to_str(buf, (knot_dname_t *)dname, sizeof(buf)) == NULL) {
sctx->ret = KNOT_EMALF;
RedisModule_ReplyWithError(sctx->ctx, RDB_ECORRUPTED);
++(sctx->count);
return;
}
char *buf_ptr = buf + knot_dname_size((knot_dname_t *)dname) - 1;
size_t mask_len = 0;
const uint8_t *mask_p = (const uint8_t *)RedisModule_StringPtrLen(mask, &mask_len);
if (mask_len != sizeof(uint8_t)) {
sctx->ret = KNOT_EMALF;
RedisModule_ReplyWithError(sctx->ctx, RDB_ECORRUPTED);
++(sctx->count);
return;
}
if (sctx->instances) { if (sctx->instances) {
int count = 0; const uint8_t *mask_p = (const uint8_t *)RedisModule_StringPtrLen(mask, &len);
for (int it = 0; it < TXN_MAX; ++it) { RedisModule_Assert(len == sizeof(uint8_t));
const char separator = (count) ? ',' : ':';
if ((*mask_p) & (1 << it)) { bool first = true;
*(buf_ptr++) = separator; for (unsigned inst = 1; inst <= INSTANCE_MAX; ++inst) {
*(buf_ptr++) = ' '; if ((*mask_p) & (1 << (inst - 1))) {
*(buf_ptr++) = '0' + it + 1; char item[] = { first ? ':' : ',', ' ', '0' + inst, '\0' };
*buf_ptr = '\0'; strlcat(buf, item, sizeof(buf));
count++; first = false;
} }
} }
} }
@ -1347,30 +1336,36 @@ static void zone_list_cb(RedisModuleKey *key, RedisModuleString *zone_name,
RedisModule_ReplyWithString(sctx->ctx, zone_name); RedisModule_ReplyWithString(sctx->ctx, zone_name);
} }
} }
++(sctx->count); ++(sctx->count);
} }
static void zone_list(RedisModuleCtx *ctx, bool instances, bool txt) static void zone_list(RedisModuleCtx *ctx, bool instances, bool txt)
{ {
RedisModuleKey *zones_index = get_zones_index(ctx, REDISMODULE_READ);
if (zones_index == NULL) {
RedisModule_ReplyWithEmptyArray(ctx);
return;
}
RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_ARRAY_LEN);
scan_ctx_t sctx = { scan_ctx_t sctx = {
.ctx = ctx, .ctx = ctx,
.txt = txt, .txt = txt,
.instances = instances .instances = instances
}; };
RedisModuleKey *zones_index = get_zones_index(ctx, REDISMODULE_READ);
if (zones_index == NULL) {
RedisModule_ReplyWithError(ctx, RDB_EALLOC);
return;
}
RedisModuleScanCursor *cursor = RedisModule_ScanCursorCreate(); RedisModuleScanCursor *cursor = RedisModule_ScanCursorCreate();
if (cursor == NULL) {
RedisModule_CloseKey(zones_index);
RedisModule_ReplyWithError(ctx, RDB_EALLOC);
return;
}
RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_ARRAY_LEN);
while (RedisModule_ScanKey(zones_index, cursor, zone_list_cb, &sctx) && sctx.ret == KNOT_EOK); while (RedisModule_ScanKey(zones_index, cursor, zone_list_cb, &sctx) && sctx.ret == KNOT_EOK);
RedisModule_ReplySetArrayLength(ctx, sctx.count); RedisModule_ReplySetArrayLength(ctx, sctx.count);
RedisModule_CloseKey(zones_index);
RedisModule_ScanCursorDestroy(cursor); RedisModule_ScanCursorDestroy(cursor);
RedisModule_CloseKey(zones_index);
} }
exception_t zone_info_serial(RedisModuleCtx *ctx, size_t *counter, const arg_dname_t *origin, exception_t zone_info_serial(RedisModuleCtx *ctx, size_t *counter, const arg_dname_t *origin,

View file

@ -259,29 +259,37 @@ def test_zone_purge():
def test_zone_list(): def test_zone_list():
env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600']) env = Env(moduleArgs=['max-event-age', '60', 'default-ttl', '3600'])
# First zone # first zone
txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1)
env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )")
env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn)
resp = env.cmd('KNOT.ZONE.LIST', txn_get_instance(txn)) resp = env.cmd('KNOT.ZONE.LIST')
env.assertEqual(len(resp), 1, message="Failed to purge zone") env.assertEqual(len(resp), 1, message="Failed to list zones")
# Rewrite zone # rewrite zone
txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1) txn = env.cmd('KNOT.ZONE.BEGIN', 'example.com', 1)
env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") env.cmd('KNOT.ZONE.STORE', 'example.com', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )")
env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn) env.cmd('KNOT.ZONE.COMMIT', 'example.com', txn)
resp = env.cmd('KNOT.ZONE.LIST', txn_get_instance(txn)) resp = env.cmd('KNOT.ZONE.LIST')
env.assertEqual(len(resp), 1, message="Failed to purge zone") env.assertEqual(len(resp), 1, message="Failed to list zones")
# Second zone # second zone
txn = env.cmd('KNOT.ZONE.BEGIN', 'example.net', 1) txn = env.cmd('KNOT.ZONE.BEGIN', 'example.net', 1)
env.cmd('KNOT.ZONE.STORE', 'example.net', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )") env.cmd('KNOT.ZONE.STORE', 'example.net', txn, "@ IN SOA ns.icann.org. noc.dns.icann.org. ( 1 7200 3600 1209600 3600 )")
env.cmd('KNOT.ZONE.COMMIT', 'example.net', txn) env.cmd('KNOT.ZONE.COMMIT', 'example.net', txn)
resp = env.cmd('KNOT.ZONE.LIST', txn_get_instance(txn)) resp = env.cmd('KNOT.ZONE.LIST')
env.assertEqual(len(resp), 2, message="Failed to purge zone") env.assertEqual(len(resp), 2, message="Failed to list zones")
LIST = [
b'example.com.: 1',
b'example.net.: 1'
]
resp = env.cmd('KNOT.ZONE.LIST', '--instances')
env.assertEqual(resp, LIST, message="Failed to list zones with instances")
# zone info # zone info
INFO = [ INFO = [