Skip to content

Commit 2e7b1ee

Browse files
committed
Add new handlersToPrint + expiration filter
1 parent 08757bf commit 2e7b1ee

11 files changed

+561
-101
lines changed

README.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -196,17 +196,23 @@ destruction, or when newer block replacing old one.
196196

197197
### rdb-cli usage
198198

199-
Usage: rdb-cli /path/to/dump.rdb [OPTIONS] {json|resp|redis} [FORMAT_OPTIONS]
199+
Usage: rdb-cli /path/to/dump.rdb [OPTIONS] {print|json|resp|redis} [FORMAT_OPTIONS]
200200
OPTIONS:
201201
-l, --log-file <PATH> Path to the log file or stdout (Default: './rdb-cli.log')
202-
203-
Multiple filters combination of keys/types/dbs can be specified:
204202
-k, --key <REGEX> Include only keys that match REGEX
205203
-K --no-key <REGEX> Exclude all keys that match REGEX
206204
-t, --type <TYPE> Include only selected TYPE {str|list|set|zset|hash|module|func}
207205
-T, --no-type <TYPE> Exclude TYPE {str|list|set|zset|hash|module|func}
208206
-d, --dbnum <DBNUM> Include only selected db number
209207
-D, --no-dbnum <DBNUM> Exclude DB number
208+
-e, --expired Include only expired keys
209+
-E, --no-expired Exclude expired keys
210+
211+
FORMAT_OPTIONS ('print'):
212+
-a, --aux-val <FMT> %f=Auxiliary-Field, %v=Auxiliary-Value (Default: "")
213+
-k, --key <FMT> %d=Db %k=Key %v=Value %t=Type %e=Expiry %r=LRU %f=LFU %i=Items
214+
(Default: "%d,%k,%v,%t,%e,%i")
215+
-o, --output <FILE> Specify the output file. If not specified, output to stdout
210216

211217
FORMAT_OPTIONS ('json'):
212218
-i, --include <EXTRAS> To include: {aux-val|func|stream-meta}

api/librdb-api.h

+1
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ typedef struct RdbKeyInfo {
149149
long long lruIdle; /* -1 if not set */
150150
int lfuFreq; /* -1 if not set */
151151
int opcode;
152+
int dataType; /* See enum RdbDataType */
152153
} RdbKeyInfo;
153154

154155
typedef struct RdbSlotInfo {

api/librdb-ext-api.h

+26
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ typedef struct RdbxReaderFileDesc RdbxReaderFileDesc;
1515
typedef struct RdbxFilter RdbxFilter;
1616
typedef struct RdbxToJson RdbxToJson;
1717
typedef struct RdbxToResp RdbxToResp;
18+
typedef struct RdbxToPrint RdbxToPrint;
1819
typedef struct RdbxRespToRedisLoader RdbxRespToRedisLoader;
1920

2021
/****************************************************************
@@ -93,6 +94,28 @@ _LIBRDB_API RdbxToJson *RDBX_createHandlersToJson(RdbParser *p,
9394
const char *filename,
9495
RdbxToJsonConf *c);
9596

97+
/****************************************************************
98+
* Create PRINT Handlers
99+
*
100+
* auxFmt - Format string for auxiliary values, where:
101+
* %f = Auxiliary field name
102+
* %v = Auxiliary field value
103+
* keyFmt - Format string for key details, where:
104+
* %d = Database number
105+
* %k = Key
106+
* %v = Value (If the value is a string, it will be printed as escaped string)
107+
* %t = Type
108+
* %e = Expiry
109+
* %r = LRU
110+
* %f = LFU
111+
* %i = Items
112+
*
113+
****************************************************************/
114+
_LIBRDB_API RdbxToPrint *RDBX_createHandlersToPrint(RdbParser *p,
115+
const char *auxFmt,
116+
const char *keyFmt,
117+
const char *outFilename);
118+
96119
/****************************************************************
97120
* Create Filter Handlers
98121
****************************************************************/
@@ -109,6 +132,9 @@ _LIBRDB_API RdbxFilter *RDBX_createHandlersFilterDbNum(RdbParser *p,
109132
int dbnum,
110133
uint32_t exclude);
111134

135+
_LIBRDB_API RdbxFilter *RDBX_createHandlersFilterExpired(RdbParser *p,
136+
uint32_t exclude);
137+
112138
/****************************************************************
113139
* Create RDB to RESP Handlers
114140
*

src/cli/rdb-cli.c

+45-4
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,23 @@ static void printUsage(int shortUsage) {
8585
return;
8686
}
8787
printf("[v%s] ", RDB_getLibVersion(NULL,NULL,NULL));
88-
printf("Usage: rdb-cli /path/to/dump.rdb [OPTIONS] {json|resp|redis} [FORMAT_OPTIONS]\n");
88+
printf("Usage: rdb-cli /path/to/dump.rdb [OPTIONS] {print|json|resp|redis} [FORMAT_OPTIONS]\n");
8989
printf("OPTIONS:\n");
90-
printf("\t-l, --log-file <PATH> Path to the log file or stdout (Default: './rdb-cli.log')\n\n");
91-
printf("\tMultiple filters combination of keys/types/dbs can be specified:\n");
90+
printf("\t-l, --log-file <PATH> Path to the log file or stdout (Default: './rdb-cli.log')\n");
9291
printf("\t-k, --key <REGEX> Include only keys that match REGEX\n");
9392
printf("\t-K --no-key <REGEX> Exclude all keys that match REGEX\n");
9493
printf("\t-t, --type <TYPE> Include only selected TYPE {str|list|set|zset|hash|module|func}\n");
9594
printf("\t-T, --no-type <TYPE> Exclude TYPE {str|list|set|zset|hash|module|func}\n");
9695
printf("\t-d, --dbnum <DBNUM> Include only selected db number\n");
97-
printf("\t-D, --no-dbnum <DBNUM> Exclude DB number\n\n");
96+
printf("\t-D, --no-dbnum <DBNUM> Exclude DB number\n");
97+
printf("\t-e, --expired Include only expired keys\n");
98+
printf("\t-E, --no-expired Exclude expired keys\n\n");
99+
100+
printf("FORMAT_OPTIONS ('print'):\n");
101+
printf("\t-a, --aux-val <FMT> %%f=Auxiliary-Field, %%v=Auxiliary-Value (Default: \"\") \n");
102+
printf("\t-k, --key <FMT> %%d=Db %%k=Key %%v=Value %%t=Type %%e=Expiry %%r=LRU %%f=LFU %%i=Items\n");
103+
printf("\t (Default: \"%%d,%%k,%%v,%%t,%%e,%%i\")\n");
104+
printf("\t-o, --output <FILE> Specify the output file. If not specified, output to stdout\n\n");
98105

99106
printf("FORMAT_OPTIONS ('json'):\n");
100107
printf("\t-i, --include <EXTRAS> To include: {aux-val|func|stream-meta|db-info}\n");
@@ -169,6 +176,27 @@ static RdbRes formatJson(RdbParser *parser, int argc, char **argv) {
169176
return RDB_OK;
170177
}
171178

179+
static RdbRes formatPrint(RdbParser *parser, int argc, char **argv) {
180+
const char *auxFmt = NULL, *keyFmt = "%d,%k,%v,%t,%e,%i";
181+
const char *output = NULL;/*default:stdout*/
182+
183+
/* parse specific command options */
184+
for (int at = 1; at < argc; ++at) {
185+
char *opt = argv[at];
186+
if (getOptArg(argc, argv, &at, "-o", "--output", NULL, &output)) continue;
187+
if (getOptArg(argc, argv, &at, "-a", "--aux-val", NULL, &auxFmt)) continue;
188+
if (getOptArg(argc, argv, &at, "-k", "--key", NULL, &keyFmt)) continue;
189+
loggerWrap(RDB_LOG_ERR, "Invalid 'print' [FORMAT_OPTIONS] argument: %s\n", opt);
190+
printUsage(1);
191+
return RDB_ERR_GENERAL;
192+
}
193+
194+
if (RDBX_createHandlersToPrint(parser, auxFmt, keyFmt, output) == NULL)
195+
return RDB_ERR_GENERAL;
196+
197+
return RDB_OK;
198+
}
199+
172200
static RdbRes formatRedis(RdbParser *parser, int argc, char **argv) {
173201
const char *output = NULL;
174202
RdbxRedisAuth auth = {0};
@@ -354,9 +382,22 @@ int readCommonOptions(RdbParser *p, int argc, char* argv[], Options *options, in
354382
continue;
355383
}
356384

385+
if (getOptArg(argc, argv, &at, "-e", "--expired", NULL, NULL)) {
386+
if ((applyFilters) && (!RDBX_createHandlersFilterExpired(p, 0)))
387+
exit(RDBX_ERR_FAILED_CREATE_FILTER);
388+
continue;
389+
}
390+
391+
if (getOptArg(argc, argv, &at, "-E", "--no-expired", NULL, NULL)) {
392+
if ((applyFilters) && (!RDBX_createHandlersFilterExpired(p, 1)))
393+
exit(RDBX_ERR_FAILED_CREATE_FILTER);
394+
continue;
395+
}
396+
357397
if (strcmp(opt, "json") == 0) { options->formatFunc = formatJson; break; }
358398
else if (strcmp(opt, "resp") == 0) { options->formatFunc = formatResp; break; }
359399
else if (strcmp(opt, "redis") == 0) { options->formatFunc = formatRedis; break; }
400+
else if (strcmp(opt, "print") == 0) { options->formatFunc = formatPrint; break; }
360401

361402
loggerWrap(RDB_LOG_ERR, "At argv[%d], unexpected OPTIONS argument: %s\n", at, opt);
362403
printUsage(1);

src/ext/handlersFilter.c

+34-46
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ struct RdbxFilter {
1111

1212
int regexInitialized; /* for filter keys */
1313
RdbDataType type; /* for filter types */
14+
int isExpireFilter; /* for filter expired */
1415
int dbnum; /* for filter db */
1516
};
1617

@@ -22,45 +23,6 @@ static void deleteFilterCtx(RdbParser *p, void *data) {
2223
RDB_free(p, ctx);
2324
}
2425

25-
/* mapping opcode to type */
26-
static void initOpcodeToType(RdbxFilter *ctx) {
27-
memset(ctx->opToType, 0, sizeof(ctx->opToType));
28-
/*string*/
29-
ctx->opToType[RDB_TYPE_STRING] = RDB_DATA_TYPE_STRING;
30-
/*list*/
31-
ctx->opToType[RDB_TYPE_LIST] = RDB_DATA_TYPE_LIST;
32-
ctx->opToType[RDB_TYPE_LIST_ZIPLIST] = RDB_DATA_TYPE_LIST;
33-
ctx->opToType[RDB_TYPE_LIST_QUICKLIST] = RDB_DATA_TYPE_LIST;
34-
ctx->opToType[RDB_TYPE_LIST_QUICKLIST_2] = RDB_DATA_TYPE_LIST;
35-
/*set*/
36-
ctx->opToType[RDB_TYPE_SET] = RDB_DATA_TYPE_SET;
37-
ctx->opToType[RDB_TYPE_SET_INTSET] = RDB_DATA_TYPE_SET;
38-
ctx->opToType[RDB_TYPE_SET_LISTPACK] = RDB_DATA_TYPE_SET;
39-
/*zset*/
40-
ctx->opToType[RDB_TYPE_ZSET] = RDB_DATA_TYPE_ZSET;
41-
ctx->opToType[RDB_TYPE_ZSET_2] = RDB_DATA_TYPE_ZSET;
42-
ctx->opToType[RDB_TYPE_ZSET_ZIPLIST] = RDB_DATA_TYPE_ZSET;
43-
ctx->opToType[RDB_TYPE_ZSET_LISTPACK] = RDB_DATA_TYPE_ZSET;
44-
/*hash*/
45-
ctx->opToType[RDB_TYPE_HASH] = RDB_DATA_TYPE_HASH;
46-
ctx->opToType[RDB_TYPE_HASH_METADATA_PRE_GA] = RDB_DATA_TYPE_HASH;
47-
ctx->opToType[RDB_TYPE_HASH_METADATA] = RDB_DATA_TYPE_HASH;
48-
ctx->opToType[RDB_TYPE_HASH_ZIPMAP] = RDB_DATA_TYPE_HASH;
49-
ctx->opToType[RDB_TYPE_HASH_ZIPLIST] = RDB_DATA_TYPE_HASH;
50-
ctx->opToType[RDB_TYPE_HASH_LISTPACK] = RDB_DATA_TYPE_HASH;
51-
ctx->opToType[RDB_TYPE_HASH_LISTPACK_EX_PRE_GA] = RDB_DATA_TYPE_HASH;
52-
ctx->opToType[RDB_TYPE_HASH_LISTPACK_EX] = RDB_DATA_TYPE_HASH;
53-
/*module*/
54-
ctx->opToType[RDB_TYPE_MODULE_2] = RDB_DATA_TYPE_MODULE;
55-
ctx->opToType[RDB_OPCODE_MODULE_AUX] = RDB_DATA_TYPE_MODULE;
56-
/*stream*/
57-
ctx->opToType[RDB_TYPE_STREAM_LISTPACKS] = RDB_DATA_TYPE_STREAM;
58-
ctx->opToType[RDB_TYPE_STREAM_LISTPACKS_2] = RDB_DATA_TYPE_STREAM;
59-
ctx->opToType[RDB_TYPE_STREAM_LISTPACKS_3] = RDB_DATA_TYPE_STREAM;
60-
/*func*/
61-
ctx->opToType[RDB_OPCODE_FUNCTION2] = RDB_DATA_TYPE_FUNCTION;
62-
}
63-
6426
/*** filtering BY key, type or dbnum ***/
6527

6628
static RdbRes filterNewKeyByRegex(RdbParser *p, void *userData, RdbBulk key, RdbKeyInfo *info) {
@@ -75,12 +37,32 @@ static RdbRes filterNewKeyByRegex(RdbParser *p, void *userData, RdbBulk key, Rdb
7537
static RdbRes filterNewKeyByType(RdbParser *p, void *userData, RdbBulk key, RdbKeyInfo *info) {
7638
UNUSED(p, key);
7739
RdbxFilter *ctx = userData;
78-
if (ctx->opToType[info->opcode] == ctx->type) /* if match */
40+
41+
if (info->dataType == (int) ctx->type)
7942
return ctx->cbReturnValue = (ctx->exclude) ? RDB_OK_DONT_PROPAGATE : RDB_OK;
8043
else
8144
return ctx->cbReturnValue = (ctx->exclude) ? RDB_OK : RDB_OK_DONT_PROPAGATE;
8245
}
8346

47+
static RdbRes filterNewKeyByExpiry(RdbParser *p, void *userData, RdbBulk key, RdbKeyInfo *info) {
48+
UNUSED(p, key);
49+
RdbxFilter *ctx = userData;
50+
51+
/* if persistent key */
52+
if (info->expiretime == -1)
53+
return ctx->cbReturnValue = (ctx->exclude) ? RDB_OK : RDB_OK_DONT_PROPAGATE;
54+
55+
struct timeval te;
56+
gettimeofday(&te, NULL);
57+
long long milliseconds = te.tv_sec*1000LL + te.tv_usec/1000;
58+
59+
if (info->expiretime > milliseconds)
60+
return ctx->cbReturnValue = (ctx->exclude) ? RDB_OK : RDB_OK_DONT_PROPAGATE;
61+
62+
return ctx->cbReturnValue = (ctx->exclude) ? RDB_OK_DONT_PROPAGATE
63+
: RDB_OK;
64+
}
65+
8466
static RdbRes filterNewDbByNumber(RdbParser *p, void *userData, int dbnum) {
8567
UNUSED(p);
8668
RdbxFilter *ctx = userData;
@@ -356,15 +338,15 @@ static RdbxFilter *createHandlersFilterCommon(RdbParser *p,
356338
const char *keyRegex,
357339
RdbDataType *type,
358340
int *dbnum,
341+
int isExpireFilter,
359342
uint32_t exclude) {
360343
RdbRes (*handleNewKey)(RdbParser *p, void *userData, RdbBulk key, RdbKeyInfo *info) = filterNewKey;
361344
RdbRes (*handleNewDb)(RdbParser *p, void *userData, int dbnum) = filterNewDb;
362345
RdbxFilter *ctx;
363346

364347
if ( (ctx = RDB_alloc(p, sizeof(RdbxFilter))) == NULL)
365348
return NULL;
366-
367-
ctx->regexInitialized = 0;
349+
memset(ctx, 0, sizeof(RdbxFilter));
368350

369351
/* specific if-else init to filter regex/type/dbnum */
370352
if (keyRegex) { /* filter keys by regex */
@@ -383,7 +365,9 @@ static RdbxFilter *createHandlersFilterCommon(RdbParser *p,
383365
} else if (type) { /* filter keys by type */
384366
ctx->type = *type;
385367
handleNewKey = filterNewKeyByType;
386-
initOpcodeToType(ctx);
368+
} else if (isExpireFilter) {
369+
ctx->isExpireFilter = 1;
370+
handleNewKey = filterNewKeyByExpiry;
387371
} else { /* filter by dbnum */
388372
ctx->dbnum = *dbnum;
389373
handleNewDb = filterNewDbByNumber;
@@ -421,13 +405,17 @@ static RdbxFilter *createHandlersFilterCommon(RdbParser *p,
421405
/*** API ***/
422406

423407
_LIBRDB_API RdbxFilter *RDBX_createHandlersFilterKey(RdbParser *p, const char *keyRegex, uint32_t exclude) {
424-
return createHandlersFilterCommon(p, keyRegex, NULL, NULL, exclude);
408+
return createHandlersFilterCommon(p, keyRegex, NULL, NULL, 0, exclude);
425409
}
426410

427411
_LIBRDB_API RdbxFilter *RDBX_createHandlersFilterType(RdbParser *p, RdbDataType type, uint32_t exclude) {
428-
return createHandlersFilterCommon(p, NULL, &type, NULL, exclude);
412+
return createHandlersFilterCommon(p, NULL, &type, NULL, 0, exclude);
429413
}
430414

431415
_LIBRDB_API RdbxFilter *RDBX_createHandlersFilterDbNum(RdbParser *p, int dbnum, uint32_t exclude) {
432-
return createHandlersFilterCommon(p, NULL, NULL, &dbnum, exclude);
416+
return createHandlersFilterCommon(p, NULL, NULL, &dbnum, 0, exclude);
417+
}
418+
419+
_LIBRDB_API RdbxFilter *RDBX_createHandlersFilterExpired(RdbParser *p, uint32_t exclude) {
420+
return createHandlersFilterCommon(p, NULL, NULL, NULL, 1, exclude);
433421
}

0 commit comments

Comments
 (0)