Esempio n. 1
0
TEST(sds, sds)
{
    // struct sdshdr *sh;
    sds x = sdsnew("foo"), y;

    TEST_ASSERT_TRUE(
        sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0)

    sdsfree(x);
    x = sdsnewlen("foo",2);
    TEST_ASSERT_TRUE(
        sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0)

    x = sdscat(x,"bar");
    TEST_ASSERT_TRUE(
        sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0);

    x = sdscpy(x,"a");
    TEST_ASSERT_TRUE(
        sdslen(x) == 1 && memcmp(x,"a\0",2) == 0)

    x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
    TEST_ASSERT_TRUE(
        sdslen(x) == 33 &&
        memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0)

    sdsfree(x);

    x = sdscatprintf(sdsempty(),"%d",123);
    TEST_ASSERT_TRUE(
        sdslen(x) == 3 && memcmp(x,"123\0",4) ==0)

    sdsfree(x);
    x = sdsnew("xxciaoyyy");
    sdstrim(x,"xy");
    TEST_ASSERT_TRUE(
        sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)

    y = sdsdup(x);
    sdsrange(y,1,1);
    TEST_ASSERT_TRUE(
        sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)

    sdsfree(y);
    y = sdsdup(x);
    sdsrange(y,1,-1);
    TEST_ASSERT_TRUE(
        sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)

    sdsfree(y);
    y = sdsdup(x);
    sdsrange(y,-2,-1);
    TEST_ASSERT_TRUE(
        sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)

    sdsfree(y);
    y = sdsdup(x);
    sdsrange(y,2,1);
    TEST_ASSERT_TRUE(
        sdslen(y) == 0 && memcmp(y,"\0",1) == 0)

    sdsfree(y);
    y = sdsdup(x);
    sdsrange(y,1,100);
    TEST_ASSERT_TRUE(
        sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)

    sdsfree(y);
    y = sdsdup(x);
    sdsrange(y,100,100);
    TEST_ASSERT_TRUE(
        sdslen(y) == 0 && memcmp(y,"\0",1) == 0)

    sdsfree(y);
    sdsfree(x);
    x = sdsnew("foo");
    y = sdsnew("foa");
    TEST_ASSERT_TRUE( sdscmp(x,y) > 0)

    sdsfree(y);
    sdsfree(x);
    x = sdsnew("bar");
    y = sdsnew("bar");
    TEST_ASSERT_TRUE( sdscmp(x,y) == 0)

    sdsfree(y);
    sdsfree(x);
    x = sdsnew("aar");
    y = sdsnew("bar");
    TEST_ASSERT_TRUE( sdscmp(x,y) < 0)

    sdsfree(y);
    sdsfree(x);
    // x = sdsnewlen("\a\n\0foo\r",7);
    // y = sdscatrepr(sdsempty(),x,sdslen(x));
    // TEST_ASSERT_TRUE(
    //     memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0)

#if 0
    {
        int oldfree;

        sdsfree(x);
        x = sdsnew("0");
        sh = (void*) (x-(sizeof(struct sdshdr)));
        TEST_ASSERT_TRUE( sh->len == 1 && sh->free == 0);
        x = sdsMakeRoomFor(x,1);
        sh = (void*) (x-(sizeof(struct sdshdr)));
        TEST_ASSERT_TRUE( sh->len == 1 && sh->free > 0);
        oldfree = sh->free;
        x[1] = '1';
        sdsIncrLen(x,1);
        TEST_ASSERT_TRUE( x[0] == '0' && x[1] == '1');
        TEST_ASSERT_TRUE( sh->len == 2);
        TEST_ASSERT_TRUE( sh->free == oldfree-1);
    }
#endif
}
Esempio n. 2
0
static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
    client c = privdata;
    void *reply = NULL;
    UNUSED(el);
    UNUSED(fd);
    UNUSED(mask);

    /* Calculate latency only for the first read event. This means that the
     * server already sent the reply and we need to parse it. Parsing overhead
     * is not part of the latency, so calculate it only once, here. */
    if (c->latency < 0) c->latency = ustime()-(c->start);

    if (redisBufferRead(c->context) != REDIS_OK) {
        fprintf(stderr,"Error: %s\n",c->context->errstr);
        exit(1);
    } else {
        while(c->pending) {
            if (redisGetReply(c->context,&reply) != REDIS_OK) {
                fprintf(stderr,"Error: %s\n",c->context->errstr);
                exit(1);
            }
            if (reply != NULL) {
                if (reply == (void*)REDIS_REPLY_ERROR) {
                    fprintf(stderr,"Unexpected error reply, exiting...\n");
                    exit(1);
                }

                if (config.showerrors) {
                    static time_t lasterr_time = 0;
                    time_t now = time(NULL);
                    redisReply *r = reply;
                    if (r->type == REDIS_REPLY_ERROR && lasterr_time != now) {
                        lasterr_time = now;
                        printf("Error from server: %s\n", r->str);
                    }
                }

                freeReplyObject(reply);
                /* This is an OK for prefix commands such as auth and select.*/
                if (c->prefix_pending > 0) {
                    c->prefix_pending--;
                    c->pending--;
                    /* Discard prefix commands on first response.*/
                    if (c->prefixlen > 0) {
                        size_t j;
                        sdsrange(c->obuf, c->prefixlen, -1);
                        /* We also need to fix the pointers to the strings
                        * we need to randomize. */
                        for (j = 0; j < c->randlen; j++)
                            c->randptr[j] -= c->prefixlen;
                        c->prefixlen = 0;
                    }
                    continue;
                }

                if (config.requests_finished < config.requests)
                    config.latency[config.requests_finished++] = c->latency;
                c->pending--;
                if (c->pending == 0) {
                    clientDone(c);
                    break;
                }
            } else {
                break;
            }
        }
    }
}
Esempio n. 3
0
void processInputBuffer(redisClient *c) {
again:
    /* Before to process the input buffer, make sure the client is not
     * waitig for a blocking operation such as BLPOP. Note that the first
     * iteration the client is never blocked, otherwise the processInputBuffer
     * would not be called at all, but after the execution of the first commands
     * in the input buffer the client may be blocked, and the "goto again"
     * will try to reiterate. The following line will make it return asap. */
    if (c->flags & REDIS_BLOCKED || c->flags & REDIS_IO_WAIT) return;
    if (c->bulklen == -1) {
        /* Read the first line of the query */
        char *p = strchr(c->querybuf,'\n');
        size_t querylen;

        if (p) {
            sds query, *argv;
            int argc, j;

            query = c->querybuf;
            c->querybuf = sdsempty();
            querylen = 1+(p-(query));
            if (sdslen(query) > querylen) {
                /* leave data after the first line of the query in the buffer */
                c->querybuf = sdscatlen(c->querybuf,query+querylen,sdslen(query)-querylen);
            }
            *p = '\0'; /* remove "\n" */
            if (*(p-1) == '\r') *(p-1) = '\0'; /* and "\r" if any */
            sdsupdatelen(query);

            /* Now we can split the query in arguments */
            argv = sdssplitlen(query,sdslen(query)," ",1,&argc);
            sdsfree(query);

            if (c->argv) zfree(c->argv);
            c->argv = zmalloc(sizeof(robj*)*argc);

            for (j = 0; j < argc; j++) {
                if (sdslen(argv[j])) {
                    c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
                    c->argc++;
                } else {
                    sdsfree(argv[j]);
                }
            }
            zfree(argv);
            if (c->argc) {
                /* Execute the command. If the client is still valid
                 * after processCommand() return and there is something
                 * on the query buffer try to process the next command. */
                if (processCommand(c) && sdslen(c->querybuf)) goto again;
            } else {
                /* Nothing to process, argc == 0. Just process the query
                 * buffer if it's not empty or return to the caller */
                if (sdslen(c->querybuf)) goto again;
            }
            return;
        } else if (sdslen(c->querybuf) >= REDIS_REQUEST_MAX_SIZE) {
            redisLog(REDIS_VERBOSE, "Client protocol error");
            freeClient(c);
            return;
        }
    } else {
        /* Bulk read handling. Note that if we are at this point
           the client already sent a command terminated with a newline,
           we are reading the bulk data that is actually the last
           argument of the command. */
        int qbl = sdslen(c->querybuf);

        if (c->bulklen <= qbl) {
            /* Copy everything but the final CRLF as final argument */
            c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
            c->argc++;
            c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
            /* Process the command. If the client is still valid after
             * the processing and there is more data in the buffer
             * try to parse it. */
            if (processCommand(c) && sdslen(c->querybuf)) goto again;
            return;
        }
    }
}
Esempio n. 4
0
/* Use this function to handle a read event on the descriptor. It will try
 * and read some bytes from the socket and feed them to the reply parser.
 *
 * After this function is called, you may use redisContextReadReply to
 * see if there is a reply available. */
int redisBufferRead(redisContext *c) {
    char buf[1024*16];
    int nread;

    /* Return early when the context has seen an error. */
    if (c->err)
        return REDIS_ERR;

#ifndef HIREDIS_WIN
	nread = read(c->fd,buf,sizeof(buf));
	if (nread == -1) {
		if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
			/* Try again later */
#else
	nread = recv(c->fd,buf,sizeof(buf),0);
	if (nread == -1) {
		errno = WSAGetLastError();
		if ((errno == WSAEINPROGRESS || errno == WSAEWOULDBLOCK) && !(c->flags & REDIS_BLOCK)) {
			/* Try again later */
#endif
        } else {
            __redisSetError(c,REDIS_ERR_IO,NULL);
            return REDIS_ERR;
        }
    } else if (nread == 0) {
        __redisSetError(c,REDIS_ERR_EOF,"Server closed the connection");
        return REDIS_ERR;
    } else {
        if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) {
            __redisSetError(c,c->reader->err,c->reader->errstr);
            return REDIS_ERR;
        }
    }
    return REDIS_OK;
}

/* Write the output buffer to the socket.
 *
 * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
 * succesfully written to the socket. When the buffer is empty after the
 * write operation, "done" is set to 1 (if given).
 *
 * Returns REDIS_ERR if an error occured trying to write and sets
 * c->errstr to hold the appropriate error string.
 */
int redisBufferWrite(redisContext *c, int *done) {
    int nwritten;

    /* Return early when the context has seen an error. */
    if (c->err)
        return REDIS_ERR;

    if (sdslen(c->obuf) > 0) {
#ifndef HIREDIS_WIN
		nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
		if (nwritten == -1) {
			if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
				/* Try again later */
#else
		nwritten = send(c->fd,c->obuf,sdslen(c->obuf),0);
		if (nwritten == -1) {
			errno = WSAGetLastError();
			if ((errno == WSAEINPROGRESS || errno == WSAEWOULDBLOCK) && !(c->flags & REDIS_BLOCK)) {
				/* Try again later */
#endif
            } else {
                __redisSetError(c,REDIS_ERR_IO,NULL);
                return REDIS_ERR;
            }
        } else if (nwritten > 0) {
            if (nwritten == (signed)sdslen(c->obuf)) {
                sdsfree(c->obuf);
                c->obuf = sdsempty();
            } else {
                c->obuf = sdsrange(c->obuf,nwritten,-1);
            }
        }
    }
    if (done != NULL) *done = (sdslen(c->obuf) == 0);
    return REDIS_OK;
}

/* Internal helper function to try and get a reply from the reader,
 * or set an error in the context otherwise. */
int redisGetReplyFromReader(redisContext *c, void **reply) {
    if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) {
        __redisSetError(c,c->reader->err,c->reader->errstr);
        return REDIS_ERR;
    }
    return REDIS_OK;
}

int redisGetReply(redisContext *c, void **reply) {
    int wdone = 0;
    void *aux = NULL;

    /* Try to read pending replies */
    if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
        return REDIS_ERR;

    /* For the blocking context, flush output buffer and read reply */
    if (aux == NULL && c->flags & REDIS_BLOCK) {
        /* Write until done */
        do {
            if (redisBufferWrite(c,&wdone) == REDIS_ERR)
                return REDIS_ERR;
        } while (!wdone);

        /* Read until there is a reply */
        do {
            if (redisBufferRead(c) == REDIS_ERR)
                return REDIS_ERR;
            if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
                return REDIS_ERR;
        } while (aux == NULL);
    }

    /* Set reply object */
    if (reply != NULL) *reply = aux;
    return REDIS_OK;
}


/* Helper function for the redisAppendCommand* family of functions.
 *
 * Write a formatted command to the output buffer. When this family
 * is used, you need to call redisGetReply yourself to retrieve
 * the reply (or replies in pub/sub).
 */
int __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
    sds newbuf;

    newbuf = sdscatlen(c->obuf,cmd,len);
    if (newbuf == NULL) {
        __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
        return REDIS_ERR;
    }

    c->obuf = newbuf;
    return REDIS_OK;
}
Esempio n. 5
0
int main(void) {
    {
        sds x = sdsnew("foo"), y;

        test_cond("Create a string and obtain the length",
            sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0)

        sdsfree(x);
        x = sdsnewlen("foo",2);
        test_cond("Create a string with specified length",
            sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0)

        x = sdscat(x,"bar");
        test_cond("Strings concatenation",
            sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0);

        x = sdscpy(x,"a");
        test_cond("sdscpy() against an originally longer string",
            sdslen(x) == 1 && memcmp(x,"a\0",2) == 0)

        x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
        test_cond("sdscpy() against an originally shorter string",
            sdslen(x) == 33 &&
            memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0)

        sdsfree(x);
        x = sdscatprintf(sdsempty(),"%d",123);
        test_cond("sdscatprintf() seems working in the base case",
            sdslen(x) == 3 && memcmp(x,"123\0",4) ==0)

        sdsfree(x);
        x = sdstrim(sdsnew("xxciaoyyy"),"xy");
        test_cond("sdstrim() correctly trims characters",
            sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)

        y = sdsrange(sdsdup(x),1,1);
        test_cond("sdsrange(...,1,1)",
            sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)

        sdsfree(y);
        y = sdsrange(sdsdup(x),1,-1);
        test_cond("sdsrange(...,1,-1)",
            sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)

        sdsfree(y);
        y = sdsrange(sdsdup(x),-2,-1);
        test_cond("sdsrange(...,-2,-1)",
            sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)

        sdsfree(y);
        y = sdsrange(sdsdup(x),2,1);
        test_cond("sdsrange(...,2,1)",
            sdslen(y) == 0 && memcmp(y,"\0",1) == 0)

        sdsfree(y);
        y = sdsrange(sdsdup(x),1,100);
        test_cond("sdsrange(...,1,100)",
            sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)

        sdsfree(y);
        y = sdsrange(sdsdup(x),100,100);
        test_cond("sdsrange(...,100,100)",
            sdslen(y) == 0 && memcmp(y,"\0",1) == 0)

        sdsfree(y);
        sdsfree(x);
        x = sdsnew("foo");
        y = sdsnew("foa");
        test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0)

        sdsfree(y);
        sdsfree(x);
        x = sdsnew("bar");
        y = sdsnew("bar");
        test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0)

        sdsfree(y);
        sdsfree(x);
        x = sdsnew("aar");
        y = sdsnew("bar");
        test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)
    }
    test_report()
}
Esempio n. 6
0
int main(void) {
    {
        sdshdr *sh;
        sds x = sdsnew("foo"), y;

        test_cond("Create a string and obtain the length",
            sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0)

        sdsfree(x);
        x = sdsnewlen("foo",2);
        test_cond("Create a string with specified length",
            sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0)

        x = sdscat(x,"bar");
        test_cond("Strings concatenation",
            sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0);

        x = sdscpy(x,"a");
        test_cond("sdscpy() against an originally longer string",
            sdslen(x) == 1 && memcmp(x,"a\0",2) == 0)

        x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
        test_cond("sdscpy() against an originally shorter string",
            sdslen(x) == 33 &&
            memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0)

        sdsfree(x);
        x = sdscatprintf(sdsempty(),"%d",123);
        test_cond("sdscatprintf() seems working in the base case",
            sdslen(x) == 3 && memcmp(x,"123\0",4) ==0)

        sdsfree(x);
        x = sdsnew("xxciaoyyy");
        sdstrim(x,"xy");
        test_cond("sdstrim() correctly trims characters",
            sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)

        y = sdsdup(x);
        sdsrange(y,1,1);
        test_cond("sdsrange(...,1,1)",
            sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)

        sdsfree(y);
        y = sdsdup(x);
        sdsrange(y,1,-1);
        test_cond("sdsrange(...,1,-1)",
            sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)

        sdsfree(y);
        y = sdsdup(x);
        sdsrange(y,-2,-1);
        test_cond("sdsrange(...,-2,-1)",
            sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)

        sdsfree(y);
        y = sdsdup(x);
        sdsrange(y,2,1);
        test_cond("sdsrange(...,2,1)",
            sdslen(y) == 0 && memcmp(y,"\0",1) == 0)

        sdsfree(y);
        y = sdsdup(x);
        sdsrange(y,1,100);
        test_cond("sdsrange(...,1,100)",
            sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)

        sdsfree(y);
        y = sdsdup(x);
        sdsrange(y,100,100);
        test_cond("sdsrange(...,100,100)",
            sdslen(y) == 0 && memcmp(y,"\0",1) == 0)

        sdsfree(y);
        sdsfree(x);
        x = sdsnew("foo");
        y = sdsnew("foa");
        test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0)

        sdsfree(y);
        sdsfree(x);
        x = sdsnew("bar");
        y = sdsnew("bar");
        test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0)

        sdsfree(y);
        sdsfree(x);
        x = sdsnew("aar");
        y = sdsnew("bar");
        test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)

        sdsfree(y);
        sdsfree(x);
        x = sdsnewlen("\a\n\0foo\r",7);
        y = sdscatrepr(sdsempty(),x,sdslen(x));
        test_cond("sdscatrepr(...data...)",
            memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0)
	sdsfree(y);

        {
            size_t oldfree;

            sdsfree(x);
            x = sdsnew("0");
            sh = sds_start(x);
            test_cond("sdsnew() free/len buffers", sh->len == 1 && sh->free == 0);
            x = sdsMakeRoomFor(x,1);
            sh = sds_start(x);
            test_cond("sdsMakeRoomFor()", sh->len == 1 && sh->free > 0);
            oldfree = sh->free;
            x[1] = '1';
            sdsIncrLen(x,1);
            test_cond("sdsIncrLen() -- content", x[0] == '0' && x[1] == '1');
            test_cond("sdsIncrLen() -- len", sh->len == 2);
            test_cond("sdsIncrLen() -- free", sh->free == oldfree-1);
	    sdsfree(x);
        }

        x = sdsnew("0FoO1bar\n");
        sdstolower(x);
        test_cond("sdstolower(...)",
            memcmp(x,"0foo1bar\n\0",10) == 0)

        sdsfree(x);

        x = sdsnew("0FoO1bar\n");
        sdstoupper(x);
        test_cond("sdstoupper(...)",
            memcmp(x,"0FOO1BAR\n\0",10) == 0)

        sdsfree(x);
    }
    test_report()
    return 0;
}
Esempio n. 7
0
/* Write the append only file buffer on disk.
 *
 * Since we are required to write the AOF before replying to the client,
 * and the only way the client socket can get a write is entering when the
 * the event loop, we accumulate all the AOF writes in a memory
 * buffer and write it on disk using this function just before entering
 * the event loop again.
 *
 * About the 'force' argument:
 *
 * When the fsync policy is set to 'everysec' we may delay the flush if there
 * is still an fsync() going on in the background thread, since for instance
 * on Linux write(2) will be blocked by the background fsync anyway.
 * When this happens we remember that there is some aof buffer to be
 * flushed ASAP, and will try to do that in the serverCron() function.
 *
 * However if force is set to 1 we'll write regardless of the background
 * fsync. */
#define AOF_WRITE_LOG_ERROR_RATE 30 /* Seconds between errors logging. */
void flushAppendOnlyFile(int force) {
    ssize_t nwritten;
    int sync_in_progress = 0;

    if (sdslen(server.aof_buf) == 0) return;

    if (server.aof_fsync == AOF_FSYNC_EVERYSEC)
        sync_in_progress = bioPendingJobsOfType(REDIS_BIO_AOF_FSYNC) != 0;

    if (server.aof_fsync == AOF_FSYNC_EVERYSEC && !force) {
        /* With this append fsync policy we do background fsyncing.
         * If the fsync is still in progress we can try to delay
         * the write for a couple of seconds. */
        if (sync_in_progress) {
            if (server.aof_flush_postponed_start == 0) {
                /* No previous write postponinig, remember that we are
                 * postponing the flush and return. */
                server.aof_flush_postponed_start = server.unixtime;
                return;
            } else if (server.unixtime - server.aof_flush_postponed_start < 2) {
                /* We were already waiting for fsync to finish, but for less
                 * than two seconds this is still ok. Postpone again. */
                return;
            }
            /* Otherwise fall trough, and go write since we can't wait
             * over two seconds. */
            server.aof_delayed_fsync++;
            redisLog(REDIS_NOTICE,"Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.");
        }
    }
    /* If you are following this code path, then we are going to write so
     * set reset the postponed flush sentinel to zero. */
    server.aof_flush_postponed_start = 0;

    /* We want to perform a single write. This should be guaranteed atomic
     * at least if the filesystem we are writing is a real physical one.
     * While this will save us against the server being killed I don't think
     * there is much to do about the whole server stopping for power problems
     * or alike */
    nwritten = write(server.aof_fd,server.aof_buf,sdslen(server.aof_buf));
    if (nwritten != (signed)sdslen(server.aof_buf)) {
        static time_t last_write_error_log = 0;
        int can_log = 0;

        /* Limit logging rate to 1 line per AOF_WRITE_LOG_ERROR_RATE seconds. */
        if ((server.unixtime - last_write_error_log) > AOF_WRITE_LOG_ERROR_RATE) {
            can_log = 1;
            last_write_error_log = server.unixtime;
        }

        /* Lof the AOF write error and record the error code. */
        if (nwritten == -1) {
            if (can_log) {
                redisLog(REDIS_WARNING,"Error writing to the AOF file: %s",
                    strerror(errno));
                server.aof_last_write_errno = errno;
            }
        } else {
            if (can_log) {
                redisLog(REDIS_WARNING,"Short write while writing to "
                                       "the AOF file: (nwritten=%lld, "
                                       "expected=%lld)",
                                       (long long)nwritten,
                                       (long long)sdslen(server.aof_buf));
            }

            if (ftruncate(server.aof_fd, server.aof_current_size) == -1) {
                if (can_log) {
                    redisLog(REDIS_WARNING, "Could not remove short write "
                             "from the append-only file.  Redis may refuse "
                             "to load the AOF the next time it starts.  "
                             "ftruncate: %s", strerror(errno));
                }
            } else {
                /* If the ftrunacate() succeeded we can set nwritten to
                 * -1 since there is no longer partial data into the AOF. */
                nwritten = -1;
            }
            server.aof_last_write_errno = ENOSPC;
        }

        /* Handle the AOF write error. */
        if (server.aof_fsync == AOF_FSYNC_ALWAYS) {
            /* We can't recover when the fsync policy is ALWAYS since the
             * reply for the client is already in the output buffers, and we
             * have the contract with the user that on acknowledged write data
             * is synched on disk. */
            redisLog(REDIS_WARNING,"Can't recover from AOF write error when the AOF fsync policy is 'always'. Exiting...");
            exit(1);
        } else {
            /* Recover from failed write leaving data into the buffer. However
             * set an error to stop accepting writes as long as the error
             * condition is not cleared. */
            server.aof_last_write_status = REDIS_ERR;

            /* Trim the sds buffer if there was a partial write, and there
             * was no way to undo it with ftruncate(2). */
            if (nwritten > 0) {
                server.aof_current_size += nwritten;
                sdsrange(server.aof_buf,nwritten,-1);
            }
            return; /* We'll try again on the next call... */
        }
    } else {
        /* Successful write(2). If AOF was in error state, restore the
         * OK state and log the event. */
        if (server.aof_last_write_status == REDIS_ERR) {
            redisLog(REDIS_WARNING,
                "AOF write error looks solved, Redis can write again.");
            server.aof_last_write_status = REDIS_OK;
        }
    }
    server.aof_current_size += nwritten;

    /* Re-use AOF buffer when it is small enough. The maximum comes from the
     * arena size of 4k minus some overhead (but is otherwise arbitrary). */
    if ((sdslen(server.aof_buf)+sdsavail(server.aof_buf)) < 4000) {
        sdsclear(server.aof_buf);
    } else {
        sdsfree(server.aof_buf);
        server.aof_buf = sdsempty();
    }

    /* Don't fsync if no-appendfsync-on-rewrite is set to yes and there are
     * children doing I/O in the background. */
    if (server.aof_no_fsync_on_rewrite &&
        (server.aof_child_pid != -1 || server.rdb_child_pid != -1))
            return;

    /* Perform the fsync if needed. */
    if (server.aof_fsync == AOF_FSYNC_ALWAYS) {
        /* aof_fsync is defined as fdatasync() for Linux in order to avoid
         * flushing metadata. */
        aof_fsync(server.aof_fd); /* Let's try to get this data on the disk */
        server.aof_last_fsync = server.unixtime;
    } else if ((server.aof_fsync == AOF_FSYNC_EVERYSEC &&
                server.unixtime > server.aof_last_fsync)) {
        if (!sync_in_progress) aof_background_fsync(server.aof_fd);
        server.aof_last_fsync = server.unixtime;
    }
}
Esempio n. 8
0
/* Use this function to handle a read event on the descriptor. It will try
 * and read some bytes from the socket and feed them to the reply parser.
 *
 * After this function is called, you may use redisContextReadReply to
 * see if there is a reply available. */
int redisBufferRead(redisContext *c) {
    char buf[1024*16];
    int nread;

    /* Return early when the context has seen an error. */
    if (c->err)
        return REDIS_ERR;

#ifdef WIN32
    nread = recv(c->fd,buf,sizeof(buf),0);
#else
	nread = read(c->fd,buf,sizeof(buf));
#endif
    if (nread == -1) {
#ifdef WIN32
		errno = WSAGetLastError();
		if ((errno == WSAEWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == WSAEINTR)) {
#else
        if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
#endif
            /* Try again later */
        } else {
            __redisSetError(c,REDIS_ERR_IO,NULL);
            return REDIS_ERR;
        }
    } else if (nread == 0) {
        __redisSetError(c,REDIS_ERR_EOF,"Server closed the connection");
        return REDIS_ERR;
    } else {
        if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) {
            __redisSetError(c,c->reader->err,c->reader->errstr);
            return REDIS_ERR;
        }
    }
    return REDIS_OK;
}

/* Write the output buffer to the socket.
 *
 * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
 * succesfully written to the socket. When the buffer is empty after the
 * write operation, "done" is set to 1 (if given).
 *
 * Returns REDIS_ERR if an error occured trying to write and sets
 * c->errstr to hold the appropriate error string.
 */
int redisBufferWrite(redisContext *c, int *done) {
    int nwritten;

    /* Return early when the context has seen an error. */
    if (c->err)
        return REDIS_ERR;

    if (sdslen(c->obuf) > 0) {
#ifdef WIN32
        nwritten = send(c->fd,c->obuf,sdslen(c->obuf),0);
#else
		nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
#endif
        if (nwritten == -1) {
#ifdef WIN32
			errno = WSAGetLastError();
			if ((errno == WSAEWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == WSAEINTR)) {
#else
            if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
#endif
                /* Try again later */
            } else {
                __redisSetError(c,REDIS_ERR_IO,NULL);
                return REDIS_ERR;
            }
        } else if (nwritten > 0) {
            if (nwritten == (signed)sdslen(c->obuf)) {
                sdsfree(c->obuf);
                c->obuf = sdsempty();
            } else {
                c->obuf = sdsrange(c->obuf,nwritten,-1);
            }
        }
    }
    if (done != NULL) *done = (sdslen(c->obuf) == 0);
    return REDIS_OK;
}

/* Internal helper function to try and get a reply from the reader,
 * or set an error in the context otherwise. */
int redisGetReplyFromReader(redisContext *c, void **reply) {
    if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) {
        __redisSetError(c,c->reader->err,c->reader->errstr);
        return REDIS_ERR;
    }
    return REDIS_OK;
}

int redisGetReply(redisContext *c, void **reply) {
    int wdone = 0;
    void *aux = NULL;

    /* Try to read pending replies */
    if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
        return REDIS_ERR;

    /* For the blocking context, flush output buffer and read reply */
    if (aux == NULL && c->flags & REDIS_BLOCK) {
        /* Write until done */
        do {
            if (redisBufferWrite(c,&wdone) == REDIS_ERR)
                return REDIS_ERR;
        } while (!wdone);

        /* Read until there is a reply */
        do {
            if (redisBufferRead(c) == REDIS_ERR)
                return REDIS_ERR;
            if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
                return REDIS_ERR;
        } while (aux == NULL);
    }

    /* Set reply object */
    if (reply != NULL) *reply = aux;
    return REDIS_OK;
}
Esempio n. 9
0
void onClientReadable( aeEventLoop *el , int connfd , void *privdata , int mask )
{
	
	appnetServer *serv = servG;
	ssize_t nread;
	unsigned int readlen,rcvbuflen,datalen;
	int worker_id = servG->connlist[connfd].worker_id;
	int thid = servG->connlist[connfd].reactor_id;
	char buffer[TMP_BUFFER_LENGTH];
	
	while (1)
	{
		
		nread = 0;
		memset( &buffer , 0 , sizeof( buffer ) );
		nread = read( connfd , &buffer , sizeof( buffer ) );
		
		if (nread == -1 && errno == EAGAIN)
		{
			return; /* No more data ready. */
		}
		
		if (nread == 0)
		{
			onCloseByClient( el , privdata , serv , &serv->connlist[connfd] );
			return; /* Close event */
		}
		else if (nread > 0)
		{
			
			/* Append client recv_buffer */
			servG->connlist[connfd].recv_buffer =
					sdscatlen( servG->connlist[connfd].recv_buffer , &buffer , nread );
			
			int ret =
					parseRequestMessage( connfd , servG->connlist[connfd].recv_buffer ,
							sdslen( servG->connlist[connfd].recv_buffer ) );
			
			if (ret == BREAK_RECV)
			{
				int complete_length = servG->reactor_threads[thid].hh->complete_length;
				
				if (complete_length > 0)
				{
					sdsrange( servG->connlist[connfd].recv_buffer , complete_length , -1 );
				}
				else
				{
					sdsclear( servG->connlist[connfd].recv_buffer );
				}
				break;
				
			}
			else if (ret == CONTINUE_RECV)
			{
				continue;
				
			}
			else if (ret == CLOSE_CONNECT)
			{
				freeClient( &servG->connlist[connfd] );
				return;
			}
			return;
		}
		else
		{
			printf( "Recv Errno=%d,Err=%s \n" , errno , strerror( errno ) );
		}
	}
}
Esempio n. 10
0
static int process_multibulk_buffer(sub_client *c)
{
    char *newline = NULL;
    int pos = 0, ok;
    long long ll;

    if (c->multi_bulk_len == 0) {
        /* Multi bulk length cannot be read without a \r\n */
        newline = strchr(c->read_buf, '\r');
        if (newline == NULL) {
            if (sdslen(c->read_buf) > MAX_INLINE_READ) {
                srv_log(LOG_ERROR, "protocol error: too big mbulk string");
                set_protocol_err(c, 0);
            }
            return SUBCLI_ERR;
        }

        /* Buffer should also contain \n */
        if (newline-(c->read_buf) > ((signed)sdslen(c->read_buf)-2)) {
            return SUBCLI_ERR;
        }

        ok = string2ll(c->read_buf+1, newline-(c->read_buf+1), &ll);
        if (!ok || ll > SUB_READ_BUF_LEN) {
            srv_log(LOG_ERROR, "protocol error: invalid multibulk length");
            set_protocol_err(c, pos);
            return SUBCLI_ERR;
        }

        pos = (newline - c->read_buf) + 2;
        if (ll <= 0) {
            sdsrange(c->read_buf, pos, -1);
            return SUBCLI_OK;
        }

        c->multi_bulk_len = ll;
        c->argv = malloc(sizeof(sds) * c->multi_bulk_len);
    }

    while (c->multi_bulk_len) {
        /* Read bulk length if unknown */
        if (c->bulk_len == -1) {
            newline = strchr(c->read_buf + pos, '\r');
            if (newline == NULL) {
                if (sdslen(c->read_buf) > MAX_INLINE_READ) {
                    srv_log(LOG_ERROR, "protocol error: too big bulk count string");
                    set_protocol_err(c, 0);
                    return SUBCLI_ERR;
                }
                break;
            }

            /* Buffer should also contain \n */
            if (newline-(c->read_buf) > ((signed)sdslen(c->read_buf)-2)) {
                break;
            }

            if (c->read_buf[pos] != '$') {
                srv_log(LOG_ERROR, "Protocol error: expected '$', got '%c'",
                        c->read_buf[pos]);
                set_protocol_err(c, pos);
                return SUBCLI_ERR;
            }

            ok = string2ll(c->read_buf+pos+1, newline-(c->read_buf+pos+1), &ll);
            if (!ok || ll < 0 || ll > MAX_BULK_LEN) {
                srv_log(LOG_ERROR, "Protocol error: invalid bulk length");
                set_protocol_err(c, pos);
                return SUBCLI_ERR;
            }

            pos += newline - (c->read_buf + pos) + 2;
            c->bulk_len = ll;
        }

        /* Read bulk argument */
        if (sdslen(c->read_buf) - pos < (unsigned)(c->bulk_len + 2)) {
            /* Not enough data (+2 == trailing \r\n) */
            break;
        } else {
            /*c->argv[c->argc++] = create_string_obj(c->read_buf+pos, c->bulk_len);*/
            c->argv[c->argc++] = sdsnewlen(c->read_buf+pos, c->bulk_len);
            pos += c->bulk_len + 2;
        }
        c->bulk_len = -1;
        c->multi_bulk_len--;
    }

    /* Trim to pos */
    if (pos) sdsrange(c->read_buf, pos, -1);

    /* We're done when c->multibulk == 0 */
    if (c->multi_bulk_len == 0) return SUBCLI_OK;

    /* Still not read to process the command */
    return SUBCLI_ERR;
}
Esempio n. 11
0
// 这其实是一个回调函数,会作为参数传入另外一个函数中
static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
    client c = privdata;
    void *reply = NULL;
    REDIS_NOTUSED(el);
    REDIS_NOTUSED(fd);
    REDIS_NOTUSED(mask);

    /* Calculate latency only for the first read event. This means that the
     * server already sent the reply and we need to parse it. Parsing overhead
     * is not part of the latency, so calculate it only once, here. */
    // 计算延时,然后比较延时,取得第一个read的event事件
    if (c->latency < 0) c->latency = ustime()-(c->start);

    if (redisBufferRead(c->context) != REDIS_OK) {
        // 首先判断是否能读
        fprintf(stderr,"Error: %s\n",c->context->errstr);
        exit(1);
    } else {
        while(c->pending) {
            if (redisGetReply(c->context,&reply) != REDIS_OK) {
                fprintf(stderr,"Error: %s\n",c->context->errstr);
                exit(1);
            }
            if (reply != NULL) {
                if (reply == (void*)REDIS_REPLY_ERROR) {
                    // 如果获取reply回复出错,也会直接退出
                    fprintf(stderr,"Unexpected error reply, exiting...\n");
                    exit(1);
                }

                freeReplyObject(reply);
                /* This is an OK for prefix commands such as auth and select.*/
                if (c->prefix_pending > 0) {
                    c->prefix_pending--;
                    // 执行到这里,请求已经执行成功,等待的请求数-1
                    c->pending--;
                    /* Discard prefix commands on first response.*/
                    if (c->prefixlen > 0) {
                        size_t j;
                        sdsrange(c->obuf, c->prefixlen, -1);
                        /* We also need to fix the pointers to the strings
                        * we need to randomize. */
                        for (j = 0; j < c->randlen; j++)
                            c->randptr[j] -= c->prefixlen;
                        c->prefixlen = 0;
                    }
                    continue;
                }

                if (config.requests_finished < config.requests)
                    config.latency[config.requests_finished++] = c->latency;
                c->pending--;
                // 全部处理完毕,调用客户端done完成后的方法
                if (c->pending == 0) {
                    clientDone(c);
                    break;
                }
            } else {
                break;
            }
        }
    }
}
Esempio n. 12
0
static void set_protocol_err(sub_client *c, int pos)
{
    srv_log(LOG_DEBUG, "Protocol error from sub client");
    sdsrange(c->read_buf, pos, -1);
}
Esempio n. 13
0
int processMultibulkBuffer(client *c) {
    char *newline = NULL;
    int pos = 0, ok;
    long long ll;

    if (c->multibulklen == 0) {
        /* The client should have been reset */
        serverAssertWithInfo(c,NULL,c->argc == 0);

        /* Multi bulk length cannot be read without a \r\n */
        newline = strchr(c->querybuf,'\r');
        if (newline == NULL) {
            if (sdslen(c->querybuf) > PROTO_INLINE_MAX_SIZE) {
                addReplyError(c,"Protocol error: too big mbulk count string");
                setProtocolError(c,0);
            }
            return C_ERR;
        }

        /* Buffer should also contain \n */
        if (newline-(c->querybuf) > ((signed)sdslen(c->querybuf)-2))
            return C_ERR;

        /* We know for sure there is a whole line since newline != NULL,
         * so go ahead and find out the multi bulk length. */
        serverAssertWithInfo(c,NULL,c->querybuf[0] == '*');
        ok = string2ll(c->querybuf+1,newline-(c->querybuf+1),&ll);
        if (!ok || ll > 1024*1024) {
            addReplyError(c,"Protocol error: invalid multibulk length");
            setProtocolError(c,pos);
            return C_ERR;
        }

        pos = (newline-c->querybuf)+2;
        if (ll <= 0) {
            sdsrange(c->querybuf,pos,-1);
            return C_OK;
        }

        c->multibulklen = ll;

        /* Setup argv array on client structure */
        if (c->argv) free(c->argv);
        c->argv = malloc(sizeof(sds*)*c->multibulklen);
    }

    serverAssertWithInfo(c,NULL,c->multibulklen > 0);
    while(c->multibulklen) {
        /* Read bulk length if unknown */
        if (c->bulklen == -1) {
            newline = strchr(c->querybuf+pos,'\r');
            if (newline == NULL) {
                if (sdslen(c->querybuf) > PROTO_INLINE_MAX_SIZE) {
                    addReplyError(c,
                        "Protocol error: too big bulk count string");
                    setProtocolError(c,0);
                    return C_ERR;
                }
                break;
            }

            /* Buffer should also contain \n */
            if (newline-(c->querybuf) > ((signed)sdslen(c->querybuf)-2))
                break;

            if (c->querybuf[pos] != '$') {
                addReplyErrorFormat(c,
                    "Protocol error: expected '$', got '%c'",
                    c->querybuf[pos]);
                setProtocolError(c,pos);
                return C_ERR;
            }

            ok = string2ll(c->querybuf+pos+1,newline-(c->querybuf+pos+1),&ll);
            if (!ok || ll < 0 || ll > 512*1024*1024) {
                addReplyError(c,"Protocol error: invalid bulk length");
                setProtocolError(c,pos);
                return C_ERR;
            }

            pos += newline-(c->querybuf+pos)+2;
            if (ll >= PROTO_MBULK_BIG_ARG) {
                size_t qblen;

                /* If we are going to read a large object from network
                 * try to make it likely that it will start at c->querybuf
                 * boundary so that we can optimize object creation
                 * avoiding a large copy of data. */
                sdsrange(c->querybuf,pos,-1);
                pos = 0;
                qblen = sdslen(c->querybuf);
                /* Hint the sds library about the amount of bytes this string is
                 * going to contain. */
                if (qblen < (size_t)ll+2)
                    c->querybuf = sdsMakeRoomFor(c->querybuf,ll+2-qblen);
            }
            c->bulklen = ll;
        }

        /* Read bulk argument */
        if (sdslen(c->querybuf)-pos < (unsigned)(c->bulklen+2)) {
            /* Not enough data (+2 == trailing \r\n) */
            break;
        } else {
            /* Optimization: if the buffer contains JUST our bulk element
             * instead of creating a new object by *copying* the sds we
             * just use the current sds string. */
            if (pos == 0 &&
                c->bulklen >= PROTO_MBULK_BIG_ARG &&
                (signed) sdslen(c->querybuf) == c->bulklen+2)
            {
                c->argv[c->argc++] = c->querybuf;
                sdsIncrLen(c->querybuf,-2); /* remove CRLF */
                c->querybuf = sdsempty();
                /* Assume that if we saw a fat argument we'll see another one
                 * likely... */
                c->querybuf = sdsMakeRoomFor(c->querybuf,c->bulklen+2);
                pos = 0;
            } else {
                c->argv[c->argc++] = sdsnewlen(c->querybuf+pos,c->bulklen);
                pos += c->bulklen+2;
            }
            c->bulklen = -1;
            c->multibulklen--;
        }
    }

    /* Trim to pos */
    if (pos) sdsrange(c->querybuf,pos,-1);

    /* We're done when c->multibulk == 0 */
    if (c->multibulklen == 0) return C_OK;

    /* Still not read to process the command */
    return C_ERR;
}
Esempio n. 14
0
static int
conf_pre_validate(rmt_conf *cf)
{
    int ret;
    FILE *fh;
    char line[256];
    dict *organization = NULL;
    sds str = NULL;
    sds org_name = NULL;
    sds *key_value = NULL;
    int key_value_count = 0;
    sds key = NULL;
    conf_value *cv = NULL, **cv_sub;

    if (cf == NULL) {
        return RMT_ERROR;
    }

    fh = cf->fh;
    if (fh == NULL) {
        return RMT_ERROR;
    }

    while (!feof(fh)) {
        if (fgets(line,256,fh) == NULL) {
            if(feof(fh)) break;
            
            log_error("ERROR: Read a line from conf file %s failed: %s", 
                cf->fname, strerror(errno));
            goto error;
        }

        if(str != NULL){
            sdsfree(str);
            str = NULL;
        }

        if(key_value!= NULL){
            sdsfreesplitres(key_value, key_value_count);
            key_value = NULL;
            key_value_count = 0;
        }
        
        ASSERT(str == NULL);
        str = sdsnew(line);
        if(str == NULL){
            log_error("ERROR: Out of memory");
            goto error;
        }

        sdstrim(str, " \n");
        if(strchr(str, '#') != NULL){
            if(str[0] == '#'){
                log_debug(LOG_VVERB, "This line is comment");
                sdsfree(str);
                str = NULL;
                continue;
            }

            sds *content_comment = NULL;
            int content_comment_count = 0;

            content_comment = sdssplitlenonce(str, sdslen(str), 
                "#", 1, &content_comment_count);
            if(content_comment == NULL || content_comment_count != 2){
                log_error("ERROR: Split content and comment error.");
                goto error;
            }

            sdsfree(str);
            str = content_comment[0];
            content_comment[0] = NULL;
            sdsfreesplitres(content_comment, content_comment_count);
        }
        
        log_debug(LOG_VVERB, "%s", str);

        if(sdslen(str) == 0){
            log_debug(LOG_VVERB, "This line is space");
            sdsfree(str);
            str = NULL;
            continue;
        }else if(*str == '['){
            if(sdslen(str) <= 2 || *(str+sdslen(str)-1) != ']') {
                log_error("ERROR: Organization name %s in conf file %s error",
                    str, cf->fname);
                goto error;
            }

            if(key != NULL || cv != NULL){
                ret = conf_key_value_insert(organization, key, cv);
                if(ret != RMT_OK){
                    log_error("ERROR: Key value insert into organization failed");
                    goto error;
                }
                organization = NULL;
                key = NULL;
                cv = NULL;
            }

            ASSERT(org_name == NULL);
            sdsrange(str,1,-2);
            org_name = sdstrim(str, " ");
            str = NULL;

            if(sdslen(org_name) == 0){
                log_error("ERROR: Organization name %s in conf file %s error",
                    str, cf->fname);
                goto error;
            }

            organization = dictCreate(&KeyValueDictType, NULL);
            if(organization == NULL){
                log_error("ERROR: Create dict organization %s failed", 
                    org_name);
                goto error;
            }

            ret = dictAdd(cf->organizations, org_name, organization);
            if(ret != DICT_OK){
                log_error("ERROR: Organization %s in conf file is duplicate", 
                    org_name);
                goto error;
            }
            org_name = NULL;
        }else if(*str == '-'){
            
            if(cv == NULL || cv->type != CONF_VALUE_ARRAY){
                log_error("ERROR: Array %s in conf file %s has wrong conf value",
                    str, cf->fname);
                goto error;
            }

            sdsrange(str,1,-1);
            sdstrim(str, " ");
            
            cv_sub = array_push(cv->value);
            *cv_sub = conf_value_create(CONF_VALUE_STRING);
            if(*cv_sub == NULL){
                log_error("ERROR: Conf value create failed");
                goto error;
            }
            
            (*cv_sub)->value = str;
            str = NULL;
        }else{        
            key_value = sdssplitlenonce(str,sdslen(str),":",1,&key_value_count);
            log_debug(LOG_VVERB, "key_value_count: %d", key_value_count);
            if(key_value == NULL || key_value_count == 0){
                log_error("ERROR: line %s split by : failed", str);
                goto error;
            }else if(key_value_count == 1){
                log_error("ERROR: Line %s in conf file %s has no :", 
                    str, cf->fname);
                goto error;
            }else if(key_value_count == 2){           

                if(key != NULL || cv != NULL){
                    ret = conf_key_value_insert(organization, key, cv);
                    if(ret != RMT_OK){
                        log_error("ERROR: Key value insert into organization failed");
                        goto error;
                    }
                    key = NULL;
                    cv = NULL;
                }

                sdstrim(key_value[0]," ");
                sdstrim(key_value[1]," ");
                
                if(sdslen(key_value[1]) == 0){
                    ASSERT(cv == NULL);
                    cv = conf_value_create(CONF_VALUE_ARRAY);
                    if(cv == NULL){
                        log_error("ERROR: Conf value create failed");
                        goto error;
                    }

                    ASSERT(key == NULL);
                    key = key_value[0];
                    key_value[0] = NULL;
                    
                    continue;
                }

                ASSERT(cv == NULL);
                cv = conf_value_create(CONF_VALUE_STRING);
                if(cv == NULL){
                    log_error("ERROR: Conf value create failed");
                    goto error;
                }

                cv->value = key_value[1];
                key_value[1] = NULL;

                if(organization == NULL){
                    log_error("ERROR: line %s in conf file %s has no organization", 
                        str, cf->fname);
                    goto error;
                }
                ret = dictAdd(organization,key_value[0],cv);
                if(ret != DICT_OK){
                    log_error("ERROR: Key %s in organization of conf file is duplicate", 
                        key_value[0]);
                    goto error;
                }
                key_value[0] = NULL;
                cv = NULL;     
            }else{
                NOT_REACHED();
            }
        }
        
    }

    if(key != NULL || cv != NULL){
        ret = conf_key_value_insert(organization, key, cv);
        if(ret != RMT_OK){
            log_error("ERROR: Key value insert into organization failed");
            goto error;
        }
        key = NULL;
        cv = NULL;
    }

    if(str != NULL){
        sdsfree(str);
        str = NULL;
    }

    if(key_value!= NULL){
        sdsfreesplitres(key_value, key_value_count);
        key_value = NULL;
        key_value_count = 0;
    }

    return RMT_OK;

error:

    if(str != NULL){
        sdsfree(str);
    }

    if(key != NULL){
        sdsfree(key);
    }

    if(org_name != NULL){
        sdsfree(org_name);
    }

    if(key_value != NULL){
        sdsfreesplitres(key_value, key_value_count);
    }

    if(cv != NULL){
        conf_value_destroy(cv);
    }

    return RMT_ERROR;
}
Esempio n. 15
0
static int
processMultiBulk (client_t * c)
{
  char *newline = NULL;
  int pos = 0, ok;
  long long ll;

  if (c->multibulklen == 0)
    {
      newline = strchr (c->querybuf, '\r');
      if (newline == NULL)
	{
	  if (sdslen (c->querybuf) > REDIS_INLINE_MAX_SIZE)
	    {
	      addReplyStr (c,
			   "-ERR Protocol error: too big mbulk count string\r\n");
	      c->flags |= REDIS_CLOSE_AFTER_REPLY;
	    }
	  return -1;
	}
      if (newline - c->querybuf > sdslen (c->querybuf) - 2)
	return -1;

      ok = string2ll (c->querybuf + 1, newline - (c->querybuf + 1), &ll);
      if (!ok || ll > 1024 * 1024)
	{
	  addReplyStr (c,
		       "-ERR Protocol error: invalid multibulk length\r\n");
	  c->flags |= REDIS_CLOSE_AFTER_REPLY;
	  return -1;
	}
      c->multibulklen = ll;
      c->argv = malloc (sizeof (sds) * c->multibulklen);
      c->argvlen = malloc (sizeof (size_t) * c->multibulklen);
      pos = (newline - c->querybuf) + 2;
      if (ll <= 0)
	{
	  sdsrange (c->querybuf, pos, -1);
	  return 0;
	}
    }

  while (c->multibulklen)
    {
      if (c->bulklen == -1)
	{
	  newline = strchr (c->querybuf + pos, '\r');
	  if (newline == NULL)
	    {
	      if (sdslen (c->querybuf) > REDIS_INLINE_MAX_SIZE)
		{
		  addReplyStr (c,
			       "-ERR Protocol error: too big bulk count string\r\n");
		  c->flags |= REDIS_CLOSE_AFTER_REPLY;
		}
	      break;
	    }
	  if (newline - (c->querybuf) > (sdslen (c->querybuf) - 2))
	    break;

	  if (c->querybuf[pos] != '$')
	    {
	      addReplyStr (c, "-ERR Protocol error: expected '$', got '");
	      addReplyStrLen (c, c->querybuf + pos, 1);
	      addReplyStr (c, "'\r\n");
	      c->flags |= REDIS_CLOSE_AFTER_REPLY;
	      return -1;
	    }

	  ok =
	    string2ll (c->querybuf + pos + 1,
		       newline - (c->querybuf + pos + 1), &ll);
	  if (!ok || ll < 0 || ll > 512 * 1024 * 1024)
	    {
	      addReplyStr (c, "-ERR Protocol error: invalid bulk length\r\n");
	      c->flags |= REDIS_CLOSE_AFTER_REPLY;
	      return -1;
	    }

	  pos += newline - (c->querybuf + pos) + 2;
	  c->bulklen = ll;
	}

      if (sdslen (c->querybuf) - pos < (unsigned) (c->bulklen + 2))
	break;
      c->argvlen[c->argc] = c->bulklen;
      c->argv[c->argc++] = sdsnewlen (c->querybuf + pos, c->bulklen);
      pos += c->bulklen + 2;
      c->bulklen = -1;
      c->multibulklen--;
    }

  if (pos)
    sdsrange (c->querybuf, pos, -1);
  if (c->multibulklen)
    return -1;

  if (c->argc == 1 && sdslen (c->argv[0]) == 4
      && !strcasecmp (c->argv[0], "quit"))
    {
      addReplyStrLen (c, "+OK\r\n", 5);
      c->flags |= REDIS_CLOSE_AFTER_REPLY;
      return -1;
    }
  arc_append_commandcv (c->rqst, c->argc, (const char **) c->argv,
			c->argvlen);
  c->total_append_command++;
  return 0;
}
Esempio n. 16
0
static void *
clientThread (void *arg)
{
  client_t *c = (client_t *) arg;
  fd_set rfds, wfds;
  int ret;

  c->querybuf = sdsMakeRoomFor (sdsempty (), DEFAULT_QUERY_BUF_SIZE);
  c->replybuf = sdsMakeRoomFor (sdsempty (), DEFAULT_QUERY_BUF_SIZE);
  c->argc = 0;
  c->argv = NULL;
  c->argvlen = NULL;
  c->reqtype = 0;
  c->multibulklen = 0;
  c->bulklen = -1;
  c->rqst = arc_create_request ();
  c->flags = 0;
  c->total_append_command = 0;

  FD_ZERO (&rfds);
  FD_ZERO (&wfds);

  while (1)
    {
      struct timeval timeout;

      FD_CLR (c->fd, &rfds);
      FD_CLR (c->fd, &wfds);
      if (!(c->flags & REDIS_CLOSE_AFTER_REPLY))
	FD_SET (c->fd, &rfds);
      if (sdslen (c->replybuf) > 0)
	FD_SET (c->fd, &wfds);

      timeout.tv_sec = 1;
      timeout.tv_usec = 0;
      ret = select (c->fd + 1, &rfds, &wfds, NULL, &timeout);
      if (ret == -1)
	{
	  perror ("select");
	  freeClient (c);
	}

      if (server.shutdown_signal)
	{
	  c->flags |= REDIS_CLOSE_AFTER_REPLY;
	}

      /* readable */
      if (FD_ISSET (c->fd, &rfds))
	{
	  int pos = sdslen (c->querybuf);
	  int avail = sdsavail (c->querybuf);
	  ssize_t nread;

	  if (avail == 0)
	    {
	      c->querybuf =
		sdsMakeRoomFor (c->querybuf, sdslen (c->querybuf));
	      avail = sdsavail (c->querybuf);
	    }

	  nread = read (c->fd, c->querybuf + pos, avail);
	  if (nread > 0)
	    {
	      sdsIncrLen (c->querybuf, nread);
	      processInputBuffer (c);
	      if (c->total_append_command)
		{
		  int arc_errno, arc_be_errno, be_errno;
		  arc_ref_t *arc_ref;

		  arc_ref = acquire_arc_ref ();
		  ret =
		    arc_do_request (arc_ref->arc, c->rqst,
				    server.query_timeout_millis, &be_errno);
		  if (ret == -1)
		    {
		      arc_errno = errno;
		      arc_be_errno = be_errno;
		    }
		  else
		    {
		      ret = processReply (c, &be_errno);
		      if (ret == -1)
			{
			  arc_errno = errno;
			  arc_be_errno = be_errno;
			}
		    }
		  arc_free_request (c->rqst);
		  release_arc_ref (arc_ref);

		  c->rqst = arc_create_request ();

		  if (ret == -1)
		    {
		      if (arc_errno == ARC_ERR_TIMEOUT
			  || (arc_errno == ARC_ERR_BACKEND
			      && arc_be_errno == ARC_ERR_TIMEOUT))
			{
			  addReplyStr (c, "-ERR Redis Timeout\r\n");
			}
		      else
			{
			  addReplyStr (c, "-ERR Internal Error\r\n");
			}
		      c->flags |= REDIS_CLOSE_AFTER_REPLY;
		    }
		}
	    }
	  else
	    {
	      if (nread == -1 && errno == EAGAIN)
		{
		  /* Skip */
		}
	      else
		{
		  freeClient (c);
		}
	    }
	}

      /* writable */
      if (FD_ISSET (c->fd, &wfds))
	{
	  int pos = 0;
	  int avail = sdslen (c->replybuf);
	  ssize_t nwritten;

	  nwritten = write (c->fd, c->replybuf + pos, avail);
	  if (nwritten > 0)
	    {
	      avail -= nwritten;
	      pos += nwritten;
	      sdsrange (c->replybuf, pos, -1);
	    }
	  else
	    {
	      if (nwritten == -1 && errno == EAGAIN)
		{
		  /* Skip */
		}
	      else
		{
		  freeClient (c);
		}
	    }
	}

      if (sdslen (c->replybuf) == 0 && (c->flags & REDIS_CLOSE_AFTER_REPLY))
	{
	  freeClient (c);
	}
    }
  return NULL;
}