void SpellCheck_SendReplyOnTerm(RedisModuleCtx *ctx, char *term, size_t len, RS_Suggestions *s, uint64_t totalDocNumber) { #define TERM "TERM" RedisModule_ReplyWithArray(ctx, 3); RedisModule_ReplyWithStringBuffer(ctx, TERM, strlen(TERM)); RedisModule_ReplyWithStringBuffer(ctx, term, len); RS_Suggestion **suggestions = spellCheck_GetSuggestions(s); for (int i = 0; i < array_len(suggestions); ++i) { if (suggestions[i]->score == -1) { suggestions[i]->score = 0; } else { if (totalDocNumber > 0) { suggestions[i]->score = (suggestions[i]->score) / totalDocNumber; } } } qsort(suggestions, array_len(suggestions), sizeof(RS_Suggestion *), RS_SuggestionCompare); if (array_len(suggestions) == 0) { // no results found, we return an empty array RedisModule_ReplyWithArray(ctx, 0); } else { RedisModule_ReplyWithArray(ctx, array_len(suggestions)); for (int i = 0; i < array_len(suggestions); ++i) { RedisModule_ReplyWithArray(ctx, 2); RedisModule_ReplyWithDouble(ctx, suggestions[i]->score); RedisModule_ReplyWithStringBuffer(ctx, suggestions[i]->suggestion, suggestions[i]->len); } } array_free_ex(suggestions, RS_SuggestionFree(*(RS_Suggestion **)ptr)); }
int UniqueGetAllCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 2) { return RedisModule_WrongArity(ctx); } RedisModule_AutoMemory(ctx); // open the key and make sure it is indeed a Hash and not empty RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ); int type = RedisModule_KeyType(key); if (type == REDISMODULE_KEYTYPE_EMPTY) { RedisModule_ReplyWithNull(ctx); return REDISMODULE_OK; } if (RedisModule_ModuleTypeGetType(key) != UniqueType) { return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE); } unique *unique = RedisModule_ModuleTypeGetValue(key); size_t len = uniqueLen(unique); RedisModule_ReplyWithArray(ctx, len*2); size_t i; listIter *it = listGetIterator(unique->l, AL_START_HEAD); listNode *node; for (node = listNext(it), i=0; node && i<len; node = listNext(it),i++) { dictEntry *en = node->value; RedisModule_ReplyWithStringBuffer(ctx, en->key, sdslen(en->key)); RedisModule_ReplyWithStringBuffer(ctx, en->v.val, sdslen(en->v.val)); } return REDISMODULE_OK; }
/* HELLO.LEFTPAD str len ch * This is an implementation of the infamous LEFTPAD function, that * was at the center of an issue with the npm modules system in March 2016. * * LEFTPAD is a good example of using a Redis Modules API called * "pool allocator", that was a famous way to allocate memory in yet another * open source project, the Apache web server. * * The concept is very simple: there is memory that is useful to allocate * only in the context of serving a request, and must be freed anyway when * the callback implementing the command returns. So in that case the module * does not need to retain a reference to these allocations, it is just * required to free the memory before returning. When this is the case the * module can call RedisModule_PoolAlloc() instead, that works like malloc() * but will automatically free the memory when the module callback returns. * * Note that PoolAlloc() does not necessarily require AutoMemory to be * active. */ int HelloLeftPad_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { RedisModule_AutoMemory(ctx); /* Use automatic memory management. */ long long padlen; if (argc != 4) return RedisModule_WrongArity(ctx); if ((RedisModule_StringToLongLong(argv[2],&padlen) != REDISMODULE_OK) || (padlen< 0)) { return RedisModule_ReplyWithError(ctx,"ERR invalid padding length"); } size_t strlen, chlen; const char *str = RedisModule_StringPtrLen(argv[1], &strlen); const char *ch = RedisModule_StringPtrLen(argv[3], &chlen); /* If the string is already larger than the target len, just return * the string itself. */ if (strlen >= padlen) return RedisModule_ReplyWithString(ctx,argv[1]); /* Padding must be a single character in this simple implementation. */ if (chlen != 1) return RedisModule_ReplyWithError(ctx, "ERR padding must be a single char"); /* Here we use our pool allocator, for our throw-away allocation. */ padlen -= strlen; char *buf = RedisModule_PoolAlloc(ctx,padlen+strlen); for (size_t j = 0; j < padlen; j++) buf[j] = *ch; memcpy(buf+padlen,str,strlen); RedisModule_ReplyWithStringBuffer(ctx,buf,padlen+strlen); return REDISMODULE_OK; }
static void PopReplyFV(RedisModuleCtx *ctx, sds skey, sds sval) { int i, n = sdslen(sval)/8; RedisModule_ReplyWithArray(ctx, 1+n); RedisModule_ReplyWithStringBuffer(ctx, skey, sdslen(skey)); long long *pvec = (long long*)sval; for (i=0; i<n; i++) { RedisModule_ReplyWithLongLong(ctx, pvec[i]); } }
/* Serialize all the tags in the index to the redis client */ void TagIndex_SerializeValues(TagIndex *idx, RedisModuleCtx *ctx) { TrieMapIterator *it = TrieMap_Iterate(idx->values, "", 0); char *str; tm_len_t slen; void *ptr; RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_ARRAY_LEN); long long count = 0; while (TrieMapIterator_Next(it, &str, &slen, &ptr)) { ++count; RedisModule_ReplyWithStringBuffer(ctx, str, slen); } RedisModule_ReplySetArrayLength(ctx, count); TrieMapIterator_Free(it); }
static bool SpellCheck_ReplyTermSuggestions(SpellCheckCtx *scCtx, char *term, size_t len, t_fieldMask fieldMask) { // searching the term on the term trie, if its there we just return false // because there is no need to return suggestions on it. if (SpellCheck_IsTermExistsInTrie(scCtx->sctx->spec->terms, term, len, NULL)) { if (scCtx->fullScoreInfo) { // if a full score info is requested we need to send information that // we found the term as is on the index RedisModule_ReplyWithArray(scCtx->sctx->redisCtx, 3); RedisModule_ReplyWithStringBuffer(scCtx->sctx->redisCtx, TERM, strlen(TERM)); RedisModule_ReplyWithStringBuffer(scCtx->sctx->redisCtx, term, len); RedisModule_ReplyWithStringBuffer(scCtx->sctx->redisCtx, FOUND_TERM_IN_INDEX, strlen(FOUND_TERM_IN_INDEX)); return true; } else { return false; } } // searching the term on the exclude list, if its there we just return false // because there is no need to return suggestions on it. for (int i = 0; i < array_len(scCtx->excludeDict); ++i) { RedisModuleKey *k = NULL; Trie *t = SpellCheck_OpenDict(scCtx->sctx->redisCtx, scCtx->excludeDict[i], REDISMODULE_READ, &k); if (t == NULL) { continue; } if (SpellCheck_IsTermExistsInTrie(t, term, len, NULL)) { RedisModule_CloseKey(k); return false; } RedisModule_CloseKey(k); } RS_Suggestions *s = RS_SuggestionsCreate(); SpellCheck_FindSuggestions(scCtx, scCtx->sctx->spec->terms, term, len, fieldMask, s, 1); // sorting results by score // searching the term on the include list for more suggestions. for (int i = 0; i < array_len(scCtx->includeDict); ++i) { RedisModuleKey *k = NULL; Trie *t = SpellCheck_OpenDict(scCtx->sctx->redisCtx, scCtx->includeDict[i], REDISMODULE_READ, &k); if (t == NULL) { continue; } SpellCheck_FindSuggestions(scCtx, t, term, len, fieldMask, s, 0); RedisModule_CloseKey(k); } SpellCheck_SendReplyOnTerm(scCtx->sctx->redisCtx, term, len, s, (!scCtx->fullScoreInfo) ? scCtx->sctx->spec->docs.size - 1 : 0); RS_SuggestionsFree(s); return true; }
static void PopReplyString(RedisModuleCtx *ctx, sds skey, sds sval) { RedisModule_ReplyWithArray(ctx, 2); RedisModule_ReplyWithStringBuffer(ctx, skey, sdslen(skey)); RedisModule_ReplyWithStringBuffer(ctx, sval, sdslen(sval)); }