mirror of
https://github.com/fluencelabs/redis
synced 2025-03-30 22:31:03 +00:00
Modules: DEBUG DIGEST interface.
This commit is contained in:
parent
f9fac7f777
commit
51ffd062d3
@ -239,6 +239,15 @@ void computeDatasetDigest(unsigned char *final) {
|
|||||||
xorDigest(digest,eledigest,20);
|
xorDigest(digest,eledigest,20);
|
||||||
}
|
}
|
||||||
hashTypeReleaseIterator(hi);
|
hashTypeReleaseIterator(hi);
|
||||||
|
} else if (o->type == OBJ_MODULE) {
|
||||||
|
RedisModuleDigest md;
|
||||||
|
moduleValue *mv = o->ptr;
|
||||||
|
moduleType *mt = mv->type;
|
||||||
|
moduleInitDigestContext(md);
|
||||||
|
if (mt->digest) {
|
||||||
|
mt->digest(&md,mv->value);
|
||||||
|
xorDigest(digest,md.x,sizeof(md.x));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
serverPanic("Unknown object type");
|
serverPanic("Unknown object type");
|
||||||
}
|
}
|
||||||
|
63
src/module.c
63
src/module.c
@ -3057,6 +3057,66 @@ loaderr:
|
|||||||
return 0; /* Never reached. */
|
return 0; /* Never reached. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------
|
||||||
|
* Key digest API (DEBUG DIGEST interface for modules types)
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Add a new element to the digest. This function can be called multiple times
|
||||||
|
* one element after the other, for all the elements that constitute a given
|
||||||
|
* data structure. The function call must be followed by the call to
|
||||||
|
* `RedisModule_DigestEndSequence` eventually, when all the elements that are
|
||||||
|
* always in a given order are added. See the Redis Modules data types
|
||||||
|
* documentation for more info. However this is a quick example that uses Redis
|
||||||
|
* data types as an example.
|
||||||
|
*
|
||||||
|
* To add a sequence of unordered elements (for example in the case of a Redis
|
||||||
|
* Set), the pattern to use is:
|
||||||
|
*
|
||||||
|
* foreach element {
|
||||||
|
* AddElement(element);
|
||||||
|
* EndSequence();
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Because Sets are not ordered, so every element added has a position that
|
||||||
|
* does not depend from the other. However if instead our elements are
|
||||||
|
* ordered in pairs, like field-value pairs of an Hash, then one should
|
||||||
|
* use:
|
||||||
|
*
|
||||||
|
* foreach key,value {
|
||||||
|
* AddElement(key);
|
||||||
|
* AddElement(value);
|
||||||
|
* EndSquence();
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Because the key and value will be always in the above order, while instead
|
||||||
|
* the single key-value pairs, can appear in any position into a Redis hash.
|
||||||
|
*
|
||||||
|
* A list of ordered elements would be implemented with:
|
||||||
|
*
|
||||||
|
* foreach element {
|
||||||
|
* AddElement(element);
|
||||||
|
* }
|
||||||
|
* EndSequence();
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void RM_DigestAddStringBuffer(RedisModuleDigest *md, unsigned char *ele, size_t len) {
|
||||||
|
mixDigest(md->o,ele,len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Like `RedisModule_DigestAddStringBuffer()` but takes a long long as input
|
||||||
|
* that gets converted into a string before adding it to the digest. */
|
||||||
|
void RM_DigestAddLongLong(RedisModuleDigest *md, long long ll) {
|
||||||
|
char buf[LONG_STR_SIZE];
|
||||||
|
size_t len = ll2string(buf,sizeof(buf),ll);
|
||||||
|
mixDigest(md->o,buf,len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See the doucmnetation for `RedisModule_DigestAddElement()`. */
|
||||||
|
void RM_DigestEndSequence(RedisModuleDigest *md) {
|
||||||
|
xorDigest(md->x,md->o,sizeof(md->o));
|
||||||
|
memset(md->o,0,sizeof(md->o));
|
||||||
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------
|
||||||
* AOF API for modules data types
|
* AOF API for modules data types
|
||||||
* -------------------------------------------------------------------------- */
|
* -------------------------------------------------------------------------- */
|
||||||
@ -3818,4 +3878,7 @@ void moduleRegisterCoreAPI(void) {
|
|||||||
REGISTER_API(FreeThreadSafeContext);
|
REGISTER_API(FreeThreadSafeContext);
|
||||||
REGISTER_API(ThreadSafeContextLock);
|
REGISTER_API(ThreadSafeContextLock);
|
||||||
REGISTER_API(ThreadSafeContextUnlock);
|
REGISTER_API(ThreadSafeContextUnlock);
|
||||||
|
REGISTER_API(DigestAddStringBuffer);
|
||||||
|
REGISTER_API(DigestAddLongLong);
|
||||||
|
REGISTER_API(DigestEndSequence);
|
||||||
}
|
}
|
||||||
|
@ -238,6 +238,16 @@ void HelloTypeFree(void *value) {
|
|||||||
HelloTypeReleaseObject(value);
|
HelloTypeReleaseObject(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HelloTypeDigest(RedisModuleDigest *md, void *value) {
|
||||||
|
struct HelloTypeObject *hto = value;
|
||||||
|
struct HelloTypeNode *node = hto->head;
|
||||||
|
while(node) {
|
||||||
|
RedisModule_DigestAddLongLong(md,node->value);
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
RedisModule_DigestEndSequence(md);
|
||||||
|
}
|
||||||
|
|
||||||
/* This function must be present on each Redis module. It is used in order to
|
/* This function must be present on each Redis module. It is used in order to
|
||||||
* register the commands into the Redis server. */
|
* register the commands into the Redis server. */
|
||||||
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||||
@ -253,7 +263,8 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
|||||||
.rdb_save = HelloTypeRdbSave,
|
.rdb_save = HelloTypeRdbSave,
|
||||||
.aof_rewrite = HelloTypeAofRewrite,
|
.aof_rewrite = HelloTypeAofRewrite,
|
||||||
.mem_usage = HelloTypeMemUsage,
|
.mem_usage = HelloTypeMemUsage,
|
||||||
.free = HelloTypeFree
|
.free = HelloTypeFree,
|
||||||
|
.digest = HelloTypeDigest
|
||||||
};
|
};
|
||||||
|
|
||||||
HelloType = RedisModule_CreateDataType(ctx,"hellotype",0,&tm);
|
HelloType = RedisModule_CreateDataType(ctx,"hellotype",0,&tm);
|
||||||
|
@ -218,6 +218,9 @@ RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetThreadSafeContext)(RedisModu
|
|||||||
void REDISMODULE_API_FUNC(RedisModule_FreeThreadSafeContext)(RedisModuleCtx *ctx);
|
void REDISMODULE_API_FUNC(RedisModule_FreeThreadSafeContext)(RedisModuleCtx *ctx);
|
||||||
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextLock)(RedisModuleCtx *ctx);
|
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextLock)(RedisModuleCtx *ctx);
|
||||||
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextUnlock)(RedisModuleCtx *ctx);
|
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextUnlock)(RedisModuleCtx *ctx);
|
||||||
|
void REDISMODULE_API_FUNC(RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, unsigned char *ele, size_t len);
|
||||||
|
void REDISMODULE_API_FUNC(RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele);
|
||||||
|
void REDISMODULE_API_FUNC(RedisModule_DigestEndSequence)(RedisModuleDigest *md);
|
||||||
|
|
||||||
/* This is included inline inside each Redis module. */
|
/* This is included inline inside each Redis module. */
|
||||||
static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) __attribute__((unused));
|
static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) __attribute__((unused));
|
||||||
@ -330,6 +333,9 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
|
|||||||
REDISMODULE_GET_API(FreeThreadSafeContext);
|
REDISMODULE_GET_API(FreeThreadSafeContext);
|
||||||
REDISMODULE_GET_API(ThreadSafeContextLock);
|
REDISMODULE_GET_API(ThreadSafeContextLock);
|
||||||
REDISMODULE_GET_API(ThreadSafeContextUnlock);
|
REDISMODULE_GET_API(ThreadSafeContextUnlock);
|
||||||
|
REDISMODULE_GET_API(DigestAddStringBuffer);
|
||||||
|
REDISMODULE_GET_API(DigestAddLongLong);
|
||||||
|
REDISMODULE_GET_API(DigestEndSequence);
|
||||||
|
|
||||||
RedisModule_SetModuleAttribs(ctx,name,ver,apiver);
|
RedisModule_SetModuleAttribs(ctx,name,ver,apiver);
|
||||||
return REDISMODULE_OK;
|
return REDISMODULE_OK;
|
||||||
|
18
src/server.h
18
src/server.h
@ -546,6 +546,22 @@ typedef struct RedisModuleIO {
|
|||||||
iovar.ctx = NULL; \
|
iovar.ctx = NULL; \
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
|
/* This is a structure used to export DEBUG DIGEST capabilities to Redis
|
||||||
|
* modules. We want to capture both the ordered and unordered elements of
|
||||||
|
* a data structure, so that a digest can be created in a way that correctly
|
||||||
|
* reflects the values. See the DEBUG DIGEST command implementation for more
|
||||||
|
* background. */
|
||||||
|
typedef struct RedisModuleDigest {
|
||||||
|
unsigned char o[20]; /* Ordered elements. */
|
||||||
|
unsigned char x[20]; /* Xored elements. */
|
||||||
|
} RedisModuleDigest;
|
||||||
|
|
||||||
|
/* Just start with a digest composed of all zero bytes. */
|
||||||
|
#define moduleInitDigestContext(mdvar) do { \
|
||||||
|
memset(mdvar.o,0,sizeof(mdvar.o)); \
|
||||||
|
memset(mdvar.x,0,sizeof(mdvar.x)); \
|
||||||
|
} while(0);
|
||||||
|
|
||||||
/* Objects encoding. Some kind of objects like Strings and Hashes can be
|
/* Objects encoding. Some kind of objects like Strings and Hashes can be
|
||||||
* internally represented in multiple ways. The 'encoding' field of the object
|
* internally represented in multiple ways. The 'encoding' field of the object
|
||||||
* is set to one of this fields for this object. */
|
* is set to one of this fields for this object. */
|
||||||
@ -1993,6 +2009,8 @@ void disableWatchdog(void);
|
|||||||
void watchdogScheduleSignal(int period);
|
void watchdogScheduleSignal(int period);
|
||||||
void serverLogHexDump(int level, char *descr, void *value, size_t len);
|
void serverLogHexDump(int level, char *descr, void *value, size_t len);
|
||||||
int memtest_preserving_test(unsigned long *m, size_t bytes, int passes);
|
int memtest_preserving_test(unsigned long *m, size_t bytes, int passes);
|
||||||
|
void mixDigest(unsigned char *digest, void *ptr, size_t len);
|
||||||
|
void xorDigest(unsigned char *digest, void *ptr, size_t len);
|
||||||
|
|
||||||
#define redisDebug(fmt, ...) \
|
#define redisDebug(fmt, ...) \
|
||||||
printf("DEBUG %s:%d > " fmt "\n", __FILE__, __LINE__, __VA_ARGS__)
|
printf("DEBUG %s:%d > " fmt "\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user