mirror of https://github.com/redis/redis.git
				
				
				
			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);
 | 
			
		||||
                }
 | 
			
		||||
                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 {
 | 
			
		||||
                serverPanic("Unknown object type");
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										63
									
								
								src/module.c
								
								
								
								
							
							
						
						
									
										63
									
								
								src/module.c
								
								
								
								
							| 
						 | 
				
			
			@ -3057,6 +3057,66 @@ loaderr:
 | 
			
		|||
    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
 | 
			
		||||
 * -------------------------------------------------------------------------- */
 | 
			
		||||
| 
						 | 
				
			
			@ -3818,4 +3878,7 @@ void moduleRegisterCoreAPI(void) {
 | 
			
		|||
    REGISTER_API(FreeThreadSafeContext);
 | 
			
		||||
    REGISTER_API(ThreadSafeContextLock);
 | 
			
		||||
    REGISTER_API(ThreadSafeContextUnlock);
 | 
			
		||||
    REGISTER_API(DigestAddStringBuffer);
 | 
			
		||||
    REGISTER_API(DigestAddLongLong);
 | 
			
		||||
    REGISTER_API(DigestEndSequence);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -238,6 +238,16 @@ void HelloTypeFree(void *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
 | 
			
		||||
 * register the commands into the Redis server. */
 | 
			
		||||
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,
 | 
			
		||||
        .aof_rewrite = HelloTypeAofRewrite,
 | 
			
		||||
        .mem_usage = HelloTypeMemUsage,
 | 
			
		||||
        .free = HelloTypeFree
 | 
			
		||||
        .free = HelloTypeFree,
 | 
			
		||||
        .digest = HelloTypeDigest
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    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_ThreadSafeContextLock)(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. */
 | 
			
		||||
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(ThreadSafeContextLock);
 | 
			
		||||
    REDISMODULE_GET_API(ThreadSafeContextUnlock);
 | 
			
		||||
    REDISMODULE_GET_API(DigestAddStringBuffer);
 | 
			
		||||
    REDISMODULE_GET_API(DigestAddLongLong);
 | 
			
		||||
    REDISMODULE_GET_API(DigestEndSequence);
 | 
			
		||||
 | 
			
		||||
    RedisModule_SetModuleAttribs(ctx,name,ver,apiver);
 | 
			
		||||
    return REDISMODULE_OK;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								src/server.h
								
								
								
								
							
							
						
						
									
										18
									
								
								src/server.h
								
								
								
								
							| 
						 | 
				
			
			@ -546,6 +546,22 @@ typedef struct RedisModuleIO {
 | 
			
		|||
    iovar.ctx = NULL; \
 | 
			
		||||
} 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
 | 
			
		||||
 * internally represented in multiple ways. The 'encoding' field of the object
 | 
			
		||||
 * is set to one of this fields for this object. */
 | 
			
		||||
| 
						 | 
				
			
			@ -1993,6 +2009,8 @@ void disableWatchdog(void);
 | 
			
		|||
void watchdogScheduleSignal(int period);
 | 
			
		||||
void serverLogHexDump(int level, char *descr, void *value, size_t len);
 | 
			
		||||
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, ...) \
 | 
			
		||||
    printf("DEBUG %s:%d > " fmt "\n", __FILE__, __LINE__, __VA_ARGS__)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue