/* Search the list for a node matching a given key. * The match is performed using the 'match' method * set with listSetMatchMethod(). If no 'match' method * is set, the 'value' pointer of every node is directly * compared with the 'key' pointer. * * On success the first matching node pointer is returned * (search starts from head). If no matching node exists * NULL is returned. */ listNode *listSearchKey(list *list, void *key) { listIter *iter; listNode *node; //遍历整个链表 iter = listGetIterator(list, AL_START_HEAD); while((node = listNext(iter)) != NULL) { //如果有比较的回调函数,调用该函数 if (list->match) { if (list->match(node->value, key)) { listReleaseIterator(iter); return node; } } else { //否则比较两个value是否相同 if (key == node->value) { listReleaseIterator(iter); return node; } } } //也就是默认的match函数就是比较两个value是否相等 listReleaseIterator(iter); return NULL; }
list *listSearchKey(list *list, void *key) /*{{{*/ { listIter *iter; listNode *node; iter = listGetIterator(list, AL_START_HEAD); while((node = listNext(iter)) != NULL) { if(list->match) { if(list->match(node->value, key)) { listReleaseIterator(iter); return node; } } else { //如果match函数不存在,理论上讲是比较不了 //这时候只需要看地址就行了 if(key == node->value) { listReleaseIterator(iter); return node; } } } listReleaseIterator(iter); return NULL; }
int rdbSaveNRL(FILE *fp, robj *o) { listNode *ln; d_l_t *nrlind = o->ptr; list *nrltoks = nrlind->l1; int imatch = nrlind->num; if (rdbSaveLen(fp, imatch) == -1) return -1; robj *iname = Index[server.dbid][imatch].obj; if (rdbSaveStringObject(fp, iname) == -1) return -1; int tmatch = Index[server.dbid][imatch].table; if (rdbSaveLen(fp, tmatch) == -1) return -1; if (rdbSaveLen(fp, listLength(nrltoks)) == -1) return -1; listIter *li = listGetIterator(nrltoks, AL_START_HEAD); while((ln = listNext(li)) != NULL) { sds s = ln->value; robj *r = createStringObject(s, sdslen(s)); if (rdbSaveStringObject(fp, r) == -1) return -1; decrRefCount(r); } listReleaseIterator(li); list *nrlcols = nrlind->l2; if (rdbSaveLen(fp, listLength(nrlcols)) == -1) return -1; li = listGetIterator(nrlcols, AL_START_HEAD); while((ln = listNext(li)) != NULL) { uint32 i = (uint32)(long)ln->value; if (rdbSaveLen(fp, i) == -1) return -1; } listReleaseIterator(li); return 0; }
/* Search the list for a node matching a given key. * The match is performed using the 'match' method * set with listSetMatchMethod(). If no 'match' method * is set, the 'value' pointer of every node is directly * compared with the 'key' pointer. * * On success the first matching node pointer is returned * (search starts from head). If no matching node exists * NULL is returned. */ listNode *listSearchKey(list *pList, void *key) { listIter *iter = listGetIterator(pList, DL_START_HEAD); listNode *node = listNext(iter); while(node != NULL) { if (pList->match) { if (pList->match(node->value, key)) { listReleaseIterator(iter); return node; } } else { if (key == node->value) { listReleaseIterator(iter); return node; } } } listReleaseIterator(iter); return NULL; }
/* for REWRITEAOF and DESC */ sds rebuildOrigNRLcmd(robj *o) { d_l_t *nrlind = o->ptr; int tmatch = Index[server.dbid][nrlind->num].table; list *nrltoks = nrlind->l1; list *nrlcols = nrlind->l2; listIter *li1 = listGetIterator(nrltoks, AL_START_HEAD); listNode *ln1 = listNext(li1); listIter *li2 = listGetIterator(nrlcols, AL_START_HEAD); listNode *ln2 = listNext(li2); sds cmd = sdsnewlen("\"", 1); /* has to be one arg */ while (ln1 || ln2) { if (ln1) { sds token = ln1->value; cmd = sdscatlen(cmd, token, sdslen(token)); ln1 = listNext(li1); } if (ln2) { int cmatch = (int)(long)ln2->value; cmatch--; /* because (0 != NULL) */ sds cname = Tbl[server.dbid][tmatch].col_name[cmatch]->ptr; cmd = sdscatlen(cmd, "$", 1); /* "$" variable delim */ cmd = sdscatlen(cmd, cname, sdslen(cname)); ln2 = listNext(li2); } } listReleaseIterator(li1); listReleaseIterator(li2); cmd = sdscatlen(cmd, "\"", 1); /* has to be one arg */ return cmd; }
/* 关键字搜索Node结点此时用到了list的match方法了 */ listNode *listSearchKey(list *list, void *key) { listIter *iter; listNode *node; //获取迭代器 iter = listGetIterator(list, AL_START_HEAD); while((node = listNext(iter)) != NULL) { //遍历循环 if (list->match) { //如果定义了list的match方法,则调用match方法 if (list->match(node->value, key)) { //如果方法返回true,则代表找到结点,释放迭代器 listReleaseIterator(iter); return node; } } else { //如果没有定义list 的match方法,则直接比较函数指针 if (key == node->value) { //如果相等,则代表找到结点,释放迭代器 listReleaseIterator(iter); return node; } } } listReleaseIterator(iter); return NULL; }
/* Duplicate the whole list. On out of memory NULL is returned. * On success a copy of the original list is returned. * * The 'Dup' method set with listSetDupMethod() function is used * to copy the node value. Otherwise the same pointer value of * the original node is used as value of the copied node. * * The original list both on success or error is never modified. */ hilist *listDup(hilist *orig) { hilist *copy; listIter *iter; listNode *node; if ((copy = listCreate()) == NULL) return NULL; copy->dup = orig->dup; copy->free = orig->free; copy->match = orig->match; iter = listGetIterator(orig, AL_START_HEAD); while((node = listNext(iter)) != NULL) { void *value; if (copy->dup) { value = copy->dup(node->value); if (value == NULL) { listRelease(copy); listReleaseIterator(iter); return NULL; } } else value = node->value; if (listAddNodeTail(copy, value) == NULL) { listRelease(copy); listReleaseIterator(iter); return NULL; } } listReleaseIterator(iter); return copy; }
/* compare msg content with a string * * return 0 : equal * return 1 : msg content bigger than string * return -1: string bigger than msg content * return -2: error */ int msg_cmp_str(struct msg *msg, const uint8_t *str, uint32_t len) { int ret; struct mbuf *mbuf; listIter *iter; listNode *node; uint8_t *p, *q, *start; uint32_t mlen, left; //mbuf len if(msg == NULL) { return -2; } if(str == NULL || len == 0) { return -2; } if(msg->mlen > len) { return 1; } else if(msg->mlen < len) { return -1; } start = (uint8_t *)str; left = len; iter = listGetIterator(msg->data, AL_START_HEAD); while((node = listNext(iter)) != NULL && left > 0) { mbuf = listNodeValue(node); p = mbuf->start; q = mbuf->last; mlen = (uint32_t)(q - p); ret = memcmp(p, start, mlen); if(ret != 0) { listReleaseIterator(iter); return ret; } left -= mlen; } listReleaseIterator(iter); return 0; }
/* creates text for trigger's command */ static sds genNRL_Cmd(bt *btr, d_l_t *nrlind, aobj *apk, char *vals, uint32 cofsts[], void *rrow, int tmatch) { sds cmd = sdsempty(); /* DESTROY ME 016 */ list *nrltoks = nrlind->l1; list *nrlcols = nrlind->l2; listIter *li1 = listGetIterator(nrltoks, AL_START_HEAD); listIter *li2 = listGetIterator(nrlcols, AL_START_HEAD); listNode *ln1 = listNext(li1); listNode *ln2 = listNext(li2); while (ln1 || ln2) { if (ln1) { sds token = ln1->value; cmd = sdscatlen(cmd, token, sdslen(token)); ln1 = listNext(li1); } int cmatch = -1; if (ln2) { cmatch = ((int)(long)ln2->value) - 1; /* because (0 != NULL) */ ln2 = listNext(li2); } if (cmatch != -1) { char *x; int xlen; if (vals) { /* from INSERT */ if (!cmatch) { /* PK not stored in ROW */ x = strFromAobj(apk, &xlen); } else { /* get COL from cofsts */ x = vals + cofsts[cmatch - 1]; xlen = cofsts[cmatch] - cofsts[cmatch - 1] - 1; } cmd = sdscatlen(cmd, x, xlen); if (!cmatch) free(x); /* FREED 015 */ } else { /* not from INSERT -> fetch row */ aobj rcol = getRawCol(btr, rrow, cmatch, apk, tmatch, NULL, 1); x = rcol.s; xlen = rcol.len; cmd = sdscatlen(cmd, x, xlen); releaseAobj(&rcol); } } } listReleaseIterator(li1); listReleaseIterator(li2); return cmd; }
void freeClient(vuiClient *c) { listNode *ln; listIter *it; cJSON *json; /* Free the query buffer */ sdsfree(c->querybuf); sdsfree(c->querymsg); sdsfree(c->res.body); sdsfree(c->res.reason); sdsfree(c->res.buf); /* Close socket, unregister events, and remove list of replies and * accumulated arguments. */ if (c->fd != -1) { aeDeleteFileEvent(server.el,c->fd,AE_READABLE); aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE); close(c->fd); } it = listGetIterator(c->jsons, AL_START_HEAD); while((ln = listNext(it))) { json = (cJSON *)ln->value; cJSON_Delete(json); listDelNode(c->jsons, ln); } listRelease(c->jsons); listReleaseIterator(it); zfree(c); server.client = NULL; }
static void calculate_bm25(fts_t *fts, list *indices, dict_t *scores) { listIter *iter; listNode *node; unsigned long doc_size = fts_size(fts); unsigned long list_size = listLength(indices); doc_size = doc_size ? doc_size : 1; double avgdl = (fts->len * 1.0) / doc_size; iter = listGetIterator(indices, AL_START_HEAD); while((node = listNext(iter)) != NULL) { index_item_t *idx = node->value; int dl = idx->doc->len; fts_doc_score_t *fds = dict_get(scores, idx->doc->title->ptr); if (!fds) { fds = rr_malloc(sizeof(*fds)); fds->doc = idx->doc; fds->score = .0f; dict_set(scores, idx->doc->title->ptr, fds); } double idf = log((doc_size - list_size + 0.5) / (list_size + 0.5)); double tf = idx->tf * (BM25_K + 1) / (idx->tf + BM25_K * (1 - BM25_B + BM25_B*dl/avgdl)); fds->score += tf * idf; } listReleaseIterator(iter); }
int luaworkDoDir(lua_State *L,const char *path, char *err) { int ret = UGOK; sds relpath = sdsempty(); list *queue = listCreate(); listNode *node=NULL; listIter *iter = NULL; if (xfilelistdir(path, "*.lua", queue) == UGERR) { luaworkSetError(err, "list files for %s failed", path); ret = UGERR; goto END; } iter = listGetIterator(queue, AL_START_HEAD); while ((node=listNext(iter))!=NULL) { const char *filename = (char *) (node->value); sdsclear(relpath); relpath = sdscatprintf(relpath, "%s/%s", path, filename); ret = luaworkDoFile(L, relpath, err); if (ret != UGOK) break; } listReleaseIterator(iter); END: listRelease(queue); sdsfree(relpath); return ret; }
static void sendStaticFileReply(cli *c) { robj *o; if ((o = lookupKeyRead(c->db, c->http.file)) == NULL) SEND_404 else if (o->type != REDIS_STRING) SEND_404 else { //NOTE: STATIC expire in 10 years (HARDCODED) listNode *ln; bool dfl = 0; listIter *li = listGetIterator(c->http.req_hdr, AL_START_HEAD); while((ln = listNext(li))) { // check for "deflate" two_sds *ss = ln->value; if (!strncasecmp(ss->a, "Accept-Encoding", 15)) { if (DXDB_strcasestr(ss->b, "deflate")) { dfl = 1; break; } } } listReleaseIterator(li); if (dfl) { robj *dfile = _createStringObject("DEFLATE/"); dfile->ptr = sdscatlen(dfile->ptr, c->http.file->ptr, sdslen(c->http.file->ptr)); robj *od; if ((od = lookupKeyRead(c->db, dfile)) && od->type == REDIS_STRING){ o = od; addHttpResponseHeader(sdsnew("Content-Encoding"), sdsnew("deflate")); } } addHttpResponseHeader(sdsnew("Expires"), sdsnew("Wed, 09 Jun 2021 10:18:14 GMT;")); SEND_REPLY_FROM_STRING(send_http200_reponse_header(c, sdslen(o->ptr))); addReply(c, o); } }
int _msg_check(const char *file, int line, rmtContext *ctx, struct msg *msg, int panic) { struct mbuf *mbuf; listIter *iter; listNode *node; uint32_t total_mbuf_len = 0; int err = 0; if (msg == NULL) { return RMT_ERROR; } //check msg length iter = listGetIterator(msg->data, AL_START_HEAD); while ((node = listNext(iter)) != NULL) { mbuf = listNodeValue(node); total_mbuf_len += mbuf_length(mbuf); if (mbuf->pos < mbuf->start) { _log(file, line, 0, "MSG CHECK Error: mbuf->pos(%p) < mbuf->start(%p)", mbuf->pos, mbuf->start); err = 1; } if (mbuf->pos > mbuf->last) { _log(file, line, 0, "MSG CHECK Error: mbuf->pos(%p) > mbuf->last(%p)", mbuf->pos, mbuf->last); err = 1; } } listReleaseIterator(iter); if (msg->mlen != total_mbuf_len) { _log(file, line, 0, "MSG CHECK Error: msg->mlen(%u) != total_mbuf_len(%u)", msg->mlen, total_mbuf_len); err = 1; } if (msg->request == 1) { if (memcmp(ctx->cmd, RMT_CMD_REDIS_MIGRATE, MIN(sdslen(ctx->cmd),strlen(RMT_CMD_REDIS_MIGRATE))) == 0 && msg->noreply != ctx->noreply) { _log(file, line, 0, "MSG CHECK Error: msg->noreply(%u) != ctx->noreply(%d)", msg->noreply, ctx->noreply); err = 1; } } if (err) goto error; return RMT_OK; error: MSG_DUMP(msg, LOG_ERR, 0); if (panic) { rmt_stacktrace(1); abort(); } return RMT_ERROR; }
list *listDup(list *orign) /*{{{*/ { list *cpy; listIter *iter; listNode *node; if((cpy = listCreate()) == NULL) { return NULL; } cpy->free = orign->free; cpy->dup = orign->dup; cpy->match = orign->match; iter = listGetIterator(orign, AL_START_HEAD); while((node = listNext(iter)) != NULL) { void *value; if(cpy->dup) { value = cpy->dup(node->value); if(value == NULL) { listRelease(cpy); listReleaseIterator(iter); return NULL; } } else { value = node->value; } //出错只有一种情况,就是malloc失败了,return NULL; if(listAddNodeTail(cpy, value) == NULL) { listRelease(cpy); listReleaseIterator(iter); return NULL; } } listReleaseIterator(iter); return cpy; }
static void freeListOfIndRow(list *ll, int num_cols, bool is_ob) { listNode *ln; listIter *li = listGetIterator(ll, AL_START_HEAD); while((ln = listNext(li)) != NULL) { freeIndRow(ln->value, num_cols, is_ob, 1); } listReleaseIterator(li); listRelease(ll); }
struct gwseriport *find_transfer_media(const char *transfer_type) { struct gwseriport *s; listNode *node; listIter *iter; iter = listGetIterator(server.seriports,AL_START_HEAD); while( (node=listNext(iter)) != NULL){ s = node->value; if(strcasecmp(transfer_type,s->transfer_media) == 0){ listReleaseIterator(iter); return s; } } listReleaseIterator(iter); return NULL; }
/* 列表赋值方法,传入的参数为原始列表 */ list *listDup(list *orig) { list *copy; listIter *iter; listNode *node; //如果创建列表失败则直接返回 if ((copy = listCreate()) == NULL) return NULL; //为新列表赋值好3个函数指针 copy->dup = orig->dup; copy->free = orig->free; copy->match = orig->match; //获得从头方向开始的迭代器 iter = listGetIterator(orig, AL_START_HEAD); while((node = listNext(iter)) != NULL) { //从前往后遍历结点 void *value; if (copy->dup) { //如果定义了列表复制方法,则调用dup方法 value = copy->dup(node->value); if (value == NULL) { //如果发生OOM内存溢出问题,直接释放所有空间 listRelease(copy); listReleaseIterator(iter); return NULL; } } else //没定义直接复制函数指针 value = node->value; if (listAddNodeTail(copy, value) == NULL) { //后面的结点都是从尾部逐一添加结点,如果内存溢出,同上操作 listRelease(copy); listReleaseIterator(iter); return NULL; } } //最后释放迭代器 listReleaseIterator(iter); return copy; }
static sds send_http_response_header_extended(cli *c, sds s) { if (c->http.resp_hdr) { listNode *ln; listIter *li = listGetIterator(c->http.resp_hdr, AL_START_HEAD); while((ln = listNext(li))) {// POPULATE Lua Global HTTP_HEADER[] two_sds *ss = ln->value; s = sdscatprintf(s, "%s: %s\r\n", ss->a, ss->b); } listReleaseIterator(li); } return sdscatlen(s, "\r\n", 2); }
/* Search the list for a node matching a given key. * The match is performed using the 'match' method * set with listSetMatchMethod(). If no 'match' method * is set, the 'value' pointer of every node is directly * compared with the 'key' pointer. * * On success the first matching node pointer is returned * (search starts from head). If no matching node exists * NULL is returned. */ listNode *listSearchKey(list *list, void *value) { listIter *iter = listGetIterator(list, DL_START_HEAD); listNode *node; while((node = listNextElement(iter)) != NULL) { if (list->match) { if (list->match(node->value, value)) { listReleaseIterator(iter); return node; } } else { if (value == node->value) { listReleaseIterator(iter); return node; } } } listReleaseIterator(iter); return NULL; }
/* Duplicate the whole list. On out of memory NULL is returned. * On success a copy of the original list is returned. * * The 'Dup' method set with listSetDupMethod() function is used * to copy the node value. Otherwise the same pointer value of * the original node is used as value of the copied node. * * The original list both on success or error is never modified. */ list *listDup(list *orig) { list *copy; listIter *iter; listNode *node; if ((copy = listCreate()) == NULL) return NULL; /* set the auxiliary function */ copy->dup = orig->dup; copy->free = orig->free; copy->match = orig->match; /* get iter of list from head */ iter = listGetIterator(orig, AL_START_HEAD); /* loop all the node of list */ while((node = listNext(iter)) != NULL) { void *value; /* if there is a user defined copy function */ if (copy->dup) { /* set value by calling user defined function */ value = copy->dup(node->value); if (value == NULL) { /* opppps, we get some error */ listRelease(copy);/* release the new list */ listReleaseIterator(iter); /* release the iterator */ return NULL; } } else value = node->value; /* shadow copy if there isn't a user defined function */ if (listAddNodeTail(copy, value) == NULL) { /* if we get some error when add the new node to the end of the new list */ listRelease(copy);/* release the new list */ listReleaseIterator(iter); /* release the iterator */ return NULL; } } listReleaseIterator(iter);/* release the iterator */ return copy; }
/* Search the list for a node matching a given key. * The match is performed using the 'match' method * set with listSetMatchMethod(). If no 'match' method * is set, the 'value' pointer of every node is directly * compared with the 'key' pointer. * * On success the first matching node pointer is returned * (search starts from head). If no matching node exists * NULL is returned. */ listNode *listSearchKey(list *list, void *key) { listIter *iter; listNode *node; /* get the head iterator of list */ iter = listGetIterator(list, AL_START_HEAD); /* loop all the node */ while((node = listNext(iter)) != NULL) { if (list->match) {/* if there is a user defined match function */ if (list->match(node->value, key)) {/* find the node */ listReleaseIterator(iter); /* release the iterator */ return node; /* return the node */ } } else {/* there isn't a user defined match function */ if (key == node->value) { /* if key equals to node->value */ listReleaseIterator(iter); /* release the iterator */ return node; /* return the node */ } } } listReleaseIterator(iter); /*release the iterator */ return NULL;/*didn't find the node with key */ }
void displayall_list() { if(listall->len==0){ printf("没有任何链表,返回\n"); return ; } listIter *iter=listGetIterator(listall,0); listNode *node; while((node=listNext(iter))!=NULL){ list *ll=(list*)node->value; printf("链表%s:",ll->name); listpretraval(ll); } listReleaseIterator(iter); }
static void fts_cat_index(fts_t *fts) { dict_iterator_t *iter; iter = dict_iter_create(fts->index); while (dict_iter_hasnext(iter)) { dict_kv_t kv = dict_iter_next(iter); rr_debug("key: %s", kv.key); list *l = kv.value; listIter *liter = listGetIterator(l, AL_START_HEAD); listNode *node; while((node = listNext(liter)) != NULL) { index_item_t *item = node->value; rr_debug("doc title: %s, tf: %d", (char *) item->doc->title->ptr, item->tf); } listReleaseIterator(liter); } dict_iter_free(iter); }
int main() { list * ls = listCreate(); listIter *iter; listNode *node; char val1[] = "value1"; char val2[] = "value2"; char val3[] = "value3"; listAddNodeHead(ls, val1); listAddNodeHead(ls, val2); listAddNodeHead(ls, val3); iter = listGetIterator(ls, AL_START_HEAD); while((node = listNext(iter)) != NULL) { printf("value = %s\n", (char*)node->value); } listReleaseIterator(iter); return 0; }
void _msg_dump(const char *file, int line, struct msg *msg, int level, int begin) { struct mbuf *mbuf; listIter *iter; listNode *node; uint8_t *p, *q; long int len; if (log_loggable(level) == 0) { return; } _log(file, line, 0, "msg dump id %"PRIu64" request %d len %"PRIu32" type %d " "(err %d) kind %d result %d mbuf_count %u keys_count %u", msg->id, msg->request, msg->mlen, msg->type, msg->err, msg->kind, msg->result, listLength(msg->data), msg->keys == NULL?0:array_n(msg->keys)); iter = listGetIterator(msg->data, AL_START_HEAD); ASSERT(iter != NULL); while((node = listNext(iter)) != NULL) { mbuf = listNodeValue(node); if (begin) { p = mbuf->start; } else { p = mbuf->pos; } q = mbuf->last; len = q - p; _log(file, line, 0, "mbuf [%p] with %ld bytes of data, pos %p last %p", p, len, mbuf->pos, mbuf->last); _log_hexdump(file, line, p, len, NULL); } listReleaseIterator(iter); }
ssize_t aofRewriteBufferWrite(int fd){ /*write cotents in AOF rewrite buffer blocks into given file*/ /*return -1 for short count or write error, else return bytes written*/ listIter *li; listNode *ln; aofrwblock *block; int nwritten, nbytes=0; li = listGetIterator(server.aof_rewrite_buf_blocks, AL_START_HEAD); while((ln = listNext(li)) != NULL){ block = listNodeValue(ln); if((nwritten = write(fd, block->buf, block->used)) == -1){ return -1; } else if((nwritten == 0) && (block.used != 0)){ errno = EIO; return 0; } nbytes += nwritten; } listReleaseIterator(li); return nbytes; }
static list* found_list(listNode**pnode) { if(listall->len==0){ printf("没有任何链表\n"); return NULL; } char name[10]; listNode *node; listIter *iter; list *ll; printf("输入链表的名字:"); scanf("%s",name); iter=listGetIterator(listall,0); while((node=listNext(iter))!=NULL){ ll=(list*)(node->value); if(strcmp(ll->name,name)==0){ *pnode=node; return ll; } } listReleaseIterator(iter); return NULL; }
/* NOTE: this function implements a fakeClient pipe */ long fakeClientPipe(redisClient *c, redisClient *rfc, void *wfc, /* can be redisClient,list,LuaState */ int is_ins, flag *flg, bool (* adder) (redisClient *c, void *x, robj *key, long *l, int b, int n), bool (* emptyer) (redisClient *c)) { redisCommand *cmd = lookupCommand(rfc->argv[0]->ptr); rsql_resetFakeClient(rfc); cmd->proc(rfc); listNode *ln; *flg = PIPE_NONE_FLAG; robj *r = NULL; int nlines = 0; long card = 1; /* ZER0 as pk can cause problems */ bool fline = 1; bool ldef = 0; listIter *li = listGetIterator(rfc->reply, AL_START_HEAD); while((ln = listNext(li)) != NULL) { robj *o = ln->value; sds s = o->ptr; bool o_fl = fline; fline = 0; //RL4 "PIPE: %s", s); if (o_fl) { if (*s == '-') { /* -ERR */ *flg = PIPE_ONE_LINER_FLAG; r = parseUpToR(li, &ln, s); if (!r) goto p_err; if (!(*adder)(c, wfc, r, &card, is_ins, nlines)) goto p_err; break; } else if (*s == '+') { /* +OK */ *flg = PIPE_ONE_LINER_FLAG; r = parseUpToR(li, &ln, s); if (!r) goto p_err; if (!(*adder)(c, wfc, r, &card, is_ins, nlines)) goto p_err; break; } else if (*s == ':') { /* :INT */ *flg = PIPE_ONE_LINER_FLAG; r = parseUpToR(li, &ln, s); if (!r) goto p_err; if (!(*adder)(c, wfc, r, &card, is_ins, nlines)) goto p_err; break; } else if (*s == '*') { nlines = atoi(s + 1); /* some pipes need to know num_lines */ if (nlines == -1) { *flg = PIPE_EMPTY_SET_FLAG; break; /* "*-1" multibulk empty */ } } continue; } /* not first line -> 2+ */ if (*s == '$') { /* parse length [and element] */ if (*(s + 1) == '-') { /* $-1 -> nil */ *flg = PIPE_EMPTY_SET_FLAG; /* NOTE: "-1" must be "adder()"d for Multi-NonRelIndxs */ r = createStringObject("-1", 2); if (!(*adder)(c, wfc, r, &card, is_ins, nlines)) goto p_err; continue; } ldef = 1; char *x = strchr(s, '\r'); if (!x) goto p_err; uint32 llen = x - s; if (llen + 2 < sdslen(s)) { /* more on next line (past "\r\n") */ x += 2; /* move past \r\n */ r = parseUpToR(li, &ln, x); if (!r) goto p_err; if (!(*adder)(c, wfc, r, &card, is_ins, nlines)) goto p_err; ldef = 0; } continue; } /* ignore empty protocol lines */ if (!ldef && sdslen(s) == 2 && *s == '\r' && *(s + 1) == '\n') continue; r = createStringObject(s, sdslen(s)); if (!(*adder)(c, wfc, r, &card, is_ins, nlines)) goto p_err; ldef = 0; } listReleaseIterator(li); if (card == 1) { /* rfc never got called, call empty handler */ if (!(*emptyer)(c)) goto p_err; } return card - 1; /* started at 1 */ p_err: listReleaseIterator(li); if (r) decrRefCount(r); return -1; }
void joinGeneric(redisClient *c, jb_t *jb) { if (jb->w.nob > 1) { addReply(c, shared.join_m_obc); return; } Order_by = jb->w.nob; Order_by_col_val = NULL; /* sort queried-columns to queried-indices */ jqo_t o_csort_order[MAX_COLUMN_PER_TABLE]; jqo_t csort_order [MAX_COLUMN_PER_TABLE]; for (int i = 0; i < jb->qcols; i++) { for (int j = 0; j < jb->n_ind; j++) { if (jb->j_tbls[i] == Index[server.dbid][jb->j_indxs[j]].table) { csort_order[i].t = jb->j_tbls[i]; csort_order[i].i = j; csort_order[i].c = jb->j_cols[i]; csort_order[i].n = i; } } } memcpy(&o_csort_order, &csort_order, sizeof(jqo_t) * jb->qcols); qsort(&csort_order, jb->qcols, sizeof(jqo_t), cmp_jqo); /* reorder queried-columns to queried-indices, will sort @ output time */ bool reordered = 0; for (int i = 0; i < jb->qcols; i++) { if (jb->j_tbls[i] != csort_order[i].t || jb->j_cols[i] != csort_order[i].c) { reordered = 1; jb->j_tbls[i] = csort_order[i].t; jb->j_cols[i] = csort_order[i].c; } } cswc_t *w = &jb->w; /* makes coding more compact */ w->tmatch = w->obt[0]; /* HACK: initOBsort needs w->tmatch */ list *ll = initOBsort(Order_by, w); uchar pk1type = Tbl[server.dbid] [Index[server.dbid][jb->j_indxs[0]].table].col_type[0]; bt *jbtr = createJoinResultSet(pk1type); robj *rset[MAX_JOIN_INDXS]; for (int i = 1; i < jb->n_ind; i++) { rset[i] = createValSetObject(); } int j_ind_len [MAX_JOIN_INDXS]; int jind_ncols[MAX_JOIN_INDXS]; join_add_cols_t jc; /* these dont change in the loop below */ jc.qcols = jb->qcols; jc.j_tbls = jb->j_tbls; jc.j_cols = jb->j_cols; jc.jind_ncols = jind_ncols; jc.j_ind_len = j_ind_len; jc.jbtr = jbtr; for (int i = 0; i < jb->n_ind; i++) { /* iterate join indices */ btEntry *be, *nbe; j_ind_len[i] = 0; jc.index = i; jc.itable = Index[server.dbid][jb->j_indxs[i]].table; robj *btt = lookupKeyRead(c->db, Tbl[server.dbid][jc.itable].name); jc.btr = (bt *)btt->ptr; jc.virt = Index[server.dbid][jb->j_indxs[i]].virt; if (w->low) { /* RANGE QUERY */ if (jc.virt) { /* PK */ btSIter *bi = btGetRangeIterator(jc.btr, w->low, w->high); while ((be = btRangeNext(bi)) != NULL) { jc.ajk = be->key; jc.rrow = be->val; joinAddColsFromInd(&jc, rset, w); } btReleaseRangeIterator(bi); } else { /* FK */ robj *ind = Index[server.dbid][jb->j_indxs[i]].obj; robj *ibtt = lookupKey(c->db, ind); bt *ibtr = (bt *)ibtt->ptr; btSIter *bi = btGetRangeIterator(ibtr, w->low, w->high); while ((be = btRangeNext(bi)) != NULL) { jc.ajk = be->key; bt *nbtr = be->val; btSIter *nbi = btGetFullRangeIterator(nbtr); while ((nbe = btRangeNext(nbi)) != NULL) { jc.rrow = btFindVal(jc.btr, nbe->key); joinAddColsFromInd(&jc, rset, w); } btReleaseRangeIterator(nbi); } btReleaseRangeIterator(bi); } } else { /* IN() QUERY */ listNode *ln; listIter *li = listGetIterator(w->inl, AL_START_HEAD); if (jc.virt) { while((ln = listNext(li)) != NULL) { jc.ajk = ln->value; jc.rrow = btFindVal(jc.btr, jc.ajk); if (jc.rrow) joinAddColsFromInd(&jc, rset, w); } } else { btSIter *nbi; robj *ind = Index[server.dbid][jb->j_indxs[i]].obj; robj *ibtt = lookupKey(c->db, ind); bt *ibtr = (bt *)ibtt->ptr; while((ln = listNext(li)) != NULL) { jc.ajk = ln->value; bt *nbtr = btIndFindVal(ibtr, jc.ajk); if (nbtr) { nbi = btGetFullRangeIterator(nbtr); while ((nbe = btRangeNext(nbi)) != NULL) { jc.rrow = btFindVal(jc.btr, nbe->key); joinAddColsFromInd(&jc, rset, w); } btReleaseRangeIterator(nbi); } } } listReleaseIterator(li); } } /* cant join if one table had ZERO rows */ bool one_empty = 0; if (jbtr->numkeys == 0) one_empty = 1; else { for (int i = 1; i < jb->n_ind; i++) { if (dictSize((dict *)rset[i]->ptr) == 0) { one_empty = 1; break; } } } LEN_OBJ bool err = 0; long sent = 0; btIterator *bi = NULL; /* B4 GOTO */ char *reply = NULL; /* B4 GOTO */ if (!one_empty) { int reply_size = 0; for (int i = 0; i < jb->n_ind; i++) { // get maxlen possbl 4 joined row reply_size += j_ind_len[i] + 1; } reply = malloc(reply_size); /* freed after while() loop */ build_jrow_reply_t bjr; /* none of these change during a join */ bzero(&bjr, sizeof(build_jrow_reply_t)); bjr.j.c = c; bjr.j.jind_ncols = jind_ncols; bjr.j.reply = reply; bjr.j.csort_order = csort_order; bjr.j.reordered = reordered; bjr.j.qcols = jb->qcols; bjr.n_ind = jb->n_ind; bjr.card = &card; bjr.j.obt = w->obt[0]; bjr.j.obc = w->obc[0]; bjr.j_indxs = jb->j_indxs; bjr.j.ll = ll; bjr.j.cstar = jb->cstar; joinRowEntry *be; bi = btGetJoinFullRangeIterator(jbtr, pk1type); while ((be = btJoinRangeNext(bi, pk1type)) != NULL) { /* iter BT */ listNode *ln; bjr.jk = be->key; list *jll = (list *)be->val; listIter *li = listGetIterator(jll, AL_START_HEAD); while((ln = listNext(li)) != NULL) { /* iter LIST */ char *first_entry; char *item = ln->value; if (bjr.j.obt == Index[server.dbid][bjr.j_indxs[0]].table) { obsl_t *ob = (obsl_t *)item; Order_by_col_val = ob->keys[0]; first_entry = (char *)ob->row; } else { first_entry = item; } for (int j = 0; j < jind_ncols[0]; j++) { Rcols[0][j] = (char **)first_entry; first_entry += PTR_SIZE; memcpy(&Rc_lens[0][j], first_entry, UINT_SIZE); first_entry += UINT_SIZE; } if (!buildJRowReply(&bjr, 1, rset)) { err = 1; goto join_end; } } listReleaseIterator(li); } if (Order_by) { sent = sortJoinOrderByAndReply(c, &bjr, w); if (sent == -1) err = 1; releaseOBsort(ll); } } join_end: if (bi) btReleaseJoinRangeIterator(bi); if (reply) free(reply); /* free joinRowEntry malloc from joinAddColsFromInd() */ bool is_ob = (w->obt[0] == Index[server.dbid][jb->j_indxs[0]].table); btJoinRelease(jbtr, jind_ncols[0], is_ob, freeListOfIndRow); /* free joinRowEntry malloc from joinAddColsFromInd() */ dictEntry *de; for (int i = 1; i < jb->n_ind; i++) { dict *set = rset[i]->ptr; bool is_ob = (w->obt[0] == Index[server.dbid][jb->j_indxs[i]].table); dictIterator *di = dictGetIterator(set); while((de = dictNext(di)) != NULL) { robj *val = dictGetEntryVal(de); dict *iset = val->ptr; freeDictOfIndRow(iset, jind_ncols[i], is_ob); } dictReleaseIterator(di); } for (int i = 1; i < jb->n_ind; i++) { decrRefCount(rset[i]); } if (err) return; if (w->lim != -1 && sent < card) card = sent; if (jb->cstar) { lenobj->ptr = sdscatprintf(sdsempty(), ":%ld\r\n", card); } else { lenobj->ptr = sdscatprintf(sdsempty(), "*%ld\r\n", card); if (w->ovar) incrOffsetVar(c, w, card); } }